2014-11-20 13:21:19 +00:00
/ *
* Copyright ( C ) 2010 - 2014 Laurent CLOUET
* Author Laurent CLOUET < laurent . clouet @nopnop.net >
*
2020-05-28 13:28:42 +02:00
* This program is free software ; you can redistribute it and / or
2014-11-20 13:21:19 +00:00
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; version 2
* of the License .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 , USA .
* /
package com.sheepit.client.standalone ;
import org.kohsuke.args4j.CmdLineException ;
import org.kohsuke.args4j.CmdLineParser ;
import org.kohsuke.args4j.Option ;
2020-04-09 23:39:09 +08:00
import org.kohsuke.args4j.OptionHandlerFilter ;
2014-11-20 13:21:19 +00:00
import java.io.File ;
import java.net.MalformedURLException ;
import java.text.ParseException ;
import java.text.SimpleDateFormat ;
import java.util.Calendar ;
import java.util.LinkedList ;
2020-05-28 13:28:42 +02:00
2014-11-20 13:21:19 +00:00
import com.sheepit.client.Client ;
import com.sheepit.client.Configuration ;
import com.sheepit.client.Configuration.ComputeType ;
import com.sheepit.client.Gui ;
import com.sheepit.client.Log ;
import com.sheepit.client.Pair ;
2015-04-08 20:45:54 +01:00
import com.sheepit.client.SettingsLoader ;
2014-11-20 13:21:19 +00:00
import com.sheepit.client.ShutdownHook ;
2019-02-20 13:53:18 +01:00
import com.sheepit.client.Utils ;
2014-11-20 13:21:19 +00:00
import com.sheepit.client.hardware.gpu.GPU ;
import com.sheepit.client.hardware.gpu.GPUDevice ;
2018-08-24 19:46:03 +02:00
import com.sheepit.client.hardware.gpu.nvidia.Nvidia ;
import com.sheepit.client.hardware.gpu.opencl.OpenCL ;
2015-07-06 18:41:28 +01:00
import com.sheepit.client.network.Proxy ;
2014-11-20 13:21:19 +00:00
public class Worker {
2020-05-28 13:28:42 +02:00
@Option ( name = " -server " , usage = " Render-farm server, default https://client.sheepit-renderfarm.com " , metaVar = " URL " , required = false ) private String server = " https://client.sheepit-renderfarm.com " ;
2014-11-20 13:21:19 +00:00
2020-05-28 13:28:42 +02:00
@Option ( name = " -login " , usage = " User's login " , metaVar = " LOGIN " , required = false ) private String login = " " ;
2014-11-20 13:21:19 +00:00
2020-06-27 01:52:00 +02:00
@Option ( name = " -password " , usage = " User's password or public key (accessible under the Keys tab of the profile page) " , metaVar = " PASSWORD " , required = false ) private String password = " " ;
2014-11-20 13:21:19 +00:00
2020-05-28 13:28:42 +02:00
@Option ( name = " -cache-dir " , usage = " Cache/Working directory. Caution, everything in it not related to the render-farm will be removed " , metaVar = " /tmp/cache " , required = false ) private String cache_dir = null ;
2014-11-20 13:21:19 +00:00
2020-05-28 13:28:42 +02:00
@Option ( name = " -gpu " , usage = " Name of the GPU used for the render, for example CUDA_0 for Nvidia or OPENCL_0 for AMD/Intel card " , metaVar = " CUDA_0 " , required = false ) private String gpu_device = null ;
2014-11-20 13:21:19 +00:00
2020-05-28 13:28:42 +02:00
@Option ( name = " --no-gpu " , usage = " Don't detect GPUs " , required = false ) private boolean no_gpu_detection = false ;
2018-08-24 19:46:03 +02:00
2020-05-28 13:28:42 +02:00
@Option ( name = " -compute-method " , usage = " CPU: only use cpu, GPU: only use gpu, CPU_GPU: can use cpu and gpu (not at the same time) if -gpu is not use it will not use the gpu " , metaVar = " CPU " , required = false ) private String method = null ;
2014-11-20 13:21:19 +00:00
2020-05-28 13:28:42 +02:00
@Option ( name = " -cores " , usage = " Number of cores/threads to use for the render " , metaVar = " 3 " , required = false ) private int nb_cores = - 1 ;
2014-11-20 13:21:19 +00:00
2020-05-28 13:28:42 +02:00
@Option ( name = " -memory " , usage = " Maximum memory allow to be used by renderer, number with unit (800M, 2G, ...) " , required = false ) private String max_ram = null ;
2017-04-04 23:06:31 +02:00
2020-05-28 13:28:42 +02:00
@Option ( name = " -rendertime " , usage = " Maximum time allow for each frame (in minutes) " , required = false ) private int max_rendertime = - 1 ;
2017-04-25 13:06:23 +02:00
2020-05-28 13:28:42 +02:00
@Option ( name = " --verbose " , usage = " Display log " , required = false ) private boolean print_log = false ;
2014-11-20 13:21:19 +00:00
2020-05-28 13:28:42 +02:00
@Option ( name = " -request-time " , usage = " H1:M1-H2:M2,H3:M3-H4:M4 Use the 24h format. For example to request job between 2am-8.30am and 5pm-11pm you should do --request-time 2:00-8:30,17:00-23:00 Caution, it's the requesting job time to get a project, not the working time " , metaVar = " 2:00-8:30,17:00-23:00 " , required = false ) private String request_time = null ;
2014-11-20 13:21:19 +00:00
2020-05-28 13:28:42 +02:00
@Option ( name = " -proxy " , usage = " URL of the proxy " , metaVar = " http://login:password@host:port " , required = false ) private String proxy = null ;
2014-11-20 13:21:19 +00:00
2020-05-28 13:28:42 +02:00
@Option ( name = " -extras " , usage = " Extras data push on the authentication request " , required = false ) private String extras = null ;
2014-11-20 13:21:19 +00:00
2020-05-28 13:28:42 +02:00
@Option ( name = " -ui " , usage = " Specify the user interface to use, default ' " + GuiSwing . type + " ', available ' " + GuiTextOneLine . type + " ', ' "
+ GuiText . type + " ', ' " + GuiSwing . type + " ' (graphical) " , required = false ) private String ui_type = null ;
2014-11-20 17:50:23 +00:00
2020-05-28 13:28:42 +02:00
@Option ( name = " -config " , usage = " Specify the configuration file " , required = false ) private String config_file = null ;
2015-04-07 20:07:53 +01:00
2020-05-28 13:28:42 +02:00
@Option ( name = " --version " , usage = " Display application version " , required = false , handler = VersionParameterHandler . class ) private VersionParameterHandler versionHandler ;
2014-11-20 13:21:19 +00:00
2020-05-28 13:28:42 +02:00
@Option ( name = " --show-gpu " , usage = " Print available CUDA devices and exit " , required = false , handler = ListGpuParameterHandler . class ) private ListGpuParameterHandler listGpuParameterHandler ;
2017-01-19 18:08:26 +01:00
2020-06-09 14:47:39 +10:00
@Option ( name = " --no-systray " , usage = " Don't use SysTray " , required = false ) private boolean useSysTray = false ;
2016-04-28 19:37:05 +02:00
2020-05-28 13:28:42 +02:00
@Option ( name = " -priority " , usage = " Set render process priority (19 lowest to -19 highest) " , required = false ) private int priority = 19 ;
2017-01-05 09:58:27 +01:00
2020-05-28 13:28:42 +02:00
@Option ( name = " -title " , usage = " Custom title for the GUI Client " , required = false ) private String title = " SheepIt Render Farm " ;
@Option ( name = " -theme " , usage = " Specify the theme to use for the graphical client, default 'light', available 'light', 'dark' " , required = false ) private String theme = null ;
@Option ( name = " -renderbucket-size " , usage = " Set a custom GPU renderbucket size (32 for 32x32px, 64 for 64x64px, and so on). NVIDIA GPUs support a maximum renderbucket size of 512x512 pixel, while AMD GPUs support a maximum 2048x2048 pixel renderbucket size. Minimum renderbucket size is 32 pixels for all GPUs " , required = false ) private int renderbucketSize = - 1 ;
2020-05-16 18:20:38 +10:00
2014-11-20 13:21:19 +00:00
public static void main ( String [ ] args ) {
new Worker ( ) . doMain ( args ) ;
}
public void doMain ( String [ ] args ) {
CmdLineParser parser = new CmdLineParser ( this ) ;
try {
parser . parseArgument ( args ) ;
}
catch ( CmdLineException e ) {
System . err . println ( e . getMessage ( ) ) ;
System . err . println ( " Usage: " ) ;
parser . printUsage ( System . err ) ;
System . err . println ( ) ;
2020-04-09 23:39:09 +08:00
System . err . println ( " Example: java " + this . getClass ( ) . getName ( ) + " " + parser . printExample ( OptionHandlerFilter . REQUIRED ) ) ;
2014-11-20 13:21:19 +00:00
return ;
}
2020-06-21 02:31:31 +10:00
ComputeType compute_method = null ;
2014-11-20 13:21:19 +00:00
Configuration config = new Configuration ( null , login , password ) ;
config . setPrintLog ( print_log ) ;
2017-01-05 09:58:27 +01:00
config . setUsePriority ( priority ) ;
2020-05-28 13:28:42 +02:00
config . setDetectGPUs ( ! no_gpu_detection ) ;
2014-11-20 13:21:19 +00:00
if ( cache_dir ! = null ) {
File a_dir = new File ( cache_dir ) ;
2016-11-26 20:42:45 +01:00
a_dir . mkdirs ( ) ;
2014-11-20 13:21:19 +00:00
if ( a_dir . isDirectory ( ) & & a_dir . canWrite ( ) ) {
config . setCacheDir ( a_dir ) ;
}
}
2020-04-15 17:40:51 +10:00
// We set a hard limit of 3 concurrent uploads. As the server doesn't allocate more than 3 concurrent jobs to
// a single session to avoid any client taking too many frames and not validating them, we throttle the uploads.
// If we don't set this limit, in a computer with slow uploads the server will return a "no job available" when
// the 4th concurrent job is requested and that will put the client in "wait" mode for some random time. To
// avoid that situation we set this limit.
config . setMaxUploadingJob ( 3 ) ;
2014-11-20 13:21:19 +00:00
2020-06-09 14:47:39 +10:00
// Store the SysTray preference from the user. Please note that we must ! the value of the variable because the way args4j works. If the --no-systray
// parameter is detected, args4j will store (boolean)true in the useSysTray variable but we want to store (boolean)false in the configuration class
// for further checks.
config . setUseSysTray ( ! useSysTray ) ;
2014-11-20 13:21:19 +00:00
if ( gpu_device ! = null ) {
2018-08-24 19:46:03 +02:00
if ( gpu_device . startsWith ( Nvidia . TYPE ) = = false & & gpu_device . startsWith ( OpenCL . TYPE ) = = false ) {
2020-05-28 23:05:19 +10:00
System . err . println ( " ERROR: The entered GPU_ID is invalid. The GPU_ID should look like ' " + Nvidia . TYPE + " _#' or ' " + OpenCL . TYPE
+ " _#'. Please use the proper GPU_ID from the GPU list below \ n " ) ;
showGPUList ( parser ) ;
2014-11-20 13:21:19 +00:00
}
2020-05-28 23:05:19 +10:00
2014-11-20 13:21:19 +00:00
GPUDevice gpu = GPU . getGPUDevice ( gpu_device ) ;
if ( gpu = = null ) {
2020-05-28 23:05:19 +10:00
System . err . println ( " ERROR: The entered GPU_ID is invalid. Please use the proper GPU_ID from the GPU list below \ n " ) ;
showGPUList ( parser ) ;
2014-11-20 13:21:19 +00:00
}
2019-08-07 22:17:59 +02:00
config . setGPUDevice ( gpu ) ;
2014-11-20 13:21:19 +00:00
}
if ( request_time ! = null ) {
String [ ] intervals = request_time . split ( " , " ) ;
if ( intervals ! = null ) {
2019-08-07 22:17:59 +02:00
config . setRequestTime ( new LinkedList < Pair < Calendar , Calendar > > ( ) ) ;
2014-11-20 13:21:19 +00:00
SimpleDateFormat timeFormat = new SimpleDateFormat ( " HH:mm " ) ;
for ( String interval : intervals ) {
String [ ] times = interval . split ( " - " ) ;
if ( times ! = null & & times . length = = 2 ) {
Calendar start = Calendar . getInstance ( ) ;
Calendar end = Calendar . getInstance ( ) ;
try {
start . setTime ( timeFormat . parse ( times [ 0 ] ) ) ;
end . setTime ( timeFormat . parse ( times [ 1 ] ) ) ;
}
catch ( ParseException e ) {
2020-05-28 23:05:19 +10:00
System . err . println ( String . format (
" ERROR: The entered time slot (-request-time parameter) doesn't seem to be valid. Please check the format is correct [%s] " ,
e . getMessage ( ) ) ) ;
2014-11-20 13:21:19 +00:00
System . exit ( 2 ) ;
}
if ( start . before ( end ) ) {
2019-08-07 22:17:59 +02:00
config . getRequestTime ( ) . add ( new Pair < Calendar , Calendar > ( start , end ) ) ;
2014-11-20 13:21:19 +00:00
}
else {
2020-05-28 23:05:19 +10:00
System . err . println ( String . format ( " ERROR: The start (%s) time must be earlier than the finish (%s) time " , times [ 0 ] , times [ 1 ] ) ) ;
2014-11-20 13:21:19 +00:00
System . exit ( 2 ) ;
}
}
}
}
}
2014-11-30 23:49:17 +00:00
if ( nb_cores < - 1 | | nb_cores = = 0 ) { // -1 is the default
2020-05-28 23:05:19 +10:00
System . err . println ( " ERROR: The entered number of CPU cores (-cores parameter) is not valid. Please enter a number greater than zero " ) ;
2014-11-20 13:21:19 +00:00
return ;
}
else {
2019-08-07 22:17:59 +02:00
config . setNbCores ( nb_cores ) ;
2014-11-20 13:21:19 +00:00
}
2019-02-20 13:53:18 +01:00
if ( max_ram ! = null ) {
try {
config . setMaxMemory ( Utils . parseNumber ( max_ram ) / 1000 ) ; // internal value are in kB
}
catch ( java . lang . IllegalStateException e ) {
2020-05-28 23:05:19 +10:00
System . err . println (
String . format ( " ERROR: The entered value of maximum memory (-memory parameter) doesn't seem to be a valid number [%s] " , e . getMessage ( ) ) ) ;
2019-02-20 13:53:18 +01:00
return ;
}
2017-04-04 23:06:31 +02:00
}
2017-04-25 13:06:23 +02:00
if ( max_rendertime > 0 ) {
config . setMaxRenderTime ( max_rendertime * 60 ) ;
}
2014-11-20 13:21:19 +00:00
if ( method ! = null ) {
2015-03-31 22:04:09 +01:00
try {
compute_method = ComputeType . valueOf ( method ) ;
2014-11-20 13:21:19 +00:00
}
2015-03-31 22:04:09 +01:00
catch ( IllegalArgumentException e ) {
2020-05-28 23:05:19 +10:00
System . err . println ( String . format (
" ERROR: The entered compute method (-compute-method parameter) is not valid. Available values are CPU, GPU or CPU_GPU [%s] " ,
e . getMessage ( ) ) ) ;
2014-11-20 13:21:19 +00:00
System . exit ( 2 ) ;
}
}
2014-12-02 20:21:12 +00:00
else {
2020-06-21 02:31:31 +10:00
if ( config . getGPUDevice ( ) ! = null ) {
2015-04-07 20:05:48 +01:00
compute_method = ComputeType . GPU ;
2014-12-02 20:21:12 +00:00
}
}
2014-11-20 13:21:19 +00:00
if ( proxy ! = null ) {
try {
2015-07-06 18:41:28 +01:00
Proxy . set ( proxy ) ;
2014-11-20 13:21:19 +00:00
}
catch ( MalformedURLException e ) {
2020-05-28 23:05:19 +10:00
System . err . println ( String . format ( " ERROR: The entered proxy URL (-proxy parameter) doesn't seem to have the right format. Please check it [%s] " ,
e . getMessage ( ) ) ) ;
2014-11-20 13:21:19 +00:00
System . exit ( 2 ) ;
}
}
if ( extras ! = null ) {
config . setExtras ( extras ) ;
}
2020-06-21 02:31:31 +10:00
if ( compute_method ! = null ) {
if ( compute_method = = ComputeType . CPU & & config . getGPUDevice ( ) ! = null ) {
System . err . println (
2020-05-28 23:05:19 +10:00
" ERROR: The compute method is set to use CPU only, but a GPU has also been specified. Change the compute method to CPU_GPU or remove the GPU " ) ;
2020-06-21 02:31:31 +10:00
System . exit ( 2 ) ;
}
else if ( compute_method = = ComputeType . CPU_GPU & & config . getGPUDevice ( ) = = null ) {
System . err . println (
2020-05-28 23:05:19 +10:00
" ERROR: The compute method is set to use both CPU and GPU, but no GPU has been specified. Change the compute method to CPU or add a GPU (via -gpu parameter) " ) ;
2020-06-21 02:31:31 +10:00
System . exit ( 2 ) ;
}
else if ( compute_method = = ComputeType . GPU & & config . getGPUDevice ( ) = = null ) {
System . err . println ( " ERROR: The compute method is set to use GPU only, but not GPU has been specified. Please add a GPU (via -gpu parameter) " ) ;
System . exit ( 2 ) ;
}
else if ( compute_method = = ComputeType . CPU ) {
config . setGPUDevice ( null ) ; // remove the GPU
}
2014-12-02 20:21:12 +00:00
}
config . setComputeMethod ( compute_method ) ;
2014-11-20 13:21:19 +00:00
2020-05-16 18:20:38 +10:00
// Change the default configuration if the user has specified a minimum renderbucket size of 32
2020-06-21 19:21:23 +10:00
if ( renderbucketSize > = GPU . MIN_RENDERBUCKET_SIZE ) {
2020-05-16 18:20:38 +10:00
// Send the proposed renderbucket size and check if viable
config . setRenderbucketSize ( renderbucketSize ) ;
}
2015-04-08 20:37:53 +01:00
if ( ui_type ! = null ) {
config . setUIType ( ui_type ) ;
}
2020-04-14 23:24:28 +10:00
if ( theme ! = null ) {
if ( ! theme . equals ( " light " ) & & ! theme . equals ( " dark " ) ) {
2020-05-28 23:05:19 +10:00
System . err . println ( " ERROR: The entered theme (-theme parameter) doesn't exist. Please choose either 'light' or 'dark' " ) ;
2020-04-14 23:24:28 +10:00
System . exit ( 2 ) ;
}
2020-05-28 13:28:42 +02:00
2020-04-14 23:24:28 +10:00
config . setTheme ( this . theme ) ;
}
2020-05-28 13:28:42 +02:00
2015-04-07 20:07:53 +01:00
if ( config_file ! = null ) {
if ( new File ( config_file ) . exists ( ) = = false ) {
2020-05-28 23:05:19 +10:00
System . err . println (
" ERROR: The entered configuration file (-config parameter) cannot be loaded. Please check that you've entered an existing filename " ) ;
2015-04-07 20:07:53 +01:00
System . exit ( 2 ) ;
}
2019-08-07 22:17:59 +02:00
config . setConfigFilePath ( config_file ) ;
2015-04-07 20:07:53 +01:00
}
2020-06-09 14:47:39 +10:00
new SettingsLoader ( config_file ) . merge ( config ) ;
2014-11-20 13:21:19 +00:00
Log . getInstance ( config ) . debug ( " client version " + config . getJarVersion ( ) ) ;
2014-11-20 17:50:23 +00:00
Gui gui ;
2015-04-08 20:37:53 +01:00
String type = config . getUIType ( ) ;
if ( type = = null ) {
type = " swing " ;
}
switch ( type ) {
2015-04-08 20:32:24 +01:00
case GuiTextOneLine . type :
2019-08-07 22:17:59 +02:00
if ( config . isPrintLog ( ) ) {
2020-05-28 23:05:19 +10:00
System . err . println (
" ERROR: The oneLine UI and the --verbose parameter cannot be used at the same time. Please either change the ui to text or remove the verbose mode " ) ;
2015-01-28 20:11:57 +00:00
System . exit ( 2 ) ;
}
gui = new GuiTextOneLine ( ) ;
break ;
2015-04-08 20:37:53 +01:00
case GuiText . type :
gui = new GuiText ( ) ;
break ;
default :
2015-04-08 20:32:24 +01:00
case GuiSwing . type :
2015-01-28 20:11:57 +00:00
if ( java . awt . GraphicsEnvironment . isHeadless ( ) ) {
2020-05-28 23:05:19 +10:00
System . err . println ( " ERROR: Your current configuration doesn't support graphical UI. " ) ;
System . err . println ( " Please use one of the text-based UIs provided (using -ui " + GuiTextOneLine . type + " or -ui " + GuiText . type + " ) " ) ;
2015-01-28 20:11:57 +00:00
System . exit ( 3 ) ;
}
2020-06-09 14:47:39 +10:00
gui = new GuiSwing ( config . isUseSysTray ( ) , title ) ;
2015-01-28 20:11:57 +00:00
break ;
2014-11-20 17:50:23 +00:00
}
2014-11-20 13:21:19 +00:00
Client cli = new Client ( gui , config , server ) ;
2015-01-15 23:20:17 +01:00
gui . setClient ( cli ) ;
2014-11-20 13:21:19 +00:00
ShutdownHook hook = new ShutdownHook ( cli ) ;
hook . attachShutDownHook ( ) ;
2015-01-15 23:20:17 +01:00
gui . start ( ) ;
2014-11-20 13:21:19 +00:00
}
2020-05-28 23:05:19 +10:00
private void showGPUList ( CmdLineParser parser ) {
try {
parser . parseArgument ( " --show-gpu " ) ;
}
catch ( CmdLineException e ) {
System . err . println ( String . format ( " ERROR: Unable to parse the provided parameter [%s] " , e . getMessage ( ) ) ) ;
}
}
2014-11-20 13:21:19 +00:00
}