diff --git a/MobileGL/MG_Remote/Server/ServerLoop.cpp b/MobileGL/MG_Remote/Server/ServerLoop.cpp index af9098bc..08d5cfb4 100644 --- a/MobileGL/MG_Remote/Server/ServerLoop.cpp +++ b/MobileGL/MG_Remote/Server/ServerLoop.cpp @@ -28,6 +28,9 @@ #include #include #include +#if defined(__ANDROID__) +#include +#endif #include #include #include @@ -219,6 +222,23 @@ namespace MobileGL::MG_Remote::Server { return text != nullptr && text[0] != '\0'; } + // The per-frame P65ServerFrame line is a measurement aid, not a log: at one line per present + // of every session it floods the device log (and pushes the lines tests grep for out of the + // ring). Opt in with MOBILEGL_SERVER_FRAME_STATS=1, or on Android the property + // debug.mobilegl.server_frame_stats=1; read once. + Bool ServerFrameStatsEnabled() { + static const Bool enabled = [] { + const char* value = std::getenv("MOBILEGL_SERVER_FRAME_STATS"); +#if defined(__ANDROID__) + char property[PROP_VALUE_MAX] = {}; + if (value == nullptr && __system_property_get("debug.mobilegl.server_frame_stats", property) > 0) + value = property; +#endif + return value != nullptr && value[0] != '' && value[0] != '0'; + }(); + return enabled; + } + void NameThisThread(const char* name) { #if defined(__linux__) || defined(__ANDROID__) pthread_setname_np(pthread_self(), name); @@ -1099,23 +1119,25 @@ namespace MobileGL::MG_Remote::Server { // reader spent WAITING for bytes, and one that is mostly recv calls with // little read_ms is a reader that is copying. const auto read = Transport::LinkMetricsTakeReadStats(); - MGLOG_I("P65ServerFrame frame=%llu records=%llu apply_ms=%.1f wall_ms=%.1f " - "outside_ms=%.1f | read: %llu B in %llu recv(%llu reads) " - "recv_ms=%.1f total_ms=%.1f (%.0f%% blocked, %.1f MB/s)", - static_cast(++sFrameIndex), - static_cast(sFrameRecords), applyMs, wallMs, - wallMs - applyMs, - static_cast(read.bytes), - static_cast(read.calls), - static_cast(read.reads), - static_cast(read.nsInRecv) / 1e6, - static_cast(read.nsTotal) / 1e6, - read.nsTotal ? 100.0 * static_cast(read.nsInRecv) / - static_cast(read.nsTotal) - : 0.0, - read.nsTotal ? static_cast(read.bytes) / - (static_cast(read.nsTotal) / 1e9) / 1e6 - : 0.0); + if (ServerFrameStatsEnabled()) { + MGLOG_I("P65ServerFrame frame=%llu records=%llu apply_ms=%.1f wall_ms=%.1f " + "outside_ms=%.1f | read: %llu B in %llu recv(%llu reads) " + "recv_ms=%.1f total_ms=%.1f (%.0f%% blocked, %.1f MB/s)", + static_cast(++sFrameIndex), + static_cast(sFrameRecords), applyMs, wallMs, + wallMs - applyMs, + static_cast(read.bytes), + static_cast(read.calls), + static_cast(read.reads), + static_cast(read.nsInRecv) / 1e6, + static_cast(read.nsTotal) / 1e6, + read.nsTotal ? 100.0 * static_cast(read.nsInRecv) / + static_cast(read.nsTotal) + : 0.0, + read.nsTotal ? static_cast(read.bytes) / + (static_cast(read.nsTotal) / 1e9) / 1e6 + : 0.0); + } sFrameWallStart = now; sFrameApplyNs = 0; sFrameRecords = 0; diff --git a/README.md b/README.md index fac07295..4da0ac05 100644 --- a/README.md +++ b/README.md @@ -173,6 +173,7 @@ MobileGL supports runtime configuration via environment variables. | `MOBILEGL_ESPRYT_AVOID_SAMPLER_MIPMAP_MIN_FILTER` | Avoid sampler mipmap minification filters. | `0`, `1` | `0` | | `MOBILEGL_COHERENT_AS_FLUSH` | Treat persistent `GL_MAP_FLUSH_EXPLICIT_BIT` maps as coherent (app-compat for engines like Flywheel that never flush them). | `0`, `1` | `0` | | `MOBILEGL_ESPRYT_FORCE_DS_READBACK_EMULATION` | Always emulate depth/stencil `glReadPixels`/`glGetTexImage` by shader sampling on Espryt, instead of using the driver's own depth/stencil readback where it has one. | `0`, `1` | `0` | +| `MOBILEGL_SERVER_FRAME_STATS` | Log one `P65ServerFrame` timing line per presented frame on the server (apply vs. wall time, socket read rate). On Android also `debug.mobilegl.server_frame_stats`. | `0`, `1` | `0` | | `VK_ICD_FILENAMES` | Select the Vulkan ICD used by the Vulkan loader. | Path to an ICD JSON file | Loader default | ## License diff --git a/tools/device_bench/disagg/README.md b/tools/device_bench/disagg/README.md index 10982057..06e8b2ef 100644 --- a/tools/device_bench/disagg/README.md +++ b/tools/device_bench/disagg/README.md @@ -95,7 +95,7 @@ P6.5 link numbers: `docs/Disaggregated/notes/p12/CROSSHOST-ACCEPTANCE.md`. ## netbench.sh — Wi-Fi TCP throughput baseline **Understates the link**: the `toybox nc` sink capped at 18-22 MiB/s while the render server -read 52 MB/s on the same Wi-Fi. Use the server's `P65ServerFrame` read rate as the throughput number. +read 52 MB/s on the same Wi-Fi. Use the server's `P65ServerFrame` read rate as the throughput number (enable it with `MOBILEGL_SERVER_FRAME_STATS=1` or `setprop debug.mobilegl.server_frame_stats 1`; it is off by default). WSL -> phone bulk transfer over `toybox nc` sink, 3 reps; refuses to run unless `tcp_path_check.sh` passes. The `nc` listener must keep stdin open or it