From 01abee0f700c2f563d403d4f7e5c442dcc422ca2 Mon Sep 17 00:00:00 2001 From: Laurent Clouet Date: Wed, 6 May 2015 20:34:59 +0100 Subject: [PATCH] Cleanup: move Job render call to Job class --- src/com/sheepit/client/Client.java | 343 +--------------------------- src/com/sheepit/client/Job.java | 352 ++++++++++++++++++++++++++++- src/com/sheepit/client/Server.java | 2 + 3 files changed, 355 insertions(+), 342 deletions(-) diff --git a/src/com/sheepit/client/Client.java b/src/com/sheepit/client/Client.java index 46bdc6b..fd180d6 100644 --- a/src/com/sheepit/client/Client.java +++ b/src/com/sheepit/client/Client.java @@ -19,25 +19,14 @@ package com.sheepit.client; -import java.io.BufferedReader; import java.io.File; import java.io.FileOutputStream; -import java.io.FileWriter; -import java.io.FilenameFilter; import java.io.IOException; -import java.io.InputStreamReader; import java.io.PrintWriter; import java.io.StringWriter; -import java.text.DateFormat; -import java.text.ParseException; -import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.TimeZone; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; @@ -47,13 +36,9 @@ import com.sheepit.client.exception.FermeException; import com.sheepit.client.exception.FermeExceptionNoRightToRender; import com.sheepit.client.exception.FermeExceptionNoSession; import com.sheepit.client.exception.FermeExceptionSessionDisabled; -import com.sheepit.client.hardware.gpu.GPUDevice; import com.sheepit.client.os.OS; public class Client { - public static final String UPDATE_METHOD_BY_REMAINING_TIME = "remainingtime"; - public static final String UPDATE_METHOD_BLENDER_INTERNAL_BY_PART = "blenderinternal"; - private Gui gui; private Server server; private Configuration config; @@ -102,6 +87,10 @@ public class Client { return this.server; } + public Log getLog() { + return this.log; + } + public int run() { if (this.config.checkOSisSupported() == false) { this.gui.error(Error.humanString(Error.Type.OS_NOT_SUPPORTED)); @@ -512,7 +501,7 @@ public class Client { return Error.Type.MISSING_RENDER; } - Error.Type err = this.runRenderer(ajob); + Error.Type err = ajob.render(); if (err != Error.Type.OK) { this.log.error("Client::work problem with runRenderer (ret " + err + ")"); return err; @@ -521,188 +510,6 @@ public class Client { return Error.Type.OK; } - protected Error.Type runRenderer(Job ajob) { - this.gui.status("Rendering"); - RenderProcess process = ajob.getProcessRender(); - String core_script = "import bpy\n" + "bpy.context.user_preferences.system.compute_device_type = \"%s\"\n" + "bpy.context.scene.cycles.device = \"%s\"\n" + "bpy.context.user_preferences.system.compute_device = \"%s\"\n"; - if (ajob.getUseGPU() && this.config.getGPUDevice() != null) { - core_script = String.format(core_script, "CUDA", "GPU", this.config.getGPUDevice().getCudaName()); - } - else { - core_script = String.format(core_script, "NONE", "CPU", "CPU"); - } - core_script += String.format("bpy.context.scene.render.tile_x = %1$d\nbpy.context.scene.render.tile_y = %1$d\n", this.getTileSize(ajob)); - File script_file = null; - String command1[] = ajob.getRenderCommand().split(" "); - int size_command = command1.length + 2; // + 2 for script - - if (this.config.getNbCores() > 0) { // user has specified something - size_command += 2; - } - - List command = new ArrayList(size_command); - - Map new_env = new HashMap(); - - new_env.put("BLENDER_USER_CONFIG", this.config.workingDirectory.getAbsolutePath().replace("\\", "\\\\")); - - for (String arg : command1) { - switch (arg) { - case ".c": - command.add(ajob.getScenePath()); - command.add("-P"); - - try { - script_file = File.createTempFile("script_", "", this.config.workingDirectory); - File file = new File(script_file.getAbsolutePath()); - FileWriter txt; - txt = new FileWriter(file); - - PrintWriter out = new PrintWriter(txt); - out.write(ajob.getScript()); - out.write("\n"); - out.write(core_script); // GPU part - out.write("\n"); // GPU part - out.close(); - - command.add(script_file.getAbsolutePath()); - } - catch (IOException e) { - StringWriter sw = new StringWriter(); - e.printStackTrace(new PrintWriter(sw)); - this.log.error("Client:runRenderer exception on script generation, will return UNKNOWN " + e + " stacktrace " + sw.toString()); - return Error.Type.UNKNOWN; - } - script_file.deleteOnExit(); - break; - case ".e": - command.add(ajob.getRendererPath()); - // the number of cores has to be put after the binary and before the scene arg - if (this.config.getNbCores() > 0) { - command.add("-t"); - command.add(Integer.toString(this.config.getNbCores())); - } - break; - case ".o": - command.add(this.config.workingDirectory.getAbsolutePath() + File.separator + ajob.getPrefixOutputImage()); - break; - case ".f": - command.add(ajob.getFrameNumber()); - break; - default: - command.add(arg); - break; - } - } - - try { - String line; - this.log.debug(command.toString()); - OS os = OS.getOS(); - process.start(); - ajob.getProcessRender().setProcess(os.exec(command, new_env)); - BufferedReader input = new BufferedReader(new InputStreamReader(ajob.getProcessRender().getProcess().getInputStream())); - - long last_update_status = 0; - this.log.debug("renderer output"); - try { - while ((line = input.readLine()) != null) { - this.updateRenderingMemoryPeak(line, ajob); - - this.log.debug(line); - if ((new Date().getTime() - last_update_status) > 2000) { // only call the update every two seconds - this.updateRenderingStatus(line, ajob); - last_update_status = new Date().getTime(); - } - Type error = this.detectError(line, ajob); - if (error != Error.Type.OK) { - if (script_file != null) { - script_file.delete(); - } - return error; - } - } - input.close(); - } - catch (IOException err1) { // for the input.readline - // most likely The handle is invalid - this.log.error("Client:runRenderer exception(B) (silent error) " + err1); - } - this.log.debug("end of rendering"); - } - catch (Exception err) { - if (script_file != null) { - script_file.delete(); - } - StringWriter sw = new StringWriter(); - err.printStackTrace(new PrintWriter(sw)); - this.log.error("Client:runRenderer exception(A) " + err + " stacktrace " + sw.toString()); - return Error.Type.FAILED_TO_EXECUTE; - } - - int exit_value = process.exitValue(); - process.finish(); - - if (script_file != null) { - script_file.delete(); - } - - // find the picture file - final String filename_without_extension = ajob.getPrefixOutputImage() + ajob.getFrameNumber(); - - FilenameFilter textFilter = new FilenameFilter() { - public boolean accept(File dir, String name) { - return name.startsWith(filename_without_extension); - } - }; - - File[] files = this.config.workingDirectory.listFiles(textFilter); - - if (files.length == 0) { - this.log.error("Client::runRenderer no picture file found (after finished render (filename_without_extension " + filename_without_extension + ")"); - - if (ajob.getAskForRendererKill()) { - this.log.debug("Client::runRenderer renderer didn't generate any frame but died due to a kill request"); - return Error.Type.RENDERER_KILLED; - } - - String basename = ""; - try { - basename = ajob.getPath().substring(0, ajob.getPath().lastIndexOf('.')); - } - catch (Exception e) { - e.printStackTrace(); - } - File crash_file = new File(this.config.workingDirectory + File.separator + basename + ".crash.txt"); - if (crash_file.exists()) { - this.log.error("Client::runRenderer crash file found => the renderer crashed"); - crash_file.delete(); - return Error.Type.RENDERER_CRASHED; - } - - if (exit_value == 127 && process.getDuration() < 10) { - this.log.error("Client::runRenderer renderer returned 127 and took " + process.getDuration() + "s, some libraries may be missing"); - return Error.Type.RENDERER_MISSING_LIBRARIES; - } - - return Error.Type.NOOUTPUTFILE; - } - else { - ajob.setOutputImagePath(files[0].getAbsolutePath()); - this.log.debug("Client::runRenderer pictureFilename: '" + ajob.getOutputImagePath() + "'"); - } - - File scene_dir = new File(ajob.getSceneDirectory()); - long date_modification_scene_directory = (long) Utils.lastModificationTime(scene_dir); - if (date_modification_scene_directory > process.getStartTime()) { - scene_dir.delete(); - } - - this.gui.status(String.format("Frame rendered in %dmin%ds", process.getDuration() / 60, process.getDuration() % 60)); - - return Error.Type.OK; - } - protected int downloadSceneFile(Job ajob_) { this.gui.status("Downloading project"); return this.downloadFile(ajob_, ajob_.getSceneArchivePath(), ajob_.getSceneMD5(), String.format("%s?type=job&job=%s&revision=%s", this.server.getPage("download-archive"), ajob_.getId(), ajob_.getRevision()), "Downloading project %s %%"); @@ -875,144 +682,4 @@ public class Client { } return (concurrent_job >= this.config.maxUploadingJob()); } - - protected void updateRenderingStatus(String line, Job ajob) { - if (ajob.getUpdateRenderingStatusMethod() != null && ajob.getUpdateRenderingStatusMethod().equals(Client.UPDATE_METHOD_BLENDER_INTERNAL_BY_PART)) { - String search = " Part "; - int index = line.lastIndexOf(search); - if (index != -1) { - String buf = line.substring(index + search.length()); - String[] parts = buf.split("-"); - if (parts != null && parts.length == 2) { - try { - int current = Integer.parseInt(parts[0]); - int total = Integer.parseInt(parts[1]); - if (total != 0) { - this.gui.status(String.format("Rendering %s %%", (int) (100.0 * current / total))); - return; - } - } - catch (NumberFormatException e) { - System.out.println("Exception 92: " + e); - } - } - } - this.gui.status("Rendering"); - } - else if (ajob.getUpdateRenderingStatusMethod() == null || ajob.getUpdateRenderingStatusMethod().equals(Client.UPDATE_METHOD_BY_REMAINING_TIME)) { - String search_remaining = "remaining:"; - int index = line.toLowerCase().indexOf(search_remaining); - if (index != -1) { - String buf1 = line.substring(index + search_remaining.length()); - index = buf1.indexOf(" "); - - if (index != -1) { - String remaining_time = buf1.substring(0, index).trim(); - int last_index = remaining_time.lastIndexOf('.'); //format 00:00:00.00 (hr:min:sec) - if (last_index > 0) { - remaining_time = remaining_time.substring(0, last_index); - } - - try { - DateFormat date_parse_minute = new SimpleDateFormat("m:s"); - DateFormat date_parse_hour = new SimpleDateFormat("h:m:s"); - DateFormat date_parse = date_parse_minute; - if (remaining_time.split(":").length > 2) { - date_parse = date_parse_hour; - } - date_parse.setTimeZone(TimeZone.getTimeZone("GMT")); - Date date = date_parse.parse(remaining_time); - this.gui.status(String.format("Rendering (remaining %s)", Utils.humanDuration(date))); - ajob.getProcessRender().setRemainingDuration((int) (date.getTime() / 1000)); - } - catch (ParseException err) { - this.log.error("Client::updateRenderingStatus ParseException " + err); - } - } - } - } - } - - protected void updateRenderingMemoryPeak(String line, Job ajob) { - String[] elements = line.toLowerCase().split("(peak)"); - - for (String element : elements) { - if (element.isEmpty() == false && element.charAt(0) == ' ') { - int end = element.indexOf(')'); - if (end > 0) { - long mem = Utils.parseNumber(element.substring(1, end).trim()); - if (mem > ajob.getProcessRender().getMemoryUsed()) { - ajob.getProcessRender().setMemoryUsed(mem); - } - } - } - else { - if (element.isEmpty() == false && element.charAt(0) == ':') { - int end = element.indexOf('|'); - if (end > 0) { - long mem = Utils.parseNumber(element.substring(1, end).trim()); - if (mem > ajob.getProcessRender().getMemoryUsed()) { - ajob.getProcessRender().setMemoryUsed(mem); - } - } - } - } - } - } - - private Type detectError(String line, Job ajob) { - - if (line.indexOf("CUDA error: Out of memory") != -1) { - // Fra:151 Mem:405.91M (0.00M, Peak 633.81M) | Mem:470.26M, Peak:470.26M | Scene, RenderLayer | Updating Device | Writing constant memory - // Fra:151 Mem:405.91M (0.00M, Peak 633.81M) | Mem:470.26M, Peak:470.26M | Scene, RenderLayer | Path Tracing Tile 0/135, Sample 0/200 - // Fra:151 Mem:405.91M (0.00M, Peak 633.81M) | Mem:470.82M, Peak:470.82M | Scene, RenderLayer | Path Tracing Tile 1/135, Sample 0/200 - // CUDA error: Out of memory in cuLaunchKernel(cuPathTrace, xblocks , yblocks, 1, xthreads, ythreads, 1, 0, 0, args, 0) - // Refer to the Cycles GPU rendering documentation for possible solutions: - // http://www.blender.org/manual/render/cycles/gpu_rendering.html - // Fra:151 Mem:405.91M (0.00M, Peak 633.81M) | Remaining:09:26.57 | Mem:470.26M, Peak:470.82M | Scene, RenderLayer | Path Tracing Tile 1/135, Sample 200/200 - // Fra:151 Mem:405.91M (0.00M, Peak 633.81M) | Remaining:00:00.06 | Mem:470.50M, Peak:470.82M | Scene, RenderLayer | Path Tracing Tile 134/135, Sample 0/200 - // Fra:151 Mem:405.91M (0.00M, Peak 633.81M) | Remaining:00:00.03 | Mem:470.26M, Peak:470.82M | Scene, RenderLayer | Path Tracing Tile 134/135, Sample 200/200 - // Fra:151 Mem:405.91M (0.00M, Peak 633.81M) | Remaining:00:00.03 | Mem:470.50M, Peak:470.82M | Scene, RenderLayer | Path Tracing Tile 135/135, Sample 0/200 - // Fra:151 Mem:405.91M (0.00M, Peak 633.81M) | Mem:470.26M, Peak:470.82M | Scene, RenderLayer | Path Tracing Tile 135/135, Sample 200/200 - // Error: CUDA error: Out of memory in cuLaunchKernel(cuPathTrace, xblocks , yblocks, 1, xthreads, ythreads, 1, 0, 0, args, 0) - // Fra:151 Mem:405.91M (0.00M, Peak 633.81M) | Mem:470.26M, Peak:470.82M | Scene, RenderLayer | Cancel | CUDA error: Out of memory in cuLaunchKernel(cuPathTrace, xblocks , yblocks, 1, xthreads, ythreads, 1, 0, 0, args, 0) - // Fra:151 Mem:405.89M (0.00M, Peak 633.81M) Sce: Scene Ve:0 Fa:0 La:0 - // Saved: /tmp/xx/26885_0151.png Time: 00:04.67 (Saving: 00:00.22) - // Blender quit - return Type.RENDERER_OUT_OF_VIDEO_MEMORY; - } - else if (line.indexOf("CUDA device supported only with compute capability") != -1) { - // found bundled python: /tmp/xx/2.73/python - // read blend: /tmp/xx/compute-method.blend - // Fra:340 Mem:7.64M (0.00M, Peak 8.23M) | Mem:0.00M, Peak:0.00M | Scene, RenderLayer | Synchronizing object | Sun - // Fra:340 Mem:7.64M (0.00M, Peak 8.23M) | Mem:0.00M, Peak:0.00M | Scene, RenderLayer | Synchronizing object | Plane - // Fra:340 Mem:7.64M (0.00M, Peak 8.23M) | Mem:0.00M, Peak:0.00M | Scene, RenderLayer | Synchronizing object | Cube - // Fra:340 Mem:7.64M (0.00M, Peak 8.23M) | Mem:0.00M, Peak:0.00M | Scene, RenderLayer | Synchronizing object | Camera - // Fra:340 Mem:7.64M (0.00M, Peak 8.23M) | Mem:0.00M, Peak:0.00M | Scene, RenderLayer | Initializing - // Fra:340 Mem:7.64M (0.00M, Peak 8.23M) | Mem:0.00M, Peak:0.00M | Scene, RenderLayer | Loading render kernels (may take a few minutes the first time) - // CUDA device supported only with compute capability 2.0 or up, found 1.2. - // Refer to the Cycles GPU rendering documentation for possible solutions: - // http://www.blender.org/manual/render/cycles/gpu_rendering.html - // Fra:340 Mem:7.64M (0.00M, Peak 8.23M) | Mem:0.00M, Peak:0.00M | Scene, RenderLayer | Error | CUDA device supported only with compute capability 2.0 or up, found 1.2. - // Error: CUDA device supported only with compute capability 2.0 or up, found 1.2. - // Fra:340 Mem:7.64M (0.00M, Peak 8.23M) | Mem:0.00M, Peak:0.00M | Scene, RenderLayer | Waiting for render to start - // Fra:340 Mem:7.64M (0.00M, Peak 8.23M) | Mem:0.00M, Peak:0.00M | Scene, RenderLayer | Cancel | CUDA device supported only with compute capability 2.0 or up, found 1.2. - // Fra:340 Mem:7.64M (0.00M, Peak 8.23M) Sce: Scene Ve:0 Fa:0 La:0 - // Saved: /tmp/xx/0_0340.png Time: 00:00.12 (Saving: 00:00.03) - // Blender quit - return Type.GPU_NOT_SUPPORTED; - } - return Type.OK; - } - - protected int getTileSize(Job ajob) { - int size = 32; // CPU - GPUDevice gpu = this.config.getGPUDevice(); - if (ajob.getUseGPU() && this.config.getGPUDevice() != null) { - // GPU - // if the vram is lower than 1G reduce the size of tile to avoid black output - size = (gpu.getMemory() > 1073741824L) ? 256 : 128; - } - return size; - } } diff --git a/src/com/sheepit/client/Job.java b/src/com/sheepit/client/Job.java index 764d7f2..f9f209b 100644 --- a/src/com/sheepit/client/Job.java +++ b/src/com/sheepit/client/Job.java @@ -19,11 +19,32 @@ package com.sheepit.client; +import java.io.BufferedReader; import java.io.File; +import java.io.FileWriter; +import java.io.FilenameFilter; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.TimeZone; +import com.sheepit.client.Error.Type; +import com.sheepit.client.hardware.gpu.GPUDevice; import com.sheepit.client.os.OS; public class Job { + public static final String UPDATE_METHOD_BY_REMAINING_TIME = "remainingtime"; + public static final String UPDATE_METHOD_BLENDER_INTERNAL_BY_PART = "blenderinternal"; + private String numFrame; private String sceneMD5; private String rendererMD5; @@ -39,10 +60,11 @@ public class Job { private boolean synchronousUpload; private RenderProcess render; private boolean askForRendererKill; - + private Gui gui; private Configuration config; + private Log log; - public Job(Configuration config_, String id_, String frame_, String revision_, String path_, boolean use_gpu, String command_, String script_, String sceneMd5_, String rendererMd5_, String extras_, boolean synchronous_upload_, String update_method_) { + public Job(Configuration config_, Gui gui_, Log log_, String id_, String frame_, String revision_, String path_, boolean use_gpu, String command_, String script_, String sceneMd5_, String rendererMd5_, String extras_, boolean synchronous_upload_, String update_method_) { config = config_; id = id_; numFrame = frame_; @@ -54,12 +76,12 @@ public class Job { rendererMD5 = rendererMd5_; extras = extras_; synchronousUpload = synchronous_upload_; - + gui = gui_; pictureFilename = null; script = script_; updateRenderingStatusMethod = update_method_; askForRendererKill = false; - + log = log_; render = new RenderProcess(); } @@ -162,4 +184,326 @@ public class Job { public boolean simultaneousUploadIsAllowed() { return synchronousUpload; } + + public Error.Type render() { + gui.status("Rendering"); + RenderProcess process = getProcessRender(); + String core_script = "import bpy\n" + "bpy.context.user_preferences.system.compute_device_type = \"%s\"\n" + "bpy.context.scene.cycles.device = \"%s\"\n" + "bpy.context.user_preferences.system.compute_device = \"%s\"\n"; + if (getUseGPU() && config.getGPUDevice() != null) { + core_script = String.format(core_script, "CUDA", "GPU", config.getGPUDevice().getCudaName()); + } + else { + core_script = String.format(core_script, "NONE", "CPU", "CPU"); + } + core_script += String.format("bpy.context.scene.render.tile_x = %1$d\nbpy.context.scene.render.tile_y = %1$d\n", getTileSize()); + File script_file = null; + String command1[] = getRenderCommand().split(" "); + int size_command = command1.length + 2; // + 2 for script + + if (config.getNbCores() > 0) { // user has specified something + size_command += 2; + } + + List command = new ArrayList(size_command); + + Map new_env = new HashMap(); + + new_env.put("BLENDER_USER_CONFIG", config.workingDirectory.getAbsolutePath().replace("\\", "\\\\")); + + for (String arg : command1) { + switch (arg) { + case ".c": + command.add(getScenePath()); + command.add("-P"); + + try { + script_file = File.createTempFile("script_", "", config.workingDirectory); + File file = new File(script_file.getAbsolutePath()); + FileWriter txt; + txt = new FileWriter(file); + + PrintWriter out = new PrintWriter(txt); + out.write(getScript()); + out.write("\n"); + out.write(core_script); // GPU part + out.write("\n"); // GPU part + out.close(); + + command.add(script_file.getAbsolutePath()); + } + catch (IOException e) { + StringWriter sw = new StringWriter(); + e.printStackTrace(new PrintWriter(sw)); + log.error("Client:runRenderer exception on script generation, will return UNKNOWN " + e + " stacktrace " + sw.toString()); + return Error.Type.UNKNOWN; + } + script_file.deleteOnExit(); + break; + case ".e": + command.add(getRendererPath()); + // the number of cores has to be put after the binary and before the scene arg + if (config.getNbCores() > 0) { + command.add("-t"); + command.add(Integer.toString(config.getNbCores())); + } + break; + case ".o": + command.add(config.workingDirectory.getAbsolutePath() + File.separator + getPrefixOutputImage()); + break; + case ".f": + command.add(getFrameNumber()); + break; + default: + command.add(arg); + break; + } + } + + try { + String line; + log.debug(command.toString()); + OS os = OS.getOS(); + process.start(); + getProcessRender().setProcess(os.exec(command, new_env)); + BufferedReader input = new BufferedReader(new InputStreamReader(getProcessRender().getProcess().getInputStream())); + + long last_update_status = 0; + log.debug("renderer output"); + try { + while ((line = input.readLine()) != null) { + updateRenderingMemoryPeak(line); + + log.debug(line); + if ((new Date().getTime() - last_update_status) > 2000) { // only call the update every two seconds + updateRenderingStatus(line); + last_update_status = new Date().getTime(); + } + Type error = detectError(line); + if (error != Error.Type.OK) { + if (script_file != null) { + script_file.delete(); + } + return error; + } + } + input.close(); + } + catch (IOException err1) { // for the input.readline + // most likely The handle is invalid + log.error("Client:runRenderer exception(B) (silent error) " + err1); + } + log.debug("end of rendering"); + } + catch (Exception err) { + if (script_file != null) { + script_file.delete(); + } + StringWriter sw = new StringWriter(); + err.printStackTrace(new PrintWriter(sw)); + log.error("Client:runRenderer exception(A) " + err + " stacktrace " + sw.toString()); + return Error.Type.FAILED_TO_EXECUTE; + } + + int exit_value = process.exitValue(); + process.finish(); + + if (script_file != null) { + script_file.delete(); + } + + // find the picture file + final String filename_without_extension = getPrefixOutputImage() + getFrameNumber(); + + FilenameFilter textFilter = new FilenameFilter() { + public boolean accept(File dir, String name) { + return name.startsWith(filename_without_extension); + } + }; + + File[] files = config.workingDirectory.listFiles(textFilter); + + if (files.length == 0) { + log.error("Client::runRenderer no picture file found (after finished render (filename_without_extension " + filename_without_extension + ")"); + + if (getAskForRendererKill()) { + log.debug("Client::runRenderer renderer didn't generate any frame but died due to a kill request"); + return Error.Type.RENDERER_KILLED; + } + + String basename = ""; + try { + basename = getPath().substring(0, getPath().lastIndexOf('.')); + } + catch (Exception e) { + e.printStackTrace(); + } + File crash_file = new File(config.workingDirectory + File.separator + basename + ".crash.txt"); + if (crash_file.exists()) { + log.error("Client::runRenderer crash file found => the renderer crashed"); + crash_file.delete(); + return Error.Type.RENDERER_CRASHED; + } + + if (exit_value == 127 && process.getDuration() < 10) { + log.error("Client::runRenderer renderer returned 127 and took " + process.getDuration() + "s, some libraries may be missing"); + return Error.Type.RENDERER_MISSING_LIBRARIES; + } + + return Error.Type.NOOUTPUTFILE; + } + else { + setOutputImagePath(files[0].getAbsolutePath()); + log.debug("Client::runRenderer pictureFilename: '" + getOutputImagePath() + "'"); + } + + File scene_dir = new File(getSceneDirectory()); + long date_modification_scene_directory = (long) Utils.lastModificationTime(scene_dir); + if (date_modification_scene_directory > process.getStartTime()) { + scene_dir.delete(); + } + + gui.status(String.format("Frame rendered in %dmin%ds", process.getDuration() / 60, process.getDuration() % 60)); + + return Error.Type.OK; + } + + private void updateRenderingStatus(String line) { + if (getUpdateRenderingStatusMethod() != null && getUpdateRenderingStatusMethod().equals(Job.UPDATE_METHOD_BLENDER_INTERNAL_BY_PART)) { + String search = " Part "; + int index = line.lastIndexOf(search); + if (index != -1) { + String buf = line.substring(index + search.length()); + String[] parts = buf.split("-"); + if (parts != null && parts.length == 2) { + try { + int current = Integer.parseInt(parts[0]); + int total = Integer.parseInt(parts[1]); + if (total != 0) { + gui.status(String.format("Rendering %s %%", (int) (100.0 * current / total))); + return; + } + } + catch (NumberFormatException e) { + System.out.println("Exception 92: " + e); + } + } + } + gui.status("Rendering"); + } + else if (getUpdateRenderingStatusMethod() == null || getUpdateRenderingStatusMethod().equals(Job.UPDATE_METHOD_BY_REMAINING_TIME)) { + String search_remaining = "remaining:"; + int index = line.toLowerCase().indexOf(search_remaining); + if (index != -1) { + String buf1 = line.substring(index + search_remaining.length()); + index = buf1.indexOf(" "); + + if (index != -1) { + String remaining_time = buf1.substring(0, index).trim(); + int last_index = remaining_time.lastIndexOf('.'); //format 00:00:00.00 (hr:min:sec) + if (last_index > 0) { + remaining_time = remaining_time.substring(0, last_index); + } + + try { + DateFormat date_parse_minute = new SimpleDateFormat("m:s"); + DateFormat date_parse_hour = new SimpleDateFormat("h:m:s"); + DateFormat date_parse = date_parse_minute; + if (remaining_time.split(":").length > 2) { + date_parse = date_parse_hour; + } + date_parse.setTimeZone(TimeZone.getTimeZone("GMT")); + Date date = date_parse.parse(remaining_time); + gui.status(String.format("Rendering (remaining %s)", Utils.humanDuration(date))); + getProcessRender().setRemainingDuration((int) (date.getTime() / 1000)); + } + catch (ParseException err) { + log.error("Client::updateRenderingStatus ParseException " + err); + } + } + } + } + } + + private void updateRenderingMemoryPeak(String line) { + String[] elements = line.toLowerCase().split("(peak)"); + + for (String element : elements) { + if (element.isEmpty() == false && element.charAt(0) == ' ') { + int end = element.indexOf(')'); + if (end > 0) { + long mem = Utils.parseNumber(element.substring(1, end).trim()); + if (mem > getProcessRender().getMemoryUsed()) { + getProcessRender().setMemoryUsed(mem); + } + } + } + else { + if (element.isEmpty() == false && element.charAt(0) == ':') { + int end = element.indexOf('|'); + if (end > 0) { + long mem = Utils.parseNumber(element.substring(1, end).trim()); + if (mem > getProcessRender().getMemoryUsed()) { + getProcessRender().setMemoryUsed(mem); + } + } + } + } + } + } + + private Type detectError(String line) { + + if (line.indexOf("CUDA error: Out of memory") != -1) { + // Fra:151 Mem:405.91M (0.00M, Peak 633.81M) | Mem:470.26M, Peak:470.26M | Scene, RenderLayer | Updating Device | Writing constant memory + // Fra:151 Mem:405.91M (0.00M, Peak 633.81M) | Mem:470.26M, Peak:470.26M | Scene, RenderLayer | Path Tracing Tile 0/135, Sample 0/200 + // Fra:151 Mem:405.91M (0.00M, Peak 633.81M) | Mem:470.82M, Peak:470.82M | Scene, RenderLayer | Path Tracing Tile 1/135, Sample 0/200 + // CUDA error: Out of memory in cuLaunchKernel(cuPathTrace, xblocks , yblocks, 1, xthreads, ythreads, 1, 0, 0, args, 0) + // Refer to the Cycles GPU rendering documentation for possible solutions: + // http://www.blender.org/manual/render/cycles/gpu_rendering.html + // Fra:151 Mem:405.91M (0.00M, Peak 633.81M) | Remaining:09:26.57 | Mem:470.26M, Peak:470.82M | Scene, RenderLayer | Path Tracing Tile 1/135, Sample 200/200 + // Fra:151 Mem:405.91M (0.00M, Peak 633.81M) | Remaining:00:00.06 | Mem:470.50M, Peak:470.82M | Scene, RenderLayer | Path Tracing Tile 134/135, Sample 0/200 + // Fra:151 Mem:405.91M (0.00M, Peak 633.81M) | Remaining:00:00.03 | Mem:470.26M, Peak:470.82M | Scene, RenderLayer | Path Tracing Tile 134/135, Sample 200/200 + // Fra:151 Mem:405.91M (0.00M, Peak 633.81M) | Remaining:00:00.03 | Mem:470.50M, Peak:470.82M | Scene, RenderLayer | Path Tracing Tile 135/135, Sample 0/200 + // Fra:151 Mem:405.91M (0.00M, Peak 633.81M) | Mem:470.26M, Peak:470.82M | Scene, RenderLayer | Path Tracing Tile 135/135, Sample 200/200 + // Error: CUDA error: Out of memory in cuLaunchKernel(cuPathTrace, xblocks , yblocks, 1, xthreads, ythreads, 1, 0, 0, args, 0) + // Fra:151 Mem:405.91M (0.00M, Peak 633.81M) | Mem:470.26M, Peak:470.82M | Scene, RenderLayer | Cancel | CUDA error: Out of memory in cuLaunchKernel(cuPathTrace, xblocks , yblocks, 1, xthreads, ythreads, 1, 0, 0, args, 0) + // Fra:151 Mem:405.89M (0.00M, Peak 633.81M) Sce: Scene Ve:0 Fa:0 La:0 + // Saved: /tmp/xx/26885_0151.png Time: 00:04.67 (Saving: 00:00.22) + // Blender quit + return Type.RENDERER_OUT_OF_VIDEO_MEMORY; + } + else if (line.indexOf("CUDA device supported only with compute capability") != -1) { + // found bundled python: /tmp/xx/2.73/python + // read blend: /tmp/xx/compute-method.blend + // Fra:340 Mem:7.64M (0.00M, Peak 8.23M) | Mem:0.00M, Peak:0.00M | Scene, RenderLayer | Synchronizing object | Sun + // Fra:340 Mem:7.64M (0.00M, Peak 8.23M) | Mem:0.00M, Peak:0.00M | Scene, RenderLayer | Synchronizing object | Plane + // Fra:340 Mem:7.64M (0.00M, Peak 8.23M) | Mem:0.00M, Peak:0.00M | Scene, RenderLayer | Synchronizing object | Cube + // Fra:340 Mem:7.64M (0.00M, Peak 8.23M) | Mem:0.00M, Peak:0.00M | Scene, RenderLayer | Synchronizing object | Camera + // Fra:340 Mem:7.64M (0.00M, Peak 8.23M) | Mem:0.00M, Peak:0.00M | Scene, RenderLayer | Initializing + // Fra:340 Mem:7.64M (0.00M, Peak 8.23M) | Mem:0.00M, Peak:0.00M | Scene, RenderLayer | Loading render kernels (may take a few minutes the first time) + // CUDA device supported only with compute capability 2.0 or up, found 1.2. + // Refer to the Cycles GPU rendering documentation for possible solutions: + // http://www.blender.org/manual/render/cycles/gpu_rendering.html + // Fra:340 Mem:7.64M (0.00M, Peak 8.23M) | Mem:0.00M, Peak:0.00M | Scene, RenderLayer | Error | CUDA device supported only with compute capability 2.0 or up, found 1.2. + // Error: CUDA device supported only with compute capability 2.0 or up, found 1.2. + // Fra:340 Mem:7.64M (0.00M, Peak 8.23M) | Mem:0.00M, Peak:0.00M | Scene, RenderLayer | Waiting for render to start + // Fra:340 Mem:7.64M (0.00M, Peak 8.23M) | Mem:0.00M, Peak:0.00M | Scene, RenderLayer | Cancel | CUDA device supported only with compute capability 2.0 or up, found 1.2. + // Fra:340 Mem:7.64M (0.00M, Peak 8.23M) Sce: Scene Ve:0 Fa:0 La:0 + // Saved: /tmp/xx/0_0340.png Time: 00:00.12 (Saving: 00:00.03) + // Blender quit + return Type.GPU_NOT_SUPPORTED; + } + return Type.OK; + } + + private int getTileSize() { + int size = 32; // CPU + GPUDevice gpu = this.config.getGPUDevice(); + if (getUseGPU() && this.config.getGPUDevice() != null) { + // GPU + // if the vram is lower than 1G reduce the size of tile to avoid black output + size = (gpu.getMemory() > 1073741824L) ? 256 : 128; + } + return size; + } } diff --git a/src/com/sheepit/client/Server.java b/src/com/sheepit/client/Server.java index ddfc75a..6bf5110 100644 --- a/src/com/sheepit/client/Server.java +++ b/src/com/sheepit/client/Server.java @@ -399,6 +399,8 @@ public class Server extends Thread implements HostnameVerifier, X509TrustManager Job a_job = new Job( this.user_config, + this.client.getGui(), + this.client.getLog(), job_node.getAttribute("id"), job_node.getAttribute("frame"), job_node.getAttribute("revision"),