diff --git a/src/com/sheepit/client/Client.java b/src/com/sheepit/client/Client.java index 43adfeb..9342759 100644 --- a/src/com/sheepit/client/Client.java +++ b/src/com/sheepit/client/Client.java @@ -621,7 +621,7 @@ import okhttp3.HttpUrl; StringBuilder logHeader = new StringBuilder() .append("====================================================================================================\n") .append(String.format("%s / %s / %s / SheepIt v%s\n", conf.getLogin(), conf.getHostname(), OS.getOS().name(), conf.getJarVersion())) - .append(String.format("%s x%d %.1f GB RAM\n", cpu.name(), conf.getNbCores(), conf.getMaxMemory() / 1024.0 / 1024.0)); + .append(String.format("%s x%d %.1f GB RAM\n", cpu.name(), conf.getNbCores(), conf.getMaxAllowedMemory() / 1024.0 / 1024.0)); if (conf.getComputeMethod() == Configuration.ComputeType.GPU || conf.getComputeMethod() == Configuration.ComputeType.CPU_GPU) { logHeader.append(String.format("%s %s %.1f GB VRAM\n", conf.getGPUDevice().getId(), conf.getGPUDevice().getModel(), @@ -657,7 +657,7 @@ import okhttp3.HttpUrl; remoteURL.addQueryParameter("frame", job_to_reset_.getFrameNumber()); remoteURL.addQueryParameter("job", job_to_reset_.getId()); remoteURL.addQueryParameter("render_time", Integer.toString(job_to_reset_.getProcessRender().getDuration())); - remoteURL.addQueryParameter("memoryused", Long.toString(job_to_reset_.getProcessRender().getMemoryUsed())); + remoteURL.addQueryParameter("memoryused", Long.toString(job_to_reset_.getProcessRender().getPeakMemoryUsed())); if (job_to_reset_.getExtras() != null && job_to_reset_.getExtras().isEmpty() == false) { remoteURL.addQueryParameter("extras", job_to_reset_.getExtras()); } @@ -1017,7 +1017,7 @@ import okhttp3.HttpUrl; protected Error.Type confirmJob(Job ajob, int checkpoint) { String url_real = String.format("%s&rendertime=%d&memoryused=%s", ajob.getValidationUrl(), ajob.getProcessRender().getDuration(), - ajob.getProcessRender().getMemoryUsed()); + ajob.getProcessRender().getPeakMemoryUsed()); this.log.debug(checkpoint, "Client::confirmeJob url " + url_real); this.log.debug(checkpoint, "path frame " + ajob.getOutputImagePath()); diff --git a/src/com/sheepit/client/Configuration.java b/src/com/sheepit/client/Configuration.java index f6bc2ff..71ea5cc 100644 --- a/src/com/sheepit/client/Configuration.java +++ b/src/com/sheepit/client/Configuration.java @@ -55,7 +55,7 @@ import lombok.Data; private String proxy; private int maxUploadingJob; private int nbCores; - private long maxMemory; // max memory allowed for render + private long maxAllowedMemory; // in KiB, max memory allowed for render private int maxRenderTime; // max render time per frame allowed private int priority; private ComputeType computeMethod; @@ -83,7 +83,7 @@ import lombok.Data; this.static_exeDirName = "exe"; this.maxUploadingJob = 1; this.nbCores = -1; // ie not set - this.maxMemory = -1; // ie not set + this.maxAllowedMemory = -1; // ie not set this.maxRenderTime = -1; // ie not set this.priority = 19; // default lowest this.computeMethod = null; @@ -109,7 +109,7 @@ import lombok.Data; public Configuration(Configuration config) { this(config.configFilePath, config.workingDirectory, config.sharedDownloadsDirectory, config.storageDirectory, config.userHasSpecifiedACacheDir, - config.static_exeDirName, config.login, config.password, config.proxy, config.maxUploadingJob, config.nbCores, config.maxMemory, config.maxRenderTime, + config.static_exeDirName, config.login, config.password, config.proxy, config.maxUploadingJob, config.nbCores, config.maxAllowedMemory, config.maxRenderTime, config.priority, config.computeMethod, config.GPUDevice, config.renderbucketSize, config.detectGPUs, config.printLog, config.requestTime, config.shutdownTime, config.shutdownMode, config.extras, config.autoSignIn, config.useSysTray, config.headless, config.UIType, config.hostname, config.theme); } diff --git a/src/com/sheepit/client/Job.java b/src/com/sheepit/client/Job.java index 288b9f8..f4ac633 100644 --- a/src/com/sheepit/client/Job.java +++ b/src/com/sheepit/client/Job.java @@ -22,10 +22,10 @@ package com.sheepit.client; import com.sheepit.client.Configuration.ComputeType; import com.sheepit.client.Error.Type; import com.sheepit.client.hardware.cpu.CPU; -import com.sheepit.client.hardware.gpu.opencl.OpenCL; import com.sheepit.client.os.OS; import lombok.Data; import lombok.Getter; +import oshi.software.os.OSProcess; import java.io.BufferedReader; import java.io.File; @@ -133,6 +133,25 @@ import java.util.regex.Pattern; frameNumber, sceneMD5, rendererMD5, id, outputImagePath, path, useGPU, name, extras, updateRenderingStatusMethod, render); } + private OSProcess getRenderOSProcess() { + return OS.operatingSystem.getProcess((int) getProcessRender().getProcess().pid()); + } + + public long getUsedMemory() { + OSProcess osp = getRenderOSProcess(); + return osp != null ? osp.getResidentSetSize() : 0; + } + + public long getTotalUsedMemory() { + OSProcess osp = getRenderOSProcess(); + return osp != null ? osp.getVirtualSize() : 0; + } + + private int getThreadCount() { + OSProcess osp = getRenderOSProcess(); + return osp != null ? osp.getThreadCount() : 0; + } + public String getPrefixOutputImage() { return id + "_"; } @@ -284,6 +303,7 @@ import java.util.regex.Pattern; } } + Timer memoryCheck = new Timer(); try { renderStartedObservable event = new renderStartedObservable(renderStarted); String line; @@ -293,6 +313,12 @@ import java.util.regex.Pattern; process.start(); getProcessRender().setProcess(os.exec(command, new_env)); BufferedReader input = new BufferedReader(new InputStreamReader(getProcessRender().getProcess().getInputStream())); + memoryCheck.scheduleAtFixedRate(new TimerTask() { + @Override + public void run() { + updateRenderingMemoryPeak(); + } + }, 0L, 1000L); // Make initial test/power frames ignore the maximum render time in user configuration. Initial test frames have Job IDs below 20 // so we just activate the user defined timeout when the scene is not one of the initial ones. @@ -338,11 +364,10 @@ import java.util.regex.Pattern; } progress = computeRenderingProgress(line, tilePattern, progress); - - updateRenderingMemoryPeak(line); - if (configuration.getMaxMemory() != -1 && process.getMemoryUsed() > configuration.getMaxMemory()) { - log.debug("Blocking render because process ram used (" + process.getMemoryUsed() + "k) is over user setting (" + configuration - .getMaxMemory() + "k)"); + updateRenderingMemoryPeak(); + if (configuration.getMaxAllowedMemory() != -1 && (getUsedMemory() / 1024L) > configuration.getMaxAllowedMemory()) { + log.debug("Blocking render because process ram used (" + (getUsedMemory() / 1024L) + "k) is over user setting (" + configuration + .getMaxAllowedMemory() + "k)"); OS.getOS().kill(process.getProcess()); process.finish(); if (script_file != null) { @@ -369,7 +394,7 @@ import java.util.regex.Pattern; return error; } - if (!event.isStarted() && (process.getMemoryUsed() > 0 || process.getRemainingDuration() > 0)) { + if (!event.isStarted() && (getUsedMemory() > 0 || process.getRemainingDuration() > 0)) { event.doNotifyIsStarted(); } } @@ -379,6 +404,9 @@ import java.util.regex.Pattern; // most likely The handle is invalid log.error("Job::render exception(B) (silent error) " + err1); } + finally { + memoryCheck.cancel(); + } // Put back base icon gui.updateTrayIcon(Job.SHOW_BASE_ICON); @@ -580,41 +608,19 @@ import java.util.regex.Pattern; } } - private void updateRenderingMemoryPeak(String line) { - String[] elements = line.toLowerCase().split("(peak)"); - - for (String element : elements) { - if (!element.isEmpty() && element.charAt(0) == ' ') { - int end = element.indexOf(')'); - if (end > 0) { - try { - long mem = Utils.parseNumber(element.substring(1, end).trim()) / 1000; // internal use of ram is in kB - if (mem > getProcessRender().getMemoryUsed()) { - getProcessRender().setMemoryUsed(mem); - } - } - catch (IllegalStateException | NumberFormatException e) { - // failed to parseNumber - } - } - } - else { - if (!element.isEmpty() && element.charAt(0) == ':') { - int end = element.indexOf('|'); - if (end > 0) { - try { - long mem = Utils.parseNumber(element.substring(1, end).trim()) / 1000; // internal use of ram is in kB - if (mem > getProcessRender().getMemoryUsed()) { - getProcessRender().setMemoryUsed(mem); - } - } - catch (IllegalStateException | NumberFormatException e) { - // failed to parseNumber - } - } - } - } + private void updateRenderingMemoryPeak() { + long mem = getUsedMemory() / 1024L; // convert into kB + getProcessRender().setMemoryUsed(mem); + if (getProcessRender().getPeakMemoryUsed() < mem) { + getProcessRender().setPeakMemoryUsed(mem); } + double memoryConsumed = getUsedMemory() / 1024.0 / 1024.0; + double peakMemoryConsumed = getProcessRender().getPeakMemoryUsed() / 1024.0; + double totalUsedMemory = getTotalUsedMemory() / 1024.0 / 1024.0; + double systemMemoryAvailable = OS.getOS().getFreeMemory() / 1024.0; + int threadCount = getThreadCount(); + log.debug(String.format("RAM Consumed: %(,.2fMB | Peak RAM Consumed: %(,.2fMB | Virtual Mem Consumed: %(,.2fMB | System Available Memory: %(,.2fMB | Thread Count: %d", + memoryConsumed, peakMemoryConsumed, totalUsedMemory, systemMemoryAvailable, threadCount)); } private Type detectError(String line) { diff --git a/src/com/sheepit/client/RenderProcess.java b/src/com/sheepit/client/RenderProcess.java index 105f445..211c668 100644 --- a/src/com/sheepit/client/RenderProcess.java +++ b/src/com/sheepit/client/RenderProcess.java @@ -28,6 +28,7 @@ import java.util.Date; private long endTime; private int remainingDuration; // in seconds private long memoryUsed; // in kB + private long peakMemoryUsed; // in kB private int coresUsed; private Process process; @@ -36,6 +37,7 @@ import java.util.Date; startTime = -1; endTime = -1; memoryUsed = 0; + peakMemoryUsed = 0; coresUsed = 0; remainingDuration = 0; } diff --git a/src/com/sheepit/client/Server.java b/src/com/sheepit/client/Server.java index bff84e1..1c6a2a4 100644 --- a/src/com/sheepit/client/Server.java +++ b/src/com/sheepit/client/Server.java @@ -40,6 +40,7 @@ import java.util.stream.Collectors; import com.sheepit.client.datamodel.SpeedTestTarget; import com.sheepit.client.datamodel.SpeedTestResult; import com.sheepit.client.datamodel.SpeedTestTargetResult; +import com.sheepit.client.os.Windows; import lombok.Getter; import org.simpleframework.xml.core.Persister; @@ -205,7 +206,7 @@ public class Server extends Thread { .add("cpu_cores", String.valueOf(user_config.getNbCores() == -1 ? os.getCPU().cores() : Math.max(CPU.MIN_CORES, user_config.getNbCores()))) .add("os", os.name()) .add("os_version", os.getVersion()) - .add("ram", String.valueOf(os.getMemory())) + .add("ram", String.valueOf(os.getTotalMemory())) .add("bits", os.getCPU().arch()) .add("version", user_config.getJarVersion()) .add("hostname", user_config.getHostname()) @@ -305,8 +306,8 @@ public class Server extends Thread { try { OS os = OS.getOS(); - long maxMemory = this.user_config.getMaxMemory(); - long freeMemory = os.getFreeMemory(); + long maxMemory = this.user_config.getMaxAllowedMemory(); + long freeMemory = os.getFreeMemory() - 1024^2 /*One gigabyte*/ * (os instanceof Windows ? 2 : 1); //Make RAM to reserve 2GB on Windows if (maxMemory < 0) { maxMemory = freeMemory; } diff --git a/src/com/sheepit/client/SettingsLoader.java b/src/com/sheepit/client/SettingsLoader.java index c592bf1..91ba9bf 100644 --- a/src/com/sheepit/client/SettingsLoader.java +++ b/src/com/sheepit/client/SettingsLoader.java @@ -524,8 +524,8 @@ public class SettingsLoader { config.setNbCores(Integer.parseInt(cores.getValue())); } - if (config.getMaxMemory() == -1 && ram != null) { - config.setMaxMemory(Utils.parseNumber(ram.getValue()) / 1000); // internal ram value is in kB + if (config.getMaxAllowedMemory() == -1 && ram != null) { + config.setMaxAllowedMemory(Utils.parseNumber(ram.getValue()) / 1024); // internal ram value is in KiB } if (config.getMaxRenderTime() == -1 && renderTime != null) { diff --git a/src/com/sheepit/client/os/OS.java b/src/com/sheepit/client/os/OS.java index dc4440f..744767b 100644 --- a/src/com/sheepit/client/os/OS.java +++ b/src/com/sheepit/client/os/OS.java @@ -31,7 +31,7 @@ import com.sheepit.client.hardware.cpu.CPU; public abstract class OS { private static SystemInfo systemInfo = new SystemInfo(); - static OperatingSystem operatingSystem = systemInfo.getOperatingSystem(); + public static OperatingSystem operatingSystem = systemInfo.getOperatingSystem(); private static HardwareAbstractionLayer hardwareAbstractionLayer = systemInfo.getHardware(); @@ -48,7 +48,7 @@ public abstract class OS { return (name() + " " + operatingSystem.getVersionInfo()).toLowerCase(); } - public long getMemory() { + public long getTotalMemory() { return hardwareAbstractionLayer.getMemory().getTotal() / 1024; } diff --git a/src/com/sheepit/client/standalone/Worker.java b/src/com/sheepit/client/standalone/Worker.java index 698b99f..07ca43c 100644 --- a/src/com/sheepit/client/standalone/Worker.java +++ b/src/com/sheepit/client/standalone/Worker.java @@ -247,7 +247,7 @@ public class Worker { if (max_ram != null) { try { - config.setMaxMemory(Utils.parseNumber(max_ram) / 1000); // internal value are in kB + config.setMaxAllowedMemory(Utils.parseNumber(max_ram) / 1024); // internal value is in KiB } catch (java.lang.IllegalStateException e) { System.err.println( diff --git a/src/com/sheepit/client/standalone/swing/activity/Settings.java b/src/com/sheepit/client/standalone/swing/activity/Settings.java index 78715d9..9afcf08 100644 --- a/src/com/sheepit/client/standalone/swing/activity/Settings.java +++ b/src/com/sheepit/client/standalone/swing/activity/Settings.java @@ -407,7 +407,7 @@ public class Settings implements Activity { // max ram allowed to render OS os = OS.getOS(); - int all_ram = (int) os.getMemory(); + int all_ram = (int) os.getTotalMemory(); ram = new JSlider(0, all_ram); int step = 1000000; double display = (double) all_ram / (double) step; @@ -428,7 +428,7 @@ public class Settings implements Activity { } }); ram.setPaintLabels(true); - ram.setValue((int) (config.getMaxMemory() != -1 ? config.getMaxMemory() : os.getMemory())); + ram.setValue((int) (config.getMaxAllowedMemory() != -1 ? config.getMaxAllowedMemory() : os.getTotalMemory())); JLabel ramLabel = new JLabel("Memory:"); ramLabel.setToolTipText(SwingTooltips.MEMORY.getText()); @@ -798,7 +798,7 @@ public class Settings implements Activity { } if (max_ram > 0) { - config.setMaxMemory(max_ram); + config.setMaxAllowedMemory(max_ram); } int max_rendertime = -1;