native: frame-rate setting, idle frame rate and battery power telemetry

- MtFrameRate setting (30 / 60 default / display max) as app.Get/SetFrameRateMode,
  with a "画面帧率" row injected into the system option dialog (mt_framerate); saved
  in the SDL pref path.
- FrameRatePolicy in the live loop: 30 fps after 15 s without input (not while auto
  hunting), display switched to 60 Hz unless the highest mode, ADPF
  setPreferPowerEfficiency, vsync pacing when the display already runs at the target.
  --fps-mode / --idle-fps / --idle-after; --fps-cap / --refresh-rate still pin a test run.
- Perf log: battery current/voltage/power, plugged, fps_mode, idle columns;
  perf_summary groups power by mode.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
shenlei
2026-09-29 18:14:19 +09:00
co-authored by Claude Opus 5.5
parent c2cc093ed0
commit 82503315c6
9 changed files with 453 additions and 19 deletions
+13
View File
@@ -74,6 +74,19 @@ def main():
print("median fps %.1f frame p95 %.1f ms jank>33ms %d frames jank>50ms %d frames" % (
median(rows, "fps"), median(rows, "frame_p95_ms"),
sum(int(num(r, "jank33")) for r in rows), sum(int(num(r, "jank50")) for r in rows)))
if "power_mw" in rows[0]:
# power_mw is -1 in a window with any sample on the charger: the battery current is then the
# charger's surplus, not the app's draw. Split by frame-rate mode and idle.
print("power (battery, unplugged windows only; plugged windows show current only)")
groups = {}
for r in rows:
groups.setdefault((r.get("fps_mode", "?"), r.get("idle", "?")), []).append(r)
for (mode, idle), rs in sorted(groups.items()):
powered = [r for r in rs if num(r, "power_mw") >= 0]
print(" mode %s%s: %d windows fps %.1f %s current %.0f mA" % (
mode, " idle" if idle == "1" else "", len(rs), median(rs, "fps"),
("power %.0f mW (%d windows)" % (median(powered, "power_mw"), len(powered))) if powered
else "power n/a (plugged)", median(rs, "batt_ma")))
print("median actors %.0f draws %.0f skinned %.0f python calls/frame %.0f (missing %.0f)" % (
median(rows, "actors"), median(rows, "draws"), median(rows, "skinned_draws"),
median(rows, "py_calls"), median(rows, "py_missing")))