Feature: add session data consumption information in GUI/text UIs (#287)

* Feature: add session data consumption information in GUI/text UIs

Adds the total bytes downloaded and uploaded in the current session as well as the average data transfer rate for both UL/DL. The information is not added to the 1-line UI as the line will take 150+ characters in the screen.
This commit is contained in:
Luis Uguina
2020-09-12 10:00:24 +10:00
committed by GitHub
parent 4fa886c4de
commit d152e0b0ff
9 changed files with 126 additions and 10 deletions

View File

@@ -647,7 +647,7 @@ import lombok.Data;
args += "&extras=" + job_to_reset_.getExtras(); args += "&extras=" + job_to_reset_.getExtras();
} }
} }
this.server.HTTPSendFile(this.server.getPage("error") + args, temp_file.getAbsolutePath(), step_); this.server.HTTPSendFile(this.server.getPage("error") + args, temp_file.getAbsolutePath(), step_, this.gui);
temp_file.delete(); temp_file.delete();
} }
catch (Exception e) { catch (Exception e) {
@@ -938,7 +938,7 @@ import lombok.Data;
Type confirmJobReturnCode = Error.Type.OK; Type confirmJobReturnCode = Error.Type.OK;
retryLoop: retryLoop:
while (nb_try < max_try && ret != ServerCode.OK) { while (nb_try < max_try && ret != ServerCode.OK) {
ret = this.server.HTTPSendFile(url_real, ajob.getOutputImagePath(), checkpoint); ret = this.server.HTTPSendFile(url_real, ajob.getOutputImagePath(), checkpoint, this.gui);
switch (ret) { switch (ret) {
case OK: case OK:
// no issue, exit the loop // no issue, exit the loop

View File

@@ -40,6 +40,8 @@ public interface Gui {
public void setRenderingTime(String time_); public void setRenderingTime(String time_);
public void displayTransferStats(TransferStats downloads, TransferStats uploads);
public void displayStats(Stats stats); public void displayStats(Stats stats);
public void displayUploadQueueStats(int queueSize, long queueVolume); public void displayUploadQueueStats(int queueSize, long queueVolume);

View File

@@ -28,6 +28,8 @@ import java.io.PrintWriter;
import java.io.StringWriter; import java.io.StringWriter;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.net.*; import java.net.*;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
@@ -83,6 +85,9 @@ public class Server extends Thread {
private long lastRequestTime; private long lastRequestTime;
private int keepmealive_duration; // time in ms private int keepmealive_duration; // time in ms
private TransferStats dlStats = new TransferStats();
private TransferStats ulStats = new TransferStats();
public Server(String url_, Configuration user_config_, Client client_) { public Server(String url_, Configuration user_config_, Client client_) {
super(); super();
this.base_url = url_; this.base_url = url_;
@@ -427,7 +432,6 @@ public class Server extends Thread {
return Error.Type.DOWNLOAD_FILE; return Error.Type.DOWNLOAD_FILE;
} }
long start = new Date().getTime();
is = response.body().byteStream(); is = response.body().byteStream();
output = new FileOutputStream(destination_); output = new FileOutputStream(destination_);
@@ -437,6 +441,8 @@ public class Server extends Thread {
long written = 0; long written = 0;
long lastUpd = 0; // last GUI progress update long lastUpd = 0; // last GUI progress update
LocalDateTime startRequestTime = LocalDateTime.now();
while ((len = is.read(buffer)) != -1) { while ((len = is.read(buffer)) != -1) {
if (this.client.getRenderingJob().isServerBlockJob()) { if (this.client.getRenderingJob().isServerBlockJob()) {
return Error.Type.RENDERER_KILLED_BY_SERVER; return Error.Type.RENDERER_KILLED_BY_SERVER;
@@ -454,10 +460,13 @@ public class Server extends Thread {
} }
} }
LocalDateTime endRequestTime = LocalDateTime.now();
Duration duration = Duration.between(startRequestTime, endRequestTime);
this.dlStats.calc(written, ((duration.getSeconds() * 1000) + (duration.getNano() / 1000000)));
gui_.displayTransferStats(dlStats, ulStats);
gui_.status(status_, 100, size); gui_.status(status_, 100, size);
long end = new Date().getTime(); this.log.debug(String.format("File downloaded at %.1f KB/s, written %d bytes", (float) (size/1024) / duration.getSeconds(), written));
this.log.debug(String.format("File downloaded at %.1f kB/s, written %d B", ((float) (size / 1000)) / ((float) (end - start) / 1000), written));
this.lastRequestTime = new Date().getTime(); this.lastRequestTime = new Date().getTime();
return Error.Type.OK; return Error.Type.OK;
@@ -491,22 +500,33 @@ public class Server extends Thread {
return Error.Type.DOWNLOAD_FILE; return Error.Type.DOWNLOAD_FILE;
} }
public ServerCode HTTPSendFile(String surl, String file1, int checkpoint) { public ServerCode HTTPSendFile(String surl, String file1, int checkpoint, Gui gui) {
this.log.debug(checkpoint, "Server::HTTPSendFile(" + surl + "," + file1 + ")"); this.log.debug(checkpoint, "Server::HTTPSendFile(" + surl + "," + file1 + ")");
try { try {
String fileMimeType = Utils.findMimeType(file1); String fileMimeType = Utils.findMimeType(file1);
File fileHandler = new File(file1);
MediaType MEDIA_TYPE = MediaType.parse(fileMimeType); // e.g. "image/png" MediaType MEDIA_TYPE = MediaType.parse(fileMimeType); // e.g. "image/png"
RequestBody uploadContent = new MultipartBody.Builder().setType(MultipartBody.FORM) RequestBody uploadContent = new MultipartBody.Builder().setType(MultipartBody.FORM)
.addFormDataPart("file", new File(file1).getName(), RequestBody.create(new File(file1), MEDIA_TYPE)).build(); .addFormDataPart("file", fileHandler.getName(), RequestBody.create(fileHandler, MEDIA_TYPE)).build();
Request request = new Request.Builder().addHeader("User-Agent", HTTP_USER_AGENT).url(surl).post(uploadContent).build(); Request request = new Request.Builder().addHeader("User-Agent", HTTP_USER_AGENT).url(surl).post(uploadContent).build();
LocalDateTime startRequestTime = LocalDateTime.now();
Call call = httpClient.newCall(request); Call call = httpClient.newCall(request);
Response response = call.execute(); Response response = call.execute();
LocalDateTime endRequestTime = LocalDateTime.now();
Duration duration = Duration.between(startRequestTime, endRequestTime);
this.ulStats.calc(fileHandler.length(), ((duration.getSeconds() * 1000) + (duration.getNano() / 1000000)));
gui.displayTransferStats(dlStats, ulStats);
this.log.debug(String.format("File uploaded at %s/s, uploaded %d bytes", Utils.formatDataConsumption((long) fileHandler.length() / duration.getSeconds()), fileHandler.length()));
int r = response.code(); int r = response.code();
String contentType = response.body().contentType().toString(); String contentType = response.body().contentType().toString();

View File

@@ -0,0 +1,36 @@
package com.sheepit.client;
import lombok.AllArgsConstructor;
/****************
* Holds the session traffic statistics. The constructor accepts two parameters:
* @long bytes - bytes transferred in the session
* @Job seconds - seconds spent transferring the data
*/
@AllArgsConstructor
public class TransferStats {
private long bytes;
private long millis;
public TransferStats() {
this.bytes = 0;
this.millis = 0;
}
public void calc(long bytes, long millis) {
this.bytes += bytes;
this.millis += millis;
}
public String getSessionTraffic() {
return Utils.formatDataConsumption(this.bytes);
}
public String getAverageSessionSpeed() {
try {
return Utils.formatDataConsumption((long) (this.bytes / (this.millis / 1000f)));
} catch (ArithmeticException e) { // Unlikely, but potential division by zero fallback if first transfer is done in zero millis
return Utils.formatDataConsumption((long) (this.bytes / (0.1f)));
}
}
}

View File

@@ -228,4 +228,24 @@ public class Utils {
return mimeType; return mimeType;
} }
public static String formatDataConsumption(long bytes) {
float divider = 0;
String suffix = "";
if (bytes > 1099511627776f) { // 1TB
divider = 1099511627776f;
suffix = "TB";
}
else if (bytes > 1073741824) { // 1GB
divider = 1073741824;
suffix = "GB";
}
else { // 1MB
divider = 1048576;
suffix = "MB";
}
return String.format("%.2f%s", (bytes / divider), suffix);
}
} }

View File

@@ -50,6 +50,7 @@ import com.sheepit.client.Configuration;
import com.sheepit.client.Gui; import com.sheepit.client.Gui;
import com.sheepit.client.SettingsLoader; import com.sheepit.client.SettingsLoader;
import com.sheepit.client.Stats; import com.sheepit.client.Stats;
import com.sheepit.client.TransferStats;
import com.sheepit.client.standalone.swing.activity.Settings; import com.sheepit.client.standalone.swing.activity.Settings;
import com.sheepit.client.standalone.swing.activity.Working; import com.sheepit.client.standalone.swing.activity.Working;
import lombok.Getter; import lombok.Getter;
@@ -223,6 +224,10 @@ public class GuiSwing extends JFrame implements Gui {
} }
} }
@Override public synchronized void displayTransferStats(TransferStats downloads, TransferStats uploads) {
this.activityWorking.displayTransferStats(downloads, uploads);
}
@Override public void AddFrameRendered() { @Override public void AddFrameRendered() {
framesRendered++; framesRendered++;

View File

@@ -23,6 +23,7 @@ import com.sheepit.client.Client;
import com.sheepit.client.Gui; import com.sheepit.client.Gui;
import com.sheepit.client.Log; import com.sheepit.client.Log;
import com.sheepit.client.Stats; import com.sheepit.client.Stats;
import com.sheepit.client.TransferStats;
import com.sheepit.client.standalone.text.CLIInputActionHandler; import com.sheepit.client.standalone.text.CLIInputActionHandler;
import com.sheepit.client.standalone.text.CLIInputObserver; import com.sheepit.client.standalone.text.CLIInputObserver;
@@ -132,6 +133,12 @@ public class GuiText implements Gui {
System.out.println(String.format("%s Frames rendered: %d", this.df.format(new Date()), this.framesRendered)); System.out.println(String.format("%s Frames rendered: %d", this.df.format(new Date()), this.framesRendered));
} }
@Override public synchronized void displayTransferStats(TransferStats downloads, TransferStats uploads) {
System.out.println(String
.format("%s Session downloads: %s @ %s/s / Uploads: %s @ %s/s", this.df.format(new Date()), downloads.getSessionTraffic(),
downloads.getAverageSessionSpeed(), uploads.getSessionTraffic(), uploads.getAverageSessionSpeed()));
}
@Override public void displayStats(Stats stats) { @Override public void displayStats(Stats stats) {
System.out.println(String.format("%s Frames remaining: %d", this.df.format(new Date()), stats.getRemainingFrame())); System.out.println(String.format("%s Frames remaining: %d", this.df.format(new Date()), stats.getRemainingFrame()));
System.out.println(String.format("%s Credits earned: %d", this.df.format(new Date()), stats.getCreditsEarnedDuringSession())); System.out.println(String.format("%s Credits earned: %d", this.df.format(new Date()), stats.getCreditsEarnedDuringSession()));

View File

@@ -22,6 +22,7 @@ package com.sheepit.client.standalone;
import com.sheepit.client.Client; import com.sheepit.client.Client;
import com.sheepit.client.Gui; import com.sheepit.client.Gui;
import com.sheepit.client.Stats; import com.sheepit.client.Stats;
import com.sheepit.client.TransferStats;
import com.sheepit.client.standalone.text.CLIInputActionHandler; import com.sheepit.client.standalone.text.CLIInputActionHandler;
import com.sheepit.client.standalone.text.CLIInputObserver; import com.sheepit.client.standalone.text.CLIInputObserver;
@@ -154,6 +155,10 @@ public class GuiTextOneLine implements Gui {
updateLine(); updateLine();
} }
@Override public synchronized void displayTransferStats(TransferStats downloads, TransferStats uploads) {
// Session traffic stats not shown in the 1 line UI to avoid increasing the line length above 120 chars
}
@Override public void displayStats(Stats stats) { @Override public void displayStats(Stats stats) {
remaining = stats.getRemainingFrame(); remaining = stats.getRemainingFrame();
creditsEarned = String.valueOf(stats.getCreditsEarnedDuringSession()); creditsEarned = String.valueOf(stats.getCreditsEarnedDuringSession());

View File

@@ -49,6 +49,7 @@ import com.sheepit.client.Client;
import com.sheepit.client.Job; import com.sheepit.client.Job;
import com.sheepit.client.Log; import com.sheepit.client.Log;
import com.sheepit.client.Stats; import com.sheepit.client.Stats;
import com.sheepit.client.TransferStats;
import com.sheepit.client.Utils; import com.sheepit.client.Utils;
import com.sheepit.client.standalone.GuiSwing; import com.sheepit.client.standalone.GuiSwing;
import com.sheepit.client.standalone.GuiSwing.ActivityType; import com.sheepit.client.standalone.GuiSwing.ActivityType;
@@ -75,6 +76,8 @@ public class Working implements Activity {
private JLabel connected_machines_value; private JLabel connected_machines_value;
private JLabel user_info_total_rendertime_this_session_value; private JLabel user_info_total_rendertime_this_session_value;
private JLabel userInfoQueuedUploadsAndSizeValue; private JLabel userInfoQueuedUploadsAndSizeValue;
private JLabel sessionDownloadsStatsValue;
private JLabel sessionUploadsStatsValue;
private String currentTheme; private String currentTheme;
private Log log; private Log log;
@@ -97,6 +100,8 @@ public class Working implements Activity {
lastRenderTime = new JLabel(""); lastRenderTime = new JLabel("");
lastRender = new JLabel(""); lastRender = new JLabel("");
userInfoQueuedUploadsAndSizeValue = new JLabel("0"); userInfoQueuedUploadsAndSizeValue = new JLabel("0");
sessionDownloadsStatsValue = new JLabel("0KB");
sessionUploadsStatsValue = new JLabel("0KB");
currentTheme = UIManager.getLookAndFeel().getName(); // Capture the theme on component instantiation currentTheme = UIManager.getLookAndFeel().getName(); // Capture the theme on component instantiation
previousStatus = ""; previousStatus = "";
log = Log.getInstance(parent_.getConfiguration()); log = Log.getInstance(parent_.getConfiguration());
@@ -126,6 +131,8 @@ public class Working implements Activity {
lastRenderTime = new JLabel(lastRenderTime.getText()); lastRenderTime = new JLabel(lastRenderTime.getText());
lastRender = new JLabel(lastRender.getText()); lastRender = new JLabel(lastRender.getText());
userInfoQueuedUploadsAndSizeValue = new JLabel(userInfoQueuedUploadsAndSizeValue.getText()); userInfoQueuedUploadsAndSizeValue = new JLabel(userInfoQueuedUploadsAndSizeValue.getText());
sessionDownloadsStatsValue = new JLabel(sessionDownloadsStatsValue.getText());
sessionUploadsStatsValue = new JLabel(sessionUploadsStatsValue.getText());
// set the new theme as the current one // set the new theme as the current one
currentTheme = UIManager.getLookAndFeel().getName(); currentTheme = UIManager.getLookAndFeel().getName();
@@ -163,6 +170,8 @@ public class Working implements Activity {
JLabel user_info_credits_this_session = new JLabel("Points earned: ", JLabel.TRAILING); JLabel user_info_credits_this_session = new JLabel("Points earned: ", JLabel.TRAILING);
JLabel user_info_total_rendertime_this_session = new JLabel("Duration: ", JLabel.TRAILING); JLabel user_info_total_rendertime_this_session = new JLabel("Duration: ", JLabel.TRAILING);
JLabel user_info_pending_uploads_and_size = new JLabel("Queued uploads: ", JLabel.TRAILING); JLabel user_info_pending_uploads_and_size = new JLabel("Queued uploads: ", JLabel.TRAILING);
JLabel session_download_stats = new JLabel("Total Downloads: ", JLabel.TRAILING);
JLabel session_upload_stats = new JLabel("Total Uploads: ", JLabel.TRAILING);
JLabel user_info_rendered_frame_this_session = new JLabel("Rendered frames: ", JLabel.TRAILING); JLabel user_info_rendered_frame_this_session = new JLabel("Rendered frames: ", JLabel.TRAILING);
JLabel global_static_renderable_project = new JLabel("Renderable projects: ", JLabel.TRAILING); JLabel global_static_renderable_project = new JLabel("Renderable projects: ", JLabel.TRAILING);
@@ -175,6 +184,12 @@ public class Working implements Activity {
session_info_panel.add(user_info_pending_uploads_and_size); session_info_panel.add(user_info_pending_uploads_and_size);
session_info_panel.add(userInfoQueuedUploadsAndSizeValue); session_info_panel.add(userInfoQueuedUploadsAndSizeValue);
session_info_panel.add(session_download_stats);
session_info_panel.add(sessionDownloadsStatsValue);
session_info_panel.add(session_upload_stats);
session_info_panel.add(sessionUploadsStatsValue);
session_info_panel.add(global_static_renderable_project); session_info_panel.add(global_static_renderable_project);
session_info_panel.add(renderable_projects_value); session_info_panel.add(renderable_projects_value);
@@ -260,10 +275,10 @@ public class Working implements Activity {
widthLeftColumn = Spring.max(widthLeftColumn, getBestWidth(session_info_panel, 4, 2)); widthLeftColumn = Spring.max(widthLeftColumn, getBestWidth(session_info_panel, 4, 2));
alignPanel(current_project_panel, 5, 2, widthLeftColumn); alignPanel(current_project_panel, 5, 2, widthLeftColumn);
alignPanel(global_stats_panel, 4, 2, widthLeftColumn); alignPanel(global_stats_panel, 4, 2, widthLeftColumn);
alignPanel(session_info_panel, 5, 2, widthLeftColumn); alignPanel(session_info_panel, 7, 2, widthLeftColumn);
// Set the proper size for the Working (if coming from Settings screen, the window size will be too big for the content!) // Set the proper size for the Working (if coming from Settings screen, the window size will be too big for the content!)
parent.setSize(520, 760); parent.setSize(520, 820);
} }
public void setStatus(String msg_) { public void setStatus(String msg_) {
@@ -303,6 +318,12 @@ public class Working implements Activity {
this.current_project_compute_method_value.setText(computeMethod_); this.current_project_compute_method_value.setText(computeMethod_);
} }
public void displayTransferStats(TransferStats downloads, TransferStats uploads) {
sessionDownloadsStatsValue.setText(String.format("%s @ %s/s", downloads.getSessionTraffic(), downloads.getAverageSessionSpeed()));
sessionUploadsStatsValue.setText(String.format("%s @ %s/s", uploads.getSessionTraffic(), uploads.getAverageSessionSpeed()));
updateTime();
}
public void displayStats(Stats stats) { public void displayStats(Stats stats) {
DecimalFormat df = new DecimalFormat("##,##,##,##,##,##,##0"); DecimalFormat df = new DecimalFormat("##,##,##,##,##,##,##0");
remainingFrameContent.setText(df.format(stats.getRemainingFrame())); remainingFrameContent.setText(df.format(stats.getRemainingFrame()));
@@ -334,7 +355,7 @@ public class Working implements Activity {
} }
} }
public void updateTime() { public synchronized void updateTime() {
if (this.parent.getClient().getStartTime() != 0) { if (this.parent.getClient().getStartTime() != 0) {
user_info_total_rendertime_this_session_value user_info_total_rendertime_this_session_value
.setText(Utils.humanDuration(new Date((new Date().getTime() - this.parent.getClient().getStartTime())))); .setText(Utils.humanDuration(new Date((new Date().getTime() - this.parent.getClient().getStartTime()))));