Merge slowing down, then pausing, the scan when the tower computer runs hot or cannot keep up

Built and tested in an Ubuntu 22.04 container (mock and Vimba+MQTT, 494/494)
and running on tower 111 since 2026-10-14.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Peter Bochmann 2026-10-14 19:30:21 +02:00
commit a03da2d8f4
Signed by: peter.bochmann
GPG Key ID: 94E8C523489B8AC1
63 changed files with 4685 additions and 42 deletions

View File

@ -95,6 +95,7 @@ add_library(fgc_core STATIC
src/core/ChannelTopics.cpp
src/core/RawImage.cpp
src/core/SettleRule.cpp
src/core/ThermalGuard.cpp
src/sensors/I2cBus.cpp
src/sensors/Sht41Protocol.cpp
src/sensors/McuEnvSensor.cpp

View File

@ -273,6 +273,9 @@ enable_env = false
; The mocks are NOT legacy: substituting a simulated device is a choice about
; this run, not a statement about what is bolted to the tower, so it stays here.
mock_camera = false
; The simulated camera's frames: small (640x480 colour) or full (the real
; camera's 5328x3040 12-bit raw - saving then loads the CPU as on a tower).
;mock_camera_size = small
mock_serial = false
mock_imu = false
mock_env = false

View File

@ -76,6 +76,42 @@ save_queue_max = 4
; A tower with no hardware.ini at all is never reconciled, whatever
; strict_presence says: gaining this file must not change how a tower behaves.
[Thermal]
; The CPU guard: in summer the sun and the gimbal heat this computer until its
; CPU slows itself down. The guard spaces pictures out, then pauses them (gimbal
; parked, camera stream stopped) until it cools - it never stops the program and
; never touches picture quality. Every key may be left out; these are the
; defaults. See docs/thermal-throttling.md.
;enabled = true
; Slowed: pictures at least slow_factor times further apart (more if saving
; needs it: 1.5 x the save time per worker), from slow_c, or when the CPU
; throttles, or when saving is the bottleneck - the scan waited for it
; held_share_pct of the last minute, or held_slow_s in one go. Back to full pace
; once below slow_c - hysteresis_c, keeping up, and saving fast enough for it,
; for calm_s.
;slow_c = 85
;hysteresis_c = 5
;slow_factor = 2
;calm_s = 120
;held_share_pct = 25
;held_slow_s = 30
; Paused: at pause_c for pause_after_s, or saving still the bottleneck
; held_pause_s after slowing (or one wait that long). Resumes (slowed) after
; min_pause_s once at resume_c or below and nothing is left to save.
;pause_c = 92
;pause_after_s = 20
;held_pause_s = 120
;resume_c = 75
;min_pause_s = 300
; Throttling is also judged from the clock - below clock_low_pct of the chip's
; top speed while at least busy_high_pct busy - which catches the power-limit
; slow-downs the kernel does not count.
;clock_low_pct = 50
;busy_high_pct = 50
;sample_ms = 2000
; A fake /sys + /proc tree for a simulation (tools/thermal-sim/fake-temp.sh).
;sysfs_root = /
; --- Where to find it -----------------------------------------------------
; Device bindings. These follow the hardware, not the tower, so they belong here
; rather than in config.ini.

View File

@ -84,6 +84,7 @@ Parsed and validated by `ConfigLoader` ([src/core/Config.cpp](../src/core/Config
| `Features` | `enable_serial` | bool | `true` | (reserved) |
| `Features` | `enable_imu` | bool | `false` | **Legacy.** Derived from `[Hardware] imu` wherever that is declared; kept only for towers without a `hardware.ini`. A flag contradicting the declaration is warned about and ignored |
| `Features` | `mock_camera` | bool | `false` | Use the simulated camera |
| `Features` | `mock_camera_size` | `small`/`full` | `small` | The simulated camera's frames: `small` = 640×480 colour; `full` = the real camera's 5328×3040 12-bit raw, so saving costs the CPU what it does on a tower (throttling simulations) |
| `Features` | `mock_serial` | bool | `false` | Use the simulated motor controller |
| `Features` | `mock_imu` | bool | `false` | Use the simulated IMU instead of the MTi |
| `Features` | `enable_env` | bool | `false` | **Legacy.** Derived from `[Hardware] env` wherever that is declared; same rule as `enable_imu` |
@ -541,6 +542,35 @@ measured), both edges included - so `mode pan 90 30` takes six pictures, 75°
to 105°. It is a property of the camera and lens, so it lives in
`hardware.ini`. Must be above 0. See [mqtt-api.md](mqtt-api.md#modes-auto-pan-manual).
### When the computer runs hot: `[Thermal]`
The CPU guard ([ThermalGuard.h](../include/fgc/ThermalGuard.h)) reads the CPU's
temperature, clock, throttle counters and busy time every `sample_ms` and paces
the scan to them. It never stops the program, never changes the mode and never
touches picture quality. Per computer, so normally in `hardware.ini`
(`config.ini` works too). Every key is optional.
| Key | Default | Meaning |
|---|---|---|
| `enabled` | `true` | `false`: full pace however hot (readings and throttling log go on) |
| `slow_c` | 85 | Slowed from this CPU temperature (°C) |
| `hysteresis_c` | 5 | Back to normal needs `slow_c - hysteresis_c` |
| `slow_factor` | 2 | Slowed = pictures at least this many times further apart (1..10); further still when saving needs it (1.5 × the save time per worker) |
| `calm_s` | 120 | Slowed → normal once all clear this long, and the normal pace fits what saving takes |
| `held_share_pct` | 25 | Slowed when the scan spent this share of the last minute waiting for saving |
| `held_slow_s` | 30 | Slowed when saving has kept the scan waiting this long in one go |
| `pause_c` | 92 | Paused once at this temperature for `pause_after_s` |
| `pause_after_s` | 20 | |
| `held_pause_s` | 120 | Paused when saving has kept the scan waiting this long in one go, or is still the bottleneck this long after slowing down |
| `resume_c` | 75 | A pause ends at or below this, after `min_pause_s`, with nothing left to save |
| `min_pause_s` | 300 | |
| `clock_low_pct` / `busy_high_pct` | 50 / 50 | Throttling judged from the clock: below this share of the top clock while at least this busy |
| `sample_ms` | 2000 | 500..60000 |
| `sysfs_root` | `/` | A fake `/sys` + `/proc` tree for a simulation ([tools/thermal-sim](../tools/thermal-sim/)) |
Must hold: `resume_c < slow_c < pause_c`, `held_slow_s <= held_pause_s`. The
whole story, and how to simulate it, is in [thermal-throttling.md](thermal-throttling.md).
### The legacy towers: a DHT11 and a fan on the motor MCU
Four towers carry an ambient DHT11 and an enclosure fan wired to the Leonardo
@ -683,6 +713,7 @@ Parsed by Boost.Program_options ([main.cpp](../main.cpp)). Flags override `[Feat
| `-c, --config <path>` | Explicit config file path |
| `--no-mqtt` | Disable MQTT (use the null channel) |
| `--mock-camera` | Use the simulated camera |
| `--mock-camera-full` | Simulated camera with tower-size 12-bit frames (implies `--mock-camera`) |
| `--mock-serial` | Use the simulated motor controller |
| `--mock-env` | Use the simulated ambient temp/humidity sensor (implies `[Features] enable_env`) |
| `--degraded` | Start even though declared hardware is missing (field triage; overrides `strict_presence` and says so loudly in the log) |
@ -725,6 +756,8 @@ Handled in `Application::Impl::handleCommand`.
| `snapshot` | One image now, through the scan's settle-and-trigger path (manual mode, homed) |
| `capture [on\|off]` | Continuous capture where the gimbal is aimed: one image per `image_interval` since the last, each once the gimbal has stood still for `settle_wait_ms`. Manual mode, homed; ends on any mode change, homing, heading setup or test. Bare: report |
| `camera reset` | Reboot the cameras and put them back on their profiles |
| `thermal` | The CPU's temperature, clock, load and throttling, and whether the scan is slowed or paused for it. Any mode |
| `thermal resume` / `thermal off` / `thermal on` | Back to full pace now (the rules then apply afresh) / turn the CPU guard off or on until restart. Any mode |
| `test camera [frames\|dark\|bright]` | Check the camera delivers frames and responds to exposure/gain |
| `test [<subsystem> [<leaf>]] [<profile>]` | Run the hardware self-test suite (see below) |
| `test list` / `test baseline` | List profiles / pin the last report as the comparison baseline |

View File

@ -26,7 +26,7 @@ Per-file reference for the refactored tree, plus the shared data structures.
| [include/fgc/DiagParser.h](../include/fgc/DiagParser.h), [src/core/DiagParser.cpp](../src/core/DiagParser.cpp) | `parseDiag` firmware `DG` self-test stream → `DiagResult` (per-axis tests, PASS/FAIL); `formatDiag` |
| [include/fgc/TestRunner.h](../include/fgc/TestRunner.h), [src/core/TestRunner.cpp](../src/core/TestRunner.cpp) | The `test` command: resolves `test [<subsystem> [<leaf>]]` to a set of leaf tests, knows which need a homed gimbal (the `test hardware` leaves deliberately do not), and runs them on a worker thread with live progress, handing back a `TestReport` |
| [include/fgc/TestReport.h](../include/fgc/TestReport.h), [src/core/TestReport.cpp](../src/core/TestReport.cpp) | A self-test run's result as plain data: formats a human-readable text report that `parseTestReport` reads back, so a run can be compared with the baseline or the previous one |
| [include/fgc/HostMetrics.h](../include/fgc/HostMetrics.h), [src/core/HostMetrics.cpp](../src/core/HostMetrics.cpp) | Tower computer health for `test host`: CPU temperature, disk, memory and load. Pure parsers split from the live `/sys` and `/proc` readers so they unit-test anywhere; readers report `ok = false` rather than throw |
| [include/fgc/HostMetrics.h](../include/fgc/HostMetrics.h), [src/core/HostMetrics.cpp](../src/core/HostMetrics.cpp) | Tower computer health for `test host` and the CPU guard: CPU temperature, clock, kernel throttle counters, busy time, disk, memory and load. Every `/sys` and `/proc` path sits under a `root`, so a fake tree stands in for a simulation. Pure parsers split from the live `/sys` and `/proc` readers so they unit-test anywhere; readers report `ok = false` rather than throw |
| [include/fgc/Calibration.h](../include/fgc/Calibration.h), [src/core/Calibration.cpp](../src/core/Calibration.cpp) | `linearFit` (least-squares, R²) + `circularMeanDeg` for the IMU-referenced calibration |
| [include/fgc/PitchSetup.h](../include/fgc/PitchSetup.h), [src/core/PitchSetup.cpp](../src/core/PitchSetup.cpp) | `gimbal pitch setup` worker thread: home-if-needed → pitch sweep dwelling on the gravity-referenced IMU pitch → least-squares fit → park level; tunable via `CalibParams`; exposes `progress()`/`report()`/`takeResult()`. Yaw is not touched |
| [include/fgc/HeadingFit.h](../include/fgc/HeadingFit.h), [src/core/HeadingFit.cpp](../src/core/HeadingFit.cpp) | `gimbal heading fit`: least-squares fit of the yaw map from operator sightings of landmarks with known true bearings. Sorts by encoder position, unwraps bearings so a set spanning north fits one line, and refuses a baseline under 10° (two points always fit exactly, so a short baseline looks perfect and is wrong). No IMU involved |
@ -41,7 +41,8 @@ Per-file reference for the refactored tree, plus the shared data structures.
| [include/fgc/ChannelHistory.h](../include/fgc/ChannelHistory.h), [src/core/ChannelHistory.cpp](../src/core/ChannelHistory.cpp) | Ring buffer of recently published messages (time, topic, payload, outcome) plus the delivery counters — sent, failed, connects, losses, last status. Feeds the expanded Connectivity view so a publish can be confirmed without a broker-side subscriber |
| [include/fgc/RemoteCommands.h](../include/fgc/RemoteCommands.h), [src/core/RemoteCommands.cpp](../src/core/RemoteCommands.cpp) | Console commands that arrive over MQTT: run through the same handler as typed ones, on the control thread, and answered on `CommandReply` with every line they logged. Retained messages are never run, a repeated id is answered again rather than re-run, each is audited in the log, and a reply that depends on the firmware (`gimbal dump`) waits for its answer |
| [include/fgc/Hash.h](../include/fgc/Hash.h), [src/core/Hash.cpp](../src/core/Hash.cpp) | FNV-1a 64 over a string or a file, with an algorithm-prefixed label. Change detection for the profile records, deliberately not a crypto hash |
| [include/fgc/CaptureScheduler.h](../include/fgc/CaptureScheduler.h), [src/core/CaptureScheduler.cpp](../src/core/CaptureScheduler.cpp) | Capture state machine over the interfaces: move, standstill, settle wait (+ `SettleRule`), the rest of the interval since the last frame, keep; holds while saving is behind; injectable clock; `setGeometry` adopts a recalibration |
| [include/fgc/CaptureScheduler.h](../include/fgc/CaptureScheduler.h), [src/core/CaptureScheduler.cpp](../src/core/CaptureScheduler.cpp) | Capture state machine over the interfaces: move, standstill, settle wait (+ `SettleRule`), the rest of the interval since the last frame, keep; holds while saving is behind; slowed (`setIntervalScale`) or paused (`setPaused`) by the CPU guard; injectable clock; `setGeometry` adopts a recalibration |
| [include/fgc/ThermalGuard.h](../include/fgc/ThermalGuard.h), [src/core/ThermalGuard.cpp](../src/core/ThermalGuard.cpp) | The CPU guard, pure: fed one host sample at a time (temperature, clock, throttle counters, busy %, whether saving holds the scan), it says normal / slowed / paused and returns the log lines; `ThrottleWatch` logs throttling as it starts, once a minute while it lasts, and when it ends. Never stops the program or changes the mode ([thermal-throttling.md](thermal-throttling.md)) |
| [include/fgc/SettleRule.h](../include/fgc/SettleRule.h), [src/core/SettleRule.cpp](../src/core/SettleRule.cpp) | The `settle_rule = brightness` keep rule, pure: fed one frame's brightness, exposure and gain at a time, says when the image has settled (in the camera's target band and steady for 3 frames) or is pinned at the auto-exposure limits |
| [include/fgc/RawImage.h](../include/fgc/RawImage.h), [src/core/RawImage.cpp](../src/core/RawImage.cpp) | Pixel layouts the program accepts (`Mono8`, `RGB8`, `BayerRG8`, `BayerRG12p`), their sizes and bit depths, `unpack12p`, and `sampleBrightness` - the cheap per-frame sample the keep rule reads |
| [include/fgc/CameraStall.h](../include/fgc/CameraStall.h), [src/core/CameraStall.cpp](../src/core/CameraStall.cpp) | When a camera stream delivers nothing new: wait, restart the stream, or reset the camera. Pure policy, scaled by the exposure and frame period so a slow frame is not taken for a stall |

View File

@ -78,6 +78,7 @@ setup, or while a test or calibration runs.
|-------|------|---------|--------------|
| `GGS/FWT/<tower>/StatusCode` | At startup, on every mode change, and again on every reconnect | the mode: `"0"` auto, `"1"` pan, `"2"` manual | 1 / retained |
| `GGS/FWT/<tower>/CamEvent` | After each image is saved | JSON object (below) | 1 / retained |
| `GGS/FWT/<tower>/Health` | When the CPU guard changes state or throttling starts/ends, once a minute, after a `thermal` command, and on every reconnect | JSON object (below) | 1 / retained |
StatusCode says what the tower **is doing**, not what it was last asked to do:
it is published by the mode change itself, whatever caused it. Being retained,
@ -134,6 +135,42 @@ Both `hdg` and `pit` are sampled **when the frame arrives**, not when its JPEG X
finishes, so a slow encode or a backed-up queue cannot attribute a later pose to earlier
pixels.
CamEvent and Health leave through a small queue on their own thread, so a slow link
never holds an image save or the control loop. If 64 are waiting, the oldest is
dropped (and shows as dropped in the connectivity view).
### Health payload
The tower computer's heat and load, and whether the scan is slowed or paused for it
(see [thermal-throttling.md](thermal-throttling.md)). The mode in StatusCode does
**not** change: a paused auto scan is still `"0"`, and carries on by itself once cool.
```json
{"fwt":"t121","state":"paused","reason":"CPU at 93 °C for 20 s","guard":true,
"cpu_c":93.0,"cpu_mhz":1188,"cpu_busy_pct":41,"throttling":true,
"throttle_events_last_min":14,"enclosure_c":48.2,"saved_last_min":0,
"save_ms_mean":null,"save_ms_max":null,"held_s":0,"interval_s":10.0,
"time":1759917600000}
```
| Field | Type | Meaning |
|-------|------|---------|
| `state` | string | `normal`, `slowed` (pictures `slow_factor`× further apart) or `paused` (gimbal parked, camera stream stopped) |
| `reason` | string | Why not normal, in words; `""` when normal |
| `guard` | bool | `false` after `thermal off`: full pace whatever the heat |
| `cpu_c` | number/null | Hottest CPU thermal zone, °C |
| `cpu_mhz` | number/null | Mean clock over the cores |
| `cpu_busy_pct` | number/null | How busy the CPU was since the last sample |
| `throttling` | bool | The CPU is slowing itself (kernel counters, or a low clock while busy) |
| `throttle_events_last_min` | int | Kernel throttle events counted in the last minute |
| `enclosure_c` | number/null | The ambient sensor (SHT41/DHT11), when there is one |
| `saved_last_min`, `save_ms_mean`, `save_ms_max` | int, number/null | Pictures saved in the last minute and how long each took |
| `held_s` | int | How long the scan has been waiting for saving to catch up |
| `interval_s` | number | Time between pictures now |
| `time` | int | Unix epoch ms |
A missing reading is `null`, never `0`.
## Remote commands: `Command` / `CommandReply`
For development and maintenance: **any console command** - everything that can
@ -239,6 +276,7 @@ subscribe: GGS/FWT/<tower>/Command (any console command: JSON {id, cmd}
publish: GGS/FWT/<tower>/StatusCode (the mode: 0 auto, 1 pan, 2 manual)
GGS/FWT/<tower>/CamEvent (JSON: fwt, cam, hdg×10, pit×10, time-ms)
GGS/FWT/<tower>/Health (JSON: CPU guard state, CPU °C/MHz/busy, throttling, saving)
GGS/FWT/<tower>/CommandReply (JSON: id, cmd, level, lines, truncated - not retained)
```

247
docs/thermal-throttling.md Normal file
View File

@ -0,0 +1,247 @@
# When the tower computer runs hot
In summer the sun and the gimbal heat the LattePanda until its CPU slows itself
down (throttles). Since the 12-bit raw pipeline, the tower also de-Bayers and
encodes every picture, ~1.4 CPU-seconds each
([raw12-pipeline-measurements.md](raw12-pipeline-measurements.md)). This page
says what happens then, what the program does about it, and how to simulate it.
**The rule:** heat or overload only ever **pauses** the program - it never
exits, never changes the mode, never touches picture quality or resolution. It
slows the scan, then parks it, and carries on by itself once the computer has
cooled. An exit would leave the tower dark until someone restarted it; a paused
tower costs some pictures and comes back alone.
## What was already safe, and what was not
| | Before | Now |
|---|---|---|
| Saving falls behind | The scan holds at its waypoint (`save_queue_max`), so frames never pile up in memory | Same, and a long hold now slows, then pauses the scan |
| CPU temperature | Read only by `test host` | Read every 2 s; on the Sensors panel, in the log, on MQTT `Health` |
| Throttling | Invisible (`ThermalInfo::throttled` was never set) | Logged when it starts, once a minute while it lasts, and when it ends |
| A hot, struggling CPU | Kept at full pace: the camera streaming, the encoder busy, the modem starved | Pictures spaced out (to fit the measured save time), then paused with the camera stream off |
| Slow 5G link | Each picture's CamEvent held the save worker up to 3 s | CamEvent and Health leave through their own queue and thread |
| Save workers | Same priority as the control loop, serial, IMU, MQTT | nice +5 (libjxl's threads inherit it) |
| Camera streaming, nothing saved | ~40% of one core on tower 111, always | Stopped while paused (buffer reuse was tried and measured no gain, so dropped) |
## The CPU guard
[ThermalGuard.h](../include/fgc/ThermalGuard.h). Every `sample_ms` (2 s) the
control loop reads the hottest thermal zone, the cores' clock, the kernel's
throttle counters and how busy the CPU was, plus whether saving is holding the
scan. The guard is pure - a reading in, a state and log lines out - so every
rule is unit-tested ([test_thermalguard.cpp](../tests/test_thermalguard.cpp)).
```
CPU >= slow_c (85), or throttling, or the scan waited for saving
25% of the last minute (or 30 s in one go)
NORMAL -----------------------------------------------------------> SLOWED
(as <-- 120 s all clear: CPU < 80, no throttling, waiting under pictures 2x further
configured) 12%, and saving fast enough for the normal pace --------- apart, or 1.5x the
| save time if longer
| CPU >= pause_c (92) for 20 s, or one 120 s wait for saving, |
| or saving still the bottleneck 120 s after slowing |
+--------------------------------> PAUSED <-------------------------+
gimbal parked where it is,
camera stream stopped, saving drains
|
| after 300 s, CPU <= resume_c (75)
v and nothing left to save
SLOWED
```
- **Slowed** stretches the interval (`CaptureScheduler::setIntervalScale`):
at least `slow_factor`, and as far as 1.5 × the measured save time per worker
when that is longer - so a CPU that saves slowly runs about two-thirds busy
instead of flat out. Fewer pictures per minute is less encoding and less motor
work. It returns to the normal pace only once that pace fits what saving
takes, so a saver that is simply too slow does not flap between the two.
- **Saving as the bottleneck** is judged by the share of each minute the scan
waits for it, not only by one long wait: a saver a little too slow holds the
scan 2-3 s at every waypoint and never once for long, yet keeps the CPU
pegged (see the results below).
- **Paused** finishes the waypoint under way, then starts no new move
(`setPaused`); once parked, the camera stream stops, so the CPU all but idles.
A snapshot an operator asks for is still taken.
- **Throttling** counts two ways: the kernel's `thermal_throttle` counters rising
(heat), or the clock below 50% of the chip's top while at least 50% busy, two
samples running. The second catches the power-limit slow-downs the counters
never count - and a clock capped by `cap-cpu.sh`.
- Missing readings (no thermal zone, no cpufreq) are left out of the rules, never
read as 0 °C or as hot.
- The mode does not change: StatusCode still says `0` for a paused auto scan.
Health says `paused`, and why.
All thresholds are `[Thermal]` keys, normally in `hardware.ini`
([configuration.md](configuration.md#when-the-computer-runs-hot-thermal)).
### Seeing it
- **Sensors panel** (`s`): a *LattePanda CPU* group - CPU temp, clock, load,
throttled - with a `HOT` / `THROTTLED` / `SLOWED` / `PAUSED` badge. The
expanded view adds the per-core clocks and any cap, load averages, throttle
counts, save time per picture, and the guard's state and reason.
- **Log**, in plain words:
```
CPU is slowing itself to stay cool: 94 °C, running at 1.2 GHz of 3.6 GHz
CPU still slowed: 14 times in the last minute, 94 °C, 1.1 GHz
CPU at 94 °C for 20 s: pausing pictures for at least 5 min, until the CPU is at 75 °C or below and saving has caught up
camera stream stopped while pictures are paused
CPU at 72 °C: pictures resume, one picture every 10.0 s instead of 5.0 until it has been calm for 2 min
Saving kept the scan waiting 27% of the last minute: one picture every 6.9 s instead of 2.0 until saving is fast enough for the normal pace, for 2 min
CPU no longer slowed: 72 °C
saving: 28 pictures in the last minute, 653 ms each on average (longest 817 ms)
```
- **MQTT** `GGS/FWT/<tower>/Health`, retained ([mqtt-api.md](mqtt-api.md#health-payload)).
- **Console / MQTT Command**: `thermal` (readings and pace), `thermal resume`,
`thermal off|on`. Allowed in every mode.
## Simulating it
[tools/thermal-sim/](../tools/thermal-sim/):
| Script | What it does | Root |
|---|---|---|
| `fake-temp.sh <root> init\|<C> [throttle]\|clock <MHz>\|ramp ...` | A fake `/sys` tree (busy % stays the real `/proc/stat`); the program reads it with `[Thermal] sysfs_root = <root>` | no |
| `cap-cpu.sh <MHz>\|restore` | Caps every core's clock (`scaling_max_freq`) | yes |
| `cap-power.sh <W>\|restore` | Caps package power (RAPL), like the 6 W TDP mode | yes |
| `heat-load.sh <cores> <secs>` | Busy cores competing with the program | no |
With `--mock-camera-full` (or `[Features] mock_camera_size = full`) the mock
camera delivers the real camera's 5328×3040 12-bit raw frames, so the program
saves - and loads the CPU - as on a tower, on any machine:
```
fire_gimbal_control -c sim/config.ini --mock-camera-full --mock-serial --no-mqtt
```
A CPU that cannot keep up, without root: `systemd-run --user --scope -p CPUQuota=50% fire_gimbal_control ...`.
## Results on the desk (2026-10-08)
i5-7300U (4 threads, 3.5 GHz - near the IOTA's N150), mock gimbal, tower-size
12-bit mock frames, `image_interval = 2`, short guard timings for the test
(`pause_after_s 10`, `calm_s 20`, `min_pause_s 30`, `held_pause_s 60`). A save
took 0.65-0.85 s.
**A. Heat (fake temperatures, real program).** `fake-temp.sh` walked the CPU
70 → 88 → 94 (+ throttle events) → 72 °C while the scan ran:
| Time | CPU | What the program did | Picture spacing |
|---|---|---|---|
| 0:00 | 70 °C | normal | 2.1-2.2 s |
| +0:01 | 88 °C | slowed (within one sample) | 4.2 s |
| +0:30 | 94 °C, throttling | "CPU is slowing itself to stay cool" at once; paused after 11 s, camera stream off 2 s later once the waypoint finished | none for 29 s |
| +1:11 | 72 °C | resumed, still slowed, after the 30 s minimum pause | 4.2 s |
| +2:09 | 72 °C | "CPU no longer slowed" one quiet minute after the last throttle event | 4.2 s |
| +2:51 | 72 °C | back to the normal pace after 20 s calm | 2.1 s |
No waypoint skipped, no overrun warnings, clean shutdown, 68 pictures.
**B. A CPU that cannot keep up (no heat).** The program held to half of one core
(`CPUQuota=50%`), so a save took 4.5-5 s against the 2 s interval:
- *Before* the share rule: the save gate held the scan 2-3 s at every waypoint,
pictures came every ~4.6 s, and the CPU sat **pegged for all 5 minutes**. The
guard never acted - no single wait reached 30 s - and the log said "saving is
behind / caught up" twice per picture.
- *After:* "Saving kept the scan waiting 27% of the last minute: one picture every
6.9 s instead of 2.0" after the first minute; from then on no holds at all and
the spacing followed the save time (7-10 s), stable for the rest of the run -
no flapping back to the 2 s pace it could not hold, no pause needed. The hold
warning is now said once, not at every waypoint.
The dashboard was checked in a real terminal: the Sensors panel's *LattePanda
CPU* group (88.0 °C, 2.8 GHz, 37 %, "yes, 2x last min", `SLOWED`) and the
expanded view's CPU section.
## Results on tower 111 (3 Delta, N5105, 2026-10-08)
Ambient: the enclosure sensor read 21 °C. The tower program was stopped for the
benchmark and replaced by the test build for the run; the tower's own build and
config were not touched. Raw data: `tools/camera-bench/results-2026-10-08-tower111-throttle/`.
### What a throttled Delta can sustain (`raw12_bench`)
The synthetic 5328×3040 12-bit frame (`make_synthetic.py`), edge-aware
de-Bayer, JPEG XL distance 1.0 effort 3, the tower's 1 worker × 4 threads. Each
condition: 60 s flat out, then 120 s at one picture per 2 s. `cap-cpu.sh` and
`cap-power.sh` set the limits; `stress-ng --cpu 2` is "2 busy cores".
| Condition | Save time | Most per second | CPU-s / picture | Pile-up after 2 min at one per 2 s | Temp mean / max |
|---|---|---|---|---|---|
| none (2.9 GHz) | 1.0 s | 0.98 | 2.3 | 0 | 63 / 80 °C |
| clock capped 1.6 GHz | 1.7 s | 0.58 | 4.0 | 0 | 57 / 59 °C |
| clock capped 1.2 GHz | 2.2 s | 0.45 | 5.2 | 6 frames (latency to 14.6 s) | 56 / 58 °C |
| clock capped 0.8 GHz | 3.3 s | 0.30 | 7.6 | 23 frames (latency to 51 s) | 54 / 56 °C |
| power capped 6 W | 1.0 s | 0.87 | 2.4-2.7 | 0 | 61 / 74 °C |
| 2 busy cores | 1.4 s | - | 2.3 | 0 | 79 / **88** °C |
| 0.8 GHz + 2 busy cores | 4.4 s | 0.22 | 6.9 | 33 frames (latency to 69 s) | 52 / 54 °C |
- At the tower's real pace, a picture every **5 s**, it keeps up in every case:
at 0.8 GHz saving takes two-thirds of the time, and with 2 busy cores on top
(4.4 s per save) it is on the edge - where the guard's headroom rule would
space pictures to ~6.6 s.
- The bare benchmark has no brake, so a slow CPU piles frames up (23-33 in two
minutes, ~24 MB each). In the program the save gate stops that and the guard
then slows the scan.
- The 6 W power cap hardly matters: saving draws only 6-8 W of the 10 W limit.
- The hottest run was competing load, not saving: 88 °C with 2 busy cores.
- **The kernel never counted a throttle event** in any run (all counters 0) -
21 °C was not hot enough. The counters exist on this kernel, so real heat
will be counted; the clock caps here are seen by the clock rule instead.
- Tower 111's camera is a 1800 U-1240c, 4024×3036: its real saves are 0.64-0.68 s,
about two-thirds of the synthetic frame's.
### The program on the tower, CPU capped to 0.8 GHz with 2 busy cores
The test build with the tower's own config, camera, gimbal and local MQTT
broker: 3 min normal, 6 min capped + loaded, 3 min restored.
| Time | What happened | Pictures | Save time |
|---|---|---|---|
| 16:57 | homed, auto scan, Health `normal`, CPU 51 °C | one per 5 s | 0.64-0.68 s |
| 16:59:32 | clock capped, 2 cores busy | | |
| 16:59:36 | "CPU is running slow while busy (judged from its clock...): 53 °C, running at 0.8 GHz of 2.9 GHz"; Health `slowed` | one per 10 s | 3.6-3.8 s |
| every minute | "CPU still slowed: clock low all minute" | | |
| 17:05:32 | cap lifted | | 0.64-0.72 s |
| 17:06:31 | "CPU no longer slowed" | one per 10 s | |
| 17:08:31 | "back to the normal picture pace"; Health `normal` | one per 5 s | |
The scan never waited for saving (`held_s` 0 throughout), the CPU ran 66-91%
busy while capped and loaded, and the program shut down cleanly; 34 pictures,
13 Health messages on `GGS/FWT/dev/Health`.
### What the camera stream costs on its own
Manual mode, one snapshot to start the stream, then 60 s of the program's own
CPU time with nothing saved (`stream_cost.sh`):
| Build | CPU while streaming |
|---|---|
| installed (main) | 39.2% of one core |
| reusing the frame buffer instead of a fresh 24 MB per frame | 40.8% of one core |
Reusing the buffer made no difference, so it was dropped. The stream itself
costs **about 40% of one core - a tenth of the computer - all the time it runs**,
whether or not pictures are saved: the program copies every frame it streams.
That is why a pause stops the stream. A lower streaming frame rate, or copying
only the frame that is kept, would cut it while scanning too; both touch the
fragile camera stream, so they are left for a separate change.
### Found on the way
- `x86_pkg_temp` is not the only thermal zone on the towers: tower 111 also lists
the Wi-Fi card (`iwlwifi_1`) and `acpitz`. The guard now reads the CPU package
zone, so a hot Wi-Fi card cannot pause the scan; `test host` still reports the
hottest zone.
- Tower 111's camera refuses its profile at every start since 2026-10-07 17:22
("applying profile 'standard' ... failed (error -39)"), with the installed
build as with this one, and captures anyway. Unrelated to this work; worth a
look.
## Still to do
- Tower 121 (the IOTA), when cleared: the same matrix and program run.
- A real hot day: the clock caps stand in for throttling; the kernel counters
have not yet seen any.

View File

@ -21,6 +21,7 @@ struct RuntimeOptions {
// Tri-state feature overrides (unset => use the config value).
std::optional<bool> use_mqtt;
std::optional<bool> mock_camera;
std::optional<bool> mock_camera_full; // --mock-camera-full: tower-size 12-bit frames
std::optional<bool> mock_serial;
std::optional<bool> mock_env; // implies [Features] enable_env
std::optional<bool> use_tui; // --tui / --no-tui; unset => [UI] enable_tui

View File

@ -86,6 +86,27 @@ public:
void setSaveGate(std::function<bool()> can_save) { can_save_ = std::move(can_save); }
// True while the scan is held for saving to catch up.
bool holdingForSave() const { return holding_; }
// All the time spent held for saving since construction, the current hold
// included (ms). Only rises; the CPU guard takes its share of each minute.
long long heldForSaveTotalMs() const;
// The CPU guard (ThermalGuard) pacing the scan to the computer's heat.
// Interval scale: pictures this many times further apart (>= 1; 1 = as
// configured). Takes effect from the next picture.
void setIntervalScale(double scale);
double intervalScale() const { return interval_scale_; }
// Paused: the waypoint under way finishes, then no new move starts, and in
// manual no continuous-capture frame is kept - the gimbal stays where it is.
// A requested snapshot is still taken: an operator asked for it. Resuming
// carries on from the next waypoint with no overrun warning for the wait.
void setPaused(bool paused);
bool paused() const { return paused_; }
// Paused and nothing under way: what the camera stream may stop for.
bool pausedAtRest() const {
return paused_ && !moving_ && !snapshot_pending_ && continuous_hold_.due_ms == 0;
}
// The current interval between pictures, scale included. 0 = never.
double intervalMs() const { return interval_ms_; }
// Per-camera-profile timing (see CameraProfile): how long to wait after standstill
// for the exposure to settle, and how long to keep retrying before abandoning
@ -166,8 +187,15 @@ private:
std::function<long long()> now_ms_;
std::function<bool()> can_save_;
bool holding_ = false;
long long hold_started_ms_ = 0;
long long held_total_ms_ = 0;
long long last_hold_end_ms_ = -1;
bool hold_logged_ = false;
double image_rate_;
double interval_ms_; // 1000 / image_rate_; 0 = never
double base_interval_ms_; // 1000 / image_rate_; 0 = never
double interval_ms_; // base_interval_ms_ x interval_scale_
double interval_scale_ = 1.0;
bool paused_ = false;
long long timer_start_ = 0; // the last frame kept or given up, or the mode start
Mode mode_ = Mode::Manual;

View File

@ -17,6 +17,8 @@ namespace fgc {
// The tower's mode, out (0 auto, 1 pan, 2 manual - see OperatingMode.h).
inline constexpr const char* kTopicStatusCode = "StatusCode";
inline constexpr const char* kTopicCamEvent = "CamEvent";
// The computer's heat and load, and whether the scan is slowed or paused for it.
inline constexpr const char* kTopicHealth = "Health";
// Any console command, in; its answer, out. See docs/mqtt-api.md.
inline constexpr const char* kTopicCommand = "Command";
inline constexpr const char* kTopicCommandReply = "CommandReply";
@ -25,6 +27,7 @@ std::string towerTopic(const std::string& tower, const std::string& leaf);
// Payload builders. One definition each, used by both channels.
std::string camEventJson(const CamEvent& e);
std::string healthJson(const HealthReport& h);
// A Command payload: {"id":"...","cmd":"..."} (a flat JSON object of strings;
// other keys ignored), or a bare command line with no id - for testing from a

View File

@ -3,6 +3,7 @@
#include "fgc/ImuMount.h"
#include "fgc/Geometry.h"
#include "fgc/OperatingMode.h"
#include "fgc/ThermalGuard.h"
#include <map>
#include <string>
@ -244,6 +245,10 @@ struct FeaturesConfig {
bool enable_serial = true;
bool enable_imu = false; // Xsens MTi orientation/IMU (off by default)
bool mock_camera = false; // use a simulated camera instead of Vimba X
// The simulated camera's frames: false = small 640x480 colour (cheap), true =
// the real camera's 5328x3040 12-bit raw, so saving costs the CPU what it
// does on a tower (throttling simulations, tools/thermal-sim/).
bool mock_camera_full = false;
bool mock_serial = false; // use a simulated motor controller
bool mock_imu = false; // use a simulated IMU instead of the MTi
bool enable_env = false; // ambient temp/humidity sensor (off by default)
@ -389,6 +394,7 @@ struct AppConfig {
PathsConfig paths;
BoardConfig board; // [Board] from hardware.ini
HardwareConfig hardware; // [Hardware] from hardware.ini
ThermalParams thermal; // [Thermal] the CPU guard, normally from hardware.ini
FeaturesConfig features;
LoggingConfig logging;
UiConfig ui; // [UI] terminal dashboard toggle

View File

@ -1,18 +1,58 @@
#pragma once
#include <string>
#include <vector>
namespace fgc::hostmetrics {
// Host (LattePanda / Linux) health reads for the `test host` subsystem. Pure
// parsers are split from the live readers so they unit-test without a real /sys
// or /proc. All readers degrade gracefully (ok=false) rather than throw.
// Host (LattePanda / Linux) health reads, for the `test host` subsystem and the
// running program's CPU watch (ThermalGuard). Pure parsers are split from the
// live readers so they unit-test without a real /sys or /proc. All readers
// degrade gracefully (ok=false) rather than throw.
//
// `root` is put in front of every /sys and /proc path ("/" = the real ones), so
// a test or a throttling simulation can hand in a fake tree:
// <root>/sys/class/thermal/thermal_zone*/{temp,type}
// <root>/sys/devices/system/cpu/cpu*/cpufreq/{scaling_cur_freq,cpuinfo_max_freq,scaling_max_freq}
// <root>/sys/devices/system/cpu/cpu*/thermal_throttle/{package,core}_throttle_count
// <root>/proc/stat (when the tree has none, the real /proc/stat)
struct ThermalInfo {
bool ok = false;
double max_temp_c = 0.0; // hottest thermal zone
std::string hottest_zone; // e.g. "x86_pkg_temp"
bool throttled = false; // best-effort (false if unknown)
// The CPU's own zone, for the CPU guard: x86_pkg_temp where there is one,
// else the hottest. Not simply the hottest: the towers also list the Wi-Fi
// card (iwlwifi_1) and the ACPI zone, and the guard watches the CPU.
double cpu_temp_c = 0.0;
std::string cpu_zone;
};
// CPU clock, from cpufreq. MHz.
struct CpuFreqInfo {
bool ok = false;
double mean_mhz = 0.0; // mean of scaling_cur_freq over the cores
double hw_max_mhz = 0.0; // cpuinfo_max_freq: what the chip can do
double cap_mhz = 0.0; // lowest scaling_max_freq: what it may do now
std::vector<double> core_mhz; // per core, cpu0 first
};
// The kernel's count of times the CPU slowed itself because it ran too hot
// (x86 thermal_throttle). It only rises; a rise between two reads is throttling.
// Slow-downs to stay inside the power limit are NOT counted here - ThrottleWatch
// (ThermalGuard.h) also watches the clock for those.
struct ThrottleCount {
bool ok = false;
long long events = 0; // package count (cpu0) + every core's count
};
// Cumulative CPU time from the first line of /proc/stat, in clock ticks. Busy %
// is the change in `busy` over the change in `total` between two reads.
struct CpuTimes {
bool ok = false;
long long busy = 0;
long long total = 0;
};
struct DiskInfo {
@ -37,7 +77,10 @@ struct LoadInfo {
};
// ---- live readers ----
ThermalInfo readThermal(); // scans /sys/class/thermal
ThermalInfo readThermal(const std::string& root = "/"); // scans sys/class/thermal
CpuFreqInfo readCpuFreq(const std::string& root = "/");
ThrottleCount readThrottleCount(const std::string& root = "/");
CpuTimes readCpuTimes(const std::string& root = "/");
DiskInfo readDisk(const std::string& path); // statvfs() on the filesystem holding `path`
MemInfo readMeminfo(); // /proc/meminfo
LoadInfo readLoad(); // getloadavg() + nproc
@ -45,5 +88,8 @@ LoadInfo readLoad(); // getloadavg() + nproc
// ---- pure parsers (reused by the readers; exposed for tests) ----
MemInfo parseMeminfo(const std::string& proc_meminfo);
double parseMilliCelsius(const std::string& zone_temp_contents); // "52000\n" -> 52.0
CpuTimes parseProcStatCpu(const std::string& proc_stat); // its "cpu " line
// Busy percentage between two reads; -1 when either is bad or no time passed.
double busyPercent(const CpuTimes& before, const CpuTimes& after);
} // namespace fgc::hostmetrics

View File

@ -14,6 +14,31 @@ struct CamEvent {
long long timestamp_ms = 0; // Unix epoch ms; matches the image filename
};
// The tower computer's health, on GGS/FWT/<tower>/Health (retained): the CPU
// guard's state and the readings behind it (ThermalGuard.h). A reading that is
// unknown goes out as null.
struct HealthReport {
std::string tower;
std::string state = "normal"; // normal / slowed / paused
std::string reason; // why not normal, in plain words; "" when normal
bool guard_on = true; // false after `thermal off`
bool cpu_c_ok = false;
double cpu_c = 0.0;
bool cpu_mhz_ok = false;
double cpu_mhz = 0.0;
double cpu_busy_pct = -1.0; // -1 = unknown
bool throttling = false;
long long throttle_events_last_min = 0;
bool enclosure_c_ok = false;
double enclosure_c = 0.0;
int save_count_last_min = 0;
double save_ms_mean = 0.0;
double save_ms_max = 0.0;
long long held_s = 0; // the scan waiting for saving, seconds
double interval_s = 0.0; // the time between pictures now
long long timestamp_ms = 0; // Unix epoch ms
};
// A console command that arrived over MQTT, on GGS/FWT/<tower>/Command. It is
// run by the same handleCommand() as a typed one, on the control thread.
struct RemoteCommand {
@ -75,6 +100,8 @@ public:
// StatusCode - on every change, and again on every reconnect.
virtual void publishStatus(int code) = 0;
virtual void publishCamEvent(const CamEvent& event) = 0;
// The computer's health (HealthReport), retained. Default: dropped.
virtual void publishHealth(const HealthReport& /*report*/) {}
// Commands received since the last call, oldest first; clears them. And the
// answer to one. Defaults: none / dropped, for a channel that takes no commands.

View File

@ -5,6 +5,7 @@
#include <atomic>
#include <condition_variable>
#include <deque>
#include <functional>
#include <mutex>
#include <optional>
@ -92,6 +93,20 @@ public:
// Number of images successfully written this session (for the camera view).
long long imagesSaved() const { return saved_.load(); }
// How long saving took over the last minute: de-Bayer, encode and write, per
// picture (the MQTT publish after it is not included). count = 0: none saved.
struct SaveTiming {
int count = 0;
double mean_ms = 0.0;
double max_ms = 0.0;
};
SaveTiming saveTiming() const;
// Workers run at this nice value (and libjxl's threads, which inherit it), so
// the control loop, serial, IMU and MQTT threads keep their share when the
// CPU is short. 0 = leave as is.
static constexpr int kWorkerNice = 5;
private:
// A frame and the pose it was taken at, captured together at submit() time so
// encoding latency and queue depth cannot separate them.
@ -122,6 +137,12 @@ private:
mutable std::mutex last_event_mutex_;
std::optional<CamEvent> last_event_;
std::atomic<long long> saved_{0}; // images successfully written this session
// (steady ms when done, save ms) of each picture saved in the last minute.
void noteSaveTime(double ms);
mutable std::mutex timing_mutex_;
std::deque<std::pair<long long, double>> save_times_;
long long timing_logged_ms_ = 0;
};
} // namespace fgc

View File

@ -4,9 +4,13 @@
#include "fgc/IControlChannel.h"
#include <atomic>
#include <condition_variable>
#include <deque>
#include <memory>
#include <mutex>
#include <string>
#include <thread>
#include <utility>
#include <vector>
#include <mqtt/async_client.h>
@ -35,6 +39,7 @@ public:
void publishStatus(int code) override;
void publishCamEvent(const CamEvent& event) override;
void publishHealth(const HealthReport& report) override;
std::vector<RemoteCommand> takeCommands() override;
void publishCommandReply(const CommandReply& reply) override;
@ -52,11 +57,20 @@ private:
void publish(const std::string& topic, const std::string& payload, bool retained = true);
// CamEvent and Health go out through a small queue with its own thread, so a
// slow link (each publish waits up to 3 s for the broker) never holds an
// image-save worker or the control loop. Bounded: when full, the oldest
// waiting message is dropped and recorded as such.
void post(const std::string& topic, const std::string& payload);
void runOutbox();
void stopOutbox(); // sends what is waiting (a few seconds at most), then ends
ChannelHistory history_;
std::string broker_uri_;
std::string tower_;
std::string topic_status_;
std::string topic_cam_event_;
std::string topic_health_;
std::string topic_command_;
std::string topic_command_reply_;
@ -66,7 +80,14 @@ private:
std::mutex mutex_;
std::string last_status_; // republished on reconnect (under mutex_)
std::string last_health_; // republished on reconnect (under mutex_)
std::vector<RemoteCommand> commands_; // received, not yet taken (under mutex_)
std::mutex outbox_mutex_;
std::condition_variable outbox_cv_;
std::deque<std::pair<std::string, std::string>> outbox_; // (topic, payload)
bool outbox_stop_ = false;
std::thread outbox_thread_;
};
} // namespace fgc

196
include/fgc/ThermalGuard.h Normal file
View File

@ -0,0 +1,196 @@
#pragma once
#include <deque>
#include <string>
#include <utility>
#include <vector>
namespace fgc {
// Watching the tower computer's CPU heat and load, and pacing the scan to it.
//
// In summer the sun and the gimbal heat the LattePanda until its CPU slows itself
// down (throttles). Saving a 12-bit picture costs ~1.4 CPU-seconds, so a slowed
// CPU may stop keeping up. The scan already holds while saving is behind
// (CaptureScheduler::setSaveGate), so nothing piles up in memory - but a computer
// held at its limit stays hot, and starves the modem and the control loop with it.
// So the guard backs off before that:
//
// Normal - full pace.
// Slowed - pictures further apart: slow_factor times the interval, or more
// when saving needs it - 1.5 x the measured save time per worker, so
// the saver keeps some headroom instead of running flat out. Entered
// when the CPU is at slow_c or more, when it is throttling, or when
// saving is the bottleneck: the scan spent held_share_pct of the last
// minute waiting for it, or held_slow_s in one go. Back to Normal once
// all of that has been clear for calm_s.
// Paused - no new pictures: the gimbal parks where it is and the camera stream
// stops, so the CPU all but idles. Entered when the CPU has stayed at
// pause_c or more for pause_after_s, or saving is still the
// bottleneck held_pause_s after slowing down (or kept the scan waiting
// held_pause_s in one go). Resumes (to Slowed) after min_pause_s, once
// the CPU is at resume_c or below and nothing is waiting to be saved.
//
// Why a share and not only one long wait: a CPU that saves a picture in 4.6 s
// against a 2 s interval never makes the scan wait long - the save gate lets it
// on after 2-3 s each time - yet it runs pegged for as long as the scan does
// (measured on the desk with a CPU quota, docs/thermal-throttling.md).
//
// It never stops the program and never changes the operating mode: auto stays
// auto, so the scan picks up by itself once the computer has cooled. Picture
// quality is never touched - only the pace.
//
// Pure: fed one reading at a time with its own clock, no I/O, so every rule here
// is unit-tested (test_thermalguard.cpp). Application samples the host every
// sample_ms and logs what update() returns.
struct ThermalParams {
bool enabled = true;
std::string sysfs_root = "/"; // fake /sys + /proc tree for a simulation
int sample_ms = 2000;
double slow_c = 85.0;
double pause_c = 92.0;
double resume_c = 75.0;
double hysteresis_c = 5.0; // Slowed -> Normal needs slow_c - this
int pause_after_s = 20;
int calm_s = 120;
int min_pause_s = 300;
int held_slow_s = 30;
int held_pause_s = 120;
double held_share_pct = 25.0; // of the last minute spent waiting for saving
double slow_factor = 2.0;
// Throttling is also inferred from the clock (see ThrottleWatch): below this
// share of the chip's top clock while at least this busy.
double clock_low_pct = 50.0;
double busy_high_pct = 50.0;
};
// One sample of the host. Each part has its own ok flag: a reading that is
// missing is left out of the rules, never taken as zero.
struct HostReading {
long long now_ms = 0;
bool temp_ok = false;
double cpu_c = 0.0;
std::string zone; // hottest thermal zone's name
bool clock_ok = false;
double mhz = 0.0; // mean over the cores
double hw_max_mhz = 0.0; // the chip's top clock
bool count_ok = false;
long long throttle_count = 0; // kernel thermal_throttle counters, summed
double busy_pct = -1.0; // since the last sample; -1 = unknown
bool held_for_save = false; // the scan is waiting for saving
long long held_total_ms = 0; // all the time it has waited so far (only rises)
int save_pending = 0; // frames waiting or being saved
// For the slowed pace: what the scan is configured to, and what saving takes.
double base_interval_ms = 0.0; // 0 = unknown
double save_ms_mean = 0.0; // last minute; 0 = unknown
int save_workers = 1;
};
enum class GuardLevel { Info, Warn };
using GuardLog = std::pair<GuardLevel, std::string>;
// "93 °C", "1.2 GHz" - for log lines and the UI.
std::string celsiusText(double c);
std::string ghzText(double mhz);
// Is the CPU slowing itself down? Two signs:
// - the kernel's thermal_throttle counters rose since the last sample (heat);
// - the clock is below clock_low_pct of the chip's top clock while the CPU is
// at least busy_high_pct busy. This catches the power-limit slow-downs the
// counters never count, and a clock capped for a simulation (cap-cpu.sh).
// Logs one line when it starts, at most one summary a minute while it lasts,
// and one when it has been clear for a minute.
class ThrottleWatch {
public:
explicit ThrottleWatch(const ThermalParams& p = {}) : p_(p) {}
void setParams(const ThermalParams& p) { p_ = p; }
void update(const HostReading& r, std::vector<GuardLog>& log);
bool throttling() const { return throttling_; }
// Samples that showed throttling in the last minute, and counter rises since start.
int samplesLastMinute() const { return static_cast<int>(recent_.size()); }
long long eventsTotal() const { return events_total_; }
long long eventsLastMinute() const;
// "counters" / "clock" / "counters and clock" - what said so last time.
const std::string& cause() const { return cause_; }
private:
ThermalParams p_;
bool have_count_ = false;
long long last_count_ = 0;
long long events_total_ = 0;
// (time, counter rise) of each sample that showed throttling, last 60 s.
std::deque<std::pair<long long, long long>> recent_;
bool throttling_ = false;
long long last_seen_ms_ = 0; // last sample that showed throttling
long long last_summary_ms_ = 0;
int low_clock_run_ = 0; // consecutive samples with a low, busy clock
std::string cause_;
};
enum class GuardState { Normal, Slowed, Paused };
const char* guardStateName(GuardState s); // "normal" / "slowed" / "paused"
class ThermalGuard {
public:
explicit ThermalGuard(const ThermalParams& p = {});
// One sample in, the log lines it produced out (throttling start/summary/end
// and state changes). Call every sample_ms.
std::vector<GuardLog> update(const HostReading& r);
// What the scan should do now.
GuardState state() const { return state_; }
// 1 when Normal; when Slowed or Paused, slow_factor or what saving needs
// (see the top of this file), at most 10.
double intervalScale() const { return state_ == GuardState::Normal ? 1.0 : scale_; }
bool pauseCapture() const { return state_ == GuardState::Paused; }
// Why it is not Normal, in plain words ("" when Normal).
const std::string& reason() const { return reason_; }
// `thermal resume`: back to Normal now, every timer restarted. The rules then
// apply afresh - a CPU still at pause_c pauses again after pause_after_s.
std::vector<GuardLog> forceResume(long long now_ms);
// `thermal off|on`: off = always Normal; the readings and the throttling log go on.
std::vector<GuardLog> setEnabled(bool on, long long now_ms);
bool enabled() const { return enabled_; }
const ThermalParams& params() const { return p_; }
const HostReading& last() const { return last_; }
bool haveReading() const { return have_last_; }
const ThrottleWatch& throttle() const { return watch_; }
long long heldForSaveMs() const; // how long the scan has been waiting
long long pausedForMs() const;
// Share of the last minute the scan spent waiting for saving, in %; -1 until
// there is half a minute of history to judge from.
double heldSharePct() const;
private:
void enter(GuardState s, const std::string& why, std::vector<GuardLog>& log);
void updateScale(const HostReading& r);
std::string paceText() const; // "one picture every 4.0 s instead of 2.0"
ThermalParams p_;
ThrottleWatch watch_;
bool enabled_ = true;
GuardState state_ = GuardState::Normal;
std::string reason_;
HostReading last_;
bool have_last_ = false;
long long hot_since_ms_ = -1; // CPU at pause_c or more since (-1 = not)
long long held_since_ms_ = -1; // the scan waiting for saving since (-1 = not)
long long calm_since_ms_ = -1; // Slowed, with every reason clear, since (-1 = not)
long long paused_at_ms_ = 0;
long long slowed_at_ms_ = 0;
long long overload_since_ms_ = -1; // Slowed, and saving still the bottleneck, since
// (time, held_total_ms) per sample over the last minute, for heldSharePct().
std::deque<std::pair<long long, long long>> held_hist_;
double scale_ = 1.0;
double last_save_ms_ = 0.0; // the last save time seen (0 = none yet)
double need_scale_ = 0.0; // the scale saving needs; <= 1: the normal pace fits
};
} // namespace fgc

View File

@ -38,6 +38,13 @@ public:
<< " (null channel)";
drop(kTopicCamEvent, camEventJson(e));
}
void publishHealth(const HealthReport& h) override {
++health_published_;
last_health_ = h;
drop(kTopicHealth, healthJson(h));
}
int healthPublished() const { return health_published_; }
const HealthReport& lastHealth() const { return last_health_; }
// Commands: none arrive by themselves; inject() stands in for the broker,
// so --no-mqtt runs and tests can drive the remote-command path.
@ -71,6 +78,8 @@ private:
ChannelHistory history_;
std::vector<RemoteCommand> pending_;
std::vector<CommandReply> replies_;
int health_published_ = 0;
HealthReport last_health_;
};
} // namespace fgc

View File

@ -81,15 +81,20 @@ struct SensorGroup {
// The Sensors panel, split by source so it is clear which parameters come from
// which device. Each group is filled with pending placeholders until its driver
// lands. NOTE: the only temperature here is the env sensor's *ambient* one — the
// lands. NOTE: two temperatures show here, kept apart by their labels: the env
// sensor's *ambient* "Temp" and the computer's own "CPU temp" (host group). The
// MTi's *internal* device temperature is diagnostic detail and lives solely in
// the expanded view (ImuView::temp_c), so the compact panel never shows two
// temperatures the operator has to tell apart. The env group's title/backing
// sensor is swappable (currently SHT41 over I2C; see IEnvSensor) without
// touching this struct.
// the expanded view (ImuView::temp_c). The env group's title/backing sensor is
// swappable (currently SHT41 over I2C; see IEnvSensor) without touching this
// struct.
struct SensorsView {
SensorGroup imu; // Xsens MTi: Roll/Pitch/Yaw
SensorGroup env; // ambient temperature + humidity (SHT41)
SensorGroup host; // the LattePanda's CPU: temperature, clock, load, throttling
// The CPU is hot, slowing itself, or the scan is slowed/paused for it: the
// badge text ("HOT" / "SLOWED" / "PAUSED"), "" for none, and how loud.
std::string cpu_badge;
bool cpu_badge_red = false;
// The MTi is not streaming what the host configured (the detail is in
// ImuConfigView::problems). Flagged on the compact panel too, because the
@ -277,6 +282,40 @@ struct EnvView {
bool fan_stalled = false; // driven, but the tach reads nothing
};
// The tower computer's CPU and the guard pacing the scan to it (ThermalGuard),
// for the expanded Sensors view. Filled from the guard's last sample - the UI
// never reads /sys itself.
struct HostView {
bool present = false; // at least one sample taken
bool temp_ok = false;
double cpu_c = 0.0;
std::string zone; // hottest thermal zone, e.g. "x86_pkg_temp"
bool clock_ok = false;
double mean_mhz = 0.0;
std::vector<double> core_mhz;
double hw_max_mhz = 0.0; // what the chip can do
double cap_mhz = 0.0; // what it is allowed now (scaling_max_freq)
double busy_pct = -1.0; // -1 = unknown
double load1 = 0.0, load5 = 0.0, load15 = 0.0;
int cpus = 0;
bool throttling = false;
std::string throttle_cause; // "counters" / "clock" / "counters and clock"
bool counters_ok = false; // the kernel counts throttling on this host
long long throttle_total = 0; // counter rises since start
long long throttle_last_min = 0;
// The guard.
bool guard_on = true;
std::string state = "normal"; // normal / slowed / paused
std::string reason;
double slow_c = 0.0, pause_c = 0.0, resume_c = 0.0;
double interval_s = 0.0; // between pictures now
long long held_s = 0; // the scan waiting for saving
long long paused_s = 0;
// Saving, over the last minute.
int save_count = 0;
double save_mean_ms = 0.0, save_max_ms = 0.0;
};
// Status of the currently-running special operation (calibration, diagnostics,
// homing, capture) plus the last completed result, for the activity strip below
// the log. The result block persists until replaced so it never scrolls away.
@ -359,6 +398,7 @@ struct UiSnapshot {
DumpView dump;
ImuView imu;
EnvView env;
HostView host;
ActivityView activity;
CalibResultView calib;
DiagResultView diag;

View File

@ -50,6 +50,9 @@ int main(int argc, char* argv[]) {
"or one beside config.ini)")
("no-mqtt", po::bool_switch(), "disable MQTT (use a null control channel)")
("mock-camera", po::bool_switch(), "use a simulated camera (no hardware)")
("mock-camera-full", po::bool_switch(),
"simulated camera with the real camera's 5328x3040 12-bit frames, so saving loads "
"the CPU as on a tower (implies --mock-camera)")
("mock-serial", po::bool_switch(), "use a simulated motor controller (no hardware)")
("mock-env", po::bool_switch(),
"use a simulated ambient temp/humidity sensor (implies enable_env)")
@ -222,6 +225,10 @@ int main(int argc, char* argv[]) {
RuntimeOptions opts;
if (vm["no-mqtt"].as<bool>()) opts.use_mqtt = false;
if (vm["mock-camera"].as<bool>()) opts.mock_camera = true;
if (vm["mock-camera-full"].as<bool>()) {
opts.mock_camera = true;
opts.mock_camera_full = true;
}
if (vm["mock-serial"].as<bool>()) opts.mock_serial = true;
if (vm["mock-env"].as<bool>()) opts.mock_env = true;
opts.degraded = vm["degraded"].as<bool>();

View File

@ -5,8 +5,13 @@
#include "fgc/RawImage.h"
#include <algorithm>
#include <cerrno>
#include <chrono>
#include <filesystem>
#include <sys/resource.h>
#include <unistd.h>
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
@ -71,7 +76,54 @@ void ImagePipeline::submit(const Frame& frame) {
cv_.notify_one();
}
static long long steadyMs() {
using namespace std::chrono;
return duration_cast<milliseconds>(steady_clock::now().time_since_epoch()).count();
}
void ImagePipeline::noteSaveTime(double ms) {
const long long now = steadyMs();
std::lock_guard<std::mutex> lock(timing_mutex_);
save_times_.emplace_back(now, ms);
while (!save_times_.empty() && now - save_times_.front().first > 60000) save_times_.pop_front();
if (timing_logged_ms_ == 0) timing_logged_ms_ = now;
if (now - timing_logged_ms_ < 60000) return;
timing_logged_ms_ = now;
double sum = 0.0, max = 0.0;
for (const auto& s : save_times_) {
sum += s.second;
max = std::max(max, s.second);
}
LOG_INFO << "saving: " << save_times_.size() << " picture"
<< (save_times_.size() == 1 ? "" : "s") << " in the last minute, "
<< static_cast<long>(sum / static_cast<double>(save_times_.size()) + 0.5)
<< " ms each on average (longest " << static_cast<long>(max + 0.5) << " ms)";
}
ImagePipeline::SaveTiming ImagePipeline::saveTiming() const {
const long long now = steadyMs();
std::lock_guard<std::mutex> lock(timing_mutex_);
SaveTiming t;
double sum = 0.0;
for (const auto& s : save_times_) {
if (now - s.first > 60000) continue;
++t.count;
sum += s.second;
t.max_ms = std::max(t.max_ms, s.second);
}
if (t.count > 0) t.mean_ms = sum / t.count;
return t;
}
void ImagePipeline::run() {
// Lower this worker's priority (Linux: nice is per thread, and the encoder's
// own threads inherit it). Best effort: a failure only costs the head start.
if (kWorkerNice != 0) {
errno = 0;
const int now = getpriority(PRIO_PROCESS, static_cast<id_t>(::gettid()));
if (errno == 0 && now < kWorkerNice)
setpriority(PRIO_PROCESS, static_cast<id_t>(::gettid()), kWorkerNice);
}
while (running_) {
QueuedFrame queued;
{
@ -121,7 +173,10 @@ void ImagePipeline::process(const QueuedFrame& queued) {
return;
}
const fs::path file = dir / (std::to_string(frame.timestamp_ms) + ".jxl");
const auto t0 = std::chrono::steady_clock::now();
if (!save(frame, out, file.string())) return;
noteSaveTime(std::chrono::duration<double, std::milli>(std::chrono::steady_clock::now() - t0)
.count());
// Sampled at submit(), not here: by this point the encode above has run and
// the gimbal may already be slewing to the next waypoint.

View File

@ -30,6 +30,8 @@
#include "fgc/OperatingMode.h"
#include "fgc/RemoteCommands.h"
#include "fgc/TestRunner.h"
#include "fgc/HostMetrics.h"
#include "fgc/ThermalGuard.h"
#include "fgc/mock/MockCameraSource.h"
#include "fgc/mock/MockEnvSensor.h"
#include "fgc/mock/MockImuSource.h"
@ -297,6 +299,16 @@ struct Application::Impl {
long long fan_seen_ms_ = 0; // last ENV reading checkFan() judged
int fan_stall_count_ = 0; // consecutive stalled readings
bool fan_stalled_ = false;
// The CPU guard (ThermalGuard.h): sampled every [Thermal] sample_ms from the
// control loop; it slows or pauses the scan when the computer runs hot.
ThermalGuard thermal_;
long long thermal_next_ms_ = 0; // steady ms of the next sample
hostmetrics::CpuTimes cpu_prev_; // for busy % between samples
hostmetrics::CpuFreqInfo cpu_freq_; // last sample, for the UI
hostmetrics::LoadInfo cpu_load_;
bool thermal_camera_stopped_ = false; // the guard stopped the stream
long long health_sent_ms_ = 0; // steady ms of the last Health
std::string health_sent_key_; // state+throttling last published
std::vector<HeadingSighting> heading_marks_; // `gimbal heading mark`s this setup
std::atomic<bool> running{true};
@ -421,8 +433,12 @@ struct Application::Impl {
#endif
const auto active = cfg.camera.active();
if (mock) {
return std::make_unique<MockCameraSource>(
active.empty() ? 1 : static_cast<int>(active.size()));
const int n = active.empty() ? 1 : static_cast<int>(active.size());
if (opts.mock_camera_full.value_or(cfg.features.mock_camera_full)) {
LOG_INFO << "[mock] camera frames are tower-size: 5328x3040 12-bit raw";
return std::make_unique<MockCameraSource>(n, 5328, 3040, PixelLayout::BayerRG12p);
}
return std::make_unique<MockCameraSource>(n);
}
#if FGC_WITH_VIMBA
std::vector<CameraSpec> specs;
@ -903,6 +919,80 @@ struct Application::Impl {
}
}
// --- The computer's CPU (the guard's last sample; no /sys reads here) ---
if (thermal_.haveReading()) {
const HostReading& r = thermal_.last();
const ThermalParams& p = thermal_.params();
HostView& h = s.host;
h.present = true;
h.temp_ok = r.temp_ok;
h.cpu_c = r.cpu_c;
h.zone = r.zone;
h.clock_ok = cpu_freq_.ok;
h.mean_mhz = cpu_freq_.mean_mhz;
h.core_mhz = cpu_freq_.core_mhz;
h.hw_max_mhz = cpu_freq_.hw_max_mhz;
h.cap_mhz = cpu_freq_.cap_mhz;
h.busy_pct = r.busy_pct;
h.load1 = cpu_load_.load1;
h.load5 = cpu_load_.load5;
h.load15 = cpu_load_.load15;
h.cpus = cpu_load_.cpus;
h.throttling = thermal_.throttle().throttling();
h.throttle_cause = thermal_.throttle().cause();
h.counters_ok = r.count_ok;
h.throttle_total = thermal_.throttle().eventsTotal();
h.throttle_last_min = thermal_.throttle().eventsLastMinute();
h.guard_on = thermal_.enabled();
h.state = guardStateName(thermal_.state());
h.reason = thermal_.reason();
h.slow_c = p.slow_c;
h.pause_c = p.pause_c;
h.resume_c = p.resume_c;
h.interval_s = scheduler ? scheduler->intervalMs() / 1000.0 : 0.0;
h.held_s = thermal_.heldForSaveMs() / 1000;
h.paused_s = thermal_.pausedForMs() / 1000;
if (pipeline) {
const auto t = pipeline->saveTiming();
h.save_count = t.count;
h.save_mean_ms = t.mean_ms;
h.save_max_ms = t.max_ms;
}
auto& g = s.sensors.host;
g.present = true;
g.status = "live";
auto set = [](SensorField& f, double v, int decimals) {
char b[32];
std::snprintf(b, sizeof(b), "%.*f", decimals, v);
f.value = b;
f.present = true;
};
if (g.fields.size() >= 4) {
if (r.temp_ok) set(g.fields[0], r.cpu_c, 1);
if (cpu_freq_.ok) set(g.fields[1], cpu_freq_.mean_mhz / 1000.0, 1);
if (r.busy_pct >= 0.0) set(g.fields[2], r.busy_pct, 0);
const long long n = thermal_.throttle().eventsLastMinute();
g.fields[3].value = !h.throttling ? "no"
: n > 0 ? "yes, " + std::to_string(n) + "x last min"
: "yes (clock)";
g.fields[3].present = true;
}
// The loudest thing that is true: paused, slowed, throttling, hot.
if (thermal_.state() == GuardState::Paused) {
s.sensors.cpu_badge = "PAUSED";
s.sensors.cpu_badge_red = true;
} else if (thermal_.state() == GuardState::Slowed) {
s.sensors.cpu_badge = "SLOWED";
} else if (h.throttling) {
s.sensors.cpu_badge = "THROTTLED";
} else if (r.temp_ok && r.cpu_c >= p.slow_c) {
s.sensors.cpu_badge = "HOT";
}
if (!thermal_.enabled() && !s.sensors.cpu_badge.empty())
s.sensors.cpu_badge += " (guard off)";
}
// --- Camera / capture ---
s.capture.present = true;
s.capture.continuous = scheduler && scheduler->continuous();
@ -1143,6 +1233,184 @@ struct Application::Impl {
fan_stalled_ = stalled;
}
static long long steadyNowMs() {
using namespace std::chrono;
return duration_cast<milliseconds>(steady_clock::now().time_since_epoch()).count();
}
static void logGuard(const std::vector<GuardLog>& lines) {
for (const auto& l : lines) {
if (l.first == GuardLevel::Warn) LOG_WARN << l.second;
else LOG_INFO << l.second;
}
}
// Every [Thermal] sample_ms: read the CPU's temperature, clock, throttle
// counters and busy time, hand them to the guard, log what it says, and
// publish Health when anything changed (or once a minute).
void watchHost() {
const long long now = steadyNowMs();
if (now < thermal_next_ms_) return;
thermal_next_ms_ = now + thermal_.params().sample_ms;
const std::string& root = thermal_.params().sysfs_root;
const auto th = hostmetrics::readThermal(root);
cpu_freq_ = hostmetrics::readCpuFreq(root);
const auto count = hostmetrics::readThrottleCount(root);
const auto times = hostmetrics::readCpuTimes(root);
cpu_load_ = hostmetrics::readLoad();
HostReading r;
r.now_ms = now;
r.temp_ok = th.ok;
r.cpu_c = th.cpu_temp_c;
r.zone = th.cpu_zone;
r.clock_ok = cpu_freq_.ok;
r.mhz = cpu_freq_.mean_mhz;
r.hw_max_mhz = cpu_freq_.hw_max_mhz;
r.count_ok = count.ok;
r.throttle_count = count.events;
r.busy_pct = hostmetrics::busyPercent(cpu_prev_, times);
cpu_prev_ = times;
// While paused the scan is not waiting for saving - it is parked.
r.held_for_save = scheduler && scheduler->holdingForSave() && !scheduler->paused();
r.held_total_ms = scheduler ? scheduler->heldForSaveTotalMs() : 0;
r.save_pending = pipeline ? static_cast<int>(pipeline->pending()) : 0;
r.base_interval_ms = cfg.image_rate() > 0.0 ? 1000.0 / cfg.image_rate() : 0.0;
r.save_ms_mean = pipeline ? pipeline->saveTiming().mean_ms : 0.0;
r.save_workers = cfg.hardware.save_workers;
logGuard(thermal_.update(r));
applyGuard();
publishHealth(false);
}
// The guard's verdict, applied to the scan - every control-loop pass, since
// the camera may only stop once the waypoint under way has finished.
void applyGuard() {
if (!scheduler) return;
scheduler->setIntervalScale(thermal_.intervalScale());
scheduler->setPaused(thermal_.pauseCapture());
if (!camera) return;
// Paused and parked: stop the camera stream, so the CPU all but idles (it
// copies every frame it streams). Never under a running test or homing,
// which may need the camera.
const bool shooting = scheduler->mode() != Mode::Manual || scheduler->continuous();
if (scheduler->pausedAtRest() && shooting && !thermal_camera_stopped_ &&
!procedureBusy()) {
camera->stop();
thermal_camera_stopped_ = true;
LOG_INFO << "camera stream stopped while pictures are paused";
} else if (!scheduler->paused() && thermal_camera_stopped_) {
thermal_camera_stopped_ = false;
// Back on only where something will take pictures: a scan, or
// continuous capture. In plain manual it stays off, as setMode leaves it.
if (scheduler->mode() != Mode::Manual || scheduler->continuous()) {
camera->start();
LOG_INFO << "camera stream started again";
}
}
}
HealthReport healthReport() const {
HealthReport h;
const HostReading& r = thermal_.last();
h.tower = cfg.general.tower_name;
h.state = guardStateName(thermal_.state());
h.reason = thermal_.reason();
h.guard_on = thermal_.enabled();
h.cpu_c_ok = r.temp_ok;
h.cpu_c = r.cpu_c;
h.cpu_mhz_ok = r.clock_ok;
h.cpu_mhz = r.mhz;
h.cpu_busy_pct = r.busy_pct;
h.throttling = thermal_.throttle().throttling();
h.throttle_events_last_min = thermal_.throttle().eventsLastMinute();
if (env) {
if (auto m = env->sample()) {
h.enclosure_c_ok = true;
h.enclosure_c = m->temp_c;
}
}
if (pipeline) {
const auto t = pipeline->saveTiming();
h.save_count_last_min = t.count;
h.save_ms_mean = t.mean_ms;
h.save_ms_max = t.max_ms;
}
h.held_s = thermal_.heldForSaveMs() / 1000;
h.interval_s = scheduler ? scheduler->intervalMs() / 1000.0 : 0.0;
h.timestamp_ms = nowEpochMs();
return h;
}
// On a change of state or throttling, or once a minute; `force` for a command.
void publishHealth(bool force) {
if (!channel || !thermal_.haveReading()) return;
const long long now = steadyNowMs();
const std::string key = std::string(guardStateName(thermal_.state())) +
(thermal_.throttle().throttling() ? "+t" : "") +
(thermal_.enabled() ? "" : "+off");
if (!force && key == health_sent_key_ && now - health_sent_ms_ < 60000) return;
health_sent_key_ = key;
health_sent_ms_ = now;
channel->publishHealth(healthReport());
}
// `thermal [resume|off|on]`: the CPU's heat and the scan's pace for it.
void handleThermal(const std::string& what) {
const long long now = steadyNowMs();
if (what == "resume") {
logGuard(thermal_.forceResume(now));
} else if (what == "off" || what == "on") {
logGuard(thermal_.setEnabled(what == "on", now));
} else if (!what.empty()) {
LOG_WARN << "usage: thermal [resume|off|on]";
return;
} else {
const HostReading& r = thermal_.last();
const ThermalParams& p = thermal_.params();
if (!thermal_.haveReading()) {
LOG_INFO << "CPU: no reading yet";
} else {
LOG_INFO << "CPU: "
<< (r.temp_ok ? celsiusText(r.cpu_c) + " (" + r.zone + ")"
: std::string("temperature unknown"))
<< ", " << (r.clock_ok ? ghzText(r.mhz) : std::string("clock unknown"))
<< (r.hw_max_mhz > 0.0 ? " of " + ghzText(r.hw_max_mhz) : std::string())
<< ", " << (r.busy_pct >= 0.0 ? std::to_string(static_cast<int>(r.busy_pct + 0.5)) + "% busy"
: std::string("busy unknown"));
LOG_INFO << "throttling: "
<< (thermal_.throttle().throttling()
? "yes (" + thermal_.throttle().cause() + ")"
: std::string("no"))
<< ", " << thermal_.throttle().eventsLastMinute()
<< " in the last minute, " << thermal_.throttle().eventsTotal()
<< " since start";
}
char every[48] = "";
if (scheduler)
std::snprintf(every, sizeof(every), ", one picture every %.1f s",
scheduler->intervalMs() / 1000.0);
LOG_INFO << "scan pace: " << (thermal_.enabled() ? guardStateName(thermal_.state())
: "guard off")
<< (thermal_.reason().empty() ? "" : " - " + thermal_.reason()) << every;
if (pipeline) {
const auto t = pipeline->saveTiming();
if (t.count > 0)
LOG_INFO << "saving: " << t.count << " in the last minute, "
<< static_cast<long>(t.mean_ms + 0.5) << " ms each (longest "
<< static_cast<long>(t.max_ms + 0.5) << " ms)";
}
LOG_INFO << "limits: slows at " << celsiusText(p.slow_c) << ", pauses at "
<< celsiusText(p.pause_c) << " for " << p.pause_after_s
<< " s, resumes at " << celsiusText(p.resume_c) << " after at least "
<< p.min_pause_s << " s";
return;
}
applyGuard();
publishHealth(true);
}
void checkTrackingError() {
const long limit = cfg.enc_error_warn_counts;
if (limit <= 0) return; // disabled
@ -1848,6 +2116,9 @@ struct Application::Impl {
if (scheduler->continuous()) LOG_INFO << "continuous capture off (mode change)";
if (m == Mode::Manual) camera->stop();
else camera->start();
// The stream is as the mode left it; the CPU guard stops it again if a
// pause still holds (applyGuard).
thermal_camera_stopped_ = false;
scheduler->setMode(m, pan);
if (m == Mode::Manual && was != Mode::Manual) stopScanMove();
if (m == Mode::Pan) {
@ -2895,6 +3166,8 @@ struct Application::Impl {
takeSnapshot();
} else if (c.verb == "capture") {
handleCapture(c.device);
} else if (c.verb == "thermal") {
handleThermal(c.device);
} else if (c.verb == "mode") {
handleMode(line);
} else if (c.verb == "debug") {
@ -3161,6 +3434,19 @@ struct Application::Impl {
// the wait is the longest across them, not the first one's.
configureSettle();
thermal_ = ThermalGuard(cfg.thermal);
if (cfg.thermal.enabled)
LOG_INFO << "CPU guard: pictures slow down at " << celsiusText(cfg.thermal.slow_c)
<< " or when the CPU throttles, and pause at "
<< celsiusText(cfg.thermal.pause_c) << " (resume at "
<< celsiusText(cfg.thermal.resume_c) << ")"
<< (cfg.thermal.sysfs_root != "/" ? "; readings from the simulated tree " +
cfg.thermal.sysfs_root
: std::string());
else
LOG_WARN << "CPU guard off ([Thermal] enabled = false): the scan keeps full pace "
"however hot the CPU runs";
// Before the firmware is talked to: the registers are wanted by the very
// first sendAnchorConfig(), on both the homing and the no-homing startup path.
planMotorCurrents();
@ -3233,6 +3519,8 @@ struct Application::Impl {
scheduler->tick();
checkTrackingError(); // warn on live encoder-error excursions
checkFan(); // a legacy tower's fan, driven but not turning
watchHost(); // CPU heat and load: slow or pause the scan for it
applyGuard();
publishSnapshot();
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}

View File

@ -42,10 +42,23 @@ CaptureScheduler::CaptureScheduler(IMotorController& motor, ICameraSource& camer
grid_(grid),
now_ms_(now_ms ? std::move(now_ms) : steadyNowMs),
image_rate_(image_rate),
interval_ms_(image_rate > 0.0 ? 1000.0 / image_rate : 0.0) {
base_interval_ms_(image_rate > 0.0 ? 1000.0 / image_rate : 0.0),
interval_ms_(base_interval_ms_) {
timer_start_ = now_ms_();
}
void CaptureScheduler::setIntervalScale(double scale) {
interval_scale_ = scale > 1.0 ? scale : 1.0;
interval_ms_ = base_interval_ms_ * interval_scale_;
}
void CaptureScheduler::setPaused(bool paused) {
if (paused == paused_) return;
paused_ = paused;
// The wait is announced by the guard, so the first move after it is no overrun.
if (paused) save_held_ = true;
}
void CaptureScheduler::setMode(Mode mode, const PanSpec& pan) {
mode_ = mode;
pan_ = pan;
@ -109,16 +122,28 @@ bool CaptureScheduler::settledAt(const MotorTelemetry& t) const {
bool CaptureScheduler::roomToSave() {
const bool room = !can_save_ || can_save_();
const long long now = now_ms_();
if (!room && !holding_) {
holding_ = true;
LOG_WARN << "saving is behind: holding the scan here until it catches up";
hold_started_ms_ = now;
// Said once, not at every waypoint: a saver that is a little too slow
// holds the scan briefly each time, and the CPU guard (ThermalGuard) is
// what speaks for that. A hold a minute after the last one is news again.
hold_logged_ = last_hold_end_ms_ < 0 || now - last_hold_end_ms_ >= 60000;
if (hold_logged_) LOG_WARN << "saving is behind: holding the scan here until it catches up";
} else if (room && holding_) {
holding_ = false;
LOG_INFO << "saving caught up: the scan carries on";
held_total_ms_ += now - hold_started_ms_;
last_hold_end_ms_ = now;
if (hold_logged_) LOG_INFO << "saving caught up: the scan carries on";
}
return room;
}
long long CaptureScheduler::heldForSaveTotalMs() const {
return held_total_ms_ + (holding_ ? now_ms_() - hold_started_ms_ : 0);
}
const char* CaptureScheduler::phase() const {
if (!moving_ || hold_.settled_ms == 0) return "moving";
return hold_.ready_ms == 0 ? "settling" : "waiting";
@ -343,7 +368,7 @@ void CaptureScheduler::tick() {
// on its own clock afterwards.
if (mode_ == Mode::Manual) {
if (snapshot_pending_) serviceSnapshot(t);
else if (continuous_) serviceContinuous(t);
else if (continuous_ && (!paused_ || continuous_hold_.due_ms != 0)) serviceContinuous(t);
return;
}
@ -352,6 +377,7 @@ void CaptureScheduler::tick() {
// and wait out what is left of the interval at the end.
if (interval_ms_ <= 0.0) return;
if (!moving_) {
if (paused_) return; // the CPU guard: park here (setPaused)
if (!roomToSave()) {
save_held_ = true;
return;

View File

@ -16,6 +16,35 @@ std::string camEventJson(const CamEvent& e) {
", \"time\":" + std::to_string(e.timestamp_ms) + " }";
}
namespace {
std::string num(double v, int decimals) {
char b[32];
std::snprintf(b, sizeof(b), "%.*f", decimals, v);
return b;
}
} // namespace
std::string healthJson(const HealthReport& h) {
auto opt = [](bool ok, double v, int d) { return ok ? num(v, d) : std::string("null"); };
return "{\"fwt\":" + jsonString(h.tower) + ",\"state\":" + jsonString(h.state) +
",\"reason\":" + jsonString(h.reason) +
",\"guard\":" + (h.guard_on ? "true" : "false") +
",\"cpu_c\":" + opt(h.cpu_c_ok, h.cpu_c, 1) +
",\"cpu_mhz\":" + opt(h.cpu_mhz_ok, h.cpu_mhz, 0) +
",\"cpu_busy_pct\":" + opt(h.cpu_busy_pct >= 0.0, h.cpu_busy_pct, 0) +
",\"throttling\":" + (h.throttling ? "true" : "false") +
",\"throttle_events_last_min\":" + std::to_string(h.throttle_events_last_min) +
",\"enclosure_c\":" + opt(h.enclosure_c_ok, h.enclosure_c, 1) +
",\"saved_last_min\":" + std::to_string(h.save_count_last_min) +
",\"save_ms_mean\":" + opt(h.save_count_last_min > 0, h.save_ms_mean, 0) +
",\"save_ms_max\":" + opt(h.save_count_last_min > 0, h.save_ms_max, 0) +
",\"held_s\":" + std::to_string(h.held_s) +
",\"interval_s\":" + num(h.interval_s, 1) +
",\"time\":" + std::to_string(h.timestamp_ms) + "}";
}
std::string jsonString(const std::string& s) {
std::string out = "\"";
for (unsigned char c : s) {

View File

@ -289,6 +289,48 @@ AppConfig ConfigLoader::fromMap(const std::map<std::string, std::string>& kv) {
if (cfg.hardware.save_queue_max < 1 || cfg.hardware.save_queue_max > 32)
throw std::runtime_error("Hardware.save_queue_max must be in 1..32 (each raw frame "
"waiting holds ~24 MB)");
// [Thermal]: the CPU guard (ThermalGuard.h). Per computer, so normally in
// hardware.ini; config.ini works too (hardware.ini wins).
{
ThermalParams& t = cfg.thermal;
t.enabled = getBool(kv, "Thermal.enabled", t.enabled);
t.sysfs_root = get(kv, "Thermal.sysfs_root", t.sysfs_root);
if (t.sysfs_root.empty()) t.sysfs_root = "/";
t.sample_ms = getInt(kv, "Thermal.sample_ms", t.sample_ms);
t.slow_c = getDouble(kv, "Thermal.slow_c", t.slow_c);
t.pause_c = getDouble(kv, "Thermal.pause_c", t.pause_c);
t.resume_c = getDouble(kv, "Thermal.resume_c", t.resume_c);
t.hysteresis_c = getDouble(kv, "Thermal.hysteresis_c", t.hysteresis_c);
t.pause_after_s = getInt(kv, "Thermal.pause_after_s", t.pause_after_s);
t.calm_s = getInt(kv, "Thermal.calm_s", t.calm_s);
t.min_pause_s = getInt(kv, "Thermal.min_pause_s", t.min_pause_s);
t.held_slow_s = getInt(kv, "Thermal.held_slow_s", t.held_slow_s);
t.held_pause_s = getInt(kv, "Thermal.held_pause_s", t.held_pause_s);
t.slow_factor = getDouble(kv, "Thermal.slow_factor", t.slow_factor);
t.held_share_pct = getDouble(kv, "Thermal.held_share_pct", t.held_share_pct);
if (t.held_share_pct <= 0.0 || t.held_share_pct > 100.0)
throw std::runtime_error("Thermal.held_share_pct must be in 0..100 (exclusive of 0)");
t.clock_low_pct = getDouble(kv, "Thermal.clock_low_pct", t.clock_low_pct);
t.busy_high_pct = getDouble(kv, "Thermal.busy_high_pct", t.busy_high_pct);
if (t.sample_ms < 500 || t.sample_ms > 60000)
throw std::runtime_error("Thermal.sample_ms must be in 500..60000");
if (!(t.resume_c < t.slow_c && t.slow_c < t.pause_c))
throw std::runtime_error("Thermal: need resume_c < slow_c < pause_c (degrees C)");
if (t.hysteresis_c < 0.0)
throw std::runtime_error("Thermal.hysteresis_c must be >= 0");
if (t.slow_factor < 1.0 || t.slow_factor > 10.0)
throw std::runtime_error("Thermal.slow_factor must be in 1..10 (times the interval)");
if (t.pause_after_s < 0 || t.calm_s < 0 || t.min_pause_s < 0 || t.held_slow_s < 1 ||
t.held_pause_s < 1)
throw std::runtime_error("Thermal: the *_s durations must be >= 0 (held_*_s >= 1)");
if (t.held_pause_s < t.held_slow_s)
throw std::runtime_error("Thermal: held_pause_s must be >= held_slow_s");
if (t.clock_low_pct <= 0.0 || t.clock_low_pct >= 100.0 || t.busy_high_pct < 0.0 ||
t.busy_high_pct > 100.0)
throw std::runtime_error("Thermal: clock_low_pct must be in 0..100 (exclusive), "
"busy_high_pct in 0..100");
}
for (const auto& a : cfg.hardware.axes)
if (a != "yaw" && a != "pitch")
throw std::runtime_error("Hardware.axes: unknown axis '" + a +
@ -398,6 +440,12 @@ AppConfig ConfigLoader::fromMap(const std::map<std::string, std::string>& kv) {
cfg.features.enable_serial = getBool(kv, "Features.enable_serial", cfg.features.enable_serial);
cfg.features.enable_imu = getBool(kv, "Features.enable_imu", cfg.features.enable_imu);
cfg.features.mock_camera = getBool(kv, "Features.mock_camera", cfg.features.mock_camera);
{
const std::string size = get(kv, "Features.mock_camera_size", "small");
if (size != "small" && size != "full")
throw std::runtime_error("Features.mock_camera_size must be small or full");
cfg.features.mock_camera_full = size == "full";
}
cfg.features.mock_serial = getBool(kv, "Features.mock_serial", cfg.features.mock_serial);
cfg.features.mock_imu = getBool(kv, "Features.mock_imu", cfg.features.mock_imu);
cfg.features.enable_env = getBool(kv, "Features.enable_env", cfg.features.enable_env);

View File

@ -122,6 +122,9 @@ const std::vector<HelpSection>& helpCatalog() {
{"help [topic]", "This list; 'help <topic>' adds detail.", {
"Example: help capture / help positioning"}},
{"cancel", "Cancel the running test, homing or calibration.", {}},
{"thermal [resume|off|on]", "CPU heat, and the scan slowed or paused for it.", {
"Bare: temperature, clock, throttling, and the scan's pace. Any mode.",
"resume: back to full pace now; off/on: the guard, until restart."}},
{"debug", "Toggle debug-level logging.", {}},
{"trace <serial|mqtt|camera|control|all|off> [on|off]", "Toggle wire-trace categories.", {
"Example: trace serial on"}},

View File

@ -1,5 +1,6 @@
#include "fgc/HostMetrics.h"
#include <algorithm>
#include <cstdlib>
#include <filesystem>
#include <fstream>
@ -57,25 +58,160 @@ MemInfo parseMeminfo(const std::string& text) {
return m;
}
ThermalInfo readThermal() {
CpuTimes parseProcStatCpu(const std::string& text) {
CpuTimes t;
std::istringstream in(text);
std::string line;
while (std::getline(in, line)) {
std::istringstream ls(line);
std::string key;
if (!(ls >> key) || key != "cpu") continue;
// user nice system idle iowait irq softirq steal [guest guest_nice]
// guest time is already inside user/nice, so it is not added again.
long long v[8] = {0, 0, 0, 0, 0, 0, 0, 0};
int n = 0;
while (n < 8 && (ls >> v[n])) ++n;
if (n < 4) return t;
const long long idle = v[3] + v[4];
long long total = 0;
for (int i = 0; i < n; ++i) total += v[i];
t.ok = true;
t.total = total;
t.busy = total - idle;
return t;
}
return t;
}
double busyPercent(const CpuTimes& before, const CpuTimes& after) {
if (!before.ok || !after.ok) return -1.0;
const long long dt = after.total - before.total;
if (dt <= 0) return -1.0;
const double pct = 100.0 * static_cast<double>(after.busy - before.busy) / static_cast<double>(dt);
return pct < 0.0 ? 0.0 : (pct > 100.0 ? 100.0 : pct);
}
namespace {
fs::path under(const std::string& root, const char* path) {
return fs::path(root.empty() ? "/" : root) / path;
}
// cpu0, cpu1, ... in number order - not cpufreq/, cpuidle/ and the rest.
std::vector<fs::path> cpuDirs(const std::string& root) {
std::vector<std::pair<int, fs::path>> found;
std::error_code ec;
for (auto& e : fs::directory_iterator(under(root, "sys/devices/system/cpu"), ec)) {
const auto name = e.path().filename().string();
if (name.size() < 4 || name.rfind("cpu", 0) != 0) continue;
bool digits = true;
for (size_t i = 3; i < name.size(); ++i)
if (name[i] < '0' || name[i] > '9') digits = false;
if (digits) found.emplace_back(std::stoi(name.substr(3)), e.path());
}
std::sort(found.begin(), found.end(),
[](const auto& a, const auto& b) { return a.first < b.first; });
std::vector<fs::path> out;
for (auto& f : found) out.push_back(f.second);
return out;
}
// A sysfs number, or -1 when the file is missing or unreadable.
long long readNumber(const fs::path& p) {
std::string s = readFile(p);
if (s.empty()) return -1;
try {
return std::stoll(s);
} catch (...) {
return -1;
}
}
} // namespace
CpuFreqInfo readCpuFreq(const std::string& root) {
CpuFreqInfo f;
double sum = 0.0;
for (const auto& dir : cpuDirs(root)) {
const long long cur = readNumber(dir / "cpufreq/scaling_cur_freq"); // kHz
if (cur < 0) continue;
f.core_mhz.push_back(static_cast<double>(cur) / 1000.0);
sum += static_cast<double>(cur) / 1000.0;
const long long hw = readNumber(dir / "cpufreq/cpuinfo_max_freq");
if (hw > 0) f.hw_max_mhz = std::max(f.hw_max_mhz, static_cast<double>(hw) / 1000.0);
const long long cap = readNumber(dir / "cpufreq/scaling_max_freq");
if (cap > 0) {
const double mhz = static_cast<double>(cap) / 1000.0;
f.cap_mhz = f.cap_mhz > 0.0 ? std::min(f.cap_mhz, mhz) : mhz;
}
}
if (!f.core_mhz.empty()) {
f.ok = true;
f.mean_mhz = sum / static_cast<double>(f.core_mhz.size());
}
return f;
}
ThrottleCount readThrottleCount(const std::string& root) {
ThrottleCount c;
bool package_seen = false;
for (const auto& dir : cpuDirs(root)) {
// Every core shows the same package count; take it once.
if (!package_seen) {
const long long pkg = readNumber(dir / "thermal_throttle/package_throttle_count");
if (pkg >= 0) {
package_seen = true;
c.ok = true;
c.events += pkg;
}
}
const long long core = readNumber(dir / "thermal_throttle/core_throttle_count");
if (core >= 0) {
c.ok = true;
c.events += core;
}
}
return c;
}
CpuTimes readCpuTimes(const std::string& root) {
// A fake tree without its own proc/stat uses the real one: how busy the CPU
// is stays real in a simulation (raise it with tools/thermal-sim/heat-load.sh).
const fs::path p = under(root, "proc/stat");
std::error_code ec;
return parseProcStatCpu(readFile(fs::exists(p, ec) ? p : fs::path("/proc/stat")));
}
ThermalInfo readThermal(const std::string& root_dir) {
ThermalInfo t;
const fs::path root = "/sys/class/thermal";
const fs::path root = under(root_dir, "sys/class/thermal");
std::error_code ec;
if (!fs::exists(root, ec)) return t;
bool have_pkg = false;
for (auto& e : fs::directory_iterator(root, ec)) {
const auto name = e.path().filename().string();
if (name.rfind("thermal_zone", 0) != 0) continue;
std::string temp_s = readFile(e.path() / "temp");
if (temp_s.empty()) continue;
double c = parseMilliCelsius(temp_s);
if (!t.ok || c > t.max_temp_c) {
t.ok = true;
t.max_temp_c = c;
std::string type = readFile(e.path() / "type");
// strip trailing newline
while (!type.empty() && (type.back() == '\n' || type.back() == '\r')) type.pop_back();
t.hottest_zone = type.empty() ? name : type;
if (type.empty()) type = name;
if (type == "x86_pkg_temp" && (!have_pkg || c > t.cpu_temp_c)) {
have_pkg = true;
t.cpu_temp_c = c;
t.cpu_zone = type;
}
if (!t.ok || c > t.max_temp_c) {
t.ok = true;
t.max_temp_c = c;
t.hottest_zone = type;
}
}
if (t.ok && !have_pkg) {
t.cpu_temp_c = t.max_temp_c;
t.cpu_zone = t.hottest_zone;
}
return t;
}

View File

@ -106,7 +106,7 @@ bool allowedIn(Mode mode, const std::string& line) {
const std::string& verb = w[0];
const std::string sub = w.size() > 1 ? w[1] : "";
if (verb == "help" || verb == "mode" || verb == "cancel" || verb == "exit" ||
verb == "debug" || verb == "trace")
verb == "debug" || verb == "trace" || verb == "thermal")
return true;
if (verb == "gimbal") return sub == "status" || sub == "dump";
if (verb == "imu") return sub == "status" || sub == "config";

321
src/core/ThermalGuard.cpp Normal file
View File

@ -0,0 +1,321 @@
#include "fgc/ThermalGuard.h"
#include <algorithm>
#include <cstdio>
namespace fgc {
namespace {
constexpr long long kMinuteMs = 60000;
// How much longer than one save the slowed interval is: the saver then runs
// about two-thirds busy, not flat out.
constexpr double kSaveHeadroom = 1.5;
std::string seconds(long long ms) {
const long long s = (ms + 500) / 1000;
if (s < 120) return std::to_string(s) + " s";
return std::to_string((s + 30) / 60) + " min";
}
std::string factorText(double f) {
char b[16];
std::snprintf(b, sizeof(b), "%g", f);
return b;
}
} // namespace
std::string celsiusText(double c) {
char b[24];
std::snprintf(b, sizeof(b), "%.0f \xC2\xB0""C", c);
return b;
}
std::string ghzText(double mhz) {
char b[24];
std::snprintf(b, sizeof(b), "%.1f GHz", mhz / 1000.0);
return b;
}
const char* guardStateName(GuardState s) {
switch (s) {
case GuardState::Normal: return "normal";
case GuardState::Slowed: return "slowed";
case GuardState::Paused: return "paused";
}
return "?";
}
// ---- ThrottleWatch -----------------------------------------------------------
long long ThrottleWatch::eventsLastMinute() const {
long long n = 0;
for (const auto& e : recent_) n += e.second;
return n;
}
void ThrottleWatch::update(const HostReading& r, std::vector<GuardLog>& log) {
// Counter rise since the last sample. A counter that went backwards (the
// driver reloaded, or a simulation reset it) is a fresh start, not throttling.
long long rise = 0;
if (r.count_ok) {
if (have_count_ && r.throttle_count > last_count_) rise = r.throttle_count - last_count_;
last_count_ = r.throttle_count;
have_count_ = true;
}
// A low clock while busy, two samples running: one low sample is as likely
// the governor catching up with a burst.
const bool low_clock = r.clock_ok && r.hw_max_mhz > 0.0 && r.busy_pct >= 0.0 &&
r.mhz < r.hw_max_mhz * p_.clock_low_pct / 100.0 &&
r.busy_pct >= p_.busy_high_pct;
low_clock_run_ = low_clock ? low_clock_run_ + 1 : 0;
const bool by_clock = low_clock_run_ >= 2;
while (!recent_.empty() && r.now_ms - recent_.front().first >= kMinuteMs) recent_.pop_front();
if (rise > 0 || by_clock) {
events_total_ += rise;
recent_.emplace_back(r.now_ms, rise);
last_seen_ms_ = r.now_ms;
cause_ = rise > 0 && by_clock ? "counters and clock" : (rise > 0 ? "counters" : "clock");
const std::string where =
(r.temp_ok ? celsiusText(r.cpu_c) + ", " : std::string()) +
(r.clock_ok ? "running at " + ghzText(r.mhz) +
(r.hw_max_mhz > 0.0 ? " of " + ghzText(r.hw_max_mhz) : std::string())
: std::string());
if (!throttling_) {
throttling_ = true;
last_summary_ms_ = r.now_ms;
log.emplace_back(GuardLevel::Warn,
rise > 0 ? "CPU is slowing itself to stay cool: " + where
: "CPU is running slow while busy (judged from its clock, "
"not the kernel's count): " + where);
} else if (r.now_ms - last_summary_ms_ >= kMinuteMs) {
last_summary_ms_ = r.now_ms;
const long long n = eventsLastMinute();
log.emplace_back(GuardLevel::Warn,
"CPU still slowed: " +
(n > 0 ? std::to_string(n) + " times in the last minute"
: std::string("clock low all minute")) +
", " + where);
}
} else if (throttling_ && r.now_ms - last_seen_ms_ >= kMinuteMs) {
throttling_ = false;
// No clock here: a CPU with nothing to do idles at a low clock, and
// "back to full speed: 0.8 GHz" (seen on tower 111) reads as a contradiction.
log.emplace_back(GuardLevel::Info,
"CPU no longer slowed" +
(r.temp_ok ? ": " + celsiusText(r.cpu_c) : std::string()));
}
}
// ---- ThermalGuard ------------------------------------------------------------
ThermalGuard::ThermalGuard(const ThermalParams& p) : p_(p), watch_(p), enabled_(p.enabled) {}
long long ThermalGuard::heldForSaveMs() const {
return held_since_ms_ >= 0 && have_last_ ? last_.now_ms - held_since_ms_ : 0;
}
long long ThermalGuard::pausedForMs() const {
return state_ == GuardState::Paused && have_last_ ? last_.now_ms - paused_at_ms_ : 0;
}
double ThermalGuard::heldSharePct() const {
if (held_hist_.size() < 2) return -1.0;
const auto& a = held_hist_.front();
const auto& b = held_hist_.back();
const long long span = b.first - a.first;
if (span < kMinuteMs / 2) return -1.0;
const double pct = 100.0 * static_cast<double>(b.second - a.second) / static_cast<double>(span);
return pct < 0.0 ? 0.0 : (pct > 100.0 ? 100.0 : pct);
}
// Slowed: slow_factor, or kSaveHeadroom x what one picture takes to save per worker,
// whichever is longer - so a slow saver gets headroom, not a scan that waits
// on it at every waypoint. The last save time seen is kept: after a pause there
// is none for a while, and the pace should not forget why it was slowed.
void ThermalGuard::updateScale(const HostReading& r) {
if (r.save_ms_mean > 0.0) last_save_ms_ = r.save_ms_mean;
need_scale_ = 0.0;
if (r.base_interval_ms > 0.0 && last_save_ms_ > 0.0)
need_scale_ = kSaveHeadroom * last_save_ms_ / std::max(1, r.save_workers) / r.base_interval_ms;
scale_ = std::min(std::max(p_.slow_factor, need_scale_), 10.0);
}
std::string ThermalGuard::paceText() const {
if (last_.base_interval_ms > 0.0) {
char b[64];
std::snprintf(b, sizeof(b), "one picture every %.1f s instead of %.1f",
last_.base_interval_ms * scale_ / 1000.0, last_.base_interval_ms / 1000.0);
return b;
}
return "pictures " + factorText(scale_) + "x further apart";
}
void ThermalGuard::enter(GuardState s, const std::string& why, std::vector<GuardLog>& log) {
const GuardState was = state_;
state_ = s;
reason_ = s == GuardState::Normal ? std::string() : why;
calm_since_ms_ = -1;
overload_since_ms_ = -1;
const long long now = last_.now_ms;
const std::string temp = last_.temp_ok ? "CPU at " + celsiusText(last_.cpu_c) : "CPU";
switch (s) {
case GuardState::Slowed:
slowed_at_ms_ = now;
if (was == GuardState::Paused)
log.emplace_back(GuardLevel::Info,
temp + ": pictures resume, " + paceText() +
" until it has been calm for " + seconds(p_.calm_s * 1000LL));
else if (why.rfind("Saving", 0) == 0)
log.emplace_back(GuardLevel::Warn,
why + ": " + paceText() + " until saving is fast enough for "
"the normal pace, for " + seconds(p_.calm_s * 1000LL));
else
log.emplace_back(GuardLevel::Warn,
why + ": " + paceText() + " until the CPU is below " +
celsiusText(p_.slow_c - p_.hysteresis_c) +
" and keeping up for " + seconds(p_.calm_s * 1000LL));
break;
case GuardState::Paused:
paused_at_ms_ = now;
log.emplace_back(GuardLevel::Warn,
why + ": pausing pictures for at least " +
seconds(p_.min_pause_s * 1000LL) + ", until the CPU is at " +
celsiusText(p_.resume_c) + " or below and saving has caught up");
break;
case GuardState::Normal:
log.emplace_back(GuardLevel::Info, temp + ": back to the normal picture pace");
break;
}
}
std::vector<GuardLog> ThermalGuard::update(const HostReading& r) {
std::vector<GuardLog> log;
last_ = r;
have_last_ = true;
watch_.update(r, log);
const long long now = r.now_ms;
hot_since_ms_ = r.temp_ok && r.cpu_c >= p_.pause_c ? (hot_since_ms_ >= 0 ? hot_since_ms_ : now) : -1;
held_since_ms_ = r.held_for_save ? (held_since_ms_ >= 0 ? held_since_ms_ : now) : -1;
// The waiting total only rises; one that fell is a restarted count.
if (!held_hist_.empty() && r.held_total_ms < held_hist_.back().second) held_hist_.clear();
held_hist_.emplace_back(now, r.held_total_ms);
while (held_hist_.size() > 1 && now - held_hist_.front().first > kMinuteMs) held_hist_.pop_front();
updateScale(r);
if (!enabled_) return log;
const long long hot_ms = hot_since_ms_ >= 0 ? now - hot_since_ms_ : 0;
const long long held_ms = heldForSaveMs();
const double share = heldSharePct();
const bool bottleneck = share >= p_.held_share_pct;
auto shareText = [&] {
return "Saving kept the scan waiting " + std::to_string(static_cast<int>(share + 0.5)) +
"% of the last minute";
};
// Pause: from either running state.
if (state_ != GuardState::Paused) {
if (hot_since_ms_ >= 0 && hot_ms >= p_.pause_after_s * 1000LL) {
enter(GuardState::Paused,
"CPU at " + celsiusText(r.cpu_c) + " for " + seconds(hot_ms), log);
return log;
}
if (held_since_ms_ >= 0 && held_ms >= p_.held_pause_s * 1000LL) {
enter(GuardState::Paused,
"Saving has kept the scan waiting for " + seconds(held_ms), log);
return log;
}
// Slowed, and saving still the bottleneck once the minute it is judged
// over holds only slowed pictures: the slower pace did not help.
if (state_ == GuardState::Slowed) {
const bool judged = now - slowed_at_ms_ >= kMinuteMs;
overload_since_ms_ = judged && bottleneck
? (overload_since_ms_ >= 0 ? overload_since_ms_ : now)
: -1;
if (overload_since_ms_ >= 0 && now - overload_since_ms_ >= p_.held_pause_s * 1000LL) {
enter(GuardState::Paused, shareText() + ", even slowed", log);
return log;
}
}
}
switch (state_) {
case GuardState::Normal: {
std::string why;
if (r.temp_ok && r.cpu_c >= p_.slow_c) why = "CPU at " + celsiusText(r.cpu_c);
else if (watch_.throttling()) why = "CPU is slowing itself down";
else if (held_since_ms_ >= 0 && held_ms >= p_.held_slow_s * 1000LL)
why = "Saving has kept the scan waiting for " + seconds(held_ms);
else if (bottleneck) why = shareText();
if (!why.empty()) enter(GuardState::Slowed, why, log);
break;
}
case GuardState::Slowed: {
// Calm: cool enough, not throttling, not waiting for saving now, and
// under half of held_share_pct over the minute - a brief wait now and
// then is a saver with headroom, as it should be.
// And the normal pace must fit what saving takes now: a saver that is
// simply too slow for it would overload again at once, and flap.
const bool calm = !(r.temp_ok && r.cpu_c >= p_.slow_c - p_.hysteresis_c) &&
!watch_.throttling() && held_since_ms_ < 0 &&
!(share >= p_.held_share_pct / 2.0) && need_scale_ <= 1.0;
if (!calm) {
calm_since_ms_ = -1;
} else {
if (calm_since_ms_ < 0) calm_since_ms_ = now;
if (now - calm_since_ms_ >= p_.calm_s * 1000LL) enter(GuardState::Normal, "", log);
}
break;
}
case GuardState::Paused: {
// Saving drains while paused; resume once it has and the CPU cooled.
const bool cool = !r.temp_ok || r.cpu_c <= p_.resume_c;
if (now - paused_at_ms_ >= p_.min_pause_s * 1000LL && cool && r.save_pending == 0)
enter(GuardState::Slowed, "Resuming after a pause", log);
break;
}
}
return log;
}
std::vector<GuardLog> ThermalGuard::forceResume(long long now_ms) {
std::vector<GuardLog> log;
hot_since_ms_ = held_since_ms_ = calm_since_ms_ = overload_since_ms_ = -1;
held_hist_.clear();
if (have_last_) last_.now_ms = now_ms;
if (state_ != GuardState::Normal) {
state_ = GuardState::Normal;
reason_.clear();
log.emplace_back(GuardLevel::Info,
"thermal resume: back to the normal picture pace (the CPU is still "
"watched; it will slow or pause again if it stays hot)");
} else {
log.emplace_back(GuardLevel::Info, "thermal resume: already at the normal picture pace");
}
return log;
}
std::vector<GuardLog> ThermalGuard::setEnabled(bool on, long long now_ms) {
std::vector<GuardLog> log;
if (on == enabled_) {
log.emplace_back(GuardLevel::Info, std::string("CPU guard already ") + (on ? "on" : "off"));
return log;
}
enabled_ = on;
hot_since_ms_ = held_since_ms_ = calm_since_ms_ = overload_since_ms_ = -1;
held_hist_.clear();
if (have_last_) last_.now_ms = now_ms;
state_ = GuardState::Normal;
reason_.clear();
log.emplace_back(on ? GuardLevel::Info : GuardLevel::Warn,
on ? "CPU guard on: the scan slows or pauses when the CPU runs hot"
: "CPU guard off until restart: the scan keeps full pace however hot the "
"CPU runs (temperature and throttling are still shown and logged)");
return log;
}
} // namespace fgc

View File

@ -12,6 +12,8 @@ namespace {
constexpr int kQos = 1;
const auto kConnectTimeout = std::chrono::seconds(5);
const auto kPublishTimeout = std::chrono::seconds(3);
constexpr size_t kOutboxMax = 64;
const auto kOutboxFlush = std::chrono::seconds(5);
} // namespace
MqttControlChannel::MqttControlChannel(const std::string& broker_uri, const std::string& tower,
@ -20,6 +22,7 @@ MqttControlChannel::MqttControlChannel(const std::string& broker_uri, const std:
tower_(tower),
topic_status_(towerTopic(tower, kTopicStatusCode)),
topic_cam_event_(towerTopic(tower, kTopicCamEvent)),
topic_health_(towerTopic(tower, kTopicHealth)),
topic_command_(towerTopic(tower, kTopicCommand)),
topic_command_reply_(towerTopic(tower, kTopicCommandReply)),
client_(broker_uri, tower) {
@ -29,9 +32,60 @@ MqttControlChannel::MqttControlChannel(const std::string& broker_uri, const std:
if (!user.empty()) conn_opts_.set_user_name(user);
if (!password.empty()) conn_opts_.set_password(password);
client_.set_callback(*this);
outbox_thread_ = std::thread(&MqttControlChannel::runOutbox, this);
}
MqttControlChannel::~MqttControlChannel() { disconnect(); }
MqttControlChannel::~MqttControlChannel() {
disconnect();
stopOutbox();
}
void MqttControlChannel::post(const std::string& topic, const std::string& payload) {
{
std::lock_guard<std::mutex> lock(outbox_mutex_);
if (outbox_.size() >= kOutboxMax) {
history_.record(/*outbound=*/true, Delivery::Dropped, outbox_.front().first,
outbox_.front().second);
outbox_.pop_front();
}
outbox_.emplace_back(topic, payload);
}
outbox_cv_.notify_one();
}
void MqttControlChannel::runOutbox() {
std::unique_lock<std::mutex> lock(outbox_mutex_);
for (;;) {
outbox_cv_.wait(lock, [this] { return outbox_stop_ || !outbox_.empty(); });
if (outbox_.empty()) return; // stopping, and nothing left
auto m = std::move(outbox_.front());
outbox_.pop_front();
lock.unlock();
publish(m.first, m.second);
lock.lock();
}
}
void MqttControlChannel::stopOutbox() {
if (!outbox_thread_.joinable()) return;
// Give what is waiting a few seconds to go out; drop (and record) the rest.
const auto deadline = std::chrono::steady_clock::now() + kOutboxFlush;
for (;;) {
{
std::lock_guard<std::mutex> lock(outbox_mutex_);
if (outbox_.empty() || std::chrono::steady_clock::now() >= deadline) {
for (const auto& m : outbox_)
history_.record(/*outbound=*/true, Delivery::Dropped, m.first, m.second);
outbox_.clear();
outbox_stop_ = true;
break;
}
}
std::this_thread::sleep_for(std::chrono::milliseconds(20));
}
outbox_cv_.notify_all();
outbox_thread_.join();
}
bool MqttControlChannel::connect() {
try {
@ -47,6 +101,7 @@ bool MqttControlChannel::connect() {
}
void MqttControlChannel::disconnect() {
stopOutbox(); // the last pictures' events go out before the link closes
if (!client_.is_connected()) return;
try {
client_.disconnect()->wait();
@ -66,22 +121,28 @@ void MqttControlChannel::connected(const std::string& /*cause*/) {
// Say the mode again: whoever watches StatusCode may have missed changes
// while the link was down. Not waited on - this runs on Paho's callback
// thread, which is the one that would deliver the acknowledgement.
std::string status;
// Health likewise: a paused tower must not look healthy to a page that
// subscribed while the link was down.
std::string status, health;
{
std::lock_guard<std::mutex> lock(mutex_);
status = last_status_;
health = last_health_;
}
if (!status.empty()) {
auto republish = [this](const std::string& topic, const std::string& payload) {
if (payload.empty()) return;
try {
auto msg = mqtt::make_message(topic_status_, status);
auto msg = mqtt::make_message(topic, payload);
msg->set_qos(kQos);
msg->set_retained(true);
client_.publish(msg);
history_.record(/*outbound=*/true, Delivery::Ok, topic_status_, status);
history_.record(/*outbound=*/true, Delivery::Ok, topic, payload);
} catch (const mqtt::exception& e) {
LOG_WARN << "MQTT status republish failed: " << e.what();
}
LOG_WARN << "MQTT republish of " << topic << " failed: " << e.what();
}
};
republish(topic_status_, status);
republish(topic_health_, health);
}
void MqttControlChannel::connection_lost(const std::string& cause) {
@ -160,7 +221,16 @@ void MqttControlChannel::publishStatus(int code) {
}
void MqttControlChannel::publishCamEvent(const CamEvent& e) {
publish(topic_cam_event_, camEventJson(e));
post(topic_cam_event_, camEventJson(e));
}
void MqttControlChannel::publishHealth(const HealthReport& h) {
const std::string payload = healthJson(h);
{
std::lock_guard<std::mutex> lock(mutex_);
last_health_ = payload;
}
post(topic_health_, payload);
}
} // namespace fgc

View File

@ -369,9 +369,14 @@ Element sensorsPanel(const SensorsView& s) {
? (text(" IMU CFG ") | color(Color::Red) | bold)
: text("");
Element fan_badge = s.fan_alert ? (text(" FAN ") | color(Color::Red) | bold) : text("");
Element cpu_badge = s.cpu_badge.empty()
? text("")
: (text(" " + s.cpu_badge + " ") |
color(s.cpu_badge_red ? Color::Red : Color::Yellow) | bold);
return panel("[s] SENSORS", Color::Magenta,
vbox({group(s.imu, std::move(imu_badge)), separator(),
group(s.env, std::move(fan_badge))}));
group(s.env, std::move(fan_badge)), separator(),
group(s.host, std::move(cpu_badge))}));
}
Element cameraPanel(const CaptureView& c) {
@ -967,7 +972,8 @@ Element gimbalDetailPanel(const GimbalView& g, const DumpView& dump, const Calib
// then the ambient sensor. The two devices get their own headed sections, and
// each temperature is labelled with its provenance ("internal" vs "ambient"),
// so the reading the main window shows is never confused with the MTi's.
Element sensorsDetailPanel(const ImuView& v, const EnvView& e, ScrollState& st) {
Element sensorsDetailPanel(const ImuView& v, const EnvView& e, const HostView& h,
ScrollState& st) {
// Fixed-width, right-aligned to 2 decimals. The constant width keeps the sign
// column and decimal point from jumping as values cross zero or change digit
// count, so the readout stays steady instead of flickering. The width is kept
@ -1085,6 +1091,79 @@ Element sensorsDetailPanel(const ImuView& v, const EnvView& e, ScrollState& st)
}
}
// LATTEPANDA CPU section: the computer's own heat and load, and how the CPU
// guard (ThermalGuard) is pacing the scan for it. Live like the two above,
// so it sits above the static IMU CONFIG block too.
{
auto row = [](const std::string& k, Element val) {
return hbox({text(k) | dim | size(WIDTH, EQUAL, 16), std::move(val)});
};
auto fx = [](double x, int d) {
char b[32];
std::snprintf(b, sizeof(b), "%.*f", d, x);
return std::string(b);
};
body.push_back(separator());
body.push_back(text("LattePanda \xE2\x80\x94 CPU") | bold | color(Color::Magenta));
if (!h.present) {
body.push_back(text("(no reading yet)") | dim);
} else {
const bool hot = h.temp_ok && h.cpu_c >= h.slow_c;
Element temp = h.temp_ok ? text(fx(h.cpu_c, 1) + " \xC2\xB0""C") | bold
: text("unknown") | dim;
if (hot) temp = temp | color(h.cpu_c >= h.pause_c ? Color::Red : Color::Yellow);
body.push_back(row("CPU temp", hbox({temp, text(" " + h.zone) | dim})));
if (h.clock_ok) {
std::string cores;
for (double m : h.core_mhz) cores += (cores.empty() ? "" : " ") + fx(m / 1000.0, 1);
std::string cap;
if (h.cap_mhz > 0.0 && h.hw_max_mhz > 0.0 && h.cap_mhz < h.hw_max_mhz - 1.0)
cap = ", capped at " + fx(h.cap_mhz / 1000.0, 1);
body.push_back(row("Clock", hbox({text(fx(h.mean_mhz / 1000.0, 2) + " GHz") | bold,
text(" of " + fx(h.hw_max_mhz / 1000.0, 1) +
cap + " (cores " + cores + ")") | dim})));
} else {
body.push_back(row("Clock", text("unknown") | dim));
}
body.push_back(row("Load",
hbox({text(h.busy_pct >= 0.0 ? fx(h.busy_pct, 0) + " % busy"
: std::string("-- % busy")) | bold,
text(" load " + fx(h.load1, 2) + " / " + fx(h.load5, 2) +
" / " + fx(h.load15, 2) + " on " +
std::to_string(h.cpus) + " cores") | dim})));
std::string thr = h.throttling ? "yes, now (" + h.throttle_cause + ")" : "no";
std::string thr_detail = h.counters_ok
? " " + std::to_string(h.throttle_last_min) + " in the last minute, " +
std::to_string(h.throttle_total) + " since start"
: " (the kernel does not count it here; judged from the clock)";
body.push_back(row("Throttled",
hbox({h.throttling ? text(thr) | color(Color::Red) | bold
: text(thr) | bold,
text(thr_detail) | dim})));
if (h.save_count > 0)
body.push_back(row("Saving", hbox({text(fx(h.save_mean_ms, 0) + " ms") | bold,
text(" per picture, longest " +
fx(h.save_max_ms, 0) + " ms, " +
std::to_string(h.save_count) +
" in the last minute") | dim})));
Element st = text(h.state);
if (!h.guard_on) st = text("off (full pace whatever the heat)") | color(Color::Yellow) | bold;
else if (h.state == "paused") st = st | color(Color::Red) | bold;
else if (h.state == "slowed") st = st | color(Color::Yellow) | bold;
else st = st | color(Color::Green);
std::string pace = " one picture every " + fx(h.interval_s, 1) + " s";
if (h.state == "paused") pace = " for " + std::to_string(h.paused_s) + " s";
body.push_back(row("Scan pace", hbox({st, text(pace) | dim})));
if (!h.reason.empty()) body.push_back(row("", text(h.reason) | dim));
if (h.held_s > 0)
body.push_back(row("", text("waiting " + std::to_string(h.held_s) +
" s for saving to catch up") | color(Color::Yellow)));
body.push_back(text("slows at " + fx(h.slow_c, 0) + " \xC2\xB0""C, pauses at " +
fx(h.pause_c, 0) + ", resumes at " + fx(h.resume_c, 0) +
" ('thermal' to see, 'thermal off|on|resume')") | dim);
}
}
// IMU CONFIG section (device configuration read back at startup). Shown
// whenever it is known, even if the live stream is offline.
const auto& c = v.config;
@ -1370,7 +1449,7 @@ void TuiUi::uiLoop() {
bottom});
case Overlay::Sensors:
return vbox({header, separator(),
sensorsDetailPanel(s.imu, s.env, sensors_scroll) | flex, bottom});
sensorsDetailPanel(s.imu, s.env, s.host, sensors_scroll) | flex, bottom});
case Overlay::Cameras:
return vbox({header, separator(), cameraDetailPanel(s.capture, cam_scroll) | flex, bottom});
case Overlay::Conn:

View File

@ -99,6 +99,15 @@ SensorsView pendingSensorsView() {
v.env.status = "pending";
v.env.fields.push_back({"Temp", "--.-", "\xC2\xB0""C", false});
v.env.fields.push_back({"Humid", "--", "%RH", false});
// The computer itself: its CPU's own temperature (not the box's - that is
// the ambient Temp above), clock, how busy it is, and whether it is
// slowing itself down to stay cool.
v.host.title = "LattePanda CPU";
v.host.status = "pending";
v.host.fields.push_back({"CPU temp", "--.-", "\xC2\xB0""C", false});
v.host.fields.push_back({"Clock", "-.-", "GHz", false});
v.host.fields.push_back({"Load", "--", "%", false});
v.host.fields.push_back({"Throttled", "--", "", false});
return v;
}

View File

@ -59,6 +59,7 @@ add_executable(fgc_tests
test_testrunner.cpp
test_rawimage.cpp
test_settlerule.cpp
test_thermalguard.cpp
)
target_link_libraries(fgc_tests PRIVATE fgc_core doctest::doctest)
# So a test can read the shipped config/config.example.ini and hold it to what

View File

@ -185,6 +185,22 @@ TEST_CASE("several workers save every frame") {
CHECK(files == 9);
}
TEST_CASE("save timing counts the pictures saved in the last minute and how long they took") {
TempDir t;
FakeChannel ch;
ImagePipeline pipe(ch, nullptr, params(t, 1.0));
CHECK(pipe.saveTiming().count == 0);
pipe.start();
for (int i = 0; i < 3; ++i)
pipe.submit(bayerFrame(PixelLayout::BayerRG12p, 64, 48, 3000, 1500, 700, 7000 + i));
REQUIRE(waitSaved(pipe, 3));
pipe.stop();
const auto s = pipe.saveTiming();
CHECK(s.count == 3);
CHECK(s.mean_ms > 0.0);
CHECK(s.max_ms >= s.mean_ms);
}
TEST_CASE("canAccept says no once queue_max frames are waiting, yes once they are saved") {
TempDir t;
FakeChannel ch;

View File

@ -914,3 +914,109 @@ TEST_CASE("the keep rule starts afresh at each waypoint") {
}
CHECK(r.cam.triggers == 2);
}
TEST_CASE("the CPU guard's pause finishes the waypoint under way, parks, and loses nothing") {
long long clock = 0;
FakeMotor motor;
FakeCamera cam;
ScanGrid grid({{0.0, 0.0}, {90.0, 0.0}});
CaptureScheduler sch(motor, cam, 1.0 /*1000 ms*/, testGeometry(), grid,
[&] { return clock; });
sch.setSettleWait(0, 0);
sch.setMode(Mode::Auto);
clock = 1100; sch.tick(); // first move
REQUIRE(motor.cmds.size() == 1);
sch.setPaused(true); // paused mid-waypoint
CHECK_FALSE(sch.pausedAtRest()); // the waypoint is still under way
settleAt(motor, 0, 0);
clock = 1200; sch.tick();
clock = 1300; sch.tick();
CHECK(cam.triggers == 1); // ...and keeps its frame
CHECK(sch.pausedAtRest());
clock = 60000; sch.tick();
CHECK(motor.cmds.size() == 1); // parked: no next move however long
CHECK(cam.triggers == 1);
sch.setPaused(false);
clock = 60100; sch.tick();
REQUIRE(motor.cmds.size() == 2);
CHECK(motor.cmds[1] == "MOVE 900,0"); // the waypoint it was due, not skipped
motor.tel.yaw.standstill = false;
clock = 60200; settleAt(motor, 900, 0); sch.tick();
clock = 60300; sch.tick();
CHECK(cam.triggers == 2);
CHECK(sch.overruns() == 0); // the pause is not an overrun
}
TEST_CASE("the time held for saving adds up, the hold under way included") {
long long clock = 0;
FakeMotor motor;
FakeCamera cam;
ScanGrid grid({{0.0, 0.0}, {0.0, 0.0}});
CaptureScheduler sch(motor, cam, 1.0 /*1000 ms*/, testGeometry(), grid,
[&] { return clock; });
sch.setSettleWait(0, 0);
bool room = false;
sch.setSaveGate([&room] { return room; });
sch.setMode(Mode::Auto);
settleAt(motor, 0, 0);
clock = 1000; sch.tick(); // held from here
clock = 3000; sch.tick();
CHECK(sch.heldForSaveTotalMs() == 2000); // still held: counted so far
room = true;
clock = 3500; sch.tick(); // released after 2.5 s
CHECK(sch.heldForSaveTotalMs() == 2500);
clock = 9000;
CHECK(sch.heldForSaveTotalMs() == 2500); // not held: no more
}
TEST_CASE("the CPU guard's interval scale spaces pictures further apart") {
long long clock = 0;
FakeMotor motor;
FakeCamera cam;
ScanGrid grid({{0.0, 0.0}, {0.0, 0.0}});
CaptureScheduler sch(motor, cam, 1.0 /*1000 ms*/, testGeometry(), grid,
[&] { return clock; });
sch.setSettleWait(0, 0);
sch.setMode(Mode::Auto);
sch.setIntervalScale(2.0);
CHECK(sch.intervalMs() == doctest::Approx(2000.0));
settleAt(motor, 0, 0);
clock = 10; sch.tick(); // move
clock = 100; sch.tick(); // standstill
clock = 1500; sch.tick();
CHECK(cam.triggers == 0); // 1 s would have fired; 2 s has not
clock = 2000; sch.tick();
CHECK(cam.triggers == 1);
sch.setIntervalScale(0.5); // never faster than configured
CHECK(sch.intervalScale() == doctest::Approx(1.0));
CHECK(sch.intervalMs() == doctest::Approx(1000.0));
}
TEST_CASE("the CPU guard's pause stops continuous capture keeping frames; a snapshot still fires") {
long long clock = 0;
FakeMotor motor;
FakeCamera cam;
ScanGrid grid({{0.0, 0.0}});
CaptureScheduler sch(motor, cam, 1.0 /*1000 ms*/, testGeometry(), grid,
[&] { return clock; });
sch.setSettleWait(0, 0);
sch.setContinuous(true);
settleAt(motor, 0, 0);
sch.setPaused(true);
for (clock = 100; clock < 5000; clock += 100) sch.tick();
CHECK(cam.triggers == 0);
sch.requestSnapshot();
for (clock = 5000; clock < 5300; clock += 100) sch.tick();
CHECK(cam.triggers == 1);
sch.setPaused(false);
for (clock = 5300; clock < 7000; clock += 100) sch.tick();
CHECK(cam.triggers >= 2);
}

483
tests/test_thermalguard.cpp Normal file
View File

@ -0,0 +1,483 @@
#include <doctest/doctest.h>
#include "fgc/ChannelTopics.h"
#include "fgc/Config.h"
#include "fgc/HostMetrics.h"
#include "fgc/OperatingMode.h"
#include "fgc/ThermalGuard.h"
#include <filesystem>
#include <fstream>
#include <string>
#include <vector>
#include <unistd.h>
using namespace fgc;
namespace fs = std::filesystem;
namespace {
// A host at `c` degrees, 2.8 of 3.6 GHz, 30% busy, counters at `count`.
HostReading at(long long t_s, double c, long long count = 0) {
HostReading r;
r.now_ms = t_s * 1000;
r.temp_ok = true;
r.cpu_c = c;
r.zone = "x86_pkg_temp";
r.clock_ok = true;
r.mhz = 2800;
r.hw_max_mhz = 3600;
r.count_ok = true;
r.throttle_count = count;
r.busy_pct = 30;
return r;
}
bool logged(const std::vector<GuardLog>& log, const std::string& part) {
for (const auto& l : log)
if (l.second.find(part) != std::string::npos) return true;
return false;
}
// Feed a reading every 2 s from t0 to t1 (inclusive), collecting the log.
std::vector<GuardLog> run(ThermalGuard& g, long long t0, long long t1, double c,
long long count = 0) {
std::vector<GuardLog> all;
for (long long t = t0; t <= t1; t += 2) {
auto l = g.update(at(t, c, count));
all.insert(all.end(), l.begin(), l.end());
}
return all;
}
struct FakeSys {
fs::path root;
FakeSys() {
root = fs::temp_directory_path() / ("fgc_fakesys_" + std::to_string(::getpid()));
fs::remove_all(root);
}
~FakeSys() { fs::remove_all(root); }
void put(const std::string& rel, const std::string& text) {
fs::path p = root / rel;
fs::create_directories(p.parent_path());
std::ofstream(p) << text;
}
};
} // namespace
TEST_CASE("a cool, idle CPU stays at the normal pace") {
ThermalGuard g;
auto log = run(g, 0, 600, 60.0);
CHECK(g.state() == GuardState::Normal);
CHECK(g.intervalScale() == doctest::Approx(1.0));
CHECK_FALSE(g.pauseCapture());
CHECK(log.empty());
}
TEST_CASE("a hot CPU slows the scan, and the slow-down lifts only after it has been calm") {
ThermalParams p;
ThermalGuard g(p);
run(g, 0, 10, 70.0);
auto log = g.update(at(12, 86.0));
CHECK(g.state() == GuardState::Slowed);
CHECK(g.intervalScale() == doctest::Approx(p.slow_factor));
CHECK(logged(log, "CPU at 86 \xC2\xB0""C"));
CHECK(logged(log, "2x further apart"));
// Below slow_c but inside the hysteresis band: stays slowed.
run(g, 14, 400, 82.0);
CHECK(g.state() == GuardState::Slowed);
// Below slow_c - hysteresis, but not yet for calm_s.
run(g, 402, 402 + p.calm_s - 4, 78.0);
CHECK(g.state() == GuardState::Slowed);
// A hot blip restarts the calm clock.
g.update(at(402 + p.calm_s - 2, 81.0));
run(g, 402 + p.calm_s, 402 + 2 * p.calm_s - 2, 78.0);
CHECK(g.state() == GuardState::Slowed);
log = run(g, 402 + 2 * p.calm_s, 402 + 2 * p.calm_s + 4, 78.0);
CHECK(g.state() == GuardState::Normal);
CHECK(logged(log, "back to the normal picture pace"));
}
TEST_CASE("a CPU that stays very hot pauses pictures, and resumes once cool and the pause is served") {
ThermalParams p;
ThermalGuard g(p);
// One hot sample is not enough: pause_after_s of it is.
g.update(at(0, 93.0));
CHECK(g.state() == GuardState::Slowed);
auto log = run(g, 2, p.pause_after_s, 93.0);
CHECK(g.state() == GuardState::Paused);
CHECK(g.pauseCapture());
CHECK(logged(log, "pausing pictures"));
// Cooled quickly, but the pause runs its minimum.
const long long paused_at = p.pause_after_s;
run(g, paused_at + 2, paused_at + p.min_pause_s - 2, 70.0);
CHECK(g.state() == GuardState::Paused);
log = run(g, paused_at + p.min_pause_s, paused_at + p.min_pause_s + 2, 70.0);
CHECK(g.state() == GuardState::Slowed); // resumes slowed, not straight to full pace
CHECK(logged(log, "pictures resume"));
}
TEST_CASE("a pause lasts while the CPU is above resume_c, or saving has not caught up") {
ThermalParams p;
ThermalGuard g(p);
run(g, 0, p.pause_after_s + 2, 95.0);
REQUIRE(g.state() == GuardState::Paused);
run(g, 30, 30 + 2 * p.min_pause_s, p.resume_c + 3);
CHECK(g.state() == GuardState::Paused); // served its time, still too warm
HostReading r = at(1000, 70.0);
r.save_pending = 1;
g.update(r);
CHECK(g.state() == GuardState::Paused); // cool, but a frame is still saving
g.update(at(1002, 70.0));
CHECK(g.state() == GuardState::Slowed);
}
TEST_CASE("saving that keeps the scan waiting slows it, then pauses it") {
ThermalParams p;
ThermalGuard g(p);
auto held = [](long long t) {
HostReading r = at(t, 60.0);
r.held_for_save = true;
r.save_pending = 4;
return r;
};
// Brief holds are normal.
for (long long t = 0; t < p.held_slow_s; t += 2) g.update(held(t));
CHECK(g.state() == GuardState::Normal);
g.update(at(p.held_slow_s, 60.0)); // caught up: the clock restarts
for (long long t = p.held_slow_s + 2; t < 2 * p.held_slow_s; t += 2) g.update(held(t));
CHECK(g.state() == GuardState::Normal);
std::vector<GuardLog> log;
long long t = 100;
for (; t <= 100 + p.held_slow_s; t += 2) {
auto l = g.update(held(t));
log.insert(log.end(), l.begin(), l.end());
}
CHECK(g.state() == GuardState::Slowed);
CHECK(logged(log, "Saving has kept the scan waiting"));
for (; t <= 100 + p.held_pause_s; t += 2) g.update(held(t));
CHECK(g.state() == GuardState::Paused);
}
// A saver too slow for the interval: the scan waits `wait_s` out of every
// `cycle_s`, never long in one go - the overload the desk run with a CPU quota
// showed (save 4.6 s against a 2 s interval). Feeds samples every 2 s from t0
// to t1, keeping the running waiting total in `held`.
std::vector<GuardLog> runSlowSaver(ThermalGuard& g, long long t0, long long t1, double wait_frac,
long long& held, double save_ms = 4600.0) {
std::vector<GuardLog> all;
for (long long t = t0; t <= t1; t += 2) {
HostReading r = at(t, 60.0);
held += static_cast<long long>(2000 * wait_frac);
r.held_total_ms = held;
r.held_for_save = (t / 2) % 2 == 0 && wait_frac > 0.0; // short waits, on and off
r.save_pending = 2;
r.base_interval_ms = 2000;
r.save_ms_mean = save_ms;
r.save_workers = 1;
auto l = g.update(r);
all.insert(all.end(), l.begin(), l.end());
}
return all;
}
TEST_CASE("a saver that holds the scan briefly but often slows it, to a pace saving can keep") {
ThermalParams p;
ThermalGuard g(p);
long long held = 0;
// 10% of the time waiting: a saver with headroom; nothing to do.
runSlowSaver(g, 0, 120, 0.10, held);
CHECK(g.state() == GuardState::Normal);
// 50%: the bottleneck. Judged on half a minute at least, then slowed.
auto log = runSlowSaver(g, 122, 200, 0.50, held);
CHECK(g.state() == GuardState::Slowed);
CHECK(logged(log, "of the last minute"));
// The pace follows what saving takes: 1.5 x 4.6 s = 6.9 s, not 2 x 2 s.
CHECK(g.intervalScale() == doctest::Approx(1.5 * 4600.0 / 2000.0));
CHECK(logged(log, "one picture every 6.9 s instead of 2.0"));
}
TEST_CASE("slowed, but saving still the bottleneck: paused; with headroom: back to normal") {
ThermalParams p;
{
ThermalGuard g(p);
long long held = 0;
long long s = 0; // when it slowed
while (g.state() == GuardState::Normal && s < 120) {
s += 2;
runSlowSaver(g, s, s, 0.5, held);
}
REQUIRE(g.state() == GuardState::Slowed);
// Judged only once a minute of slowed pictures is in the window, then
// held_pause_s of it.
runSlowSaver(g, s + 2, s + 60 + p.held_pause_s - 4, 0.5, held);
CHECK(g.state() == GuardState::Slowed);
auto log = runSlowSaver(g, s + 60 + p.held_pause_s - 2, s + 60 + p.held_pause_s + 4,
0.5, held);
CHECK(g.state() == GuardState::Paused);
CHECK(logged(log, "even slowed"));
}
{
ThermalGuard g(p);
long long held = 0;
runSlowSaver(g, 0, 60, 0.5, held);
REQUIRE(g.state() == GuardState::Slowed);
// The slower pace gave saving its headroom: no waiting at all. But a
// save still 4.6 s long does not fit the 2 s pace, so going back would
// only overload again: it stays slowed, at a pace it can hold, no flapping.
runSlowSaver(g, 62, 62 + 60 + p.calm_s, 0.0, held);
CHECK(g.state() == GuardState::Slowed);
// Saving fast again (the CPU cooled, the load went): back to normal.
long long t = 62 + 60 + p.calm_s + 2;
runSlowSaver(g, t, t + p.calm_s + 4, 0.0, held, 1000.0);
CHECK(g.state() == GuardState::Normal);
}
}
TEST_CASE("the slowed pace never goes past 10x, and remembers the save time through a pause") {
ThermalGuard g;
long long held = 0;
runSlowSaver(g, 0, 60, 0.5, held, 60000.0); // a minute per picture
REQUIRE(g.state() == GuardState::Slowed);
CHECK(g.intervalScale() == doctest::Approx(10.0));
}
TEST_CASE("missing readings are left out of the rules, not taken as zero or as hot") {
ThermalGuard g;
for (long long t = 0; t < 600; t += 2) {
HostReading r;
r.now_ms = t * 1000;
auto log = g.update(r);
CHECK(log.empty());
}
CHECK(g.state() == GuardState::Normal);
}
TEST_CASE("thermal off keeps full pace; thermal resume clears a pause") {
ThermalParams p;
ThermalGuard g(p);
run(g, 0, p.pause_after_s + 2, 95.0);
REQUIRE(g.state() == GuardState::Paused);
auto log = g.forceResume(30000);
CHECK(g.state() == GuardState::Normal);
CHECK_FALSE(log.empty());
// Still hot: the rules apply afresh - slowed at once, paused after pause_after_s.
g.update(at(32, 95.0));
CHECK(g.state() == GuardState::Slowed);
run(g, 34, 32 + p.pause_after_s, 95.0);
CHECK(g.state() == GuardState::Paused);
g.setEnabled(false, 100000);
CHECK_FALSE(g.enabled());
CHECK(g.state() == GuardState::Normal);
run(g, 100, 1000, 99.0);
CHECK(g.state() == GuardState::Normal);
g.setEnabled(true, 1002000);
g.update(at(1004, 99.0));
CHECK(g.state() == GuardState::Slowed);
}
TEST_CASE("throttling is logged when it starts, summarised once a minute, and when it ends") {
ThermalGuard g;
// Counters still: nothing.
auto log = run(g, 0, 10, 80.0, 100);
CHECK_FALSE(g.throttle().throttling());
CHECK(log.empty());
// The counter rises: one start line, with the temperature and clock.
log = g.update(at(12, 90.0, 103));
CHECK(g.throttle().throttling());
CHECK(logged(log, "CPU is slowing itself to stay cool: 90 \xC2\xB0""C, running at 2.8 GHz of 3.6 GHz"));
CHECK(g.state() == GuardState::Slowed);
// Rising every sample for 70 s: exactly one summary.
int summaries = 0;
long long count = 103;
for (long long t = 14; t <= 82; t += 2) {
count += 2;
for (const auto& l : g.update(at(t, 90.0, count)))
if (l.second.find("CPU still slowed") != std::string::npos) ++summaries;
}
CHECK(summaries == 1);
CHECK(g.throttle().eventsLastMinute() > 0);
// Counter stops: the end line comes after a quiet minute, not before.
log = run(g, 84, 140, 80.0, count);
CHECK(g.throttle().throttling());
CHECK_FALSE(logged(log, "no longer slowed"));
log = run(g, 142, 146, 80.0, count);
CHECK_FALSE(g.throttle().throttling());
CHECK(logged(log, "CPU no longer slowed: 80 \xC2\xB0""C"));
}
TEST_CASE("throttling is inferred from a low clock while busy, as a capped or power-limited CPU shows") {
ThermalGuard g;
auto slow = [](long long t, double busy) {
HostReading r = at(t, 70.0);
r.count_ok = false; // no kernel counters on this host
r.mhz = 800;
r.busy_pct = busy;
return r;
};
// Low clock while idle is just an idle CPU.
for (long long t = 0; t < 20; t += 2) g.update(slow(t, 5));
CHECK_FALSE(g.throttle().throttling());
// One busy sample may be the governor catching up; two are not.
auto log = g.update(slow(20, 90));
CHECK_FALSE(g.throttle().throttling());
log = g.update(slow(22, 90));
CHECK(g.throttle().throttling());
CHECK(g.throttle().cause() == "clock");
CHECK(logged(log, "judged from its clock"));
}
TEST_CASE("a throttle counter that goes backwards is a fresh start, not throttling") {
ThermalGuard g;
g.update(at(0, 70.0, 500));
auto log = g.update(at(2, 70.0, 3));
CHECK_FALSE(g.throttle().throttling());
CHECK(log.empty());
}
TEST_CASE("host readers on a fake sysfs tree") {
FakeSys s;
s.put("sys/class/thermal/thermal_zone0/temp", "48000\n");
s.put("sys/class/thermal/thermal_zone0/type", "acpitz\n");
s.put("sys/class/thermal/thermal_zone1/temp", "91500\n");
s.put("sys/class/thermal/thermal_zone1/type", "x86_pkg_temp\n");
for (int c = 0; c < 4; ++c) {
const std::string cpu = "sys/devices/system/cpu/cpu" + std::to_string(c) + "/";
s.put(cpu + "cpufreq/scaling_cur_freq", std::to_string(1000000 + c * 200000) + "\n");
s.put(cpu + "cpufreq/cpuinfo_max_freq", "3600000\n");
s.put(cpu + "cpufreq/scaling_max_freq", c == 2 ? "1600000\n" : "3600000\n");
s.put(cpu + "thermal_throttle/package_throttle_count", "7\n");
s.put(cpu + "thermal_throttle/core_throttle_count", "1\n");
}
s.put("sys/devices/system/cpu/cpufreq/policy0/scaling_cur_freq", "999\n"); // not a core
s.put("proc/stat", "cpu 100 0 50 800 50 0 0 0 0 0\ncpu0 1 2 3 4\n");
const std::string root = s.root.string();
auto th = hostmetrics::readThermal(root);
REQUIRE(th.ok);
CHECK(th.max_temp_c == doctest::Approx(91.5));
CHECK(th.hottest_zone == "x86_pkg_temp");
CHECK(th.cpu_temp_c == doctest::Approx(91.5));
// A Wi-Fi card hotter than the CPU (the towers list iwlwifi_1): the hottest
// zone is the card, but the CPU guard still reads the CPU package.
s.put("sys/class/thermal/thermal_zone2/temp", "97000\n");
s.put("sys/class/thermal/thermal_zone2/type", "iwlwifi_1\n");
th = hostmetrics::readThermal(root);
CHECK(th.hottest_zone == "iwlwifi_1");
CHECK(th.cpu_zone == "x86_pkg_temp");
CHECK(th.cpu_temp_c == doctest::Approx(91.5));
auto f = hostmetrics::readCpuFreq(root);
REQUIRE(f.ok);
CHECK(f.core_mhz.size() == 4);
CHECK(f.core_mhz[0] == doctest::Approx(1000.0));
CHECK(f.mean_mhz == doctest::Approx(1300.0));
CHECK(f.hw_max_mhz == doctest::Approx(3600.0));
CHECK(f.cap_mhz == doctest::Approx(1600.0));
auto c = hostmetrics::readThrottleCount(root);
REQUIRE(c.ok);
CHECK(c.events == 7 + 4); // the package once, every core
auto t = hostmetrics::readCpuTimes(root);
REQUIRE(t.ok);
CHECK(t.total == 1000);
CHECK(t.busy == 150);
// A tree without proc/stat reads the real one: busy % stays real in a simulation.
fs::remove(s.root / "proc/stat");
CHECK(hostmetrics::readCpuTimes(root).ok);
// Nothing there: not ok, no throw.
CHECK_FALSE(hostmetrics::readCpuFreq("/nonexistent-fgc").ok);
CHECK_FALSE(hostmetrics::readThrottleCount("/nonexistent-fgc").ok);
CHECK(hostmetrics::readCpuTimes("/nonexistent-fgc").ok); // the real /proc/stat
CHECK_FALSE(hostmetrics::readThermal("/nonexistent-fgc").ok);
}
TEST_CASE("[Thermal] config: defaults, overrides and the order of the limits") {
AppConfig d = ConfigLoader::fromMap({});
CHECK(d.thermal.enabled);
CHECK(d.thermal.sysfs_root == "/");
CHECK(d.thermal.slow_c == doctest::Approx(85.0));
CHECK(d.thermal.pause_c == doctest::Approx(92.0));
CHECK(d.thermal.resume_c == doctest::Approx(75.0));
CHECK_FALSE(d.features.mock_camera_full);
AppConfig c = ConfigLoader::fromMap({{"Thermal.slow_c", "80"},
{"Thermal.pause_c", "88"},
{"Thermal.resume_c", "70"},
{"Thermal.slow_factor", "3"},
{"Thermal.sysfs_root", "/tmp/fake"},
{"Thermal.enabled", "false"},
{"Features.mock_camera_size", "full"}});
CHECK_FALSE(c.thermal.enabled);
CHECK(c.thermal.slow_c == doctest::Approx(80.0));
CHECK(c.thermal.slow_factor == doctest::Approx(3.0));
CHECK(c.thermal.sysfs_root == "/tmp/fake");
CHECK(c.features.mock_camera_full);
CHECK_THROWS(ConfigLoader::fromMap({{"Thermal.slow_c", "95"}})); // above pause_c
CHECK_THROWS(ConfigLoader::fromMap({{"Thermal.resume_c", "90"}})); // above slow_c
CHECK_THROWS(ConfigLoader::fromMap({{"Thermal.slow_factor", "0.5"}}));
CHECK_THROWS(ConfigLoader::fromMap({{"Thermal.held_pause_s", "10"}})); // under held_slow_s
CHECK_THROWS(ConfigLoader::fromMap({{"Thermal.sample_ms", "10"}}));
CHECK_THROWS(ConfigLoader::fromMap({{"Features.mock_camera_size", "huge"}}));
}
TEST_CASE("Health payload: unknown readings are null, numbers rounded") {
HealthReport h;
h.tower = "t121";
h.state = "paused";
h.reason = "CPU at 93 \xC2\xB0""C for 20 s";
h.cpu_c_ok = true;
h.cpu_c = 93.04;
h.cpu_mhz_ok = true;
h.cpu_mhz = 1187.6;
h.throttling = true;
h.throttle_events_last_min = 14;
h.interval_s = 10.0;
h.held_s = 3;
h.timestamp_ms = 1700000000000;
const std::string j = healthJson(h);
CHECK(j.find("\"state\":\"paused\"") != std::string::npos);
CHECK(j.find("\"cpu_c\":93.0") != std::string::npos);
CHECK(j.find("\"cpu_mhz\":1188") != std::string::npos);
CHECK(j.find("\"cpu_busy_pct\":null") != std::string::npos);
CHECK(j.find("\"enclosure_c\":null") != std::string::npos);
CHECK(j.find("\"save_ms_mean\":null") != std::string::npos);
CHECK(j.find("\"throttling\":true") != std::string::npos);
CHECK(j.find("\"throttle_events_last_min\":14") != std::string::npos);
CHECK(j.find("\"interval_s\":10.0") != std::string::npos);
CHECK(j.find("\"time\":1700000000000") != std::string::npos);
CHECK(j.front() == '{');
CHECK(j.back() == '}');
}
TEST_CASE("the CPU guard's commands work in every mode") {
CHECK(allowedIn(Mode::Auto, "thermal"));
CHECK(allowedIn(Mode::Pan, "thermal resume"));
CHECK(allowedIn(Mode::Auto, "thermal off"));
}
TEST_CASE("busy percent between two /proc/stat reads") {
auto a = hostmetrics::parseProcStatCpu("cpu 100 0 100 700 100 0 0 0\n");
auto b = hostmetrics::parseProcStatCpu("cpu 400 0 100 1000 100 0 0 0\n");
CHECK(hostmetrics::busyPercent(a, b) == doctest::Approx(50.0));
CHECK(hostmetrics::busyPercent(a, a) == doctest::Approx(-1.0));
CHECK(hostmetrics::busyPercent({}, b) == doctest::Approx(-1.0));
CHECK_FALSE(hostmetrics::parseProcStatCpu("intr 1 2 3\n").ok);
}

View File

@ -0,0 +1,62 @@
{"t": 1, "temp_c": 54.0, "mhz": 1200, "cpu_pct": 62.8, "watts": 4.84, "rss_mb": 565, "done": 0, "queue": 0}
{"t": 2, "temp_c": 54.0, "mhz": 1200, "cpu_pct": 65.9, "watts": 4.93, "rss_mb": 534, "done": 0, "queue": 0}
{"t": 3, "temp_c": 54.0, "mhz": 1200, "cpu_pct": 60.1, "watts": 5.00, "rss_mb": 588, "done": 1, "queue": 0}
{"t": 4, "temp_c": 55.0, "mhz": 1200, "cpu_pct": 63.1, "watts": 3.74, "rss_mb": 617, "done": 1, "queue": 0}
{"t": 5, "temp_c": 54.0, "mhz": 1200, "cpu_pct": 57.8, "watts": 4.96, "rss_mb": 473, "done": 2, "queue": 0}
{"t": 6, "temp_c": 55.0, "mhz": 1200, "cpu_pct": 65.9, "watts": 5.09, "rss_mb": 634, "done": 2, "queue": 0}
{"t": 7, "temp_c": 54.0, "mhz": 1051, "cpu_pct": 63.2, "watts": 5.06, "rss_mb": 398, "done": 2, "queue": 0}
{"t": 8, "temp_c": 55.0, "mhz": 1200, "cpu_pct": 62.4, "watts": 4.93, "rss_mb": 610, "done": 3, "queue": 0}
{"t": 9, "temp_c": 55.0, "mhz": 1200, "cpu_pct": 62.9, "watts": 3.77, "rss_mb": 576, "done": 3, "queue": 0}
{"t": 10, "temp_c": 54.0, "mhz": 1000, "cpu_pct": 60.2, "watts": 4.93, "rss_mb": 661, "done": 4, "queue": 0}
{"t": 11, "temp_c": 55.0, "mhz": 1200, "cpu_pct": 69.8, "watts": 5.07, "rss_mb": 680, "done": 4, "queue": 0}
{"t": 12, "temp_c": 55.0, "mhz": 1200, "cpu_pct": 57.1, "watts": 4.76, "rss_mb": 638, "done": 5, "queue": 0}
{"t": 13, "temp_c": 54.0, "mhz": 1000, "cpu_pct": 67.2, "watts": 5.15, "rss_mb": 691, "done": 5, "queue": 0}
{"t": 14, "temp_c": 55.0, "mhz": 1200, "cpu_pct": 61.5, "watts": 4.93, "rss_mb": 562, "done": 6, "queue": 0}
{"t": 15, "temp_c": 55.0, "mhz": 1200, "cpu_pct": 64.1, "watts": 5.07, "rss_mb": 683, "done": 6, "queue": 0}
{"t": 16, "temp_c": 55.0, "mhz": 1200, "cpu_pct": 64.2, "watts": 3.80, "rss_mb": 559, "done": 6, "queue": 0}
{"t": 17, "temp_c": 55.0, "mhz": 1200, "cpu_pct": 67.9, "watts": 5.03, "rss_mb": 689, "done": 7, "queue": 0}
{"t": 18, "temp_c": 55.0, "mhz": 1200, "cpu_pct": 61.8, "watts": 5.09, "rss_mb": 690, "done": 7, "queue": 0}
{"t": 19, "temp_c": 54.0, "mhz": 1200, "cpu_pct": 55.8, "watts": 4.77, "rss_mb": 691, "done": 8, "queue": 0}
{"t": 20, "temp_c": 55.0, "mhz": 1200, "cpu_pct": 68.2, "watts": 5.14, "rss_mb": 693, "done": 8, "queue": 0}
{"t": 21, "temp_c": 56.0, "mhz": 1200, "cpu_pct": 78.1, "watts": 5.65, "rss_mb": 687, "done": 9, "queue": 0}
{"t": 22, "temp_c": 55.0, "mhz": 1200, "cpu_pct": 75.0, "watts": 4.17, "rss_mb": 695, "done": 9, "queue": 0}
{"t": 23, "temp_c": 55.0, "mhz": 1100, "cpu_pct": 60.3, "watts": 5.08, "rss_mb": 589, "done": 10, "queue": 0}
{"t": 24, "temp_c": 54.0, "mhz": 1200, "cpu_pct": 63.9, "watts": 5.08, "rss_mb": 696, "done": 10, "queue": 0}
{"t": 25, "temp_c": 55.0, "mhz": 1200, "cpu_pct": 66.5, "watts": 4.95, "rss_mb": 696, "done": 10, "queue": 0}
{"t": 26, "temp_c": 55.0, "mhz": 1200, "cpu_pct": 62.6, "watts": 5.07, "rss_mb": 699, "done": 11, "queue": 0}
{"t": 27, "temp_c": 54.0, "mhz": 1200, "cpu_pct": 64.3, "watts": 5.04, "rss_mb": 700, "done": 11, "queue": 0}
{"t": 28, "temp_c": 55.0, "mhz": 1200, "cpu_pct": 61.6, "watts": 3.77, "rss_mb": 702, "done": 12, "queue": 0}
{"t": 29, "temp_c": 54.0, "mhz": 1200, "cpu_pct": 67.6, "watts": 5.10, "rss_mb": 702, "done": 12, "queue": 0}
{"t": 30, "temp_c": 55.0, "mhz": 1200, "cpu_pct": 61.7, "watts": 4.88, "rss_mb": 702, "done": 13, "queue": 0}
{"t": 31, "temp_c": 55.0, "mhz": 1200, "cpu_pct": 64.6, "watts": 5.06, "rss_mb": 704, "done": 13, "queue": 0}
{"t": 32, "temp_c": 56.0, "mhz": 1200, "cpu_pct": 59.9, "watts": 4.90, "rss_mb": 672, "done": 14, "queue": 0}
{"t": 33, "temp_c": 55.0, "mhz": 1199, "cpu_pct": 66.9, "watts": 5.21, "rss_mb": 704, "done": 14, "queue": 0}
{"t": 34, "temp_c": 55.0, "mhz": 1200, "cpu_pct": 60.1, "watts": 3.73, "rss_mb": 596, "done": 15, "queue": 0}
{"t": 35, "temp_c": 56.0, "mhz": 1200, "cpu_pct": 66.5, "watts": 5.18, "rss_mb": 705, "done": 15, "queue": 0}
{"t": 36, "temp_c": 54.0, "mhz": 1200, "cpu_pct": 63.3, "watts": 5.06, "rss_mb": 581, "done": 15, "queue": 0}
{"t": 37, "temp_c": 55.0, "mhz": 1200, "cpu_pct": 63.8, "watts": 4.90, "rss_mb": 706, "done": 16, "queue": 0}
{"t": 38, "temp_c": 55.0, "mhz": 1100, "cpu_pct": 64.3, "watts": 5.14, "rss_mb": 706, "done": 16, "queue": 0}
{"t": 39, "temp_c": 55.0, "mhz": 1200, "cpu_pct": 57.3, "watts": 4.79, "rss_mb": 706, "done": 17, "queue": 0}
{"t": 40, "temp_c": 54.0, "mhz": 1200, "cpu_pct": 67.0, "watts": 3.80, "rss_mb": 723, "done": 17, "queue": 0}
{"t": 41, "temp_c": 55.0, "mhz": 1200, "cpu_pct": 62.7, "watts": 4.89, "rss_mb": 707, "done": 18, "queue": 0}
{"t": 42, "temp_c": 54.0, "mhz": 1200, "cpu_pct": 65.2, "watts": 5.13, "rss_mb": 708, "done": 18, "queue": 0}
{"t": 43, "temp_c": 55.0, "mhz": 1200, "cpu_pct": 57.3, "watts": 4.92, "rss_mb": 676, "done": 19, "queue": 0}
{"t": 44, "temp_c": 54.0, "mhz": 1200, "cpu_pct": 68.9, "watts": 5.00, "rss_mb": 725, "done": 19, "queue": 0}
{"t": 45, "temp_c": 55.0, "mhz": 807, "cpu_pct": 61.1, "watts": 5.04, "rss_mb": 584, "done": 19, "queue": 0}
{"t": 46, "temp_c": 56.0, "mhz": 1200, "cpu_pct": 67.7, "watts": 5.05, "rss_mb": 725, "done": 20, "queue": 0}
{"t": 47, "temp_c": 55.0, "mhz": 1200, "cpu_pct": 65.4, "watts": 3.88, "rss_mb": 725, "done": 20, "queue": 0}
{"t": 48, "temp_c": 55.0, "mhz": 1200, "cpu_pct": 62.2, "watts": 5.00, "rss_mb": 725, "done": 21, "queue": 0}
{"t": 49, "temp_c": 56.0, "mhz": 1200, "cpu_pct": 67.0, "watts": 5.02, "rss_mb": 726, "done": 21, "queue": 0}
{"t": 50, "temp_c": 55.0, "mhz": 1100, "cpu_pct": 59.2, "watts": 4.99, "rss_mb": 726, "done": 22, "queue": 0}
{"t": 51, "temp_c": 54.0, "mhz": 1200, "cpu_pct": 67.8, "watts": 5.13, "rss_mb": 726, "done": 22, "queue": 0}
{"t": 52, "temp_c": 57.0, "mhz": 1200, "cpu_pct": 75.3, "watts": 5.67, "rss_mb": 678, "done": 23, "queue": 0}
{"t": 53, "temp_c": 55.0, "mhz": 1200, "cpu_pct": 70.9, "watts": 4.11, "rss_mb": 710, "done": 23, "queue": 0}
{"t": 54, "temp_c": 54.0, "mhz": 1000, "cpu_pct": 58.8, "watts": 5.06, "rss_mb": 493, "done": 24, "queue": 0}
{"t": 55, "temp_c": 55.0, "mhz": 1200, "cpu_pct": 68.4, "watts": 4.97, "rss_mb": 710, "done": 24, "queue": 0}
{"t": 56, "temp_c": 56.0, "mhz": 1200, "cpu_pct": 65.0, "watts": 5.00, "rss_mb": 711, "done": 24, "queue": 0}
{"t": 57, "temp_c": 55.0, "mhz": 1200, "cpu_pct": 59.4, "watts": 4.99, "rss_mb": 727, "done": 25, "queue": 0}
{"t": 58, "temp_c": 56.0, "mhz": 1200, "cpu_pct": 69.2, "watts": 3.86, "rss_mb": 727, "done": 25, "queue": 0}
{"t": 59, "temp_c": 55.0, "mhz": 1200, "cpu_pct": 57.6, "watts": 5.12, "rss_mb": 711, "done": 26, "queue": 0}
{"t": 60, "temp_c": 56.0, "mhz": 1100, "cpu_pct": 67.6, "watts": 5.12, "rss_mb": 711, "done": 26, "queue": 0}
{"t": 61, "temp_c": 53.0, "mhz": 1000, "cpu_pct": 37.3, "watts": 4.36, "rss_mb": 381, "done": 27, "queue": 0}
{"summary": "pipeline", "kind": "c12_ea", "workers": 1, "threads": 4, "effort": 3, "distance": 1.00, "period_ms": 0, "secs": 60.7, "frames": 27, "frames_per_s": 0.445, "job_ms_p50": 2219, "latency_ms_p50": 2240, "latency_ms_p95": 2339, "latency_ms_max": 2454, "max_queue": 0, "backlog_at_end": 0, "cpu_s_per_frame": 5.193, "peak_rss_mb": 726, "temp_c_mean": 54.9, "temp_c_max": 57.0, "mhz_mean": 1171, "mhz_min": 807, "cpu_pct_mean": 63.8, "watts_mean": 4.83}

View File

@ -0,0 +1,122 @@
{"t": 1, "temp_c": 55.0, "mhz": 1200, "cpu_pct": 62.5, "watts": 4.85, "rss_mb": 575, "done": 0, "queue": 0}
{"t": 2, "temp_c": 55.0, "mhz": 1200, "cpu_pct": 68.7, "watts": 5.08, "rss_mb": 534, "done": 0, "queue": 1}
{"t": 3, "temp_c": 56.0, "mhz": 1200, "cpu_pct": 59.8, "watts": 4.94, "rss_mb": 596, "done": 1, "queue": 0}
{"t": 4, "temp_c": 56.0, "mhz": 1200, "cpu_pct": 64.4, "watts": 3.82, "rss_mb": 620, "done": 1, "queue": 1}
{"t": 5, "temp_c": 55.0, "mhz": 1200, "cpu_pct": 60.0, "watts": 4.95, "rss_mb": 508, "done": 2, "queue": 0}
{"t": 6, "temp_c": 56.0, "mhz": 1200, "cpu_pct": 67.3, "watts": 4.98, "rss_mb": 636, "done": 2, "queue": 1}
{"t": 7, "temp_c": 55.0, "mhz": 1200, "cpu_pct": 56.9, "watts": 5.00, "rss_mb": 306, "done": 3, "queue": 0}
{"t": 8, "temp_c": 56.0, "mhz": 1200, "cpu_pct": 66.9, "watts": 5.01, "rss_mb": 614, "done": 3, "queue": 1}
{"t": 9, "temp_c": 56.0, "mhz": 1199, "cpu_pct": 64.2, "watts": 5.06, "rss_mb": 579, "done": 3, "queue": 1}
{"t": 10, "temp_c": 56.0, "mhz": 1200, "cpu_pct": 57.9, "watts": 3.64, "rss_mb": 669, "done": 4, "queue": 1}
{"t": 11, "temp_c": 55.0, "mhz": 1100, "cpu_pct": 67.8, "watts": 5.10, "rss_mb": 689, "done": 4, "queue": 1}
{"t": 12, "temp_c": 55.0, "mhz": 1200, "cpu_pct": 57.9, "watts": 4.81, "rss_mb": 658, "done": 5, "queue": 1}
{"t": 13, "temp_c": 56.0, "mhz": 1000, "cpu_pct": 66.8, "watts": 5.21, "rss_mb": 695, "done": 5, "queue": 1}
{"t": 14, "temp_c": 55.0, "mhz": 1200, "cpu_pct": 58.4, "watts": 4.94, "rss_mb": 597, "done": 6, "queue": 1}
{"t": 15, "temp_c": 55.0, "mhz": 1200, "cpu_pct": 65.8, "watts": 3.96, "rss_mb": 684, "done": 6, "queue": 1}
{"t": 16, "temp_c": 55.0, "mhz": 1200, "cpu_pct": 64.3, "watts": 4.93, "rss_mb": 560, "done": 6, "queue": 2}
{"t": 17, "temp_c": 56.0, "mhz": 1200, "cpu_pct": 65.2, "watts": 5.00, "rss_mb": 686, "done": 7, "queue": 1}
{"t": 18, "temp_c": 55.0, "mhz": 1000, "cpu_pct": 61.3, "watts": 5.11, "rss_mb": 687, "done": 7, "queue": 2}
{"t": 19, "temp_c": 56.0, "mhz": 1200, "cpu_pct": 60.7, "watts": 4.79, "rss_mb": 688, "done": 8, "queue": 1}
{"t": 20, "temp_c": 56.0, "mhz": 1200, "cpu_pct": 71.4, "watts": 5.35, "rss_mb": 689, "done": 8, "queue": 2}
{"t": 21, "temp_c": 56.0, "mhz": 1200, "cpu_pct": 79.3, "watts": 4.40, "rss_mb": 690, "done": 9, "queue": 1}
{"t": 22, "temp_c": 55.0, "mhz": 1200, "cpu_pct": 65.4, "watts": 5.25, "rss_mb": 692, "done": 9, "queue": 2}
{"t": 23, "temp_c": 56.0, "mhz": 1200, "cpu_pct": 57.9, "watts": 4.88, "rss_mb": 660, "done": 10, "queue": 1}
{"t": 24, "temp_c": 56.0, "mhz": 1200, "cpu_pct": 69.7, "watts": 5.01, "rss_mb": 694, "done": 10, "queue": 2}
{"t": 25, "temp_c": 55.0, "mhz": 1200, "cpu_pct": 58.2, "watts": 4.92, "rss_mb": 525, "done": 11, "queue": 1}
{"t": 26, "temp_c": 55.0, "mhz": 1200, "cpu_pct": 65.8, "watts": 5.15, "rss_mb": 695, "done": 11, "queue": 2}
{"t": 27, "temp_c": 55.0, "mhz": 1200, "cpu_pct": 66.9, "watts": 3.85, "rss_mb": 696, "done": 11, "queue": 2}
{"t": 28, "temp_c": 56.0, "mhz": 1200, "cpu_pct": 61.9, "watts": 4.79, "rss_mb": 700, "done": 12, "queue": 2}
{"t": 29, "temp_c": 55.0, "mhz": 1200, "cpu_pct": 65.1, "watts": 5.16, "rss_mb": 701, "done": 12, "queue": 2}
{"t": 30, "temp_c": 55.0, "mhz": 1000, "cpu_pct": 56.0, "watts": 4.96, "rss_mb": 702, "done": 13, "queue": 2}
{"t": 31, "temp_c": 55.0, "mhz": 1200, "cpu_pct": 68.3, "watts": 5.08, "rss_mb": 703, "done": 13, "queue": 2}
{"t": 32, "temp_c": 57.0, "mhz": 1200, "cpu_pct": 63.2, "watts": 4.99, "rss_mb": 702, "done": 14, "queue": 2}
{"t": 33, "temp_c": 56.0, "mhz": 1100, "cpu_pct": 64.2, "watts": 3.80, "rss_mb": 707, "done": 14, "queue": 2}
{"t": 34, "temp_c": 56.0, "mhz": 1200, "cpu_pct": 60.1, "watts": 4.93, "rss_mb": 631, "done": 15, "queue": 2}
{"t": 35, "temp_c": 55.0, "mhz": 1200, "cpu_pct": 65.8, "watts": 5.18, "rss_mb": 708, "done": 15, "queue": 2}
{"t": 36, "temp_c": 54.0, "mhz": 950, "cpu_pct": 62.8, "watts": 5.06, "rss_mb": 583, "done": 15, "queue": 3}
{"t": 37, "temp_c": 56.0, "mhz": 1100, "cpu_pct": 67.2, "watts": 5.09, "rss_mb": 708, "done": 16, "queue": 2}
{"t": 38, "temp_c": 55.0, "mhz": 1200, "cpu_pct": 62.0, "watts": 3.68, "rss_mb": 709, "done": 16, "queue": 3}
{"t": 39, "temp_c": 57.0, "mhz": 1200, "cpu_pct": 60.6, "watts": 5.03, "rss_mb": 709, "done": 17, "queue": 2}
{"t": 40, "temp_c": 56.0, "mhz": 1200, "cpu_pct": 67.5, "watts": 5.07, "rss_mb": 725, "done": 17, "queue": 3}
{"t": 41, "temp_c": 56.0, "mhz": 1200, "cpu_pct": 63.4, "watts": 4.99, "rss_mb": 709, "done": 18, "queue": 2}
{"t": 42, "temp_c": 57.0, "mhz": 1200, "cpu_pct": 66.7, "watts": 5.09, "rss_mb": 710, "done": 18, "queue": 3}
{"t": 43, "temp_c": 56.0, "mhz": 1200, "cpu_pct": 57.4, "watts": 4.97, "rss_mb": 678, "done": 19, "queue": 2}
{"t": 44, "temp_c": 57.0, "mhz": 1200, "cpu_pct": 69.1, "watts": 3.78, "rss_mb": 726, "done": 19, "queue": 3}
{"t": 45, "temp_c": 56.0, "mhz": 1200, "cpu_pct": 58.0, "watts": 5.05, "rss_mb": 559, "done": 20, "queue": 2}
{"t": 46, "temp_c": 56.0, "mhz": 1100, "cpu_pct": 64.8, "watts": 5.13, "rss_mb": 726, "done": 20, "queue": 3}
{"t": 47, "temp_c": 55.0, "mhz": 1000, "cpu_pct": 67.9, "watts": 5.03, "rss_mb": 727, "done": 20, "queue": 3}
{"t": 48, "temp_c": 56.0, "mhz": 1200, "cpu_pct": 61.2, "watts": 4.89, "rss_mb": 727, "done": 21, "queue": 3}
{"t": 49, "temp_c": 55.0, "mhz": 1200, "cpu_pct": 66.8, "watts": 5.16, "rss_mb": 727, "done": 21, "queue": 3}
{"t": 50, "temp_c": 55.0, "mhz": 1000, "cpu_pct": 58.1, "watts": 3.67, "rss_mb": 727, "done": 22, "queue": 3}
{"t": 51, "temp_c": 58.0, "mhz": 1200, "cpu_pct": 71.7, "watts": 5.04, "rss_mb": 728, "done": 22, "queue": 3}
{"t": 52, "temp_c": 57.0, "mhz": 1200, "cpu_pct": 75.7, "watts": 5.95, "rss_mb": 674, "done": 23, "queue": 3}
{"t": 53, "temp_c": 56.0, "mhz": 1200, "cpu_pct": 70.6, "watts": 5.31, "rss_mb": 712, "done": 23, "queue": 3}
{"t": 54, "temp_c": 56.0, "mhz": 1200, "cpu_pct": 59.9, "watts": 5.00, "rss_mb": 507, "done": 24, "queue": 3}
{"t": 55, "temp_c": 55.0, "mhz": 1200, "cpu_pct": 65.7, "watts": 5.08, "rss_mb": 714, "done": 24, "queue": 3}
{"t": 56, "temp_c": 56.0, "mhz": 1100, "cpu_pct": 67.2, "watts": 3.92, "rss_mb": 714, "done": 24, "queue": 4}
{"t": 57, "temp_c": 56.0, "mhz": 1200, "cpu_pct": 61.8, "watts": 4.74, "rss_mb": 714, "done": 25, "queue": 3}
{"t": 58, "temp_c": 55.0, "mhz": 1200, "cpu_pct": 64.8, "watts": 5.08, "rss_mb": 715, "done": 25, "queue": 4}
{"t": 59, "temp_c": 54.0, "mhz": 1200, "cpu_pct": 57.9, "watts": 5.10, "rss_mb": 715, "done": 26, "queue": 3}
{"t": 60, "temp_c": 55.0, "mhz": 1000, "cpu_pct": 69.2, "watts": 5.07, "rss_mb": 715, "done": 26, "queue": 4}
{"t": 61, "temp_c": 57.0, "mhz": 1200, "cpu_pct": 61.2, "watts": 4.91, "rss_mb": 715, "done": 27, "queue": 3}
{"t": 62, "temp_c": 56.0, "mhz": 1200, "cpu_pct": 66.1, "watts": 3.89, "rss_mb": 716, "done": 27, "queue": 4}
{"t": 63, "temp_c": 56.0, "mhz": 1200, "cpu_pct": 58.5, "watts": 4.99, "rss_mb": 684, "done": 28, "queue": 3}
{"t": 64, "temp_c": 57.0, "mhz": 1200, "cpu_pct": 71.8, "watts": 5.09, "rss_mb": 716, "done": 28, "queue": 4}
{"t": 65, "temp_c": 55.0, "mhz": 800, "cpu_pct": 57.5, "watts": 5.08, "rss_mb": 515, "done": 28, "queue": 4}
{"t": 66, "temp_c": 55.0, "mhz": 1200, "cpu_pct": 68.3, "watts": 5.03, "rss_mb": 732, "done": 29, "queue": 4}
{"t": 67, "temp_c": 56.0, "mhz": 1200, "cpu_pct": 64.4, "watts": 5.04, "rss_mb": 732, "done": 29, "queue": 4}
{"t": 68, "temp_c": 56.0, "mhz": 1200, "cpu_pct": 56.4, "watts": 3.68, "rss_mb": 716, "done": 30, "queue": 4}
{"t": 69, "temp_c": 56.0, "mhz": 1200, "cpu_pct": 66.7, "watts": 5.03, "rss_mb": 716, "done": 30, "queue": 4}
{"t": 70, "temp_c": 57.0, "mhz": 1100, "cpu_pct": 61.1, "watts": 4.92, "rss_mb": 716, "done": 31, "queue": 4}
{"t": 71, "temp_c": 56.0, "mhz": 1200, "cpu_pct": 66.2, "watts": 5.00, "rss_mb": 716, "done": 31, "queue": 4}
{"t": 72, "temp_c": 56.0, "mhz": 1200, "cpu_pct": 58.0, "watts": 4.87, "rss_mb": 684, "done": 32, "queue": 4}
{"t": 73, "temp_c": 56.0, "mhz": 1200, "cpu_pct": 70.5, "watts": 5.20, "rss_mb": 717, "done": 32, "queue": 4}
{"t": 74, "temp_c": 56.0, "mhz": 1199, "cpu_pct": 61.2, "watts": 5.01, "rss_mb": 601, "done": 33, "queue": 4}
{"t": 75, "temp_c": 55.0, "mhz": 1200, "cpu_pct": 63.9, "watts": 3.93, "rss_mb": 717, "done": 33, "queue": 4}
{"t": 76, "temp_c": 56.0, "mhz": 1200, "cpu_pct": 65.2, "watts": 4.96, "rss_mb": 652, "done": 33, "queue": 5}
{"t": 77, "temp_c": 56.0, "mhz": 1200, "cpu_pct": 65.0, "watts": 4.99, "rss_mb": 717, "done": 34, "queue": 4}
{"t": 78, "temp_c": 56.0, "mhz": 1200, "cpu_pct": 63.2, "watts": 5.08, "rss_mb": 717, "done": 34, "queue": 5}
{"t": 79, "temp_c": 56.0, "mhz": 1200, "cpu_pct": 58.4, "watts": 4.77, "rss_mb": 717, "done": 35, "queue": 4}
{"t": 80, "temp_c": 56.0, "mhz": 1200, "cpu_pct": 67.5, "watts": 5.16, "rss_mb": 717, "done": 35, "queue": 5}
{"t": 81, "temp_c": 56.0, "mhz": 1200, "cpu_pct": 63.1, "watts": 3.64, "rss_mb": 717, "done": 36, "queue": 4}
{"t": 82, "temp_c": 57.0, "mhz": 1200, "cpu_pct": 70.9, "watts": 5.25, "rss_mb": 718, "done": 36, "queue": 5}
{"t": 83, "temp_c": 56.0, "mhz": 1100, "cpu_pct": 79.0, "watts": 5.91, "rss_mb": 618, "done": 37, "queue": 4}
{"t": 84, "temp_c": 56.0, "mhz": 1200, "cpu_pct": 65.2, "watts": 5.21, "rss_mb": 718, "done": 37, "queue": 5}
{"t": 85, "temp_c": 56.0, "mhz": 1200, "cpu_pct": 62.8, "watts": 5.03, "rss_mb": 593, "done": 37, "queue": 5}
{"t": 86, "temp_c": 56.0, "mhz": 1199, "cpu_pct": 67.6, "watts": 5.23, "rss_mb": 718, "done": 38, "queue": 5}
{"t": 87, "temp_c": 56.0, "mhz": 1200, "cpu_pct": 63.2, "watts": 3.70, "rss_mb": 718, "done": 38, "queue": 5}
{"t": 88, "temp_c": 56.0, "mhz": 1200, "cpu_pct": 60.1, "watts": 4.96, "rss_mb": 718, "done": 39, "queue": 5}
{"t": 89, "temp_c": 56.0, "mhz": 1200, "cpu_pct": 68.2, "watts": 5.14, "rss_mb": 718, "done": 39, "queue": 5}
{"t": 90, "temp_c": 56.0, "mhz": 1099, "cpu_pct": 61.4, "watts": 4.95, "rss_mb": 718, "done": 40, "queue": 5}
{"t": 91, "temp_c": 56.0, "mhz": 1200, "cpu_pct": 65.9, "watts": 5.04, "rss_mb": 718, "done": 40, "queue": 5}
{"t": 92, "temp_c": 56.0, "mhz": 1200, "cpu_pct": 58.8, "watts": 4.94, "rss_mb": 686, "done": 41, "queue": 5}
{"t": 93, "temp_c": 56.0, "mhz": 1100, "cpu_pct": 69.1, "watts": 3.83, "rss_mb": 718, "done": 41, "queue": 5}
{"t": 94, "temp_c": 56.0, "mhz": 1199, "cpu_pct": 60.8, "watts": 5.00, "rss_mb": 635, "done": 42, "queue": 5}
{"t": 95, "temp_c": 56.0, "mhz": 1200, "cpu_pct": 67.2, "watts": 5.20, "rss_mb": 719, "done": 42, "queue": 5}
{"t": 96, "temp_c": 55.0, "mhz": 1200, "cpu_pct": 63.4, "watts": 5.03, "rss_mb": 594, "done": 42, "queue": 6}
{"t": 97, "temp_c": 55.0, "mhz": 1200, "cpu_pct": 68.2, "watts": 5.10, "rss_mb": 719, "done": 43, "queue": 5}
{"t": 98, "temp_c": 56.0, "mhz": 1200, "cpu_pct": 65.0, "watts": 5.10, "rss_mb": 719, "done": 43, "queue": 6}
{"t": 99, "temp_c": 56.0, "mhz": 1200, "cpu_pct": 59.3, "watts": 3.71, "rss_mb": 735, "done": 44, "queue": 5}
{"t": 100, "temp_c": 56.0, "mhz": 1200, "cpu_pct": 66.4, "watts": 5.08, "rss_mb": 735, "done": 44, "queue": 6}
{"t": 101, "temp_c": 55.0, "mhz": 1000, "cpu_pct": 61.4, "watts": 4.88, "rss_mb": 719, "done": 45, "queue": 5}
{"t": 102, "temp_c": 56.0, "mhz": 1200, "cpu_pct": 66.2, "watts": 5.09, "rss_mb": 719, "done": 45, "queue": 6}
{"t": 103, "temp_c": 57.0, "mhz": 1200, "cpu_pct": 59.8, "watts": 5.08, "rss_mb": 700, "done": 46, "queue": 5}
{"t": 104, "temp_c": 55.0, "mhz": 1200, "cpu_pct": 69.1, "watts": 5.23, "rss_mb": 719, "done": 46, "queue": 6}
{"t": 105, "temp_c": 56.0, "mhz": 1200, "cpu_pct": 61.6, "watts": 3.65, "rss_mb": 646, "done": 47, "queue": 5}
{"t": 106, "temp_c": 55.0, "mhz": 1200, "cpu_pct": 66.3, "watts": 5.15, "rss_mb": 719, "done": 47, "queue": 6}
{"t": 107, "temp_c": 55.0, "mhz": 1118, "cpu_pct": 62.1, "watts": 5.07, "rss_mb": 502, "done": 47, "queue": 6}
{"t": 108, "temp_c": 56.0, "mhz": 900, "cpu_pct": 67.2, "watts": 5.01, "rss_mb": 720, "done": 48, "queue": 6}
{"t": 109, "temp_c": 55.0, "mhz": 1200, "cpu_pct": 64.2, "watts": 4.91, "rss_mb": 720, "done": 48, "queue": 6}
{"t": 110, "temp_c": 56.0, "mhz": 1200, "cpu_pct": 61.2, "watts": 4.98, "rss_mb": 720, "done": 49, "queue": 6}
{"t": 111, "temp_c": 56.0, "mhz": 1200, "cpu_pct": 68.6, "watts": 3.92, "rss_mb": 720, "done": 49, "queue": 6}
{"t": 112, "temp_c": 55.0, "mhz": 1200, "cpu_pct": 58.4, "watts": 5.02, "rss_mb": 720, "done": 50, "queue": 6}
{"t": 113, "temp_c": 57.0, "mhz": 1200, "cpu_pct": 73.2, "watts": 5.16, "rss_mb": 720, "done": 50, "queue": 6}
{"t": 114, "temp_c": 56.0, "mhz": 1100, "cpu_pct": 72.0, "watts": 5.80, "rss_mb": 659, "done": 51, "queue": 6}
{"t": 115, "temp_c": 57.0, "mhz": 1200, "cpu_pct": 68.2, "watts": 5.13, "rss_mb": 720, "done": 51, "queue": 6}
{"t": 116, "temp_c": 55.0, "mhz": 1100, "cpu_pct": 60.4, "watts": 3.83, "rss_mb": 503, "done": 52, "queue": 6}
{"t": 117, "temp_c": 55.0, "mhz": 1200, "cpu_pct": 68.2, "watts": 4.97, "rss_mb": 737, "done": 52, "queue": 6}
{"t": 118, "temp_c": 56.0, "mhz": 1200, "cpu_pct": 64.4, "watts": 5.13, "rss_mb": 738, "done": 52, "queue": 7}
{"t": 119, "temp_c": 57.0, "mhz": 1200, "cpu_pct": 59.6, "watts": 4.81, "rss_mb": 722, "done": 53, "queue": 6}
{"t": 120, "temp_c": 57.0, "mhz": 1200, "cpu_pct": 67.4, "watts": 5.09, "rss_mb": 722, "done": 53, "queue": 6}
{"t": 121, "temp_c": 53.0, "mhz": 784, "cpu_pct": 25.3, "watts": 3.88, "rss_mb": 392, "done": 54, "queue": 6}
{"summary": "pipeline", "kind": "c12_ea", "workers": 1, "threads": 4, "effort": 3, "distance": 1.00, "period_ms": 2000, "secs": 120.6, "frames": 54, "frames_per_s": 0.448, "job_ms_p50": 2202, "latency_ms_p50": 8839, "latency_ms_p95": 13952, "latency_ms_max": 14584, "max_queue": 7, "backlog_at_end": 6, "cpu_s_per_frame": 5.184, "peak_rss_mb": 738, "temp_c_mean": 55.8, "temp_c_max": 58.0, "mhz_mean": 1167, "mhz_min": 784, "cpu_pct_mean": 64.1, "watts_mean": 4.85}

View File

@ -0,0 +1,62 @@
{"t": 1, "temp_c": 55.0, "mhz": 1400, "cpu_pct": 59.9, "watts": 5.29, "rss_mb": 578, "done": 0, "queue": 0}
{"t": 2, "temp_c": 56.0, "mhz": 1000, "cpu_pct": 62.6, "watts": 5.37, "rss_mb": 372, "done": 1, "queue": 0}
{"t": 3, "temp_c": 55.0, "mhz": 1600, "cpu_pct": 64.2, "watts": 5.57, "rss_mb": 620, "done": 1, "queue": 0}
{"t": 4, "temp_c": 56.0, "mhz": 1600, "cpu_pct": 59.3, "watts": 3.95, "rss_mb": 606, "done": 2, "queue": 0}
{"t": 5, "temp_c": 57.0, "mhz": 1600, "cpu_pct": 64.8, "watts": 5.45, "rss_mb": 632, "done": 2, "queue": 0}
{"t": 6, "temp_c": 56.0, "mhz": 1600, "cpu_pct": 57.0, "watts": 5.41, "rss_mb": 567, "done": 3, "queue": 0}
{"t": 7, "temp_c": 56.0, "mhz": 1600, "cpu_pct": 63.5, "watts": 5.29, "rss_mb": 571, "done": 3, "queue": 0}
{"t": 8, "temp_c": 57.0, "mhz": 1600, "cpu_pct": 61.6, "watts": 5.42, "rss_mb": 684, "done": 4, "queue": 0}
{"t": 9, "temp_c": 54.0, "mhz": 1000, "cpu_pct": 57.7, "watts": 5.51, "rss_mb": 452, "done": 5, "queue": 0}
{"t": 10, "temp_c": 56.0, "mhz": 1600, "cpu_pct": 68.0, "watts": 5.47, "rss_mb": 693, "done": 5, "queue": 0}
{"t": 11, "temp_c": 58.0, "mhz": 1600, "cpu_pct": 59.5, "watts": 5.41, "rss_mb": 669, "done": 6, "queue": 0}
{"t": 12, "temp_c": 57.0, "mhz": 1600, "cpu_pct": 65.5, "watts": 4.17, "rss_mb": 681, "done": 6, "queue": 0}
{"t": 13, "temp_c": 58.0, "mhz": 1600, "cpu_pct": 58.5, "watts": 5.45, "rss_mb": 687, "done": 7, "queue": 0}
{"t": 14, "temp_c": 57.0, "mhz": 1600, "cpu_pct": 65.4, "watts": 5.52, "rss_mb": 688, "done": 7, "queue": 0}
{"t": 15, "temp_c": 58.0, "mhz": 1600, "cpu_pct": 63.2, "watts": 5.57, "rss_mb": 690, "done": 8, "queue": 0}
{"t": 16, "temp_c": 57.0, "mhz": 1600, "cpu_pct": 58.2, "watts": 5.33, "rss_mb": 658, "done": 9, "queue": 0}
{"t": 17, "temp_c": 59.0, "mhz": 1600, "cpu_pct": 75.3, "watts": 5.93, "rss_mb": 696, "done": 9, "queue": 0}
{"t": 18, "temp_c": 56.0, "mhz": 1600, "cpu_pct": 65.2, "watts": 5.80, "rss_mb": 697, "done": 10, "queue": 0}
{"t": 19, "temp_c": 56.0, "mhz": 1600, "cpu_pct": 65.3, "watts": 4.09, "rss_mb": 699, "done": 10, "queue": 0}
{"t": 20, "temp_c": 58.0, "mhz": 1600, "cpu_pct": 63.2, "watts": 5.43, "rss_mb": 700, "done": 11, "queue": 0}
{"t": 21, "temp_c": 57.0, "mhz": 1600, "cpu_pct": 58.1, "watts": 5.68, "rss_mb": 525, "done": 12, "queue": 0}
{"t": 22, "temp_c": 56.0, "mhz": 1400, "cpu_pct": 64.9, "watts": 5.45, "rss_mb": 702, "done": 12, "queue": 0}
{"t": 23, "temp_c": 58.0, "mhz": 1600, "cpu_pct": 64.8, "watts": 5.56, "rss_mb": 702, "done": 13, "queue": 0}
{"t": 24, "temp_c": 57.0, "mhz": 1600, "cpu_pct": 65.2, "watts": 5.60, "rss_mb": 703, "done": 13, "queue": 0}
{"t": 25, "temp_c": 58.0, "mhz": 1600, "cpu_pct": 60.6, "watts": 5.49, "rss_mb": 704, "done": 14, "queue": 0}
{"t": 26, "temp_c": 55.0, "mhz": 789, "cpu_pct": 57.9, "watts": 5.44, "rss_mb": 580, "done": 14, "queue": 0}
{"t": 27, "temp_c": 58.0, "mhz": 1600, "cpu_pct": 66.2, "watts": 4.26, "rss_mb": 705, "done": 15, "queue": 0}
{"t": 28, "temp_c": 58.0, "mhz": 1600, "cpu_pct": 60.2, "watts": 5.29, "rss_mb": 701, "done": 16, "queue": 0}
{"t": 29, "temp_c": 56.0, "mhz": 1600, "cpu_pct": 65.9, "watts": 5.55, "rss_mb": 705, "done": 16, "queue": 0}
{"t": 30, "temp_c": 58.0, "mhz": 1600, "cpu_pct": 60.0, "watts": 5.51, "rss_mb": 709, "done": 17, "queue": 0}
{"t": 31, "temp_c": 56.0, "mhz": 1591, "cpu_pct": 64.1, "watts": 5.52, "rss_mb": 722, "done": 17, "queue": 0}
{"t": 32, "temp_c": 57.0, "mhz": 1600, "cpu_pct": 61.7, "watts": 5.53, "rss_mb": 707, "done": 18, "queue": 0}
{"t": 33, "temp_c": 58.0, "mhz": 1600, "cpu_pct": 59.8, "watts": 5.48, "rss_mb": 675, "done": 19, "queue": 0}
{"t": 34, "temp_c": 57.0, "mhz": 1600, "cpu_pct": 66.8, "watts": 5.60, "rss_mb": 724, "done": 19, "queue": 0}
{"t": 35, "temp_c": 57.0, "mhz": 1600, "cpu_pct": 58.5, "watts": 4.14, "rss_mb": 724, "done": 20, "queue": 0}
{"t": 36, "temp_c": 58.0, "mhz": 1587, "cpu_pct": 67.7, "watts": 5.62, "rss_mb": 724, "done": 20, "queue": 0}
{"t": 37, "temp_c": 56.0, "mhz": 1600, "cpu_pct": 58.8, "watts": 5.43, "rss_mb": 724, "done": 21, "queue": 0}
{"t": 38, "temp_c": 57.0, "mhz": 1600, "cpu_pct": 62.6, "watts": 5.38, "rss_mb": 648, "done": 22, "queue": 0}
{"t": 39, "temp_c": 58.0, "mhz": 1600, "cpu_pct": 65.9, "watts": 5.69, "rss_mb": 726, "done": 22, "queue": 0}
{"t": 40, "temp_c": 56.0, "mhz": 1400, "cpu_pct": 60.4, "watts": 5.55, "rss_mb": 710, "done": 23, "queue": 0}
{"t": 41, "temp_c": 57.0, "mhz": 1600, "cpu_pct": 66.2, "watts": 5.56, "rss_mb": 710, "done": 23, "queue": 0}
{"t": 42, "temp_c": 57.0, "mhz": 1600, "cpu_pct": 62.0, "watts": 4.01, "rss_mb": 710, "done": 24, "queue": 0}
{"t": 43, "temp_c": 58.0, "mhz": 1600, "cpu_pct": 59.8, "watts": 5.66, "rss_mb": 585, "done": 25, "queue": 0}
{"t": 44, "temp_c": 56.0, "mhz": 1000, "cpu_pct": 63.8, "watts": 5.49, "rss_mb": 726, "done": 25, "queue": 0}
{"t": 45, "temp_c": 58.0, "mhz": 1600, "cpu_pct": 64.4, "watts": 5.54, "rss_mb": 710, "done": 26, "queue": 0}
{"t": 46, "temp_c": 58.0, "mhz": 1600, "cpu_pct": 65.2, "watts": 5.50, "rss_mb": 711, "done": 26, "queue": 0}
{"t": 47, "temp_c": 58.0, "mhz": 1600, "cpu_pct": 61.2, "watts": 5.57, "rss_mb": 712, "done": 27, "queue": 0}
{"t": 48, "temp_c": 58.0, "mhz": 1600, "cpu_pct": 72.9, "watts": 5.92, "rss_mb": 712, "done": 27, "queue": 0}
{"t": 49, "temp_c": 57.0, "mhz": 1600, "cpu_pct": 66.2, "watts": 4.49, "rss_mb": 712, "done": 28, "queue": 0}
{"t": 50, "temp_c": 56.0, "mhz": 1600, "cpu_pct": 59.9, "watts": 5.39, "rss_mb": 673, "done": 29, "queue": 0}
{"t": 51, "temp_c": 59.0, "mhz": 1600, "cpu_pct": 67.8, "watts": 5.64, "rss_mb": 712, "done": 29, "queue": 0}
{"t": 52, "temp_c": 56.0, "mhz": 1200, "cpu_pct": 57.3, "watts": 5.47, "rss_mb": 712, "done": 30, "queue": 0}
{"t": 53, "temp_c": 57.0, "mhz": 1600, "cpu_pct": 67.6, "watts": 5.68, "rss_mb": 713, "done": 30, "queue": 0}
{"t": 54, "temp_c": 59.0, "mhz": 1600, "cpu_pct": 60.6, "watts": 5.40, "rss_mb": 713, "done": 31, "queue": 0}
{"t": 55, "temp_c": 57.0, "mhz": 1600, "cpu_pct": 58.5, "watts": 5.34, "rss_mb": 519, "done": 32, "queue": 0}
{"t": 56, "temp_c": 56.0, "mhz": 1200, "cpu_pct": 65.0, "watts": 4.19, "rss_mb": 714, "done": 32, "queue": 0}
{"t": 57, "temp_c": 58.0, "mhz": 1600, "cpu_pct": 62.2, "watts": 5.39, "rss_mb": 714, "done": 33, "queue": 0}
{"t": 58, "temp_c": 58.0, "mhz": 1600, "cpu_pct": 65.2, "watts": 5.57, "rss_mb": 715, "done": 33, "queue": 0}
{"t": 59, "temp_c": 58.0, "mhz": 1600, "cpu_pct": 61.8, "watts": 5.39, "rss_mb": 731, "done": 34, "queue": 0}
{"t": 60, "temp_c": 56.0, "mhz": 1498, "cpu_pct": 59.9, "watts": 5.56, "rss_mb": 591, "done": 34, "queue": 0}
{"t": 61, "temp_c": 53.0, "mhz": 795, "cpu_pct": 5.3, "watts": 3.18, "rss_mb": 386, "done": 35, "queue": 0}
{"summary": "pipeline", "kind": "c12_ea", "workers": 1, "threads": 4, "effort": 3, "distance": 1.00, "period_ms": 0, "secs": 60.1, "frames": 35, "frames_per_s": 0.582, "job_ms_p50": 1681, "latency_ms_p50": 1695, "latency_ms_p95": 1794, "latency_ms_max": 1881, "max_queue": 0, "backlog_at_end": 0, "cpu_s_per_frame": 3.972, "peak_rss_mb": 731, "temp_c_mean": 56.9, "temp_c_max": 59.0, "mhz_mean": 1519, "mhz_min": 789, "cpu_pct_mean": 62.0, "watts_mean": 5.30}

View File

@ -0,0 +1,121 @@
{"t": 1, "temp_c": 55.0, "mhz": 1200, "cpu_pct": 59.8, "watts": 5.29, "rss_mb": 579, "done": 0, "queue": 0}
{"t": 2, "temp_c": 55.0, "mhz": 1600, "cpu_pct": 54.7, "watts": 5.09, "rss_mb": 248, "done": 1, "queue": 0}
{"t": 3, "temp_c": 58.0, "mhz": 1600, "cpu_pct": 64.9, "watts": 4.16, "rss_mb": 616, "done": 1, "queue": 0}
{"t": 4, "temp_c": 53.0, "mhz": 800, "cpu_pct": 45.8, "watts": 5.52, "rss_mb": 288, "done": 2, "queue": 0}
{"t": 5, "temp_c": 57.0, "mhz": 1600, "cpu_pct": 64.2, "watts": 4.92, "rss_mb": 632, "done": 2, "queue": 0}
{"t": 6, "temp_c": 54.0, "mhz": 794, "cpu_pct": 46.4, "watts": 5.12, "rss_mb": 302, "done": 3, "queue": 0}
{"t": 7, "temp_c": 58.0, "mhz": 1600, "cpu_pct": 62.1, "watts": 5.11, "rss_mb": 553, "done": 3, "queue": 0}
{"t": 8, "temp_c": 54.0, "mhz": 796, "cpu_pct": 49.2, "watts": 5.15, "rss_mb": 388, "done": 4, "queue": 0}
{"t": 9, "temp_c": 58.0, "mhz": 1600, "cpu_pct": 65.8, "watts": 5.32, "rss_mb": 686, "done": 4, "queue": 0}
{"t": 10, "temp_c": 54.0, "mhz": 866, "cpu_pct": 45.0, "watts": 4.87, "rss_mb": 454, "done": 5, "queue": 0}
{"t": 11, "temp_c": 58.0, "mhz": 1600, "cpu_pct": 67.4, "watts": 4.22, "rss_mb": 694, "done": 5, "queue": 0}
{"t": 12, "temp_c": 54.0, "mhz": 800, "cpu_pct": 39.9, "watts": 5.13, "rss_mb": 461, "done": 6, "queue": 0}
{"t": 13, "temp_c": 58.0, "mhz": 1600, "cpu_pct": 67.4, "watts": 5.05, "rss_mb": 681, "done": 6, "queue": 0}
{"t": 14, "temp_c": 54.0, "mhz": 835, "cpu_pct": 41.5, "watts": 5.07, "rss_mb": 464, "done": 7, "queue": 0}
{"t": 15, "temp_c": 57.0, "mhz": 1600, "cpu_pct": 66.8, "watts": 5.23, "rss_mb": 684, "done": 7, "queue": 0}
{"t": 16, "temp_c": 54.0, "mhz": 900, "cpu_pct": 40.3, "watts": 4.72, "rss_mb": 467, "done": 8, "queue": 0}
{"t": 17, "temp_c": 59.0, "mhz": 1600, "cpu_pct": 80.7, "watts": 6.22, "rss_mb": 686, "done": 8, "queue": 0}
{"t": 18, "temp_c": 55.0, "mhz": 942, "cpu_pct": 55.8, "watts": 4.27, "rss_mb": 469, "done": 9, "queue": 0}
{"t": 19, "temp_c": 58.0, "mhz": 1600, "cpu_pct": 67.0, "watts": 5.21, "rss_mb": 688, "done": 9, "queue": 0}
{"t": 20, "temp_c": 54.0, "mhz": 1119, "cpu_pct": 39.2, "watts": 4.99, "rss_mb": 471, "done": 10, "queue": 0}
{"t": 21, "temp_c": 58.0, "mhz": 1600, "cpu_pct": 68.5, "watts": 5.30, "rss_mb": 690, "done": 10, "queue": 0}
{"t": 22, "temp_c": 55.0, "mhz": 1244, "cpu_pct": 41.4, "watts": 4.95, "rss_mb": 473, "done": 11, "queue": 0}
{"t": 23, "temp_c": 57.0, "mhz": 1600, "cpu_pct": 65.9, "watts": 5.49, "rss_mb": 694, "done": 11, "queue": 0}
{"t": 24, "temp_c": 55.0, "mhz": 1600, "cpu_pct": 40.9, "watts": 4.52, "rss_mb": 476, "done": 12, "queue": 0}
{"t": 25, "temp_c": 57.0, "mhz": 1600, "cpu_pct": 67.3, "watts": 4.26, "rss_mb": 695, "done": 12, "queue": 0}
{"t": 26, "temp_c": 54.0, "mhz": 1421, "cpu_pct": 41.1, "watts": 5.08, "rss_mb": 478, "done": 13, "queue": 0}
{"t": 27, "temp_c": 58.0, "mhz": 1200, "cpu_pct": 66.7, "watts": 5.16, "rss_mb": 697, "done": 13, "queue": 0}
{"t": 28, "temp_c": 54.0, "mhz": 1026, "cpu_pct": 38.9, "watts": 4.88, "rss_mb": 479, "done": 14, "queue": 0}
{"t": 29, "temp_c": 58.0, "mhz": 1600, "cpu_pct": 67.0, "watts": 5.39, "rss_mb": 700, "done": 14, "queue": 0}
{"t": 30, "temp_c": 55.0, "mhz": 1200, "cpu_pct": 41.2, "watts": 4.79, "rss_mb": 483, "done": 15, "queue": 0}
{"t": 31, "temp_c": 56.0, "mhz": 1600, "cpu_pct": 66.3, "watts": 5.57, "rss_mb": 702, "done": 15, "queue": 0}
{"t": 32, "temp_c": 55.0, "mhz": 1255, "cpu_pct": 39.6, "watts": 3.70, "rss_mb": 484, "done": 16, "queue": 0}
{"t": 33, "temp_c": 57.0, "mhz": 1600, "cpu_pct": 67.6, "watts": 5.03, "rss_mb": 702, "done": 16, "queue": 0}
{"t": 34, "temp_c": 54.0, "mhz": 1400, "cpu_pct": 40.9, "watts": 5.04, "rss_mb": 485, "done": 17, "queue": 0}
{"t": 35, "temp_c": 58.0, "mhz": 1600, "cpu_pct": 66.5, "watts": 5.09, "rss_mb": 719, "done": 17, "queue": 0}
{"t": 36, "temp_c": 54.0, "mhz": 1404, "cpu_pct": 41.5, "watts": 4.91, "rss_mb": 486, "done": 18, "queue": 0}
{"t": 37, "temp_c": 57.0, "mhz": 1600, "cpu_pct": 67.3, "watts": 5.39, "rss_mb": 704, "done": 18, "queue": 0}
{"t": 38, "temp_c": 55.0, "mhz": 1600, "cpu_pct": 40.7, "watts": 4.70, "rss_mb": 494, "done": 19, "queue": 0}
{"t": 39, "temp_c": 58.0, "mhz": 1600, "cpu_pct": 66.6, "watts": 4.22, "rss_mb": 722, "done": 19, "queue": 0}
{"t": 40, "temp_c": 55.0, "mhz": 1600, "cpu_pct": 42.0, "watts": 5.14, "rss_mb": 504, "done": 20, "queue": 0}
{"t": 41, "temp_c": 57.0, "mhz": 1600, "cpu_pct": 66.7, "watts": 4.99, "rss_mb": 722, "done": 20, "queue": 0}
{"t": 42, "temp_c": 55.0, "mhz": 1600, "cpu_pct": 43.1, "watts": 5.13, "rss_mb": 517, "done": 21, "queue": 0}
{"t": 43, "temp_c": 57.0, "mhz": 1400, "cpu_pct": 66.8, "watts": 5.25, "rss_mb": 722, "done": 21, "queue": 0}
{"t": 44, "temp_c": 56.0, "mhz": 1600, "cpu_pct": 42.6, "watts": 4.71, "rss_mb": 516, "done": 22, "queue": 0}
{"t": 45, "temp_c": 57.0, "mhz": 1200, "cpu_pct": 64.9, "watts": 5.57, "rss_mb": 722, "done": 22, "queue": 0}
{"t": 46, "temp_c": 55.0, "mhz": 1600, "cpu_pct": 41.9, "watts": 4.55, "rss_mb": 529, "done": 23, "queue": 0}
{"t": 47, "temp_c": 57.0, "mhz": 1400, "cpu_pct": 66.5, "watts": 4.18, "rss_mb": 707, "done": 23, "queue": 0}
{"t": 48, "temp_c": 55.0, "mhz": 1300, "cpu_pct": 60.5, "watts": 5.89, "rss_mb": 503, "done": 24, "queue": 0}
{"t": 49, "temp_c": 57.0, "mhz": 1600, "cpu_pct": 66.0, "watts": 5.10, "rss_mb": 707, "done": 24, "queue": 0}
{"t": 50, "temp_c": 57.0, "mhz": 1600, "cpu_pct": 43.4, "watts": 4.93, "rss_mb": 555, "done": 25, "queue": 0}
{"t": 51, "temp_c": 58.0, "mhz": 1600, "cpu_pct": 63.8, "watts": 5.48, "rss_mb": 724, "done": 25, "queue": 0}
{"t": 52, "temp_c": 56.0, "mhz": 1600, "cpu_pct": 43.4, "watts": 4.58, "rss_mb": 541, "done": 26, "queue": 0}
{"t": 53, "temp_c": 57.0, "mhz": 1599, "cpu_pct": 64.1, "watts": 5.53, "rss_mb": 708, "done": 26, "queue": 0}
{"t": 54, "temp_c": 55.0, "mhz": 1600, "cpu_pct": 44.3, "watts": 3.82, "rss_mb": 564, "done": 27, "queue": 0}
{"t": 55, "temp_c": 58.0, "mhz": 1400, "cpu_pct": 63.9, "watts": 5.03, "rss_mb": 709, "done": 27, "queue": 0}
{"t": 56, "temp_c": 56.0, "mhz": 1600, "cpu_pct": 43.7, "watts": 4.86, "rss_mb": 554, "done": 28, "queue": 0}
{"t": 57, "temp_c": 57.0, "mhz": 1400, "cpu_pct": 64.1, "watts": 5.39, "rss_mb": 709, "done": 28, "queue": 0}
{"t": 58, "temp_c": 57.0, "mhz": 1600, "cpu_pct": 45.5, "watts": 4.79, "rss_mb": 580, "done": 29, "queue": 0}
{"t": 59, "temp_c": 57.0, "mhz": 1400, "cpu_pct": 64.1, "watts": 5.49, "rss_mb": 709, "done": 29, "queue": 0}
{"t": 60, "temp_c": 57.0, "mhz": 1600, "cpu_pct": 45.4, "watts": 4.66, "rss_mb": 567, "done": 30, "queue": 0}
{"t": 61, "temp_c": 57.0, "mhz": 1600, "cpu_pct": 62.6, "watts": 5.49, "rss_mb": 710, "done": 30, "queue": 0}
{"t": 62, "temp_c": 58.0, "mhz": 1599, "cpu_pct": 44.5, "watts": 3.73, "rss_mb": 586, "done": 31, "queue": 0}
{"t": 63, "temp_c": 57.0, "mhz": 1400, "cpu_pct": 63.9, "watts": 5.17, "rss_mb": 710, "done": 31, "queue": 0}
{"t": 64, "temp_c": 57.0, "mhz": 1600, "cpu_pct": 45.2, "watts": 4.82, "rss_mb": 595, "done": 32, "queue": 0}
{"t": 65, "temp_c": 57.0, "mhz": 1600, "cpu_pct": 62.4, "watts": 5.48, "rss_mb": 710, "done": 32, "queue": 0}
{"t": 66, "temp_c": 58.0, "mhz": 1600, "cpu_pct": 44.8, "watts": 4.66, "rss_mb": 590, "done": 33, "queue": 0}
{"t": 67, "temp_c": 56.0, "mhz": 1600, "cpu_pct": 63.9, "watts": 5.62, "rss_mb": 710, "done": 33, "queue": 0}
{"t": 68, "temp_c": 57.0, "mhz": 1600, "cpu_pct": 44.0, "watts": 4.69, "rss_mb": 598, "done": 34, "queue": 0}
{"t": 69, "temp_c": 57.0, "mhz": 1600, "cpu_pct": 63.9, "watts": 4.11, "rss_mb": 727, "done": 34, "queue": 0}
{"t": 70, "temp_c": 57.0, "mhz": 1600, "cpu_pct": 42.4, "watts": 4.89, "rss_mb": 599, "done": 35, "queue": 0}
{"t": 71, "temp_c": 56.0, "mhz": 1600, "cpu_pct": 64.1, "watts": 5.35, "rss_mb": 711, "done": 35, "queue": 0}
{"t": 72, "temp_c": 56.0, "mhz": 1400, "cpu_pct": 46.5, "watts": 4.87, "rss_mb": 605, "done": 36, "queue": 0}
{"t": 73, "temp_c": 58.0, "mhz": 1600, "cpu_pct": 66.4, "watts": 5.52, "rss_mb": 711, "done": 36, "queue": 0}
{"t": 74, "temp_c": 56.0, "mhz": 1600, "cpu_pct": 40.5, "watts": 4.55, "rss_mb": 604, "done": 37, "queue": 0}
{"t": 75, "temp_c": 58.0, "mhz": 1600, "cpu_pct": 65.6, "watts": 5.67, "rss_mb": 712, "done": 37, "queue": 0}
{"t": 76, "temp_c": 56.0, "mhz": 1600, "cpu_pct": 42.2, "watts": 3.55, "rss_mb": 608, "done": 38, "queue": 0}
{"t": 77, "temp_c": 58.0, "mhz": 1600, "cpu_pct": 65.8, "watts": 5.29, "rss_mb": 712, "done": 38, "queue": 0}
{"t": 78, "temp_c": 56.0, "mhz": 1600, "cpu_pct": 43.9, "watts": 4.92, "rss_mb": 609, "done": 39, "queue": 0}
{"t": 79, "temp_c": 59.0, "mhz": 1600, "cpu_pct": 82.8, "watts": 6.23, "rss_mb": 713, "done": 39, "queue": 0}
{"t": 80, "temp_c": 57.0, "mhz": 1600, "cpu_pct": 52.3, "watts": 5.16, "rss_mb": 613, "done": 40, "queue": 0}
{"t": 81, "temp_c": 57.0, "mhz": 1600, "cpu_pct": 65.6, "watts": 5.65, "rss_mb": 713, "done": 40, "queue": 0}
{"t": 82, "temp_c": 57.0, "mhz": 1600, "cpu_pct": 43.5, "watts": 4.63, "rss_mb": 611, "done": 41, "queue": 0}
{"t": 83, "temp_c": 58.0, "mhz": 1600, "cpu_pct": 64.3, "watts": 4.16, "rss_mb": 713, "done": 41, "queue": 0}
{"t": 84, "temp_c": 56.0, "mhz": 1400, "cpu_pct": 43.2, "watts": 5.07, "rss_mb": 619, "done": 42, "queue": 0}
{"t": 85, "temp_c": 58.0, "mhz": 1600, "cpu_pct": 65.9, "watts": 5.34, "rss_mb": 713, "done": 42, "queue": 0}
{"t": 86, "temp_c": 57.0, "mhz": 1600, "cpu_pct": 40.5, "watts": 4.53, "rss_mb": 615, "done": 43, "queue": 0}
{"t": 87, "temp_c": 57.0, "mhz": 1600, "cpu_pct": 65.1, "watts": 5.67, "rss_mb": 714, "done": 43, "queue": 0}
{"t": 88, "temp_c": 57.0, "mhz": 1600, "cpu_pct": 43.4, "watts": 4.60, "rss_mb": 620, "done": 44, "queue": 0}
{"t": 89, "temp_c": 57.0, "mhz": 1600, "cpu_pct": 63.8, "watts": 5.52, "rss_mb": 731, "done": 44, "queue": 0}
{"t": 90, "temp_c": 57.0, "mhz": 1600, "cpu_pct": 46.0, "watts": 4.79, "rss_mb": 611, "done": 45, "queue": 0}
{"t": 91, "temp_c": 57.0, "mhz": 1600, "cpu_pct": 63.2, "watts": 4.04, "rss_mb": 731, "done": 45, "queue": 0}
{"t": 92, "temp_c": 57.0, "mhz": 1400, "cpu_pct": 44.9, "watts": 4.95, "rss_mb": 629, "done": 46, "queue": 0}
{"t": 93, "temp_c": 57.0, "mhz": 1600, "cpu_pct": 66.0, "watts": 5.47, "rss_mb": 731, "done": 46, "queue": 0}
{"t": 94, "temp_c": 57.0, "mhz": 1400, "cpu_pct": 43.2, "watts": 4.55, "rss_mb": 615, "done": 47, "queue": 0}
{"t": 95, "temp_c": 57.0, "mhz": 1600, "cpu_pct": 64.2, "watts": 5.62, "rss_mb": 715, "done": 47, "queue": 0}
{"t": 96, "temp_c": 57.0, "mhz": 1600, "cpu_pct": 43.9, "watts": 4.80, "rss_mb": 631, "done": 48, "queue": 0}
{"t": 97, "temp_c": 58.0, "mhz": 1600, "cpu_pct": 65.2, "watts": 4.12, "rss_mb": 731, "done": 48, "queue": 0}
{"t": 98, "temp_c": 57.0, "mhz": 1600, "cpu_pct": 43.4, "watts": 4.91, "rss_mb": 622, "done": 49, "queue": 0}
{"t": 99, "temp_c": 58.0, "mhz": 1600, "cpu_pct": 65.5, "watts": 5.37, "rss_mb": 731, "done": 49, "queue": 0}
{"t": 100, "temp_c": 56.0, "mhz": 1200, "cpu_pct": 41.4, "watts": 4.67, "rss_mb": 640, "done": 50, "queue": 0}
{"t": 101, "temp_c": 58.0, "mhz": 1600, "cpu_pct": 66.4, "watts": 5.59, "rss_mb": 733, "done": 50, "queue": 0}
{"t": 102, "temp_c": 56.0, "mhz": 1600, "cpu_pct": 43.3, "watts": 4.68, "rss_mb": 630, "done": 51, "queue": 0}
{"t": 103, "temp_c": 58.0, "mhz": 1600, "cpu_pct": 64.7, "watts": 5.52, "rss_mb": 733, "done": 51, "queue": 0}
{"t": 104, "temp_c": 56.0, "mhz": 1600, "cpu_pct": 42.1, "watts": 4.66, "rss_mb": 641, "done": 52, "queue": 0}
{"t": 105, "temp_c": 58.0, "mhz": 1600, "cpu_pct": 66.5, "watts": 4.27, "rss_mb": 733, "done": 52, "queue": 0}
{"t": 106, "temp_c": 56.0, "mhz": 1400, "cpu_pct": 43.0, "watts": 4.77, "rss_mb": 632, "done": 53, "queue": 0}
{"t": 107, "temp_c": 58.0, "mhz": 1600, "cpu_pct": 65.2, "watts": 5.50, "rss_mb": 717, "done": 53, "queue": 0}
{"t": 108, "temp_c": 56.0, "mhz": 1400, "cpu_pct": 43.4, "watts": 4.68, "rss_mb": 644, "done": 54, "queue": 0}
{"t": 109, "temp_c": 58.0, "mhz": 1600, "cpu_pct": 68.2, "watts": 5.60, "rss_mb": 734, "done": 54, "queue": 0}
{"t": 110, "temp_c": 58.0, "mhz": 1600, "cpu_pct": 67.5, "watts": 5.85, "rss_mb": 612, "done": 55, "queue": 0}
{"t": 111, "temp_c": 57.0, "mhz": 1600, "cpu_pct": 63.2, "watts": 5.52, "rss_mb": 718, "done": 55, "queue": 0}
{"t": 112, "temp_c": 56.0, "mhz": 1400, "cpu_pct": 44.7, "watts": 3.63, "rss_mb": 654, "done": 56, "queue": 0}
{"t": 113, "temp_c": 58.0, "mhz": 1600, "cpu_pct": 65.9, "watts": 5.42, "rss_mb": 719, "done": 56, "queue": 0}
{"t": 114, "temp_c": 57.0, "mhz": 1400, "cpu_pct": 42.3, "watts": 4.64, "rss_mb": 644, "done": 57, "queue": 0}
{"t": 115, "temp_c": 58.0, "mhz": 1600, "cpu_pct": 64.9, "watts": 5.55, "rss_mb": 720, "done": 57, "queue": 0}
{"t": 116, "temp_c": 57.0, "mhz": 1400, "cpu_pct": 40.7, "watts": 4.68, "rss_mb": 659, "done": 58, "queue": 0}
{"t": 117, "temp_c": 58.0, "mhz": 1600, "cpu_pct": 67.2, "watts": 5.55, "rss_mb": 720, "done": 58, "queue": 0}
{"t": 118, "temp_c": 56.0, "mhz": 1200, "cpu_pct": 42.0, "watts": 3.51, "rss_mb": 653, "done": 59, "queue": 0}
{"t": 119, "temp_c": 59.0, "mhz": 1600, "cpu_pct": 66.4, "watts": 5.35, "rss_mb": 737, "done": 59, "queue": 0}
{"t": 120, "temp_c": 55.0, "mhz": 800, "cpu_pct": 32.7, "watts": 4.70, "rss_mb": 391, "done": 60, "queue": 0}
{"summary": "pipeline", "kind": "c12_ea", "workers": 1, "threads": 4, "effort": 3, "distance": 1.00, "period_ms": 2000, "secs": 120.0, "frames": 60, "frames_per_s": 0.500, "job_ms_p50": 1703, "latency_ms_p50": 1718, "latency_ms_p95": 1843, "latency_ms_max": 1872, "max_queue": 1, "backlog_at_end": 0, "cpu_s_per_frame": 3.977, "peak_rss_mb": 736, "temp_c_mean": 56.6, "temp_c_max": 59.0, "mhz_mean": 1476, "mhz_min": 794, "cpu_pct_mean": 55.0, "watts_mean": 4.98}

View File

@ -0,0 +1,62 @@
{"t": 1, "temp_c": 53.0, "mhz": 800, "cpu_pct": 64.9, "watts": 4.52, "rss_mb": 527, "done": 0, "queue": 0}
{"t": 2, "temp_c": 53.0, "mhz": 800, "cpu_pct": 64.8, "watts": 4.60, "rss_mb": 531, "done": 0, "queue": 0}
{"t": 3, "temp_c": 52.0, "mhz": 800, "cpu_pct": 72.1, "watts": 4.91, "rss_mb": 534, "done": 0, "queue": 0}
{"t": 4, "temp_c": 54.0, "mhz": 800, "cpu_pct": 55.7, "watts": 3.30, "rss_mb": 478, "done": 1, "queue": 0}
{"t": 5, "temp_c": 54.0, "mhz": 800, "cpu_pct": 69.0, "watts": 4.86, "rss_mb": 621, "done": 1, "queue": 0}
{"t": 6, "temp_c": 54.0, "mhz": 800, "cpu_pct": 67.3, "watts": 4.68, "rss_mb": 626, "done": 1, "queue": 0}
{"t": 7, "temp_c": 53.0, "mhz": 800, "cpu_pct": 53.1, "watts": 4.58, "rss_mb": 296, "done": 2, "queue": 0}
{"t": 8, "temp_c": 52.0, "mhz": 800, "cpu_pct": 64.8, "watts": 3.65, "rss_mb": 614, "done": 2, "queue": 0}
{"t": 9, "temp_c": 53.0, "mhz": 800, "cpu_pct": 72.0, "watts": 4.73, "rss_mb": 635, "done": 2, "queue": 0}
{"t": 10, "temp_c": 53.0, "mhz": 800, "cpu_pct": 65.5, "watts": 4.68, "rss_mb": 636, "done": 2, "queue": 0}
{"t": 11, "temp_c": 53.0, "mhz": 800, "cpu_pct": 61.2, "watts": 4.67, "rss_mb": 601, "done": 3, "queue": 0}
{"t": 12, "temp_c": 54.0, "mhz": 800, "cpu_pct": 62.9, "watts": 4.72, "rss_mb": 618, "done": 3, "queue": 0}
{"t": 13, "temp_c": 53.0, "mhz": 800, "cpu_pct": 64.2, "watts": 3.45, "rss_mb": 582, "done": 3, "queue": 0}
{"t": 14, "temp_c": 54.0, "mhz": 800, "cpu_pct": 61.4, "watts": 4.61, "rss_mb": 469, "done": 4, "queue": 0}
{"t": 15, "temp_c": 54.0, "mhz": 800, "cpu_pct": 63.3, "watts": 4.65, "rss_mb": 670, "done": 4, "queue": 0}
{"t": 16, "temp_c": 53.0, "mhz": 800, "cpu_pct": 66.9, "watts": 4.91, "rss_mb": 687, "done": 4, "queue": 0}
{"t": 17, "temp_c": 53.0, "mhz": 800, "cpu_pct": 67.3, "watts": 3.62, "rss_mb": 688, "done": 4, "queue": 0}
{"t": 18, "temp_c": 53.0, "mhz": 800, "cpu_pct": 64.2, "watts": 4.73, "rss_mb": 693, "done": 5, "queue": 0}
{"t": 19, "temp_c": 54.0, "mhz": 800, "cpu_pct": 65.2, "watts": 4.70, "rss_mb": 696, "done": 5, "queue": 0}
{"t": 20, "temp_c": 53.0, "mhz": 800, "cpu_pct": 68.4, "watts": 4.99, "rss_mb": 696, "done": 5, "queue": 0}
{"t": 21, "temp_c": 54.0, "mhz": 800, "cpu_pct": 61.4, "watts": 3.28, "rss_mb": 664, "done": 6, "queue": 0}
{"t": 22, "temp_c": 53.0, "mhz": 800, "cpu_pct": 65.3, "watts": 4.97, "rss_mb": 684, "done": 6, "queue": 0}
{"t": 23, "temp_c": 54.0, "mhz": 800, "cpu_pct": 78.5, "watts": 4.95, "rss_mb": 685, "done": 6, "queue": 0}
{"t": 24, "temp_c": 54.0, "mhz": 800, "cpu_pct": 74.2, "watts": 5.27, "rss_mb": 532, "done": 7, "queue": 0}
{"t": 25, "temp_c": 54.0, "mhz": 800, "cpu_pct": 68.5, "watts": 3.66, "rss_mb": 688, "done": 7, "queue": 0}
{"t": 26, "temp_c": 53.0, "mhz": 800, "cpu_pct": 68.5, "watts": 5.06, "rss_mb": 689, "done": 7, "queue": 0}
{"t": 27, "temp_c": 54.0, "mhz": 800, "cpu_pct": 65.1, "watts": 4.67, "rss_mb": 689, "done": 7, "queue": 0}
{"t": 28, "temp_c": 53.0, "mhz": 800, "cpu_pct": 62.4, "watts": 4.71, "rss_mb": 690, "done": 8, "queue": 0}
{"t": 29, "temp_c": 54.0, "mhz": 800, "cpu_pct": 70.8, "watts": 4.77, "rss_mb": 692, "done": 8, "queue": 0}
{"t": 30, "temp_c": 54.0, "mhz": 800, "cpu_pct": 63.8, "watts": 3.59, "rss_mb": 692, "done": 8, "queue": 0}
{"t": 31, "temp_c": 55.0, "mhz": 800, "cpu_pct": 62.2, "watts": 4.51, "rss_mb": 692, "done": 9, "queue": 0}
{"t": 32, "temp_c": 52.0, "mhz": 800, "cpu_pct": 62.1, "watts": 4.97, "rss_mb": 692, "done": 9, "queue": 0}
{"t": 33, "temp_c": 54.0, "mhz": 800, "cpu_pct": 71.0, "watts": 4.81, "rss_mb": 693, "done": 9, "queue": 0}
{"t": 34, "temp_c": 53.0, "mhz": 800, "cpu_pct": 54.8, "watts": 3.41, "rss_mb": 661, "done": 10, "queue": 0}
{"t": 35, "temp_c": 54.0, "mhz": 800, "cpu_pct": 76.5, "watts": 4.96, "rss_mb": 694, "done": 10, "queue": 0}
{"t": 36, "temp_c": 54.0, "mhz": 800, "cpu_pct": 68.0, "watts": 4.79, "rss_mb": 694, "done": 10, "queue": 0}
{"t": 37, "temp_c": 53.0, "mhz": 800, "cpu_pct": 55.2, "watts": 4.47, "rss_mb": 517, "done": 11, "queue": 0}
{"t": 38, "temp_c": 54.0, "mhz": 800, "cpu_pct": 70.4, "watts": 3.70, "rss_mb": 696, "done": 11, "queue": 0}
{"t": 39, "temp_c": 54.0, "mhz": 800, "cpu_pct": 68.8, "watts": 4.89, "rss_mb": 697, "done": 11, "queue": 0}
{"t": 40, "temp_c": 53.0, "mhz": 800, "cpu_pct": 64.2, "watts": 4.70, "rss_mb": 627, "done": 11, "queue": 0}
{"t": 41, "temp_c": 52.0, "mhz": 800, "cpu_pct": 63.2, "watts": 4.66, "rss_mb": 697, "done": 12, "queue": 0}
{"t": 42, "temp_c": 54.0, "mhz": 800, "cpu_pct": 69.8, "watts": 4.74, "rss_mb": 698, "done": 12, "queue": 0}
{"t": 43, "temp_c": 54.0, "mhz": 800, "cpu_pct": 64.9, "watts": 3.59, "rss_mb": 698, "done": 12, "queue": 0}
{"t": 44, "temp_c": 54.0, "mhz": 800, "cpu_pct": 65.1, "watts": 4.65, "rss_mb": 698, "done": 13, "queue": 0}
{"t": 45, "temp_c": 54.0, "mhz": 800, "cpu_pct": 61.2, "watts": 4.91, "rss_mb": 699, "done": 13, "queue": 0}
{"t": 46, "temp_c": 54.0, "mhz": 800, "cpu_pct": 72.6, "watts": 4.78, "rss_mb": 699, "done": 13, "queue": 0}
{"t": 47, "temp_c": 54.0, "mhz": 800, "cpu_pct": 55.4, "watts": 3.50, "rss_mb": 667, "done": 14, "queue": 0}
{"t": 48, "temp_c": 54.0, "mhz": 800, "cpu_pct": 74.2, "watts": 4.86, "rss_mb": 700, "done": 14, "queue": 0}
{"t": 49, "temp_c": 54.0, "mhz": 800, "cpu_pct": 64.2, "watts": 4.76, "rss_mb": 700, "done": 14, "queue": 0}
{"t": 50, "temp_c": 54.0, "mhz": 800, "cpu_pct": 56.8, "watts": 4.54, "rss_mb": 506, "done": 15, "queue": 0}
{"t": 51, "temp_c": 54.0, "mhz": 800, "cpu_pct": 68.2, "watts": 4.79, "rss_mb": 701, "done": 15, "queue": 0}
{"t": 52, "temp_c": 53.0, "mhz": 800, "cpu_pct": 66.6, "watts": 3.70, "rss_mb": 701, "done": 15, "queue": 0}
{"t": 53, "temp_c": 53.0, "mhz": 800, "cpu_pct": 67.8, "watts": 4.63, "rss_mb": 701, "done": 15, "queue": 0}
{"t": 54, "temp_c": 55.0, "mhz": 800, "cpu_pct": 70.1, "watts": 4.84, "rss_mb": 703, "done": 16, "queue": 0}
{"t": 55, "temp_c": 54.0, "mhz": 800, "cpu_pct": 84.9, "watts": 4.39, "rss_mb": 706, "done": 16, "queue": 0}
{"t": 56, "temp_c": 54.0, "mhz": 800, "cpu_pct": 73.2, "watts": 4.94, "rss_mb": 706, "done": 16, "queue": 0}
{"t": 57, "temp_c": 54.0, "mhz": 800, "cpu_pct": 51.4, "watts": 4.60, "rss_mb": 674, "done": 17, "queue": 0}
{"t": 58, "temp_c": 55.0, "mhz": 800, "cpu_pct": 73.6, "watts": 4.82, "rss_mb": 723, "done": 17, "queue": 0}
{"t": 59, "temp_c": 54.0, "mhz": 800, "cpu_pct": 65.4, "watts": 4.85, "rss_mb": 723, "done": 17, "queue": 0}
{"t": 60, "temp_c": 52.0, "mhz": 800, "cpu_pct": 58.9, "watts": 3.52, "rss_mb": 454, "done": 18, "queue": 0}
{"t": 61, "temp_c": 51.0, "mhz": 798, "cpu_pct": 7.8, "watts": 3.02, "rss_mb": 377, "done": 18, "queue": 0}
{"summary": "pipeline", "kind": "c12_ea", "workers": 1, "threads": 4, "effort": 3, "distance": 1.00, "period_ms": 0, "secs": 60.1, "frames": 18, "frames_per_s": 0.299, "job_ms_p50": 3294, "latency_ms_p50": 3312, "latency_ms_p95": 3537, "latency_ms_max": 3567, "max_queue": 0, "backlog_at_end": 0, "cpu_s_per_frame": 7.664, "peak_rss_mb": 723, "temp_c_mean": 53.5, "temp_c_max": 55.0, "mhz_mean": 800, "mhz_min": 798, "cpu_pct_mean": 64.9, "watts_mean": 4.47}

View File

@ -0,0 +1,122 @@
{"t": 1, "temp_c": 54.0, "mhz": 800, "cpu_pct": 62.3, "watts": 4.46, "rss_mb": 525, "done": 0, "queue": 0}
{"t": 2, "temp_c": 53.0, "mhz": 800, "cpu_pct": 65.1, "watts": 4.70, "rss_mb": 531, "done": 0, "queue": 1}
{"t": 3, "temp_c": 53.0, "mhz": 800, "cpu_pct": 72.4, "watts": 4.95, "rss_mb": 534, "done": 0, "queue": 1}
{"t": 4, "temp_c": 54.0, "mhz": 800, "cpu_pct": 54.9, "watts": 3.32, "rss_mb": 465, "done": 1, "queue": 1}
{"t": 5, "temp_c": 54.0, "mhz": 800, "cpu_pct": 69.2, "watts": 4.74, "rss_mb": 604, "done": 1, "queue": 1}
{"t": 6, "temp_c": 54.0, "mhz": 800, "cpu_pct": 66.7, "watts": 4.75, "rss_mb": 609, "done": 1, "queue": 2}
{"t": 7, "temp_c": 53.0, "mhz": 800, "cpu_pct": 57.5, "watts": 4.57, "rss_mb": 284, "done": 2, "queue": 1}
{"t": 8, "temp_c": 53.0, "mhz": 800, "cpu_pct": 64.5, "watts": 4.66, "rss_mb": 602, "done": 2, "queue": 2}
{"t": 9, "temp_c": 53.0, "mhz": 800, "cpu_pct": 73.6, "watts": 3.63, "rss_mb": 623, "done": 2, "queue": 2}
{"t": 10, "temp_c": 54.0, "mhz": 800, "cpu_pct": 67.1, "watts": 4.83, "rss_mb": 625, "done": 2, "queue": 3}
{"t": 11, "temp_c": 54.0, "mhz": 800, "cpu_pct": 58.2, "watts": 4.50, "rss_mb": 592, "done": 3, "queue": 2}
{"t": 12, "temp_c": 54.0, "mhz": 800, "cpu_pct": 64.6, "watts": 4.87, "rss_mb": 597, "done": 3, "queue": 3}
{"t": 13, "temp_c": 54.0, "mhz": 800, "cpu_pct": 61.8, "watts": 4.51, "rss_mb": 562, "done": 3, "queue": 3}
{"t": 14, "temp_c": 54.0, "mhz": 800, "cpu_pct": 65.3, "watts": 3.58, "rss_mb": 479, "done": 4, "queue": 3}
{"t": 15, "temp_c": 55.0, "mhz": 800, "cpu_pct": 64.2, "watts": 4.58, "rss_mb": 662, "done": 4, "queue": 3}
{"t": 16, "temp_c": 54.0, "mhz": 800, "cpu_pct": 65.1, "watts": 4.94, "rss_mb": 680, "done": 4, "queue": 4}
{"t": 17, "temp_c": 54.0, "mhz": 800, "cpu_pct": 68.9, "watts": 4.77, "rss_mb": 681, "done": 4, "queue": 4}
{"t": 18, "temp_c": 54.0, "mhz": 800, "cpu_pct": 62.8, "watts": 3.43, "rss_mb": 683, "done": 5, "queue": 4}
{"t": 19, "temp_c": 54.0, "mhz": 800, "cpu_pct": 69.8, "watts": 4.79, "rss_mb": 686, "done": 5, "queue": 4}
{"t": 20, "temp_c": 53.0, "mhz": 800, "cpu_pct": 64.5, "watts": 4.88, "rss_mb": 686, "done": 5, "queue": 5}
{"t": 21, "temp_c": 54.0, "mhz": 800, "cpu_pct": 62.2, "watts": 4.57, "rss_mb": 671, "done": 6, "queue": 4}
{"t": 22, "temp_c": 54.0, "mhz": 800, "cpu_pct": 66.2, "watts": 4.78, "rss_mb": 679, "done": 6, "queue": 5}
{"t": 23, "temp_c": 56.0, "mhz": 800, "cpu_pct": 88.9, "watts": 4.14, "rss_mb": 680, "done": 6, "queue": 5}
{"t": 24, "temp_c": 54.0, "mhz": 800, "cpu_pct": 68.7, "watts": 5.29, "rss_mb": 463, "done": 7, "queue": 5}
{"t": 25, "temp_c": 54.0, "mhz": 800, "cpu_pct": 67.6, "watts": 4.70, "rss_mb": 684, "done": 7, "queue": 5}
{"t": 26, "temp_c": 54.0, "mhz": 800, "cpu_pct": 70.9, "watts": 4.95, "rss_mb": 685, "done": 7, "queue": 6}
{"t": 27, "temp_c": 53.0, "mhz": 800, "cpu_pct": 68.6, "watts": 3.59, "rss_mb": 686, "done": 7, "queue": 6}
{"t": 28, "temp_c": 53.0, "mhz": 800, "cpu_pct": 62.0, "watts": 4.72, "rss_mb": 686, "done": 8, "queue": 6}
{"t": 29, "temp_c": 54.0, "mhz": 800, "cpu_pct": 68.1, "watts": 4.81, "rss_mb": 688, "done": 8, "queue": 6}
{"t": 30, "temp_c": 54.0, "mhz": 800, "cpu_pct": 65.5, "watts": 4.80, "rss_mb": 688, "done": 8, "queue": 7}
{"t": 31, "temp_c": 54.0, "mhz": 800, "cpu_pct": 61.8, "watts": 3.31, "rss_mb": 686, "done": 9, "queue": 6}
{"t": 32, "temp_c": 54.0, "mhz": 800, "cpu_pct": 65.2, "watts": 5.06, "rss_mb": 691, "done": 9, "queue": 7}
{"t": 33, "temp_c": 54.0, "mhz": 800, "cpu_pct": 69.9, "watts": 4.56, "rss_mb": 692, "done": 9, "queue": 7}
{"t": 34, "temp_c": 53.0, "mhz": 800, "cpu_pct": 55.8, "watts": 4.59, "rss_mb": 660, "done": 10, "queue": 7}
{"t": 35, "temp_c": 54.0, "mhz": 800, "cpu_pct": 75.3, "watts": 5.00, "rss_mb": 694, "done": 10, "queue": 7}
{"t": 36, "temp_c": 54.0, "mhz": 800, "cpu_pct": 66.8, "watts": 3.44, "rss_mb": 695, "done": 10, "queue": 8}
{"t": 37, "temp_c": 54.0, "mhz": 800, "cpu_pct": 58.8, "watts": 4.74, "rss_mb": 525, "done": 11, "queue": 7}
{"t": 38, "temp_c": 54.0, "mhz": 800, "cpu_pct": 64.7, "watts": 4.60, "rss_mb": 697, "done": 11, "queue": 8}
{"t": 39, "temp_c": 53.0, "mhz": 800, "cpu_pct": 66.3, "watts": 4.95, "rss_mb": 697, "done": 11, "queue": 8}
{"t": 40, "temp_c": 54.0, "mhz": 800, "cpu_pct": 67.7, "watts": 3.59, "rss_mb": 697, "done": 11, "queue": 9}
{"t": 41, "temp_c": 54.0, "mhz": 800, "cpu_pct": 61.7, "watts": 4.93, "rss_mb": 697, "done": 12, "queue": 8}
{"t": 42, "temp_c": 54.0, "mhz": 800, "cpu_pct": 71.2, "watts": 4.77, "rss_mb": 698, "done": 12, "queue": 9}
{"t": 43, "temp_c": 54.0, "mhz": 800, "cpu_pct": 65.1, "watts": 4.75, "rss_mb": 698, "done": 12, "queue": 9}
{"t": 44, "temp_c": 54.0, "mhz": 800, "cpu_pct": 58.8, "watts": 3.32, "rss_mb": 684, "done": 13, "queue": 9}
{"t": 45, "temp_c": 54.0, "mhz": 800, "cpu_pct": 65.8, "watts": 5.05, "rss_mb": 699, "done": 13, "queue": 9}
{"t": 46, "temp_c": 54.0, "mhz": 800, "cpu_pct": 68.6, "watts": 4.62, "rss_mb": 699, "done": 13, "queue": 10}
{"t": 47, "temp_c": 53.0, "mhz": 801, "cpu_pct": 59.1, "watts": 4.68, "rss_mb": 652, "done": 14, "queue": 9}
{"t": 48, "temp_c": 54.0, "mhz": 800, "cpu_pct": 74.1, "watts": 3.62, "rss_mb": 700, "done": 14, "queue": 10}
{"t": 49, "temp_c": 53.0, "mhz": 800, "cpu_pct": 65.7, "watts": 4.80, "rss_mb": 700, "done": 14, "queue": 10}
{"t": 50, "temp_c": 54.0, "mhz": 800, "cpu_pct": 57.0, "watts": 4.76, "rss_mb": 493, "done": 15, "queue": 10}
{"t": 51, "temp_c": 54.0, "mhz": 800, "cpu_pct": 64.3, "watts": 4.57, "rss_mb": 701, "done": 15, "queue": 10}
{"t": 52, "temp_c": 54.0, "mhz": 800, "cpu_pct": 69.4, "watts": 3.77, "rss_mb": 702, "done": 15, "queue": 11}
{"t": 53, "temp_c": 54.0, "mhz": 800, "cpu_pct": 70.0, "watts": 4.80, "rss_mb": 702, "done": 15, "queue": 11}
{"t": 54, "temp_c": 55.0, "mhz": 800, "cpu_pct": 75.5, "watts": 5.33, "rss_mb": 688, "done": 16, "queue": 11}
{"t": 55, "temp_c": 54.0, "mhz": 800, "cpu_pct": 87.9, "watts": 5.57, "rss_mb": 704, "done": 16, "queue": 11}
{"t": 56, "temp_c": 54.0, "mhz": 800, "cpu_pct": 66.1, "watts": 3.65, "rss_mb": 705, "done": 16, "queue": 12}
{"t": 57, "temp_c": 55.0, "mhz": 800, "cpu_pct": 62.4, "watts": 4.67, "rss_mb": 565, "done": 17, "queue": 11}
{"t": 58, "temp_c": 54.0, "mhz": 800, "cpu_pct": 64.4, "watts": 4.61, "rss_mb": 705, "done": 17, "queue": 12}
{"t": 59, "temp_c": 54.0, "mhz": 800, "cpu_pct": 66.7, "watts": 4.98, "rss_mb": 721, "done": 17, "queue": 12}
{"t": 60, "temp_c": 54.0, "mhz": 800, "cpu_pct": 68.6, "watts": 3.54, "rss_mb": 721, "done": 17, "queue": 13}
{"t": 61, "temp_c": 53.0, "mhz": 800, "cpu_pct": 61.2, "watts": 4.78, "rss_mb": 705, "done": 18, "queue": 12}
{"t": 62, "temp_c": 54.0, "mhz": 800, "cpu_pct": 71.4, "watts": 4.73, "rss_mb": 706, "done": 18, "queue": 13}
{"t": 63, "temp_c": 54.0, "mhz": 800, "cpu_pct": 65.2, "watts": 4.85, "rss_mb": 706, "done": 18, "queue": 13}
{"t": 64, "temp_c": 54.0, "mhz": 800, "cpu_pct": 63.3, "watts": 4.63, "rss_mb": 699, "done": 19, "queue": 13}
{"t": 65, "temp_c": 53.0, "mhz": 800, "cpu_pct": 66.6, "watts": 3.70, "rss_mb": 723, "done": 19, "queue": 13}
{"t": 66, "temp_c": 54.0, "mhz": 800, "cpu_pct": 68.6, "watts": 4.75, "rss_mb": 723, "done": 19, "queue": 14}
{"t": 67, "temp_c": 54.0, "mhz": 800, "cpu_pct": 55.8, "watts": 4.63, "rss_mb": 666, "done": 20, "queue": 13}
{"t": 68, "temp_c": 55.0, "mhz": 800, "cpu_pct": 74.7, "watts": 4.97, "rss_mb": 723, "done": 20, "queue": 14}
{"t": 69, "temp_c": 54.0, "mhz": 800, "cpu_pct": 65.1, "watts": 3.47, "rss_mb": 723, "done": 20, "queue": 14}
{"t": 70, "temp_c": 54.0, "mhz": 800, "cpu_pct": 55.6, "watts": 4.73, "rss_mb": 493, "done": 21, "queue": 14}
{"t": 71, "temp_c": 54.0, "mhz": 800, "cpu_pct": 64.5, "watts": 4.70, "rss_mb": 724, "done": 21, "queue": 14}
{"t": 72, "temp_c": 54.0, "mhz": 800, "cpu_pct": 71.2, "watts": 4.94, "rss_mb": 724, "done": 21, "queue": 15}
{"t": 73, "temp_c": 54.0, "mhz": 800, "cpu_pct": 66.4, "watts": 3.57, "rss_mb": 724, "done": 21, "queue": 15}
{"t": 74, "temp_c": 54.0, "mhz": 800, "cpu_pct": 64.7, "watts": 4.61, "rss_mb": 724, "done": 22, "queue": 15}
{"t": 75, "temp_c": 54.0, "mhz": 800, "cpu_pct": 66.1, "watts": 4.77, "rss_mb": 724, "done": 22, "queue": 15}
{"t": 76, "temp_c": 54.0, "mhz": 800, "cpu_pct": 67.8, "watts": 4.95, "rss_mb": 724, "done": 22, "queue": 16}
{"t": 77, "temp_c": 54.0, "mhz": 800, "cpu_pct": 59.6, "watts": 4.58, "rss_mb": 679, "done": 23, "queue": 15}
{"t": 78, "temp_c": 53.0, "mhz": 800, "cpu_pct": 71.2, "watts": 3.69, "rss_mb": 708, "done": 23, "queue": 16}
{"t": 79, "temp_c": 55.0, "mhz": 800, "cpu_pct": 66.2, "watts": 4.74, "rss_mb": 709, "done": 23, "queue": 16}
{"t": 80, "temp_c": 54.0, "mhz": 800, "cpu_pct": 60.3, "watts": 4.70, "rss_mb": 649, "done": 24, "queue": 16}
{"t": 81, "temp_c": 54.0, "mhz": 800, "cpu_pct": 71.8, "watts": 4.91, "rss_mb": 709, "done": 24, "queue": 16}
{"t": 82, "temp_c": 54.0, "mhz": 800, "cpu_pct": 66.5, "watts": 3.47, "rss_mb": 709, "done": 24, "queue": 17}
{"t": 83, "temp_c": 54.0, "mhz": 800, "cpu_pct": 57.4, "watts": 4.79, "rss_mb": 496, "done": 25, "queue": 16}
{"t": 84, "temp_c": 54.0, "mhz": 800, "cpu_pct": 64.7, "watts": 4.70, "rss_mb": 709, "done": 25, "queue": 17}
{"t": 85, "temp_c": 54.0, "mhz": 800, "cpu_pct": 83.2, "watts": 5.34, "rss_mb": 726, "done": 25, "queue": 17}
{"t": 86, "temp_c": 54.0, "mhz": 800, "cpu_pct": 83.3, "watts": 4.00, "rss_mb": 726, "done": 25, "queue": 18}
{"t": 87, "temp_c": 54.0, "mhz": 800, "cpu_pct": 57.5, "watts": 4.54, "rss_mb": 682, "done": 26, "queue": 17}
{"t": 88, "temp_c": 55.0, "mhz": 800, "cpu_pct": 70.7, "watts": 5.03, "rss_mb": 710, "done": 26, "queue": 18}
{"t": 89, "temp_c": 54.0, "mhz": 800, "cpu_pct": 68.8, "watts": 4.69, "rss_mb": 710, "done": 26, "queue": 18}
{"t": 90, "temp_c": 54.0, "mhz": 800, "cpu_pct": 56.5, "watts": 3.47, "rss_mb": 664, "done": 27, "queue": 18}
{"t": 91, "temp_c": 55.0, "mhz": 800, "cpu_pct": 72.8, "watts": 4.82, "rss_mb": 711, "done": 27, "queue": 18}
{"t": 92, "temp_c": 53.0, "mhz": 800, "cpu_pct": 66.3, "watts": 4.85, "rss_mb": 711, "done": 27, "queue": 19}
{"t": 93, "temp_c": 54.0, "mhz": 800, "cpu_pct": 58.0, "watts": 4.62, "rss_mb": 522, "done": 28, "queue": 18}
{"t": 94, "temp_c": 54.0, "mhz": 800, "cpu_pct": 64.1, "watts": 4.70, "rss_mb": 711, "done": 28, "queue": 19}
{"t": 95, "temp_c": 53.0, "mhz": 800, "cpu_pct": 72.4, "watts": 3.76, "rss_mb": 711, "done": 28, "queue": 19}
{"t": 96, "temp_c": 54.0, "mhz": 800, "cpu_pct": 68.8, "watts": 4.74, "rss_mb": 711, "done": 28, "queue": 20}
{"t": 97, "temp_c": 53.0, "mhz": 800, "cpu_pct": 60.2, "watts": 4.78, "rss_mb": 711, "done": 29, "queue": 19}
{"t": 98, "temp_c": 54.0, "mhz": 800, "cpu_pct": 68.0, "watts": 4.79, "rss_mb": 712, "done": 29, "queue": 20}
{"t": 99, "temp_c": 54.0, "mhz": 800, "cpu_pct": 66.0, "watts": 3.54, "rss_mb": 712, "done": 29, "queue": 20}
{"t": 100, "temp_c": 54.0, "mhz": 800, "cpu_pct": 60.4, "watts": 4.52, "rss_mb": 691, "done": 30, "queue": 20}
{"t": 101, "temp_c": 54.0, "mhz": 800, "cpu_pct": 71.9, "watts": 5.11, "rss_mb": 712, "done": 30, "queue": 20}
{"t": 102, "temp_c": 54.0, "mhz": 800, "cpu_pct": 67.2, "watts": 4.64, "rss_mb": 713, "done": 30, "queue": 21}
{"t": 103, "temp_c": 53.0, "mhz": 800, "cpu_pct": 56.9, "watts": 3.45, "rss_mb": 662, "done": 31, "queue": 20}
{"t": 104, "temp_c": 54.0, "mhz": 800, "cpu_pct": 72.9, "watts": 4.85, "rss_mb": 713, "done": 31, "queue": 21}
{"t": 105, "temp_c": 54.0, "mhz": 800, "cpu_pct": 66.9, "watts": 4.87, "rss_mb": 713, "done": 31, "queue": 21}
{"t": 106, "temp_c": 54.0, "mhz": 800, "cpu_pct": 55.9, "watts": 4.62, "rss_mb": 495, "done": 32, "queue": 21}
{"t": 107, "temp_c": 54.0, "mhz": 800, "cpu_pct": 65.8, "watts": 3.75, "rss_mb": 713, "done": 32, "queue": 21}
{"t": 108, "temp_c": 54.0, "mhz": 800, "cpu_pct": 71.8, "watts": 4.72, "rss_mb": 713, "done": 32, "queue": 22}
{"t": 109, "temp_c": 54.0, "mhz": 800, "cpu_pct": 66.7, "watts": 4.71, "rss_mb": 713, "done": 32, "queue": 22}
{"t": 110, "temp_c": 55.0, "mhz": 800, "cpu_pct": 63.0, "watts": 4.88, "rss_mb": 713, "done": 33, "queue": 22}
{"t": 111, "temp_c": 54.0, "mhz": 800, "cpu_pct": 65.5, "watts": 4.77, "rss_mb": 713, "done": 33, "queue": 22}
{"t": 112, "temp_c": 54.0, "mhz": 800, "cpu_pct": 65.7, "watts": 3.55, "rss_mb": 713, "done": 33, "queue": 23}
{"t": 113, "temp_c": 55.0, "mhz": 800, "cpu_pct": 61.8, "watts": 4.61, "rss_mb": 685, "done": 34, "queue": 22}
{"t": 114, "temp_c": 54.0, "mhz": 800, "cpu_pct": 72.0, "watts": 5.02, "rss_mb": 729, "done": 34, "queue": 23}
{"t": 115, "temp_c": 54.0, "mhz": 800, "cpu_pct": 65.8, "watts": 4.65, "rss_mb": 729, "done": 34, "queue": 23}
{"t": 116, "temp_c": 54.0, "mhz": 800, "cpu_pct": 63.8, "watts": 3.50, "rss_mb": 634, "done": 35, "queue": 23}
{"t": 117, "temp_c": 55.0, "mhz": 800, "cpu_pct": 85.3, "watts": 5.43, "rss_mb": 714, "done": 35, "queue": 23}
{"t": 118, "temp_c": 54.0, "mhz": 800, "cpu_pct": 68.2, "watts": 5.08, "rss_mb": 714, "done": 35, "queue": 24}
{"t": 119, "temp_c": 53.0, "mhz": 800, "cpu_pct": 69.2, "watts": 4.74, "rss_mb": 714, "done": 35, "queue": 24}
{"t": 120, "temp_c": 54.0, "mhz": 800, "cpu_pct": 59.9, "watts": 4.59, "rss_mb": 714, "done": 36, "queue": 23}
{"t": 121, "temp_c": 54.0, "mhz": 800, "cpu_pct": 65.3, "watts": 3.50, "rss_mb": 714, "done": 36, "queue": 23}
{"summary": "pipeline", "kind": "c12_ea", "workers": 1, "threads": 4, "effort": 3, "distance": 1.00, "period_ms": 2000, "secs": 122.8, "frames": 37, "frames_per_s": 0.301, "job_ms_p50": 3246, "latency_ms_p50": 27515, "latency_ms_p95": 47924, "latency_ms_max": 50735, "max_queue": 24, "backlog_at_end": 23, "cpu_s_per_frame": 7.634, "peak_rss_mb": 729, "temp_c_mean": 53.9, "temp_c_max": 56.0, "mhz_mean": 800, "mhz_min": 800, "cpu_pct_mean": 66.3, "watts_mean": 4.51}

View File

@ -0,0 +1,122 @@
{"t": 1, "temp_c": 51.0, "mhz": 800, "cpu_pct": 91.3, "watts": -1.00, "rss_mb": 505, "done": 0, "queue": 0}
{"t": 2, "temp_c": 50.0, "mhz": 800, "cpu_pct": 94.0, "watts": -1.00, "rss_mb": 562, "done": 0, "queue": 1}
{"t": 3, "temp_c": 51.0, "mhz": 800, "cpu_pct": 92.2, "watts": -1.00, "rss_mb": 541, "done": 0, "queue": 1}
{"t": 4, "temp_c": 51.0, "mhz": 800, "cpu_pct": 91.0, "watts": -1.00, "rss_mb": 534, "done": 0, "queue": 2}
{"t": 5, "temp_c": 50.0, "mhz": 800, "cpu_pct": 91.5, "watts": -1.00, "rss_mb": 336, "done": 1, "queue": 1}
{"t": 6, "temp_c": 51.0, "mhz": 800, "cpu_pct": 92.7, "watts": -1.00, "rss_mb": 591, "done": 1, "queue": 2}
{"t": 7, "temp_c": 51.0, "mhz": 800, "cpu_pct": 91.5, "watts": -1.00, "rss_mb": 612, "done": 1, "queue": 2}
{"t": 8, "temp_c": 51.0, "mhz": 800, "cpu_pct": 95.2, "watts": -1.00, "rss_mb": 615, "done": 1, "queue": 3}
{"t": 9, "temp_c": 51.0, "mhz": 800, "cpu_pct": 92.3, "watts": -1.00, "rss_mb": 616, "done": 1, "queue": 3}
{"t": 10, "temp_c": 50.0, "mhz": 800, "cpu_pct": 85.8, "watts": -1.00, "rss_mb": 504, "done": 2, "queue": 3}
{"t": 11, "temp_c": 51.0, "mhz": 800, "cpu_pct": 92.0, "watts": -1.00, "rss_mb": 623, "done": 2, "queue": 3}
{"t": 12, "temp_c": 51.0, "mhz": 800, "cpu_pct": 92.8, "watts": -1.00, "rss_mb": 642, "done": 2, "queue": 4}
{"t": 13, "temp_c": 51.0, "mhz": 800, "cpu_pct": 91.6, "watts": -1.00, "rss_mb": 643, "done": 2, "queue": 4}
{"t": 14, "temp_c": 52.0, "mhz": 800, "cpu_pct": 96.5, "watts": -1.00, "rss_mb": 644, "done": 2, "queue": 5}
{"t": 15, "temp_c": 51.0, "mhz": 800, "cpu_pct": 99.5, "watts": -1.00, "rss_mb": 515, "done": 3, "queue": 4}
{"t": 16, "temp_c": 51.0, "mhz": 800, "cpu_pct": 91.8, "watts": -1.00, "rss_mb": 562, "done": 3, "queue": 5}
{"t": 17, "temp_c": 51.0, "mhz": 800, "cpu_pct": 92.3, "watts": -1.00, "rss_mb": 572, "done": 3, "queue": 5}
{"t": 18, "temp_c": 52.0, "mhz": 800, "cpu_pct": 91.8, "watts": -1.00, "rss_mb": 591, "done": 3, "queue": 6}
{"t": 19, "temp_c": 51.0, "mhz": 800, "cpu_pct": 90.8, "watts": -1.00, "rss_mb": 499, "done": 3, "queue": 6}
{"t": 20, "temp_c": 51.0, "mhz": 800, "cpu_pct": 93.5, "watts": -1.00, "rss_mb": 675, "done": 4, "queue": 6}
{"t": 21, "temp_c": 51.0, "mhz": 800, "cpu_pct": 94.8, "watts": -1.00, "rss_mb": 695, "done": 4, "queue": 6}
{"t": 22, "temp_c": 51.0, "mhz": 800, "cpu_pct": 90.0, "watts": -1.00, "rss_mb": 697, "done": 4, "queue": 7}
{"t": 23, "temp_c": 51.0, "mhz": 800, "cpu_pct": 92.6, "watts": -1.00, "rss_mb": 697, "done": 4, "queue": 7}
{"t": 24, "temp_c": 52.0, "mhz": 800, "cpu_pct": 90.8, "watts": -1.00, "rss_mb": 649, "done": 5, "queue": 7}
{"t": 25, "temp_c": 51.0, "mhz": 800, "cpu_pct": 95.0, "watts": -1.00, "rss_mb": 700, "done": 5, "queue": 7}
{"t": 26, "temp_c": 51.0, "mhz": 800, "cpu_pct": 93.8, "watts": -1.00, "rss_mb": 702, "done": 5, "queue": 8}
{"t": 27, "temp_c": 52.0, "mhz": 800, "cpu_pct": 92.5, "watts": -1.00, "rss_mb": 703, "done": 5, "queue": 8}
{"t": 28, "temp_c": 52.0, "mhz": 800, "cpu_pct": 90.3, "watts": -1.00, "rss_mb": 533, "done": 6, "queue": 8}
{"t": 29, "temp_c": 51.0, "mhz": 800, "cpu_pct": 90.5, "watts": -1.00, "rss_mb": 691, "done": 6, "queue": 8}
{"t": 30, "temp_c": 51.0, "mhz": 800, "cpu_pct": 94.0, "watts": -1.00, "rss_mb": 693, "done": 6, "queue": 9}
{"t": 31, "temp_c": 51.0, "mhz": 800, "cpu_pct": 94.5, "watts": -1.00, "rss_mb": 694, "done": 6, "queue": 9}
{"t": 32, "temp_c": 51.0, "mhz": 800, "cpu_pct": 90.5, "watts": -1.00, "rss_mb": 694, "done": 6, "queue": 10}
{"t": 33, "temp_c": 51.0, "mhz": 800, "cpu_pct": 91.0, "watts": -1.00, "rss_mb": 682, "done": 7, "queue": 9}
{"t": 34, "temp_c": 52.0, "mhz": 800, "cpu_pct": 95.3, "watts": -1.00, "rss_mb": 695, "done": 7, "queue": 10}
{"t": 35, "temp_c": 51.0, "mhz": 800, "cpu_pct": 89.8, "watts": -1.00, "rss_mb": 697, "done": 7, "queue": 10}
{"t": 36, "temp_c": 51.0, "mhz": 800, "cpu_pct": 93.7, "watts": -1.00, "rss_mb": 697, "done": 7, "queue": 11}
{"t": 37, "temp_c": 52.0, "mhz": 800, "cpu_pct": 88.8, "watts": -1.00, "rss_mb": 665, "done": 8, "queue": 10}
{"t": 38, "temp_c": 51.0, "mhz": 800, "cpu_pct": 94.8, "watts": -1.00, "rss_mb": 701, "done": 8, "queue": 11}
{"t": 39, "temp_c": 51.0, "mhz": 800, "cpu_pct": 94.0, "watts": -1.00, "rss_mb": 703, "done": 8, "queue": 11}
{"t": 40, "temp_c": 53.0, "mhz": 800, "cpu_pct": 91.5, "watts": -1.00, "rss_mb": 703, "done": 8, "queue": 12}
{"t": 41, "temp_c": 52.0, "mhz": 800, "cpu_pct": 92.3, "watts": -1.00, "rss_mb": 509, "done": 9, "queue": 11}
{"t": 42, "temp_c": 52.0, "mhz": 800, "cpu_pct": 93.0, "watts": -1.00, "rss_mb": 703, "done": 9, "queue": 12}
{"t": 43, "temp_c": 51.0, "mhz": 800, "cpu_pct": 94.5, "watts": -1.00, "rss_mb": 704, "done": 9, "queue": 12}
{"t": 44, "temp_c": 52.0, "mhz": 800, "cpu_pct": 91.8, "watts": -1.00, "rss_mb": 705, "done": 9, "queue": 13}
{"t": 45, "temp_c": 52.0, "mhz": 800, "cpu_pct": 94.0, "watts": -1.00, "rss_mb": 705, "done": 9, "queue": 13}
{"t": 46, "temp_c": 52.0, "mhz": 800, "cpu_pct": 99.0, "watts": -1.00, "rss_mb": 658, "done": 10, "queue": 13}
{"t": 47, "temp_c": 52.0, "mhz": 800, "cpu_pct": 95.0, "watts": -1.00, "rss_mb": 707, "done": 10, "queue": 13}
{"t": 48, "temp_c": 52.0, "mhz": 800, "cpu_pct": 93.7, "watts": -1.00, "rss_mb": 708, "done": 10, "queue": 14}
{"t": 49, "temp_c": 52.0, "mhz": 800, "cpu_pct": 91.2, "watts": -1.00, "rss_mb": 708, "done": 10, "queue": 14}
{"t": 50, "temp_c": 52.0, "mhz": 800, "cpu_pct": 91.8, "watts": -1.00, "rss_mb": 584, "done": 10, "queue": 15}
{"t": 51, "temp_c": 52.0, "mhz": 800, "cpu_pct": 91.3, "watts": -1.00, "rss_mb": 708, "done": 11, "queue": 14}
{"t": 52, "temp_c": 52.0, "mhz": 800, "cpu_pct": 93.8, "watts": -1.00, "rss_mb": 709, "done": 11, "queue": 15}
{"t": 53, "temp_c": 52.0, "mhz": 800, "cpu_pct": 91.5, "watts": -1.00, "rss_mb": 710, "done": 11, "queue": 15}
{"t": 54, "temp_c": 52.0, "mhz": 800, "cpu_pct": 92.5, "watts": -1.00, "rss_mb": 710, "done": 11, "queue": 16}
{"t": 55, "temp_c": 52.0, "mhz": 800, "cpu_pct": 90.3, "watts": -1.00, "rss_mb": 678, "done": 12, "queue": 15}
{"t": 56, "temp_c": 53.0, "mhz": 800, "cpu_pct": 94.5, "watts": -1.00, "rss_mb": 717, "done": 12, "queue": 16}
{"t": 57, "temp_c": 52.0, "mhz": 800, "cpu_pct": 94.0, "watts": -1.00, "rss_mb": 718, "done": 12, "queue": 16}
{"t": 58, "temp_c": 52.0, "mhz": 800, "cpu_pct": 91.8, "watts": -1.00, "rss_mb": 718, "done": 12, "queue": 17}
{"t": 59, "temp_c": 52.0, "mhz": 800, "cpu_pct": 90.8, "watts": -1.00, "rss_mb": 588, "done": 13, "queue": 16}
{"t": 60, "temp_c": 53.0, "mhz": 800, "cpu_pct": 92.5, "watts": -1.00, "rss_mb": 724, "done": 13, "queue": 17}
{"t": 61, "temp_c": 52.0, "mhz": 800, "cpu_pct": 92.0, "watts": -1.00, "rss_mb": 726, "done": 13, "queue": 17}
{"t": 62, "temp_c": 52.0, "mhz": 800, "cpu_pct": 93.2, "watts": -1.00, "rss_mb": 726, "done": 13, "queue": 18}
{"t": 63, "temp_c": 52.0, "mhz": 800, "cpu_pct": 90.5, "watts": -1.00, "rss_mb": 726, "done": 13, "queue": 18}
{"t": 64, "temp_c": 52.0, "mhz": 800, "cpu_pct": 91.8, "watts": -1.00, "rss_mb": 726, "done": 14, "queue": 18}
{"t": 65, "temp_c": 52.0, "mhz": 800, "cpu_pct": 94.8, "watts": -1.00, "rss_mb": 728, "done": 14, "queue": 18}
{"t": 66, "temp_c": 52.0, "mhz": 800, "cpu_pct": 90.0, "watts": -1.00, "rss_mb": 729, "done": 14, "queue": 19}
{"t": 67, "temp_c": 52.0, "mhz": 800, "cpu_pct": 92.5, "watts": -1.00, "rss_mb": 729, "done": 14, "queue": 19}
{"t": 68, "temp_c": 52.0, "mhz": 800, "cpu_pct": 88.6, "watts": -1.00, "rss_mb": 697, "done": 15, "queue": 19}
{"t": 69, "temp_c": 54.0, "mhz": 800, "cpu_pct": 94.5, "watts": -1.00, "rss_mb": 730, "done": 15, "queue": 19}
{"t": 70, "temp_c": 52.0, "mhz": 800, "cpu_pct": 93.8, "watts": -1.00, "rss_mb": 730, "done": 15, "queue": 20}
{"t": 71, "temp_c": 53.0, "mhz": 800, "cpu_pct": 91.2, "watts": -1.00, "rss_mb": 730, "done": 15, "queue": 20}
{"t": 72, "temp_c": 53.0, "mhz": 800, "cpu_pct": 89.3, "watts": -1.00, "rss_mb": 527, "done": 16, "queue": 20}
{"t": 73, "temp_c": 52.0, "mhz": 800, "cpu_pct": 91.2, "watts": -1.00, "rss_mb": 733, "done": 16, "queue": 20}
{"t": 74, "temp_c": 52.0, "mhz": 800, "cpu_pct": 94.8, "watts": -1.00, "rss_mb": 734, "done": 16, "queue": 21}
{"t": 75, "temp_c": 53.0, "mhz": 800, "cpu_pct": 95.3, "watts": -1.00, "rss_mb": 735, "done": 16, "queue": 21}
{"t": 76, "temp_c": 52.0, "mhz": 800, "cpu_pct": 92.5, "watts": -1.00, "rss_mb": 735, "done": 16, "queue": 22}
{"t": 77, "temp_c": 53.0, "mhz": 800, "cpu_pct": 97.8, "watts": -1.00, "rss_mb": 703, "done": 17, "queue": 21}
{"t": 78, "temp_c": 53.0, "mhz": 800, "cpu_pct": 99.8, "watts": -1.00, "rss_mb": 735, "done": 17, "queue": 22}
{"t": 79, "temp_c": 53.0, "mhz": 800, "cpu_pct": 95.0, "watts": -1.00, "rss_mb": 735, "done": 17, "queue": 22}
{"t": 80, "temp_c": 53.0, "mhz": 800, "cpu_pct": 94.8, "watts": -1.00, "rss_mb": 735, "done": 17, "queue": 23}
{"t": 81, "temp_c": 52.0, "mhz": 800, "cpu_pct": 91.2, "watts": -1.00, "rss_mb": 735, "done": 17, "queue": 23}
{"t": 82, "temp_c": 53.0, "mhz": 800, "cpu_pct": 91.8, "watts": -1.00, "rss_mb": 751, "done": 18, "queue": 23}
{"t": 83, "temp_c": 53.0, "mhz": 800, "cpu_pct": 92.8, "watts": -1.00, "rss_mb": 752, "done": 18, "queue": 23}
{"t": 84, "temp_c": 52.0, "mhz": 800, "cpu_pct": 94.0, "watts": -1.00, "rss_mb": 752, "done": 18, "queue": 24}
{"t": 85, "temp_c": 52.0, "mhz": 800, "cpu_pct": 91.5, "watts": -1.00, "rss_mb": 752, "done": 18, "queue": 24}
{"t": 86, "temp_c": 52.0, "mhz": 800, "cpu_pct": 89.5, "watts": -1.00, "rss_mb": 696, "done": 19, "queue": 24}
{"t": 87, "temp_c": 52.0, "mhz": 800, "cpu_pct": 93.0, "watts": -1.00, "rss_mb": 737, "done": 19, "queue": 24}
{"t": 88, "temp_c": 52.0, "mhz": 800, "cpu_pct": 95.2, "watts": -1.00, "rss_mb": 737, "done": 19, "queue": 25}
{"t": 89, "temp_c": 53.0, "mhz": 800, "cpu_pct": 94.2, "watts": -1.00, "rss_mb": 737, "done": 19, "queue": 25}
{"t": 90, "temp_c": 53.0, "mhz": 800, "cpu_pct": 89.0, "watts": -1.00, "rss_mb": 519, "done": 20, "queue": 25}
{"t": 91, "temp_c": 53.0, "mhz": 800, "cpu_pct": 93.5, "watts": -1.00, "rss_mb": 737, "done": 20, "queue": 25}
{"t": 92, "temp_c": 52.0, "mhz": 800, "cpu_pct": 91.2, "watts": -1.00, "rss_mb": 737, "done": 20, "queue": 26}
{"t": 93, "temp_c": 53.0, "mhz": 800, "cpu_pct": 96.3, "watts": -1.00, "rss_mb": 738, "done": 20, "queue": 26}
{"t": 94, "temp_c": 52.0, "mhz": 800, "cpu_pct": 91.8, "watts": -1.00, "rss_mb": 738, "done": 20, "queue": 27}
{"t": 95, "temp_c": 53.0, "mhz": 800, "cpu_pct": 87.5, "watts": -1.00, "rss_mb": 705, "done": 21, "queue": 26}
{"t": 96, "temp_c": 52.0, "mhz": 800, "cpu_pct": 93.3, "watts": -1.00, "rss_mb": 754, "done": 21, "queue": 27}
{"t": 97, "temp_c": 53.0, "mhz": 800, "cpu_pct": 94.5, "watts": -1.00, "rss_mb": 754, "done": 21, "queue": 27}
{"t": 98, "temp_c": 54.0, "mhz": 800, "cpu_pct": 94.3, "watts": -1.00, "rss_mb": 754, "done": 21, "queue": 28}
{"t": 99, "temp_c": 53.0, "mhz": 800, "cpu_pct": 88.7, "watts": -1.00, "rss_mb": 629, "done": 22, "queue": 27}
{"t": 100, "temp_c": 54.0, "mhz": 800, "cpu_pct": 87.2, "watts": -1.00, "rss_mb": 755, "done": 22, "queue": 28}
{"t": 101, "temp_c": 53.0, "mhz": 800, "cpu_pct": 95.3, "watts": -1.00, "rss_mb": 756, "done": 22, "queue": 28}
{"t": 102, "temp_c": 53.0, "mhz": 800, "cpu_pct": 94.0, "watts": -1.00, "rss_mb": 757, "done": 22, "queue": 29}
{"t": 103, "temp_c": 52.0, "mhz": 800, "cpu_pct": 90.7, "watts": -1.00, "rss_mb": 616, "done": 22, "queue": 29}
{"t": 104, "temp_c": 53.0, "mhz": 800, "cpu_pct": 92.7, "watts": -1.00, "rss_mb": 757, "done": 23, "queue": 29}
{"t": 105, "temp_c": 53.0, "mhz": 800, "cpu_pct": 92.3, "watts": -1.00, "rss_mb": 757, "done": 23, "queue": 29}
{"t": 106, "temp_c": 53.0, "mhz": 800, "cpu_pct": 94.5, "watts": -1.00, "rss_mb": 758, "done": 23, "queue": 30}
{"t": 107, "temp_c": 53.0, "mhz": 800, "cpu_pct": 91.2, "watts": -1.00, "rss_mb": 758, "done": 23, "queue": 30}
{"t": 108, "temp_c": 53.0, "mhz": 800, "cpu_pct": 92.2, "watts": -1.00, "rss_mb": 653, "done": 24, "queue": 30}
{"t": 109, "temp_c": 53.0, "mhz": 800, "cpu_pct": 99.5, "watts": -1.00, "rss_mb": 758, "done": 24, "queue": 30}
{"t": 110, "temp_c": 53.0, "mhz": 800, "cpu_pct": 97.0, "watts": -1.00, "rss_mb": 758, "done": 24, "queue": 31}
{"t": 111, "temp_c": 53.0, "mhz": 800, "cpu_pct": 95.2, "watts": -1.00, "rss_mb": 758, "done": 24, "queue": 31}
{"t": 112, "temp_c": 53.0, "mhz": 800, "cpu_pct": 91.2, "watts": -1.00, "rss_mb": 758, "done": 24, "queue": 32}
{"t": 113, "temp_c": 53.0, "mhz": 800, "cpu_pct": 90.2, "watts": -1.00, "rss_mb": 743, "done": 25, "queue": 31}
{"t": 114, "temp_c": 53.0, "mhz": 800, "cpu_pct": 93.0, "watts": -1.00, "rss_mb": 759, "done": 25, "queue": 32}
{"t": 115, "temp_c": 54.0, "mhz": 800, "cpu_pct": 94.8, "watts": -1.00, "rss_mb": 760, "done": 25, "queue": 32}
{"t": 116, "temp_c": 53.0, "mhz": 800, "cpu_pct": 92.2, "watts": -1.00, "rss_mb": 760, "done": 25, "queue": 33}
{"t": 117, "temp_c": 54.0, "mhz": 800, "cpu_pct": 89.0, "watts": -1.00, "rss_mb": 712, "done": 26, "queue": 32}
{"t": 118, "temp_c": 54.0, "mhz": 800, "cpu_pct": 93.3, "watts": -1.00, "rss_mb": 762, "done": 26, "queue": 33}
{"t": 119, "temp_c": 53.0, "mhz": 800, "cpu_pct": 95.0, "watts": -1.00, "rss_mb": 762, "done": 26, "queue": 33}
{"t": 120, "temp_c": 54.0, "mhz": 800, "cpu_pct": 95.0, "watts": -1.00, "rss_mb": 762, "done": 26, "queue": 33}
{"t": 121, "temp_c": 52.0, "mhz": 742, "cpu_pct": 83.7, "watts": -1.00, "rss_mb": 372, "done": 27, "queue": 33}
{"summary": "pipeline", "kind": "c12_ea", "workers": 1, "threads": 4, "effort": 3, "distance": 1.00, "period_ms": 2000, "secs": 121.3, "frames": 27, "frames_per_s": 0.223, "job_ms_p50": 4410, "latency_ms_p50": 37333, "latency_ms_p95": 66872, "latency_ms_max": 69294, "max_queue": 33, "backlog_at_end": 33, "cpu_s_per_frame": 6.880, "peak_rss_mb": 761, "temp_c_mean": 52.1, "temp_c_max": 54.0, "mhz_mean": 800, "mhz_min": 742, "cpu_pct_mean": 92.7, "watts_mean": -1.00}

View File

@ -0,0 +1,229 @@
16:56:32.187 [INFO ] hardware: /etc/fire_gimbal_control/hardware.ini board lattepanda-3-delta axes yaw, pitch
16:56:32.188 [INFO ] logging to /home/ggs/.local/share/fire_gimbal_control/logs/fgc_20261008-165632.000.log (level debug, 10 x 20 MB)
16:56:32.188 [INFO ] Loaded config: /home/ggs/.config/fire_gimbal_control/config.ini
16:56:32.188 [INFO ] Single-instance lock held: /run/user/1000/fire_gimbal_control.lock
16:56:32.188 [INFO ] wire trace enabled: mqtt
16:56:32.246 [INFO ] camera 'rgb': 3 profile(s) from /home/ggs/.config/fire_gimbal_control/camera_profiles/rgb; active 'standard'
16:56:32.247 [INFO ] IMU frames: reference NWU -> NED; mount x 180 y 0 z 0 (deg, Z-X-Y); readings are in the gimbal frame
16:56:32.258 [INFO ] MQTT (re)connected; subscribing
16:56:32.258 [INFO ] MQTT connected to tcp://127.0.0.1:1883 as 'dev'
16:56:32.258 [INFO ] capture output dir: /home/ggs/projects/fwt_2a/images
16:56:32.258 [INFO ] image saving: 1 worker(s) x 4 thread(s), up to 4 frame(s) waiting
16:56:32.258 [INFO ] scan grid: 15 waypoints
16:56:32.258 [INFO ] keep rule: fixed wait of 1000 ms after standstill
16:56:32.259 [INFO ] CPU guard: pictures slow down at 85 °C or when the CPU throttles, and pause at 92 °C (resume at 75 °C)
16:56:32.259 [INFO ] yaw motor current: run 756 mA (GLOBALSCALER 80, IRUN 31), homing 756 mA (IRUN 31) -- R_sense 0.075 ohm from hardware.ini [Motor.yaw]
16:56:32.259 [INFO ] pitch motor current: run 472 mA (GLOBALSCALER 50, IRUN 31), homing 472 mA (IRUN 31) -- R_sense 0.075 ohm from hardware.ini [Motor.pitch]
16:56:32.259 [INFO ] Serial controller started on /dev/serial/by-id/usb-Arduino_LLC_Arduino_Leonardo-if00 @ 115200
16:56:32.941 [INFO ] MTi config: MTi-28A53G35 fw 2.6.1 scenario 7 (machine_nomagfield) @ 100 Hz, mode 0x0007 settings 0x00000005
16:56:33.002 [INFO ] MTi IMU started on /dev/ttyS0 @ 115200
16:56:34.025 [INFO ] Opened camera 'rgb' DEV_1AB22C049CD1 (1800 U-1240c)
16:56:43.189 [ERROR] camera: applying profile 'standard' from /home/ggs/.config/fire_gimbal_control/camera_profiles/rgb/standard.xml failed (error -39)
16:56:43.190 [INFO ] hardware: declared assembly confirmed (yaw, pitch)
16:56:43.190 [MQTT] PUB GGS/FWT/dev/StatusCode 2
16:56:43.282 [INFO ] Running gimbal init sequence (enable + home)
16:56:43.282 [INFO ] drivetrain re-sent to axis Y: 12 values from hardware.ini
16:56:43.282 [INFO ] drivetrain re-sent to axis P: 12 values from hardware.ini
16:57:26.384 [INFO ] Gimbal homed (both axes READY)
16:57:26.441 [INFO ] firmware dump:
DUMP BEGIN build=8efa63b uptime=84894318 mcusr=0x0 reset=none free_ram=1607
DUMP Y state=3 hsub=8 enabled=1 lim_neg=408820 lim_pos=591181 hold_target=500000 speed=5908 center=500000 soft_margin=5000 gs=80 irun=31 irun_home=31 steps_per_rev=177000 enc_dev=1500 homing_speed=12362 center_speed=25753 sw_mode=2208 cfg_rx=0x1FFE limp=0 hold_corr=4 hold_peak=142693 hold_cumul=2969 has_encoder=1 cs=8 en=7
DUMP Y TMC GCONF=0x0000000C GSTAT=0x00000000 IOIN=0x3000002C TSTEP=0x000FFFFF RAMPMODE=0x00000000 XACTUAL=0x0007A120 VACTUAL=0x00000000 XTARGET=0x0007A120 SW_MODE=0x000008A0 RAMP_STAT=0x00000680 X_ENC=0x0007A117 ENC_STATUS=0x00000000 CHOPCONF=0x00410043 DRV_STATUS=0x801F4000 PWM_SCALE=0x00000040 PWM_AUTO=0x006C003E
DUMP P state=3 hsub=8 enabled=1 lim_neg=213898 lim_pos=786103 hold_target=500000 speed=157403 center=500000 soft_margin=5000 gs=50 irun=31 irun_home=31 steps_per_rev=500000 enc_dev=1500 homing_speed=170978 center_speed=68470 sw_mode=2211 cfg_rx=0x1FFE limp=0 hold_corr=2 hold_peak=245129 hold_cumul=615 has_encoder=1 cs=1 en=0
DUMP P TMC GCONF=0x0000000C GSTAT=0x00000000 IOIN=0x30000008 TSTEP=0x000FFFFF RAMPMODE=0x00000000 XACTUAL=0x0007A120 VACTUAL=0x00000000 XTARGET=0x0007A120 SW_MODE=0x000008A3 RAMP_STAT=0x00001688 X_ENC=0x0007A113 ENC_STATUS=0x00000000 CHOPCONF=0x00410043 DRV_STATUS=0x80084000 PWM_SCALE=0x0000000F PWM_AUTO=0x001E0038
DUMP ENV t=21 h=52 ok=1 fan=0 rpm=0 dht=9 fan_pwm=10 fan_tach=11
DUMP END
16:57:26.500 [INFO ] yaw counts_per_deg 528.254 agrees with the homed travel (182361 counts / 345 deg = 528.583); leaving the calibration alone
16:57:26.500 [INFO ] pitch counts_per_deg -14072.9 agrees with the homed travel (572205 counts / 40.5 deg = -14128.5); leaving the calibration alone
16:57:26.500 [INFO ] homed yaw travel: 112.4..438.684 deg (headings 112.4..78.6844 true), centre 500000 = 275.541 deg
16:57:26.500 [INFO ] homed pitch travel: -27.3943..12.5553 deg, centre 500000 = -7.41947 deg
16:57:26.500 [WARN ] 3 of 15 scan waypoints lie outside the reachable yaw arc (112.4..78.6844 true) and will be skipped
16:57:26.500 [INFO ] yaw speed: 7.99943 deg/s (VMAX 5908) -- 528.254 counts/deg
16:57:26.500 [INFO ] pitch speed: 8.00003 deg/s (VMAX 157403) -- -14072.9 counts/deg
16:57:26.500 [INFO ] Gimbal init finished
16:57:26.509 [INFO ] mode auto
16:57:26.509 [MQTT] PUB GGS/FWT/dev/StatusCode 0
16:57:26.509 [INFO ] Entering control loop (type 'exit' to quit, or Ctrl-C)
16:57:26.509 [INFO ] scan move 1/15: yaw 0 pitch 10 (deg)
16:57:26.511 [MQTT] PUB GGS/FWT/dev/Health {"fwt":"dev","state":"normal","reason":"","guard":true,"cpu_c":51.0,"cpu_mhz":2800,"cpu_busy_pct":null,"throttling":false,"throttle_events_last_min":0,"enclosure_c":21.0,"saved_last_min":0,"save_ms_mean":null,"save_ms_max":null,"held_s":0,"interval_s":5.0,"time":1791471446511}
16:57:38.211 [INFO ] captured waypoint 1/15
16:57:38.222 [INFO ] scan move 2/15: yaw 45 pitch 10 (deg)
16:57:39.022 [MQTT] PUB GGS/FWT/dev/CamEvent { "fwt":"dev", "cam":"RGB", "hdg":3598, "pit":86, "time":1791471458131 }
16:57:45.060 [WARN ] waypoint 2/15: 6.8 s since the last picture, over the 5.0 s interval (move 5.8 s, exposure 1.0 s)
16:57:45.084 [INFO ] captured waypoint 2/15
16:57:45.095 [WARN ] scan waypoint 3/15 heading 90 deg is outside the reachable yaw arc; skipping it (further unreachable waypoints are skipped silently)
16:57:45.095 [INFO ] scan move 4/15: yaw 135 pitch 10 (deg)
16:57:45.692 [MQTT] PUB GGS/FWT/dev/CamEvent { "fwt":"dev", "cam":"RGB", "hdg":450, "pit":86, "time":1791471464990 }
16:58:19.746 [WARN ] waypoint 4/15: 34.7 s since the last picture, over the 5.0 s interval (move 33.6 s, exposure 1.0 s)
16:58:19.760 [INFO ] captured waypoint 4/15
16:58:19.770 [INFO ] scan move 5/15: yaw 180 pitch 10 (deg)
16:58:20.384 [MQTT] PUB GGS/FWT/dev/CamEvent { "fwt":"dev", "cam":"RGB", "hdg":1353, "pit":93, "time":1791471499666 }
16:58:26.626 [WARN ] waypoint 5/15: 6.9 s since the last picture, over the 5.0 s interval (move 5.8 s, exposure 1.0 s)
16:58:26.637 [INFO ] captured waypoint 5/15
16:58:26.639 [MQTT] PUB GGS/FWT/dev/Health {"fwt":"dev","state":"normal","reason":"","guard":true,"cpu_c":53.0,"cpu_mhz":1077,"cpu_busy_pct":15,"throttling":false,"throttle_events_last_min":0,"enclosure_c":21.0,"saved_last_min":3,"save_ms_mean":681,"save_ms_max":812,"held_s":0,"interval_s":5.0,"time":1791471506639}
16:58:26.650 [INFO ] scan move 6/15: yaw 0 pitch 5 (deg)
16:58:27.239 [MQTT] PUB GGS/FWT/dev/CamEvent { "fwt":"dev", "cam":"RGB", "hdg":1800, "pit":98, "time":1791471506525 }
16:58:50.079 [WARN ] waypoint 6/15: 23.4 s since the last picture, over the 5.0 s interval (move 22.4 s, exposure 1.0 s)
16:58:50.087 [INFO ] captured waypoint 6/15
16:58:50.097 [INFO ] scan move 7/15: yaw 45 pitch 5 (deg)
16:58:50.779 [INFO ] saving: 3 pictures in the last minute, 639 ms each on average (longest 692 ms)
16:58:50.779 [MQTT] PUB GGS/FWT/dev/CamEvent { "fwt":"dev", "cam":"RGB", "hdg":3598, "pit":36, "time":1791471530055 }
16:58:56.963 [WARN ] waypoint 7/15: 6.9 s since the last picture, over the 5.0 s interval (move 5.9 s, exposure 1.0 s)
16:58:56.977 [INFO ] captured waypoint 7/15
16:58:56.987 [INFO ] scan move 9/15: yaw 135 pitch 5 (deg)
16:58:57.604 [MQTT] PUB GGS/FWT/dev/CamEvent { "fwt":"dev", "cam":"RGB", "hdg":451, "pit":36, "time":1791471536914 }
16:59:26.757 [MQTT] PUB GGS/FWT/dev/Health {"fwt":"dev","state":"normal","reason":"","guard":true,"cpu_c":52.0,"cpu_mhz":778,"cpu_busy_pct":14,"throttling":false,"throttle_events_last_min":0,"enclosure_c":21.0,"saved_last_min":3,"save_ms_mean":640,"save_ms_max":692,"held_s":0,"interval_s":5.0,"time":1791471566757}
16:59:31.624 [WARN ] waypoint 9/15: 34.6 s since the last picture, over the 5.0 s interval (move 33.6 s, exposure 1.0 s)
16:59:31.660 [INFO ] captured waypoint 9/15
16:59:31.670 [INFO ] scan move 10/15: yaw 180 pitch 5 (deg)
16:59:32.194 [INFO ] CPU: 52 °C (x86_pkg_temp), 2.8 GHz of 2.9 GHz, 14% busy
16:59:32.194 [INFO ] throttling: no, 0 in the last minute, 0 since start
16:59:32.194 [INFO ] scan pace: normal, one picture every 5.0 s
16:59:32.194 [INFO ] saving: 2 in the last minute, 659 ms each (longest 692 ms)
16:59:32.194 [INFO ] limits: slows at 85 °C, pauses at 92 °C for 20 s, resumes at 75 °C after at least 300 s
16:59:32.571 [MQTT] PUB GGS/FWT/dev/CamEvent { "fwt":"dev", "cam":"RGB", "hdg":1352, "pit":43, "time":1791471571589 }
16:59:36.780 [WARN ] CPU is running slow while busy (judged from its clock, not the kernel's count): 53 °C, running at 0.8 GHz of 2.9 GHz
16:59:36.780 [WARN ] CPU is slowing itself down: one picture every 10.0 s instead of 5.0 until the CPU is below 80 °C and keeping up for 2 min
16:59:36.780 [MQTT] PUB GGS/FWT/dev/Health {"fwt":"dev","state":"slowed","reason":"CPU is slowing itself down","guard":true,"cpu_c":53.0,"cpu_mhz":800,"cpu_busy_pct":68,"throttling":true,"throttle_events_last_min":0,"enclosure_c":21.0,"saved_last_min":3,"save_ms_mean":743,"save_ms_max":911,"held_s":0,"interval_s":10.0,"time":1791471576780}
16:59:41.678 [INFO ] captured waypoint 10/15
16:59:41.690 [INFO ] scan move 11/15: yaw 0 pitch 15 (deg)
16:59:45.715 [MQTT] PUB GGS/FWT/dev/CamEvent { "fwt":"dev", "cam":"RGB", "hdg":1800, "pit":48, "time":1791471581592 }
17:00:05.030 [WARN ] waypoint 11/15: 23.4 s since the last picture, over the 10.0 s interval (move 22.3 s, exposure 1.0 s)
17:00:05.052 [INFO ] captured waypoint 11/15
17:00:05.064 [INFO ] scan move 12/15: yaw 45 pitch 15 (deg)
17:00:08.937 [INFO ] saving: 3 pictures in the last minute, 2943 ms each on average (longest 4035 ms)
17:00:08.937 [MQTT] PUB GGS/FWT/dev/CamEvent { "fwt":"dev", "cam":"RGB", "hdg":3598, "pit":111, "time":1791471604932 }
17:00:15.076 [INFO ] captured waypoint 12/15
17:00:15.087 [INFO ] scan move 14/15: yaw 135 pitch 15 (deg)
17:00:18.694 [MQTT] PUB GGS/FWT/dev/CamEvent { "fwt":"dev", "cam":"RGB", "hdg":451, "pit":111, "time":1791471615030 }
17:00:36.922 [WARN ] CPU still slowed: clock low all minute, 53 °C, running at 0.8 GHz of 2.9 GHz
17:00:36.923 [MQTT] PUB GGS/FWT/dev/Health {"fwt":"dev","state":"slowed","reason":"CPU is slowing itself down","guard":true,"cpu_c":53.0,"cpu_mhz":800,"cpu_busy_pct":68,"throttling":true,"throttle_events_last_min":0,"enclosure_c":21.0,"saved_last_min":3,"save_ms_mean":3846,"save_ms_max":4035,"held_s":0,"interval_s":10.0,"time":1791471636922}
17:00:49.639 [WARN ] waypoint 14/15: 34.6 s since the last picture, over the 10.0 s interval (move 33.5 s, exposure 1.0 s)
17:00:49.658 [INFO ] captured waypoint 14/15
17:00:49.669 [INFO ] scan move 15/15: yaw 180 pitch 15 (deg)
17:00:53.137 [MQTT] PUB GGS/FWT/dev/CamEvent { "fwt":"dev", "cam":"RGB", "hdg":1353, "pit":119, "time":1791471649611 }
17:00:59.678 [INFO ] captured waypoint 15/15
17:00:59.691 [INFO ] scan move 1/15: yaw 0 pitch 10 (deg)
17:01:03.230 [MQTT] PUB GGS/FWT/dev/CamEvent { "fwt":"dev", "cam":"RGB", "hdg":1800, "pit":123, "time":1791471659613 }
17:01:23.125 [INFO ] captured waypoint 1/15
17:01:23.136 [INFO ] scan move 2/15: yaw 45 pitch 10 (deg)
17:01:27.270 [INFO ] saving: 3 pictures in the last minute, 3725 ms each on average (longest 4145 ms)
17:01:27.270 [MQTT] PUB GGS/FWT/dev/CamEvent { "fwt":"dev", "cam":"RGB", "hdg":3598, "pit":86, "time":1791471682953 }
17:01:32.235 [INFO ] CPU: 54 °C (x86_pkg_temp), 0.8 GHz of 2.9 GHz, 69% busy
17:01:32.235 [INFO ] throttling: yes (clock), 0 in the last minute, 0 since start
17:01:32.235 [INFO ] scan pace: slowed - CPU is slowing itself down, one picture every 10.0 s
17:01:32.235 [INFO ] saving: 3 in the last minute, 3725 ms each (longest 4145 ms)
17:01:32.235 [INFO ] limits: slows at 85 °C, pauses at 92 °C for 20 s, resumes at 75 °C after at least 300 s
17:01:33.145 [INFO ] captured waypoint 2/15
17:01:33.157 [INFO ] scan move 4/15: yaw 135 pitch 10 (deg)
17:01:36.745 [MQTT] PUB GGS/FWT/dev/CamEvent { "fwt":"dev", "cam":"RGB", "hdg":451, "pit":85, "time":1791471693053 }
17:01:37.060 [WARN ] CPU still slowed: clock low all minute, 55 °C, running at 0.8 GHz of 2.9 GHz
17:01:37.061 [MQTT] PUB GGS/FWT/dev/Health {"fwt":"dev","state":"slowed","reason":"CPU is slowing itself down","guard":true,"cpu_c":55.0,"cpu_mhz":800,"cpu_busy_pct":91,"throttling":true,"throttle_events_last_min":0,"enclosure_c":21.0,"saved_last_min":4,"save_ms_mean":3693,"save_ms_max":4145,"held_s":0,"interval_s":10.0,"time":1791471697060}
17:02:07.648 [WARN ] waypoint 4/15: 34.5 s since the last picture, over the 10.0 s interval (move 33.5 s, exposure 1.0 s)
17:02:07.666 [INFO ] captured waypoint 4/15
17:02:07.677 [INFO ] scan move 5/15: yaw 180 pitch 10 (deg)
17:02:11.187 [MQTT] PUB GGS/FWT/dev/CamEvent { "fwt":"dev", "cam":"RGB", "hdg":1353, "pit":93, "time":1791471727633 }
17:02:17.729 [INFO ] captured waypoint 5/15
17:02:17.741 [INFO ] scan move 6/15: yaw 0 pitch 5 (deg)
17:02:21.530 [MQTT] PUB GGS/FWT/dev/CamEvent { "fwt":"dev", "cam":"RGB", "hdg":1800, "pit":98, "time":1791471737641 }
17:02:37.221 [WARN ] CPU still slowed: clock low all minute, 54 °C, running at 0.8 GHz of 2.9 GHz
17:02:37.222 [MQTT] PUB GGS/FWT/dev/Health {"fwt":"dev","state":"slowed","reason":"CPU is slowing itself down","guard":true,"cpu_c":54.0,"cpu_mhz":800,"cpu_busy_pct":66,"throttling":true,"throttle_events_last_min":0,"enclosure_c":21.0,"saved_last_min":2,"save_ms_mean":3660,"save_ms_max":3799,"held_s":0,"interval_s":10.0,"time":1791471757221}
17:02:41.302 [WARN ] waypoint 6/15: 23.6 s since the last picture, over the 10.0 s interval (move 22.6 s, exposure 1.0 s)
17:02:41.322 [INFO ] captured waypoint 6/15
17:02:41.332 [INFO ] scan move 7/15: yaw 45 pitch 5 (deg)
17:02:45.136 [INFO ] saving: 3 pictures in the last minute, 3711 ms each on average (longest 3814 ms)
17:02:45.136 [MQTT] PUB GGS/FWT/dev/CamEvent { "fwt":"dev", "cam":"RGB", "hdg":3598, "pit":34, "time":1791471761260 }
17:02:51.339 [INFO ] captured waypoint 7/15
17:02:51.351 [INFO ] scan move 9/15: yaw 135 pitch 5 (deg)
17:02:54.779 [MQTT] PUB GGS/FWT/dev/CamEvent { "fwt":"dev", "cam":"RGB", "hdg":451, "pit":36, "time":1791471771262 }
17:03:25.914 [WARN ] waypoint 9/15: 34.6 s since the last picture, over the 10.0 s interval (move 33.6 s, exposure 1.0 s)
17:03:25.932 [INFO ] captured waypoint 9/15
17:03:25.945 [INFO ] scan move 10/15: yaw 180 pitch 5 (deg)
17:03:29.611 [MQTT] PUB GGS/FWT/dev/CamEvent { "fwt":"dev", "cam":"RGB", "hdg":1352, "pit":43, "time":1791471805843 }
17:03:32.234 [INFO ] CPU: 56 °C (x86_pkg_temp), 0.8 GHz of 2.9 GHz, 72% busy
17:03:32.234 [INFO ] throttling: yes (clock), 0 in the last minute, 0 since start
17:03:32.234 [INFO ] scan pace: slowed - CPU is slowing itself down, one picture every 10.0 s
17:03:32.234 [INFO ] saving: 3 in the last minute, 3644 ms each (longest 3814 ms)
17:03:32.234 [INFO ] limits: slows at 85 °C, pauses at 92 °C for 20 s, resumes at 75 °C after at least 300 s
17:03:35.956 [INFO ] captured waypoint 10/15
17:03:35.967 [INFO ] scan move 11/15: yaw 0 pitch 15 (deg)
17:03:37.373 [WARN ] CPU still slowed: clock low all minute, 55 °C, running at 0.8 GHz of 2.9 GHz
17:03:37.374 [MQTT] PUB GGS/FWT/dev/Health {"fwt":"dev","state":"slowed","reason":"CPU is slowing itself down","guard":true,"cpu_c":55.0,"cpu_mhz":800,"cpu_busy_pct":88,"throttling":true,"throttle_events_last_min":0,"enclosure_c":21.0,"saved_last_min":3,"save_ms_mean":3644,"save_ms_max":3814,"held_s":0,"interval_s":10.0,"time":1791471817373}
17:03:39.531 [MQTT] PUB GGS/FWT/dev/CamEvent { "fwt":"dev", "cam":"RGB", "hdg":1800, "pit":46, "time":1791471815845 }
17:03:59.314 [WARN ] waypoint 11/15: 23.4 s since the last picture, over the 10.0 s interval (move 22.3 s, exposure 1.0 s)
17:03:59.419 [INFO ] captured waypoint 11/15
17:03:59.433 [INFO ] scan move 12/15: yaw 45 pitch 15 (deg)
17:04:03.336 [INFO ] saving: 3 pictures in the last minute, 3723 ms each on average (longest 3917 ms)
17:04:03.336 [MQTT] PUB GGS/FWT/dev/CamEvent { "fwt":"dev", "cam":"RGB", "hdg":3598, "pit":110, "time":1791471839281 }
17:04:09.440 [INFO ] captured waypoint 12/15
17:04:09.460 [INFO ] scan move 14/15: yaw 135 pitch 15 (deg)
17:04:12.912 [MQTT] PUB GGS/FWT/dev/CamEvent { "fwt":"dev", "cam":"RGB", "hdg":451, "pit":110, "time":1791471849379 }
17:04:37.498 [WARN ] CPU still slowed: clock low all minute, 55 °C, running at 0.8 GHz of 2.9 GHz
17:04:37.498 [MQTT] PUB GGS/FWT/dev/Health {"fwt":"dev","state":"slowed","reason":"CPU is slowing itself down","guard":true,"cpu_c":55.0,"cpu_mhz":800,"cpu_busy_pct":68,"throttling":true,"throttle_events_last_min":0,"enclosure_c":21.0,"saved_last_min":3,"save_ms_mean":3654,"save_ms_max":3917,"held_s":0,"interval_s":10.0,"time":1791471877498}
17:04:43.926 [WARN ] waypoint 14/15: 34.5 s since the last picture, over the 10.0 s interval (move 33.5 s, exposure 1.0 s)
17:04:43.945 [INFO ] captured waypoint 14/15
17:04:43.958 [INFO ] scan move 15/15: yaw 180 pitch 15 (deg)
17:04:47.588 [MQTT] PUB GGS/FWT/dev/CamEvent { "fwt":"dev", "cam":"RGB", "hdg":1353, "pit":118, "time":1791471883866 }
17:04:54.005 [INFO ] captured waypoint 15/15
17:04:54.015 [INFO ] scan move 1/15: yaw 0 pitch 10 (deg)
17:04:57.678 [MQTT] PUB GGS/FWT/dev/CamEvent { "fwt":"dev", "cam":"RGB", "hdg":1800, "pit":122, "time":1791471893874 }
17:05:17.599 [INFO ] captured waypoint 1/15
17:05:17.618 [INFO ] scan move 2/15: yaw 45 pitch 10 (deg)
17:05:21.659 [INFO ] saving: 3 pictures in the last minute, 3790 ms each on average (longest 4059 ms)
17:05:21.659 [MQTT] PUB GGS/FWT/dev/CamEvent { "fwt":"dev", "cam":"RGB", "hdg":3598, "pit":86, "time":1791471917492 }
17:05:27.622 [INFO ] captured waypoint 2/15
17:05:27.636 [INFO ] scan move 4/15: yaw 135 pitch 10 (deg)
17:05:31.188 [MQTT] PUB GGS/FWT/dev/CamEvent { "fwt":"dev", "cam":"RGB", "hdg":451, "pit":85, "time":1791471927590 }
17:05:32.236 [INFO ] CPU: 55 °C (x86_pkg_temp), 0.8 GHz of 2.9 GHz, 89% busy
17:05:32.236 [INFO ] throttling: yes (clock), 0 in the last minute, 0 since start
17:05:32.236 [INFO ] scan pace: slowed - CPU is slowing itself down, one picture every 10.0 s
17:05:32.237 [INFO ] saving: 4 in the last minute, 3734 ms each (longest 4059 ms)
17:05:32.237 [INFO ] limits: slows at 85 °C, pauses at 92 °C for 20 s, resumes at 75 °C after at least 300 s
17:05:37.647 [MQTT] PUB GGS/FWT/dev/Health {"fwt":"dev","state":"slowed","reason":"CPU is slowing itself down","guard":true,"cpu_c":54.0,"cpu_mhz":800,"cpu_busy_pct":14,"throttling":true,"throttle_events_last_min":0,"enclosure_c":21.0,"saved_last_min":4,"save_ms_mean":3734,"save_ms_max":4059,"held_s":0,"interval_s":10.0,"time":1791471937647}
17:06:02.200 [WARN ] waypoint 4/15: 34.6 s since the last picture, over the 10.0 s interval (move 33.6 s, exposure 1.0 s)
17:06:02.214 [INFO ] captured waypoint 4/15
17:06:02.225 [INFO ] scan move 5/15: yaw 180 pitch 10 (deg)
17:06:02.858 [MQTT] PUB GGS/FWT/dev/CamEvent { "fwt":"dev", "cam":"RGB", "hdg":1352, "pit":92, "time":1791471962171 }
17:06:12.236 [INFO ] captured waypoint 5/15
17:06:12.247 [INFO ] scan move 6/15: yaw 0 pitch 5 (deg)
17:06:12.864 [MQTT] PUB GGS/FWT/dev/CamEvent { "fwt":"dev", "cam":"RGB", "hdg":1800, "pit":97, "time":1791471972173 }
17:06:31.739 [INFO ] CPU back to full speed: 55 °C, 0.8 GHz
17:06:31.740 [MQTT] PUB GGS/FWT/dev/Health {"fwt":"dev","state":"slowed","reason":"CPU is slowing itself down","guard":true,"cpu_c":55.0,"cpu_mhz":800,"cpu_busy_pct":12,"throttling":false,"throttle_events_last_min":0,"enclosure_c":21.0,"saved_last_min":2,"save_ms_mean":636,"save_ms_max":644,"held_s":0,"interval_s":10.0,"time":1791471991739}
17:06:35.594 [WARN ] waypoint 6/15: 23.4 s since the last picture, over the 10.0 s interval (move 22.3 s, exposure 1.0 s)
17:06:35.608 [INFO ] captured waypoint 6/15
17:06:35.619 [INFO ] scan move 7/15: yaw 45 pitch 5 (deg)
17:06:36.330 [INFO ] saving: 3 pictures in the last minute, 664 ms each on average (longest 722 ms)
17:06:36.330 [MQTT] PUB GGS/FWT/dev/CamEvent { "fwt":"dev", "cam":"RGB", "hdg":3598, "pit":36, "time":1791471995513 }
17:06:45.624 [INFO ] captured waypoint 7/15
17:06:45.634 [INFO ] scan move 9/15: yaw 135 pitch 5 (deg)
17:06:46.258 [MQTT] PUB GGS/FWT/dev/CamEvent { "fwt":"dev", "cam":"RGB", "hdg":451, "pit":33, "time":1791472005515 }
17:07:02.295 [INFO ] CPU: 55 °C (x86_pkg_temp), 2.8 GHz of 2.9 GHz, 13% busy
17:07:02.295 [INFO ] throttling: no, 0 in the last minute, 0 since start
17:07:02.295 [INFO ] scan pace: slowed - CPU is slowing itself down, one picture every 10.0 s
17:07:02.295 [INFO ] saving: 4 in the last minute, 657 ms each (longest 722 ms)
17:07:02.295 [INFO ] limits: slows at 85 °C, pauses at 92 °C for 20 s, resumes at 75 °C after at least 300 s
17:07:20.203 [WARN ] waypoint 9/15: 34.6 s since the last picture, over the 10.0 s interval (move 33.6 s, exposure 1.0 s)
17:07:20.215 [INFO ] captured waypoint 9/15
17:07:20.226 [INFO ] scan move 10/15: yaw 180 pitch 5 (deg)
17:07:20.864 [MQTT] PUB GGS/FWT/dev/CamEvent { "fwt":"dev", "cam":"RGB", "hdg":1352, "pit":43, "time":1791472040191 }
17:07:30.234 [INFO ] captured waypoint 10/15
17:07:30.244 [INFO ] scan move 11/15: yaw 0 pitch 15 (deg)
17:07:30.864 [MQTT] PUB GGS/FWT/dev/CamEvent { "fwt":"dev", "cam":"RGB", "hdg":1800, "pit":47, "time":1791472050194 }
17:07:31.859 [MQTT] PUB GGS/FWT/dev/Health {"fwt":"dev","state":"slowed","reason":"CPU is slowing itself down","guard":true,"cpu_c":55.0,"cpu_mhz":800,"cpu_busy_pct":29,"throttling":false,"throttle_events_last_min":0,"enclosure_c":21.0,"saved_last_min":4,"save_ms_mean":659,"save_ms_max":722,"held_s":0,"interval_s":10.0,"time":1791472051859}
17:07:53.593 [WARN ] waypoint 11/15: 23.4 s since the last picture, over the 10.0 s interval (move 22.3 s, exposure 1.0 s)
17:07:53.604 [INFO ] captured waypoint 11/15
17:07:53.614 [INFO ] scan move 12/15: yaw 45 pitch 15 (deg)
17:07:54.293 [INFO ] saving: 3 pictures in the last minute, 656 ms each on average (longest 689 ms)
17:07:54.293 [MQTT] PUB GGS/FWT/dev/CamEvent { "fwt":"dev", "cam":"RGB", "hdg":3598, "pit":111, "time":1791472073533 }
17:08:03.621 [INFO ] captured waypoint 12/15
17:08:03.631 [INFO ] scan move 14/15: yaw 135 pitch 15 (deg)
17:08:04.270 [MQTT] PUB GGS/FWT/dev/CamEvent { "fwt":"dev", "cam":"RGB", "hdg":451, "pit":110, "time":1791472083536 }
17:08:31.957 [INFO ] CPU at 54 °C: back to the normal picture pace
17:08:31.957 [MQTT] PUB GGS/FWT/dev/Health {"fwt":"dev","state":"normal","reason":"","guard":true,"cpu_c":54.0,"cpu_mhz":800,"cpu_busy_pct":15,"throttling":false,"throttle_events_last_min":0,"enclosure_c":21.0,"saved_last_min":2,"save_ms_mean":669,"save_ms_max":689,"held_s":0,"interval_s":5.0,"time":1791472111957}
17:08:32.296 [INFO ] CPU: 54 °C (x86_pkg_temp), 0.8 GHz of 2.9 GHz, 15% busy
17:08:32.296 [INFO ] throttling: no, 0 in the last minute, 0 since start
17:08:32.296 [INFO ] scan pace: normal, one picture every 5.0 s
17:08:32.296 [INFO ] saving: 2 in the last minute, 669 ms each (longest 689 ms)
17:08:32.296 [INFO ] limits: slows at 85 °C, pauses at 92 °C for 20 s, resumes at 75 °C after at least 300 s
17:08:37.309 [INFO ] Shutting down

View File

@ -0,0 +1,57 @@
#!/bin/sh
# The program itself on tower 111 - real camera, gimbal, the tower's own config -
# with the CPU throttled: 3 min normal, 6 min at 800 MHz + 2 busy cores, 3 min
# restored. ~13 min. nohup sh ~/thermal-test/guard_run.sh > ~/thermal-test/guard_run.out 2>&1 &
set -u
# What scripts/fgc sets up for the program: the camera SDK's transport layer,
# and the MQTT credentials (read, not sourced).
export GENICAM_GENTL64_PATH=/opt/VimbaX/cti
CRED=/etc/fire_gimbal_control/credentials.env
if [ -r "$CRED" ]; then
FGC_MQTT_USER=$(sed -n 's/^FGC_MQTT_USER=//p' "$CRED")
FGC_MQTT_PW=$(sed -n 's/^FGC_MQTT_PW=//p' "$CRED")
export FGC_MQTT_USER FGC_MQTT_PW
fi
T=~/thermal-test
SIM=$T/software/tools/thermal-sim
BIN=$T/software/build/fire_gimbal_control
LOG=$T/guard_run.log
FIFO=$T/cmd.fifo
restore() {
sudo -n "$SIM/cap-cpu.sh" restore
pkill -f "stress-ng --cpu" 2>/dev/null
}
trap restore EXIT INT TERM
rm -f "$FIFO"; mkfifo "$FIFO"
sleep 100000 > "$FIFO" & # holds the console's stdin open
holder=$!
"$BIN" -c ~/.config/fire_gimbal_control/config.ini --no-tui --trace mqtt \
< "$FIFO" > "$LOG" 2>&1 &
pid=$!
say() { echo "$(date +%T) $*"; }
cmd() { echo "$1" > "$FIFO"; }
say "started pid $pid; normal for 3 min"
sleep 180
cmd thermal
say "cap 800 MHz + 2 busy cores for 6 min"
sudo -n "$SIM/cap-cpu.sh" 800
stress-ng --cpu 2 --timeout 360s --quiet &
sleep 120; cmd thermal
sleep 120; cmd thermal
sleep 120; cmd thermal
wait $! 2>/dev/null
sudo -n "$SIM/cap-cpu.sh" restore
say "restored; 3 min more"
sleep 90; cmd thermal
sleep 90; cmd thermal
sleep 5
say "stopping"
kill -TERM "$pid"
sleep 15
kill "$holder" 2>/dev/null
sleep 3
kill -0 "$pid" 2>/dev/null && { say "still running, killing"; kill -KILL "$pid"; } || say "program exited"
rm -f "$FIFO"

View File

@ -0,0 +1,61 @@
{"t": 1, "temp_c": 55.0, "mhz": 757, "cpu_pct": 3.5, "watts": 3.22, "rss_mb": 43}
{"t": 2, "temp_c": 54.0, "mhz": 797, "cpu_pct": 3.8, "watts": 2.30, "rss_mb": 43}
{"t": 3, "temp_c": 54.0, "mhz": 763, "cpu_pct": 5.0, "watts": 2.96, "rss_mb": 43}
{"t": 4, "temp_c": 54.0, "mhz": 795, "cpu_pct": 4.3, "watts": 2.96, "rss_mb": 43}
{"t": 5, "temp_c": 54.0, "mhz": 794, "cpu_pct": 4.3, "watts": 2.92, "rss_mb": 43}
{"t": 6, "temp_c": 54.0, "mhz": 800, "cpu_pct": 4.0, "watts": 2.95, "rss_mb": 43}
{"t": 7, "temp_c": 54.0, "mhz": 768, "cpu_pct": 4.0, "watts": 3.05, "rss_mb": 43}
{"t": 8, "temp_c": 54.0, "mhz": 728, "cpu_pct": 3.8, "watts": 2.98, "rss_mb": 43}
{"t": 9, "temp_c": 54.0, "mhz": 796, "cpu_pct": 4.8, "watts": 2.22, "rss_mb": 43}
{"t": 10, "temp_c": 54.0, "mhz": 777, "cpu_pct": 3.5, "watts": 2.88, "rss_mb": 43}
{"t": 11, "temp_c": 54.0, "mhz": 762, "cpu_pct": 4.5, "watts": 2.94, "rss_mb": 43}
{"t": 12, "temp_c": 53.0, "mhz": 800, "cpu_pct": 3.5, "watts": 2.91, "rss_mb": 43}
{"t": 13, "temp_c": 53.0, "mhz": 798, "cpu_pct": 4.3, "watts": 3.03, "rss_mb": 43}
{"t": 14, "temp_c": 53.0, "mhz": 771, "cpu_pct": 3.0, "watts": 3.00, "rss_mb": 43}
{"t": 15, "temp_c": 54.0, "mhz": 747, "cpu_pct": 5.3, "watts": 3.01, "rss_mb": 43}
{"t": 16, "temp_c": 53.0, "mhz": 775, "cpu_pct": 5.3, "watts": 2.13, "rss_mb": 43}
{"t": 17, "temp_c": 54.0, "mhz": 911, "cpu_pct": 21.3, "watts": 4.54, "rss_mb": 43}
{"t": 18, "temp_c": 53.0, "mhz": 803, "cpu_pct": 3.3, "watts": 2.94, "rss_mb": 43}
{"t": 19, "temp_c": 53.0, "mhz": 775, "cpu_pct": 4.0, "watts": 3.01, "rss_mb": 43}
{"t": 20, "temp_c": 53.0, "mhz": 788, "cpu_pct": 3.3, "watts": 2.94, "rss_mb": 43}
{"t": 21, "temp_c": 53.0, "mhz": 800, "cpu_pct": 6.3, "watts": 3.07, "rss_mb": 43}
{"t": 22, "temp_c": 54.0, "mhz": 773, "cpu_pct": 5.0, "watts": 3.04, "rss_mb": 43}
{"t": 23, "temp_c": 53.0, "mhz": 794, "cpu_pct": 4.0, "watts": 2.14, "rss_mb": 43}
{"t": 24, "temp_c": 53.0, "mhz": 830, "cpu_pct": 4.1, "watts": 2.94, "rss_mb": 43}
{"t": 25, "temp_c": 52.0, "mhz": 783, "cpu_pct": 3.5, "watts": 3.01, "rss_mb": 43}
{"t": 26, "temp_c": 52.0, "mhz": 785, "cpu_pct": 4.0, "watts": 2.91, "rss_mb": 43}
{"t": 27, "temp_c": 52.0, "mhz": 1565, "cpu_pct": 6.3, "watts": 2.99, "rss_mb": 43}
{"t": 28, "temp_c": 52.0, "mhz": 788, "cpu_pct": 3.8, "watts": 2.97, "rss_mb": 43}
{"t": 29, "temp_c": 53.0, "mhz": 767, "cpu_pct": 3.8, "watts": 2.94, "rss_mb": 43}
{"t": 30, "temp_c": 53.0, "mhz": 800, "cpu_pct": 3.8, "watts": 2.12, "rss_mb": 43}
{"t": 31, "temp_c": 52.0, "mhz": 787, "cpu_pct": 3.5, "watts": 2.97, "rss_mb": 43}
{"t": 32, "temp_c": 52.0, "mhz": 794, "cpu_pct": 4.5, "watts": 2.95, "rss_mb": 43}
{"t": 33, "temp_c": 53.0, "mhz": 789, "cpu_pct": 5.0, "watts": 2.98, "rss_mb": 43}
{"t": 34, "temp_c": 53.0, "mhz": 793, "cpu_pct": 3.8, "watts": 2.98, "rss_mb": 43}
{"t": 35, "temp_c": 54.0, "mhz": 800, "cpu_pct": 3.8, "watts": 2.81, "rss_mb": 43}
{"t": 36, "temp_c": 53.0, "mhz": 1300, "cpu_pct": 4.0, "watts": 2.93, "rss_mb": 43}
{"t": 37, "temp_c": 53.0, "mhz": 788, "cpu_pct": 3.3, "watts": 2.29, "rss_mb": 43}
{"t": 38, "temp_c": 53.0, "mhz": 776, "cpu_pct": 3.8, "watts": 2.92, "rss_mb": 43}
{"t": 39, "temp_c": 53.0, "mhz": 1483, "cpu_pct": 5.6, "watts": 2.94, "rss_mb": 43}
{"t": 40, "temp_c": 53.0, "mhz": 793, "cpu_pct": 4.0, "watts": 3.12, "rss_mb": 43}
{"t": 41, "temp_c": 52.0, "mhz": 802, "cpu_pct": 3.8, "watts": 2.78, "rss_mb": 43}
{"t": 42, "temp_c": 53.0, "mhz": 1379, "cpu_pct": 4.5, "watts": 2.97, "rss_mb": 43}
{"t": 43, "temp_c": 51.0, "mhz": 760, "cpu_pct": 2.8, "watts": 2.89, "rss_mb": 43}
{"t": 44, "temp_c": 51.0, "mhz": 791, "cpu_pct": 4.5, "watts": 2.28, "rss_mb": 43}
{"t": 45, "temp_c": 52.0, "mhz": 795, "cpu_pct": 5.5, "watts": 2.94, "rss_mb": 43}
{"t": 46, "temp_c": 52.0, "mhz": 773, "cpu_pct": 4.0, "watts": 2.89, "rss_mb": 43}
{"t": 47, "temp_c": 52.0, "mhz": 1401, "cpu_pct": 6.8, "watts": 2.91, "rss_mb": 43}
{"t": 48, "temp_c": 53.0, "mhz": 1531, "cpu_pct": 22.9, "watts": 4.61, "rss_mb": 43}
{"t": 49, "temp_c": 52.0, "mhz": 777, "cpu_pct": 3.0, "watts": 2.91, "rss_mb": 43}
{"t": 50, "temp_c": 51.0, "mhz": 797, "cpu_pct": 4.3, "watts": 2.95, "rss_mb": 43}
{"t": 51, "temp_c": 52.0, "mhz": 786, "cpu_pct": 4.8, "watts": 2.28, "rss_mb": 43}
{"t": 52, "temp_c": 51.0, "mhz": 804, "cpu_pct": 3.5, "watts": 2.83, "rss_mb": 43}
{"t": 53, "temp_c": 52.0, "mhz": 928, "cpu_pct": 4.3, "watts": 2.92, "rss_mb": 43}
{"t": 54, "temp_c": 52.0, "mhz": 2590, "cpu_pct": 4.5, "watts": 2.96, "rss_mb": 43}
{"t": 55, "temp_c": 51.0, "mhz": 791, "cpu_pct": 3.3, "watts": 2.98, "rss_mb": 43}
{"t": 56, "temp_c": 52.0, "mhz": 759, "cpu_pct": 4.5, "watts": 2.94, "rss_mb": 43}
{"t": 57, "temp_c": 52.0, "mhz": 801, "cpu_pct": 6.0, "watts": 3.13, "rss_mb": 43}
{"t": 58, "temp_c": 51.0, "mhz": 800, "cpu_pct": 3.8, "watts": 2.07, "rss_mb": 43}
{"t": 59, "temp_c": 52.0, "mhz": 797, "cpu_pct": 4.5, "watts": 2.92, "rss_mb": 43}
{"t": 60, "temp_c": 52.0, "mhz": 2423, "cpu_pct": 4.5, "watts": 2.97, "rss_mb": 43}
{"summary": "idle", "secs": 60, "temp_c_mean": 52.8, "temp_c_max": 55.0, "mhz_mean": 913, "cpu_pct_mean": 4.8, "watts_mean": 2.90}

View File

@ -0,0 +1,61 @@
{"t": 1, "temp_c": 53.0, "mhz": 800, "cpu_pct": 5.5, "watts": 3.47, "rss_mb": 43}
{"t": 2, "temp_c": 52.0, "mhz": 787, "cpu_pct": 4.8, "watts": 3.01, "rss_mb": 43}
{"t": 3, "temp_c": 52.0, "mhz": 800, "cpu_pct": 4.0, "watts": 2.97, "rss_mb": 43}
{"t": 4, "temp_c": 54.0, "mhz": 1188, "cpu_pct": 4.5, "watts": 2.85, "rss_mb": 43}
{"t": 5, "temp_c": 51.0, "mhz": 878, "cpu_pct": 2.5, "watts": 2.87, "rss_mb": 43}
{"t": 6, "temp_c": 52.0, "mhz": 800, "cpu_pct": 4.5, "watts": 2.34, "rss_mb": 43}
{"t": 7, "temp_c": 51.0, "mhz": 791, "cpu_pct": 5.0, "watts": 3.03, "rss_mb": 43}
{"t": 8, "temp_c": 52.0, "mhz": 791, "cpu_pct": 4.3, "watts": 2.95, "rss_mb": 43}
{"t": 9, "temp_c": 52.0, "mhz": 835, "cpu_pct": 3.5, "watts": 2.76, "rss_mb": 43}
{"t": 10, "temp_c": 52.0, "mhz": 2785, "cpu_pct": 5.0, "watts": 2.96, "rss_mb": 43}
{"t": 11, "temp_c": 52.0, "mhz": 772, "cpu_pct": 2.3, "watts": 2.97, "rss_mb": 43}
{"t": 12, "temp_c": 52.0, "mhz": 757, "cpu_pct": 4.5, "watts": 2.93, "rss_mb": 43}
{"t": 13, "temp_c": 52.0, "mhz": 768, "cpu_pct": 5.8, "watts": 2.47, "rss_mb": 43}
{"t": 14, "temp_c": 52.0, "mhz": 797, "cpu_pct": 3.8, "watts": 2.86, "rss_mb": 43}
{"t": 15, "temp_c": 52.0, "mhz": 795, "cpu_pct": 3.0, "watts": 2.83, "rss_mb": 43}
{"t": 16, "temp_c": 52.0, "mhz": 1254, "cpu_pct": 5.5, "watts": 3.05, "rss_mb": 43}
{"t": 17, "temp_c": 51.0, "mhz": 794, "cpu_pct": 2.3, "watts": 2.94, "rss_mb": 43}
{"t": 18, "temp_c": 51.0, "mhz": 796, "cpu_pct": 4.3, "watts": 2.96, "rss_mb": 43}
{"t": 19, "temp_c": 52.0, "mhz": 761, "cpu_pct": 5.5, "watts": 3.04, "rss_mb": 43}
{"t": 20, "temp_c": 51.0, "mhz": 798, "cpu_pct": 3.8, "watts": 2.13, "rss_mb": 43}
{"t": 21, "temp_c": 52.0, "mhz": 800, "cpu_pct": 4.3, "watts": 2.92, "rss_mb": 43}
{"t": 22, "temp_c": 53.0, "mhz": 876, "cpu_pct": 4.5, "watts": 3.01, "rss_mb": 43}
{"t": 23, "temp_c": 54.0, "mhz": 900, "cpu_pct": 18.5, "watts": 3.94, "rss_mb": 43}
{"t": 24, "temp_c": 51.0, "mhz": 798, "cpu_pct": 7.3, "watts": 3.55, "rss_mb": 43}
{"t": 25, "temp_c": 51.0, "mhz": 800, "cpu_pct": 4.8, "watts": 2.98, "rss_mb": 43}
{"t": 26, "temp_c": 52.0, "mhz": 787, "cpu_pct": 3.5, "watts": 2.98, "rss_mb": 43}
{"t": 27, "temp_c": 51.0, "mhz": 794, "cpu_pct": 4.0, "watts": 2.12, "rss_mb": 43}
{"t": 28, "temp_c": 52.0, "mhz": 1107, "cpu_pct": 6.0, "watts": 3.08, "rss_mb": 43}
{"t": 29, "temp_c": 51.0, "mhz": 773, "cpu_pct": 2.8, "watts": 2.94, "rss_mb": 43}
{"t": 30, "temp_c": 51.0, "mhz": 800, "cpu_pct": 3.5, "watts": 2.95, "rss_mb": 43}
{"t": 31, "temp_c": 51.0, "mhz": 798, "cpu_pct": 5.0, "watts": 2.98, "rss_mb": 43}
{"t": 32, "temp_c": 51.0, "mhz": 790, "cpu_pct": 4.0, "watts": 2.93, "rss_mb": 43}
{"t": 33, "temp_c": 52.0, "mhz": 765, "cpu_pct": 4.0, "watts": 2.91, "rss_mb": 43}
{"t": 34, "temp_c": 52.0, "mhz": 800, "cpu_pct": 5.3, "watts": 2.19, "rss_mb": 43}
{"t": 35, "temp_c": 52.0, "mhz": 771, "cpu_pct": 3.0, "watts": 2.94, "rss_mb": 43}
{"t": 36, "temp_c": 51.0, "mhz": 800, "cpu_pct": 3.8, "watts": 2.91, "rss_mb": 43}
{"t": 37, "temp_c": 51.0, "mhz": 794, "cpu_pct": 5.0, "watts": 2.92, "rss_mb": 43}
{"t": 38, "temp_c": 51.0, "mhz": 754, "cpu_pct": 4.3, "watts": 2.94, "rss_mb": 43}
{"t": 39, "temp_c": 51.0, "mhz": 800, "cpu_pct": 4.3, "watts": 2.90, "rss_mb": 43}
{"t": 40, "temp_c": 52.0, "mhz": 1385, "cpu_pct": 4.8, "watts": 2.95, "rss_mb": 43}
{"t": 41, "temp_c": 51.0, "mhz": 778, "cpu_pct": 2.8, "watts": 2.07, "rss_mb": 43}
{"t": 42, "temp_c": 51.0, "mhz": 752, "cpu_pct": 4.3, "watts": 2.90, "rss_mb": 43}
{"t": 43, "temp_c": 51.0, "mhz": 787, "cpu_pct": 6.3, "watts": 3.10, "rss_mb": 43}
{"t": 44, "temp_c": 51.0, "mhz": 787, "cpu_pct": 4.5, "watts": 2.93, "rss_mb": 43}
{"t": 45, "temp_c": 52.0, "mhz": 765, "cpu_pct": 3.8, "watts": 2.91, "rss_mb": 43}
{"t": 46, "temp_c": 52.0, "mhz": 2499, "cpu_pct": 5.6, "watts": 2.86, "rss_mb": 43}
{"t": 47, "temp_c": 51.0, "mhz": 2820, "cpu_pct": 3.0, "watts": 2.90, "rss_mb": 43}
{"t": 48, "temp_c": 51.0, "mhz": 791, "cpu_pct": 3.8, "watts": 2.30, "rss_mb": 43}
{"t": 49, "temp_c": 51.0, "mhz": 796, "cpu_pct": 5.3, "watts": 2.96, "rss_mb": 43}
{"t": 50, "temp_c": 51.0, "mhz": 786, "cpu_pct": 3.8, "watts": 2.91, "rss_mb": 43}
{"t": 51, "temp_c": 52.0, "mhz": 801, "cpu_pct": 3.3, "watts": 2.75, "rss_mb": 43}
{"t": 52, "temp_c": 52.0, "mhz": 2800, "cpu_pct": 4.5, "watts": 2.99, "rss_mb": 43}
{"t": 53, "temp_c": 51.0, "mhz": 2414, "cpu_pct": 4.0, "watts": 2.91, "rss_mb": 43}
{"t": 54, "temp_c": 56.0, "mhz": 2800, "cpu_pct": 21.1, "watts": 4.36, "rss_mb": 43}
{"t": 55, "temp_c": 53.0, "mhz": 795, "cpu_pct": 6.5, "watts": 2.44, "rss_mb": 43}
{"t": 56, "temp_c": 51.0, "mhz": 794, "cpu_pct": 4.5, "watts": 2.87, "rss_mb": 43}
{"t": 57, "temp_c": 51.0, "mhz": 800, "cpu_pct": 3.5, "watts": 2.91, "rss_mb": 43}
{"t": 58, "temp_c": 51.0, "mhz": 800, "cpu_pct": 5.3, "watts": 3.09, "rss_mb": 43}
{"t": 59, "temp_c": 51.0, "mhz": 657, "cpu_pct": 3.8, "watts": 2.95, "rss_mb": 43}
{"t": 60, "temp_c": 51.0, "mhz": 767, "cpu_pct": 4.0, "watts": 2.92, "rss_mb": 43}
{"summary": "idle", "secs": 60, "temp_c_mean": 51.7, "temp_c_max": 56.0, "mhz_mean": 1010, "cpu_pct_mean": 4.9, "watts_mean": 2.91}

View File

@ -0,0 +1,61 @@
{"t": 1, "temp_c": 54.0, "mhz": 891, "cpu_pct": 3.0, "watts": 3.18, "rss_mb": 43}
{"t": 2, "temp_c": 53.0, "mhz": 800, "cpu_pct": 4.3, "watts": 2.30, "rss_mb": 43}
{"t": 3, "temp_c": 52.0, "mhz": 792, "cpu_pct": 6.3, "watts": 3.11, "rss_mb": 43}
{"t": 4, "temp_c": 54.0, "mhz": 800, "cpu_pct": 3.5, "watts": 2.85, "rss_mb": 43}
{"t": 5, "temp_c": 53.0, "mhz": 813, "cpu_pct": 3.8, "watts": 2.86, "rss_mb": 43}
{"t": 6, "temp_c": 54.0, "mhz": 2506, "cpu_pct": 4.5, "watts": 3.04, "rss_mb": 43}
{"t": 7, "temp_c": 53.0, "mhz": 795, "cpu_pct": 2.8, "watts": 2.94, "rss_mb": 43}
{"t": 8, "temp_c": 53.0, "mhz": 784, "cpu_pct": 4.5, "watts": 2.95, "rss_mb": 43}
{"t": 9, "temp_c": 53.0, "mhz": 784, "cpu_pct": 4.5, "watts": 2.33, "rss_mb": 43}
{"t": 10, "temp_c": 52.0, "mhz": 797, "cpu_pct": 3.0, "watts": 2.74, "rss_mb": 43}
{"t": 11, "temp_c": 53.0, "mhz": 790, "cpu_pct": 5.0, "watts": 2.93, "rss_mb": 43}
{"t": 12, "temp_c": 54.0, "mhz": 2840, "cpu_pct": 4.8, "watts": 3.02, "rss_mb": 43}
{"t": 13, "temp_c": 52.0, "mhz": 797, "cpu_pct": 2.8, "watts": 2.96, "rss_mb": 43}
{"t": 14, "temp_c": 53.0, "mhz": 791, "cpu_pct": 4.0, "watts": 2.94, "rss_mb": 43}
{"t": 15, "temp_c": 53.0, "mhz": 718, "cpu_pct": 4.5, "watts": 2.99, "rss_mb": 43}
{"t": 16, "temp_c": 52.0, "mhz": 756, "cpu_pct": 3.3, "watts": 2.08, "rss_mb": 43}
{"t": 17, "temp_c": 53.0, "mhz": 796, "cpu_pct": 4.3, "watts": 2.92, "rss_mb": 43}
{"t": 18, "temp_c": 53.0, "mhz": 1035, "cpu_pct": 4.8, "watts": 2.99, "rss_mb": 43}
{"t": 19, "temp_c": 52.0, "mhz": 800, "cpu_pct": 3.3, "watts": 2.93, "rss_mb": 43}
{"t": 20, "temp_c": 62.0, "mhz": 2800, "cpu_pct": 10.2, "watts": 3.15, "rss_mb": 43}
{"t": 21, "temp_c": 54.0, "mhz": 772, "cpu_pct": 18.3, "watts": 4.66, "rss_mb": 43}
{"t": 22, "temp_c": 53.0, "mhz": 762, "cpu_pct": 3.5, "watts": 2.93, "rss_mb": 43}
{"t": 23, "temp_c": 52.0, "mhz": 781, "cpu_pct": 4.8, "watts": 2.16, "rss_mb": 43}
{"t": 24, "temp_c": 53.0, "mhz": 1121, "cpu_pct": 5.5, "watts": 3.00, "rss_mb": 43}
{"t": 25, "temp_c": 51.0, "mhz": 711, "cpu_pct": 3.0, "watts": 2.91, "rss_mb": 43}
{"t": 26, "temp_c": 52.0, "mhz": 748, "cpu_pct": 3.5, "watts": 2.94, "rss_mb": 43}
{"t": 27, "temp_c": 52.0, "mhz": 773, "cpu_pct": 4.8, "watts": 2.99, "rss_mb": 43}
{"t": 28, "temp_c": 51.0, "mhz": 776, "cpu_pct": 4.5, "watts": 2.93, "rss_mb": 43}
{"t": 29, "temp_c": 52.0, "mhz": 731, "cpu_pct": 4.5, "watts": 2.98, "rss_mb": 43}
{"t": 30, "temp_c": 52.0, "mhz": 785, "cpu_pct": 4.0, "watts": 2.11, "rss_mb": 43}
{"t": 31, "temp_c": 52.0, "mhz": 2803, "cpu_pct": 3.0, "watts": 2.97, "rss_mb": 43}
{"t": 32, "temp_c": 51.0, "mhz": 798, "cpu_pct": 3.0, "watts": 2.97, "rss_mb": 43}
{"t": 33, "temp_c": 52.0, "mhz": 768, "cpu_pct": 4.8, "watts": 2.98, "rss_mb": 43}
{"t": 34, "temp_c": 52.0, "mhz": 776, "cpu_pct": 4.5, "watts": 2.97, "rss_mb": 43}
{"t": 35, "temp_c": 51.0, "mhz": 795, "cpu_pct": 4.3, "watts": 2.93, "rss_mb": 43}
{"t": 36, "temp_c": 52.0, "mhz": 800, "cpu_pct": 4.1, "watts": 2.99, "rss_mb": 43}
{"t": 37, "temp_c": 52.0, "mhz": 2808, "cpu_pct": 3.5, "watts": 2.12, "rss_mb": 43}
{"t": 38, "temp_c": 51.0, "mhz": 796, "cpu_pct": 2.8, "watts": 2.95, "rss_mb": 43}
{"t": 39, "temp_c": 51.0, "mhz": 766, "cpu_pct": 6.0, "watts": 3.06, "rss_mb": 43}
{"t": 40, "temp_c": 51.0, "mhz": 776, "cpu_pct": 4.3, "watts": 2.90, "rss_mb": 43}
{"t": 41, "temp_c": 51.0, "mhz": 751, "cpu_pct": 4.3, "watts": 2.97, "rss_mb": 43}
{"t": 42, "temp_c": 51.0, "mhz": 796, "cpu_pct": 4.3, "watts": 2.94, "rss_mb": 43}
{"t": 43, "temp_c": 53.0, "mhz": 2800, "cpu_pct": 4.3, "watts": 2.10, "rss_mb": 43}
{"t": 44, "temp_c": 51.0, "mhz": 793, "cpu_pct": 1.8, "watts": 2.89, "rss_mb": 43}
{"t": 45, "temp_c": 51.0, "mhz": 782, "cpu_pct": 5.8, "watts": 2.97, "rss_mb": 43}
{"t": 46, "temp_c": 51.0, "mhz": 751, "cpu_pct": 4.3, "watts": 2.93, "rss_mb": 43}
{"t": 47, "temp_c": 52.0, "mhz": 750, "cpu_pct": 3.8, "watts": 2.93, "rss_mb": 43}
{"t": 48, "temp_c": 51.0, "mhz": 796, "cpu_pct": 4.8, "watts": 2.99, "rss_mb": 43}
{"t": 49, "temp_c": 52.0, "mhz": 1222, "cpu_pct": 3.3, "watts": 2.82, "rss_mb": 43}
{"t": 50, "temp_c": 51.0, "mhz": 791, "cpu_pct": 2.3, "watts": 2.14, "rss_mb": 43}
{"t": 51, "temp_c": 54.0, "mhz": 820, "cpu_pct": 14.6, "watts": 3.35, "rss_mb": 43}
{"t": 52, "temp_c": 51.0, "mhz": 770, "cpu_pct": 12.2, "watts": 4.17, "rss_mb": 43}
{"t": 53, "temp_c": 51.0, "mhz": 765, "cpu_pct": 4.3, "watts": 2.95, "rss_mb": 43}
{"t": 54, "temp_c": 52.0, "mhz": 795, "cpu_pct": 4.0, "watts": 2.94, "rss_mb": 43}
{"t": 55, "temp_c": 52.0, "mhz": 834, "cpu_pct": 3.3, "watts": 2.81, "rss_mb": 43}
{"t": 56, "temp_c": 51.0, "mhz": 800, "cpu_pct": 3.0, "watts": 2.89, "rss_mb": 43}
{"t": 57, "temp_c": 51.0, "mhz": 800, "cpu_pct": 6.8, "watts": 3.13, "rss_mb": 43}
{"t": 58, "temp_c": 51.0, "mhz": 781, "cpu_pct": 3.3, "watts": 2.32, "rss_mb": 43}
{"t": 59, "temp_c": 51.0, "mhz": 790, "cpu_pct": 4.5, "watts": 2.95, "rss_mb": 43}
{"t": 60, "temp_c": 52.0, "mhz": 797, "cpu_pct": 4.0, "watts": 2.73, "rss_mb": 43}
{"summary": "idle", "secs": 60, "temp_c_mean": 52.2, "temp_c_max": 62.0, "mhz_mean": 999, "cpu_pct_mean": 4.7, "watts_mean": 2.89}

View File

@ -0,0 +1,61 @@
{"t": 1, "temp_c": 52.0, "mhz": 779, "cpu_pct": 3.0, "watts": 3.15, "rss_mb": 42}
{"t": 2, "temp_c": 52.0, "mhz": 1084, "cpu_pct": 4.8, "watts": 3.04, "rss_mb": 43}
{"t": 3, "temp_c": 52.0, "mhz": 798, "cpu_pct": 3.5, "watts": 2.33, "rss_mb": 43}
{"t": 4, "temp_c": 51.0, "mhz": 790, "cpu_pct": 3.8, "watts": 2.98, "rss_mb": 43}
{"t": 5, "temp_c": 52.0, "mhz": 772, "cpu_pct": 5.3, "watts": 2.94, "rss_mb": 43}
{"t": 6, "temp_c": 52.0, "mhz": 801, "cpu_pct": 3.8, "watts": 2.87, "rss_mb": 43}
{"t": 7, "temp_c": 51.0, "mhz": 800, "cpu_pct": 3.0, "watts": 2.95, "rss_mb": 43}
{"t": 8, "temp_c": 52.0, "mhz": 799, "cpu_pct": 5.8, "watts": 3.13, "rss_mb": 43}
{"t": 9, "temp_c": 51.0, "mhz": 794, "cpu_pct": 4.0, "watts": 2.32, "rss_mb": 43}
{"t": 10, "temp_c": 51.0, "mhz": 800, "cpu_pct": 3.5, "watts": 2.91, "rss_mb": 43}
{"t": 11, "temp_c": 51.0, "mhz": 777, "cpu_pct": 5.5, "watts": 2.90, "rss_mb": 43}
{"t": 12, "temp_c": 51.0, "mhz": 862, "cpu_pct": 4.0, "watts": 2.90, "rss_mb": 43}
{"t": 13, "temp_c": 52.0, "mhz": 1300, "cpu_pct": 3.5, "watts": 2.96, "rss_mb": 43}
{"t": 14, "temp_c": 51.0, "mhz": 778, "cpu_pct": 4.8, "watts": 3.06, "rss_mb": 43}
{"t": 15, "temp_c": 51.0, "mhz": 775, "cpu_pct": 3.8, "watts": 2.97, "rss_mb": 43}
{"t": 16, "temp_c": 51.0, "mhz": 758, "cpu_pct": 3.8, "watts": 2.31, "rss_mb": 43}
{"t": 17, "temp_c": 51.0, "mhz": 795, "cpu_pct": 4.0, "watts": 2.86, "rss_mb": 43}
{"t": 18, "temp_c": 51.0, "mhz": 800, "cpu_pct": 4.0, "watts": 2.91, "rss_mb": 43}
{"t": 19, "temp_c": 51.0, "mhz": 1273, "cpu_pct": 3.8, "watts": 3.00, "rss_mb": 43}
{"t": 20, "temp_c": 52.0, "mhz": 771, "cpu_pct": 4.5, "watts": 3.02, "rss_mb": 43}
{"t": 21, "temp_c": 51.0, "mhz": 797, "cpu_pct": 4.3, "watts": 2.98, "rss_mb": 43}
{"t": 22, "temp_c": 52.0, "mhz": 787, "cpu_pct": 3.8, "watts": 2.89, "rss_mb": 43}
{"t": 23, "temp_c": 51.0, "mhz": 800, "cpu_pct": 5.1, "watts": 2.19, "rss_mb": 43}
{"t": 24, "temp_c": 51.0, "mhz": 856, "cpu_pct": 5.3, "watts": 2.93, "rss_mb": 43}
{"t": 25, "temp_c": 52.0, "mhz": 799, "cpu_pct": 20.9, "watts": 4.73, "rss_mb": 43}
{"t": 26, "temp_c": 51.0, "mhz": 780, "cpu_pct": 5.6, "watts": 3.11, "rss_mb": 43}
{"t": 27, "temp_c": 51.0, "mhz": 800, "cpu_pct": 4.0, "watts": 2.87, "rss_mb": 43}
{"t": 28, "temp_c": 51.0, "mhz": 757, "cpu_pct": 4.0, "watts": 2.95, "rss_mb": 43}
{"t": 29, "temp_c": 51.0, "mhz": 800, "cpu_pct": 5.3, "watts": 2.22, "rss_mb": 43}
{"t": 30, "temp_c": 52.0, "mhz": 2051, "cpu_pct": 4.5, "watts": 2.98, "rss_mb": 43}
{"t": 31, "temp_c": 51.0, "mhz": 796, "cpu_pct": 2.5, "watts": 2.98, "rss_mb": 43}
{"t": 32, "temp_c": 51.0, "mhz": 782, "cpu_pct": 3.8, "watts": 2.94, "rss_mb": 43}
{"t": 33, "temp_c": 51.0, "mhz": 796, "cpu_pct": 3.3, "watts": 2.90, "rss_mb": 43}
{"t": 34, "temp_c": 51.0, "mhz": 790, "cpu_pct": 4.5, "watts": 2.92, "rss_mb": 43}
{"t": 35, "temp_c": 51.0, "mhz": 763, "cpu_pct": 6.3, "watts": 3.06, "rss_mb": 43}
{"t": 36, "temp_c": 52.0, "mhz": 866, "cpu_pct": 4.0, "watts": 2.14, "rss_mb": 43}
{"t": 37, "temp_c": 51.0, "mhz": 797, "cpu_pct": 2.0, "watts": 2.94, "rss_mb": 43}
{"t": 38, "temp_c": 51.0, "mhz": 787, "cpu_pct": 3.8, "watts": 2.98, "rss_mb": 43}
{"t": 39, "temp_c": 51.0, "mhz": 800, "cpu_pct": 4.8, "watts": 2.96, "rss_mb": 43}
{"t": 40, "temp_c": 51.0, "mhz": 735, "cpu_pct": 4.5, "watts": 2.93, "rss_mb": 43}
{"t": 41, "temp_c": 51.0, "mhz": 792, "cpu_pct": 6.5, "watts": 3.10, "rss_mb": 43}
{"t": 42, "temp_c": 52.0, "mhz": 1260, "cpu_pct": 3.3, "watts": 2.89, "rss_mb": 43}
{"t": 43, "temp_c": 51.0, "mhz": 800, "cpu_pct": 2.0, "watts": 2.13, "rss_mb": 43}
{"t": 44, "temp_c": 51.0, "mhz": 789, "cpu_pct": 5.0, "watts": 3.00, "rss_mb": 43}
{"t": 45, "temp_c": 51.0, "mhz": 796, "cpu_pct": 4.3, "watts": 2.93, "rss_mb": 43}
{"t": 46, "temp_c": 51.0, "mhz": 783, "cpu_pct": 4.3, "watts": 2.97, "rss_mb": 43}
{"t": 47, "temp_c": 51.0, "mhz": 777, "cpu_pct": 5.0, "watts": 2.98, "rss_mb": 43}
{"t": 48, "temp_c": 52.0, "mhz": 861, "cpu_pct": 3.3, "watts": 2.75, "rss_mb": 43}
{"t": 49, "temp_c": 51.0, "mhz": 779, "cpu_pct": 3.0, "watts": 2.90, "rss_mb": 43}
{"t": 50, "temp_c": 51.0, "mhz": 794, "cpu_pct": 4.3, "watts": 2.28, "rss_mb": 43}
{"t": 51, "temp_c": 51.0, "mhz": 778, "cpu_pct": 4.0, "watts": 2.95, "rss_mb": 43}
{"t": 52, "temp_c": 51.0, "mhz": 774, "cpu_pct": 4.8, "watts": 2.95, "rss_mb": 43}
{"t": 53, "temp_c": 51.0, "mhz": 790, "cpu_pct": 4.5, "watts": 2.84, "rss_mb": 43}
{"t": 54, "temp_c": 52.0, "mhz": 1624, "cpu_pct": 4.5, "watts": 2.92, "rss_mb": 43}
{"t": 55, "temp_c": 51.0, "mhz": 800, "cpu_pct": 5.0, "watts": 3.13, "rss_mb": 43}
{"t": 56, "temp_c": 51.0, "mhz": 764, "cpu_pct": 24.8, "watts": 4.61, "rss_mb": 43}
{"t": 57, "temp_c": 51.0, "mhz": 800, "cpu_pct": 3.8, "watts": 2.91, "rss_mb": 43}
{"t": 58, "temp_c": 51.0, "mhz": 797, "cpu_pct": 4.3, "watts": 2.12, "rss_mb": 43}
{"t": 59, "temp_c": 51.0, "mhz": 1127, "cpu_pct": 5.6, "watts": 3.01, "rss_mb": 43}
{"t": 60, "temp_c": 51.0, "mhz": 786, "cpu_pct": 3.3, "watts": 2.94, "rss_mb": 43}
{"summary": "idle", "secs": 60, "temp_c_mean": 51.2, "temp_c_max": 52.0, "mhz_mean": 862, "cpu_pct_mean": 4.8, "watts_mean": 2.91}

View File

@ -0,0 +1,61 @@
{"t": 1, "temp_c": 49.0, "mhz": 800, "cpu_pct": 7.6, "watts": -1.00, "rss_mb": 43}
{"t": 2, "temp_c": 48.0, "mhz": 800, "cpu_pct": 2.5, "watts": -1.00, "rss_mb": 43}
{"t": 3, "temp_c": 49.0, "mhz": 780, "cpu_pct": 2.5, "watts": -1.00, "rss_mb": 43}
{"t": 4, "temp_c": 49.0, "mhz": 2456, "cpu_pct": 4.5, "watts": -1.00, "rss_mb": 43}
{"t": 5, "temp_c": 48.0, "mhz": 794, "cpu_pct": 3.8, "watts": -1.00, "rss_mb": 43}
{"t": 6, "temp_c": 50.0, "mhz": 781, "cpu_pct": 22.0, "watts": -1.00, "rss_mb": 43}
{"t": 7, "temp_c": 48.0, "mhz": 786, "cpu_pct": 3.5, "watts": -1.00, "rss_mb": 43}
{"t": 8, "temp_c": 48.0, "mhz": 794, "cpu_pct": 2.8, "watts": -1.00, "rss_mb": 43}
{"t": 9, "temp_c": 48.0, "mhz": 793, "cpu_pct": 3.0, "watts": -1.00, "rss_mb": 43}
{"t": 10, "temp_c": 49.0, "mhz": 1249, "cpu_pct": 4.0, "watts": -1.00, "rss_mb": 43}
{"t": 11, "temp_c": 48.0, "mhz": 761, "cpu_pct": 1.8, "watts": -1.00, "rss_mb": 43}
{"t": 12, "temp_c": 48.0, "mhz": 798, "cpu_pct": 2.8, "watts": -1.00, "rss_mb": 43}
{"t": 13, "temp_c": 47.0, "mhz": 794, "cpu_pct": 3.5, "watts": -1.00, "rss_mb": 43}
{"t": 14, "temp_c": 48.0, "mhz": 767, "cpu_pct": 2.5, "watts": -1.00, "rss_mb": 43}
{"t": 15, "temp_c": 48.0, "mhz": 690, "cpu_pct": 2.8, "watts": -1.00, "rss_mb": 43}
{"t": 16, "temp_c": 55.0, "mhz": 2800, "cpu_pct": 12.8, "watts": -1.00, "rss_mb": 43}
{"t": 17, "temp_c": 52.0, "mhz": 800, "cpu_pct": 27.6, "watts": -1.00, "rss_mb": 43}
{"t": 18, "temp_c": 48.0, "mhz": 794, "cpu_pct": 9.4, "watts": -1.00, "rss_mb": 43}
{"t": 19, "temp_c": 48.0, "mhz": 769, "cpu_pct": 3.5, "watts": -1.00, "rss_mb": 43}
{"t": 20, "temp_c": 48.0, "mhz": 800, "cpu_pct": 2.3, "watts": -1.00, "rss_mb": 43}
{"t": 21, "temp_c": 48.0, "mhz": 812, "cpu_pct": 3.0, "watts": -1.00, "rss_mb": 43}
{"t": 22, "temp_c": 49.0, "mhz": 873, "cpu_pct": 5.3, "watts": -1.00, "rss_mb": 43}
{"t": 23, "temp_c": 48.0, "mhz": 1691, "cpu_pct": 1.8, "watts": -1.00, "rss_mb": 43}
{"t": 24, "temp_c": 48.0, "mhz": 790, "cpu_pct": 2.5, "watts": -1.00, "rss_mb": 43}
{"t": 25, "temp_c": 47.0, "mhz": 762, "cpu_pct": 3.3, "watts": -1.00, "rss_mb": 43}
{"t": 26, "temp_c": 48.0, "mhz": 800, "cpu_pct": 2.8, "watts": -1.00, "rss_mb": 43}
{"t": 27, "temp_c": 48.0, "mhz": 793, "cpu_pct": 3.3, "watts": -1.00, "rss_mb": 43}
{"t": 28, "temp_c": 48.0, "mhz": 791, "cpu_pct": 3.8, "watts": -1.00, "rss_mb": 43}
{"t": 29, "temp_c": 48.0, "mhz": 1217, "cpu_pct": 3.3, "watts": -1.00, "rss_mb": 43}
{"t": 30, "temp_c": 47.0, "mhz": 800, "cpu_pct": 1.3, "watts": -1.00, "rss_mb": 43}
{"t": 31, "temp_c": 49.0, "mhz": 794, "cpu_pct": 3.5, "watts": -1.00, "rss_mb": 43}
{"t": 32, "temp_c": 48.0, "mhz": 777, "cpu_pct": 3.3, "watts": -1.00, "rss_mb": 43}
{"t": 33, "temp_c": 48.0, "mhz": 800, "cpu_pct": 2.8, "watts": -1.00, "rss_mb": 43}
{"t": 34, "temp_c": 47.0, "mhz": 800, "cpu_pct": 3.8, "watts": -1.00, "rss_mb": 43}
{"t": 35, "temp_c": 48.0, "mhz": 764, "cpu_pct": 3.0, "watts": -1.00, "rss_mb": 43}
{"t": 36, "temp_c": 48.0, "mhz": 2800, "cpu_pct": 1.5, "watts": -1.00, "rss_mb": 43}
{"t": 37, "temp_c": 48.0, "mhz": 801, "cpu_pct": 3.8, "watts": -1.00, "rss_mb": 43}
{"t": 38, "temp_c": 48.0, "mhz": 794, "cpu_pct": 2.5, "watts": -1.00, "rss_mb": 43}
{"t": 39, "temp_c": 48.0, "mhz": 798, "cpu_pct": 2.5, "watts": -1.00, "rss_mb": 43}
{"t": 40, "temp_c": 48.0, "mhz": 790, "cpu_pct": 4.3, "watts": -1.00, "rss_mb": 43}
{"t": 41, "temp_c": 49.0, "mhz": 805, "cpu_pct": 2.3, "watts": -1.00, "rss_mb": 43}
{"t": 42, "temp_c": 49.0, "mhz": 777, "cpu_pct": 3.3, "watts": -1.00, "rss_mb": 43}
{"t": 43, "temp_c": 48.0, "mhz": 793, "cpu_pct": 2.5, "watts": -1.00, "rss_mb": 43}
{"t": 44, "temp_c": 47.0, "mhz": 791, "cpu_pct": 2.8, "watts": -1.00, "rss_mb": 43}
{"t": 45, "temp_c": 48.0, "mhz": 800, "cpu_pct": 3.0, "watts": -1.00, "rss_mb": 43}
{"t": 46, "temp_c": 48.0, "mhz": 800, "cpu_pct": 3.5, "watts": -1.00, "rss_mb": 43}
{"t": 47, "temp_c": 50.0, "mhz": 800, "cpu_pct": 17.0, "watts": -1.00, "rss_mb": 43}
{"t": 48, "temp_c": 48.0, "mhz": 779, "cpu_pct": 10.8, "watts": -1.00, "rss_mb": 43}
{"t": 49, "temp_c": 48.0, "mhz": 800, "cpu_pct": 3.3, "watts": -1.00, "rss_mb": 43}
{"t": 50, "temp_c": 48.0, "mhz": 754, "cpu_pct": 2.8, "watts": -1.00, "rss_mb": 43}
{"t": 51, "temp_c": 48.0, "mhz": 741, "cpu_pct": 2.8, "watts": -1.00, "rss_mb": 43}
{"t": 52, "temp_c": 48.0, "mhz": 800, "cpu_pct": 3.0, "watts": -1.00, "rss_mb": 43}
{"t": 53, "temp_c": 48.0, "mhz": 800, "cpu_pct": 2.5, "watts": -1.00, "rss_mb": 43}
{"t": 54, "temp_c": 49.0, "mhz": 798, "cpu_pct": 2.5, "watts": -1.00, "rss_mb": 43}
{"t": 55, "temp_c": 50.0, "mhz": 1573, "cpu_pct": 5.8, "watts": -1.00, "rss_mb": 43}
{"t": 56, "temp_c": 48.0, "mhz": 2828, "cpu_pct": 2.0, "watts": -1.00, "rss_mb": 43}
{"t": 57, "temp_c": 48.0, "mhz": 759, "cpu_pct": 3.0, "watts": -1.00, "rss_mb": 43}
{"t": 58, "temp_c": 49.0, "mhz": 790, "cpu_pct": 3.8, "watts": -1.00, "rss_mb": 43}
{"t": 59, "temp_c": 48.0, "mhz": 789, "cpu_pct": 2.8, "watts": -1.00, "rss_mb": 43}
{"t": 60, "temp_c": 48.0, "mhz": 796, "cpu_pct": 2.5, "watts": -1.00, "rss_mb": 43}
{"summary": "idle", "secs": 60, "temp_c_mean": 48.4, "temp_c_max": 55.0, "mhz_mean": 960, "cpu_pct_mean": 4.5, "watts_mean": -1.00}

View File

@ -0,0 +1,61 @@
{"t": 1, "temp_c": 55.0, "mhz": 885, "cpu_pct": 4.5, "watts": 3.53, "rss_mb": 43}
{"t": 2, "temp_c": 54.0, "mhz": 1289, "cpu_pct": 3.8, "watts": 2.96, "rss_mb": 43}
{"t": 3, "temp_c": 53.0, "mhz": 800, "cpu_pct": 4.3, "watts": 3.07, "rss_mb": 43}
{"t": 4, "temp_c": 53.0, "mhz": 762, "cpu_pct": 3.5, "watts": 2.95, "rss_mb": 43}
{"t": 5, "temp_c": 54.0, "mhz": 1200, "cpu_pct": 5.1, "watts": 2.96, "rss_mb": 43}
{"t": 6, "temp_c": 54.0, "mhz": 707, "cpu_pct": 6.0, "watts": 3.12, "rss_mb": 43}
{"t": 7, "temp_c": 54.0, "mhz": 985, "cpu_pct": 4.0, "watts": 2.13, "rss_mb": 43}
{"t": 8, "temp_c": 54.0, "mhz": 801, "cpu_pct": 4.0, "watts": 3.00, "rss_mb": 43}
{"t": 9, "temp_c": 54.0, "mhz": 756, "cpu_pct": 4.0, "watts": 3.02, "rss_mb": 43}
{"t": 10, "temp_c": 53.0, "mhz": 798, "cpu_pct": 4.3, "watts": 2.98, "rss_mb": 43}
{"t": 11, "temp_c": 54.0, "mhz": 763, "cpu_pct": 4.8, "watts": 2.96, "rss_mb": 43}
{"t": 12, "temp_c": 53.0, "mhz": 800, "cpu_pct": 4.3, "watts": 3.04, "rss_mb": 43}
{"t": 13, "temp_c": 54.0, "mhz": 1561, "cpu_pct": 3.5, "watts": 2.91, "rss_mb": 43}
{"t": 14, "temp_c": 53.0, "mhz": 784, "cpu_pct": 3.3, "watts": 2.14, "rss_mb": 43}
{"t": 15, "temp_c": 52.0, "mhz": 793, "cpu_pct": 3.5, "watts": 3.03, "rss_mb": 43}
{"t": 16, "temp_c": 53.0, "mhz": 790, "cpu_pct": 5.0, "watts": 2.98, "rss_mb": 43}
{"t": 17, "temp_c": 54.0, "mhz": 788, "cpu_pct": 5.3, "watts": 2.91, "rss_mb": 43}
{"t": 18, "temp_c": 54.0, "mhz": 797, "cpu_pct": 5.0, "watts": 3.01, "rss_mb": 43}
{"t": 19, "temp_c": 54.0, "mhz": 1884, "cpu_pct": 3.5, "watts": 2.77, "rss_mb": 43}
{"t": 20, "temp_c": 53.0, "mhz": 860, "cpu_pct": 4.0, "watts": 3.00, "rss_mb": 43}
{"t": 21, "temp_c": 52.0, "mhz": 800, "cpu_pct": 4.3, "watts": 2.28, "rss_mb": 43}
{"t": 22, "temp_c": 52.0, "mhz": 774, "cpu_pct": 3.5, "watts": 2.94, "rss_mb": 43}
{"t": 23, "temp_c": 53.0, "mhz": 935, "cpu_pct": 5.5, "watts": 2.94, "rss_mb": 43}
{"t": 24, "temp_c": 53.0, "mhz": 779, "cpu_pct": 4.5, "watts": 2.93, "rss_mb": 43}
{"t": 25, "temp_c": 54.0, "mhz": 1192, "cpu_pct": 4.5, "watts": 2.91, "rss_mb": 43}
{"t": 26, "temp_c": 54.0, "mhz": 792, "cpu_pct": 4.0, "watts": 2.93, "rss_mb": 43}
{"t": 27, "temp_c": 52.0, "mhz": 798, "cpu_pct": 3.8, "watts": 2.97, "rss_mb": 43}
{"t": 28, "temp_c": 54.0, "mhz": 800, "cpu_pct": 12.9, "watts": 2.48, "rss_mb": 43}
{"t": 29, "temp_c": 52.0, "mhz": 798, "cpu_pct": 15.4, "watts": 4.12, "rss_mb": 43}
{"t": 30, "temp_c": 53.0, "mhz": 982, "cpu_pct": 4.5, "watts": 2.91, "rss_mb": 43}
{"t": 31, "temp_c": 52.0, "mhz": 792, "cpu_pct": 2.3, "watts": 2.92, "rss_mb": 43}
{"t": 32, "temp_c": 52.0, "mhz": 800, "cpu_pct": 5.3, "watts": 2.92, "rss_mb": 43}
{"t": 33, "temp_c": 52.0, "mhz": 754, "cpu_pct": 4.5, "watts": 2.97, "rss_mb": 43}
{"t": 34, "temp_c": 52.0, "mhz": 763, "cpu_pct": 4.8, "watts": 2.92, "rss_mb": 43}
{"t": 35, "temp_c": 53.0, "mhz": 758, "cpu_pct": 4.8, "watts": 2.09, "rss_mb": 43}
{"t": 36, "temp_c": 53.0, "mhz": 2677, "cpu_pct": 4.8, "watts": 3.08, "rss_mb": 43}
{"t": 37, "temp_c": 52.0, "mhz": 799, "cpu_pct": 2.5, "watts": 2.92, "rss_mb": 43}
{"t": 38, "temp_c": 52.0, "mhz": 795, "cpu_pct": 4.0, "watts": 2.89, "rss_mb": 43}
{"t": 39, "temp_c": 52.0, "mhz": 794, "cpu_pct": 5.0, "watts": 3.02, "rss_mb": 43}
{"t": 40, "temp_c": 52.0, "mhz": 778, "cpu_pct": 4.3, "watts": 2.95, "rss_mb": 43}
{"t": 41, "temp_c": 52.0, "mhz": 800, "cpu_pct": 5.0, "watts": 3.04, "rss_mb": 43}
{"t": 42, "temp_c": 54.0, "mhz": 1473, "cpu_pct": 4.5, "watts": 2.17, "rss_mb": 43}
{"t": 43, "temp_c": 52.0, "mhz": 789, "cpu_pct": 3.0, "watts": 2.92, "rss_mb": 43}
{"t": 44, "temp_c": 52.0, "mhz": 796, "cpu_pct": 4.0, "watts": 2.88, "rss_mb": 43}
{"t": 45, "temp_c": 52.0, "mhz": 762, "cpu_pct": 4.5, "watts": 2.99, "rss_mb": 43}
{"t": 46, "temp_c": 51.0, "mhz": 698, "cpu_pct": 4.6, "watts": 2.93, "rss_mb": 43}
{"t": 47, "temp_c": 53.0, "mhz": 792, "cpu_pct": 4.8, "watts": 3.01, "rss_mb": 43}
{"t": 48, "temp_c": 54.0, "mhz": 2799, "cpu_pct": 4.0, "watts": 2.92, "rss_mb": 43}
{"t": 49, "temp_c": 51.0, "mhz": 785, "cpu_pct": 3.0, "watts": 2.14, "rss_mb": 43}
{"t": 50, "temp_c": 52.0, "mhz": 801, "cpu_pct": 5.0, "watts": 2.91, "rss_mb": 43}
{"t": 51, "temp_c": 51.0, "mhz": 796, "cpu_pct": 3.8, "watts": 3.00, "rss_mb": 43}
{"t": 52, "temp_c": 51.0, "mhz": 800, "cpu_pct": 4.5, "watts": 2.95, "rss_mb": 43}
{"t": 53, "temp_c": 52.0, "mhz": 777, "cpu_pct": 4.3, "watts": 2.93, "rss_mb": 43}
{"t": 54, "temp_c": 52.0, "mhz": 2678, "cpu_pct": 3.8, "watts": 2.75, "rss_mb": 43}
{"t": 55, "temp_c": 51.0, "mhz": 800, "cpu_pct": 2.8, "watts": 2.25, "rss_mb": 43}
{"t": 56, "temp_c": 52.0, "mhz": 801, "cpu_pct": 5.5, "watts": 2.91, "rss_mb": 43}
{"t": 57, "temp_c": 51.0, "mhz": 764, "cpu_pct": 5.0, "watts": 3.11, "rss_mb": 43}
{"t": 58, "temp_c": 52.0, "mhz": 800, "cpu_pct": 4.3, "watts": 2.95, "rss_mb": 43}
{"t": 59, "temp_c": 59.0, "mhz": 2800, "cpu_pct": 21.9, "watts": 3.74, "rss_mb": 43}
{"t": 60, "temp_c": 51.0, "mhz": 782, "cpu_pct": 6.3, "watts": 3.67, "rss_mb": 43}
{"summary": "idle", "secs": 60, "temp_c_mean": 52.8, "temp_c_max": 59.0, "mhz_mean": 991, "cpu_pct_mean": 4.9, "watts_mean": 2.91}

View File

@ -0,0 +1,61 @@
{"t": 1, "temp_c": 53.0, "mhz": 776, "cpu_pct": 4.5, "watts": 3.53, "rss_mb": 42}
{"t": 2, "temp_c": 54.0, "mhz": 794, "cpu_pct": 5.5, "watts": 2.97, "rss_mb": 43}
{"t": 3, "temp_c": 55.0, "mhz": 2773, "cpu_pct": 4.0, "watts": 2.82, "rss_mb": 43}
{"t": 4, "temp_c": 61.0, "mhz": 2800, "cpu_pct": 7.8, "watts": 3.25, "rss_mb": 43}
{"t": 5, "temp_c": 52.0, "mhz": 800, "cpu_pct": 6.6, "watts": 3.21, "rss_mb": 43}
{"t": 6, "temp_c": 52.0, "mhz": 791, "cpu_pct": 3.8, "watts": 2.18, "rss_mb": 43}
{"t": 7, "temp_c": 53.0, "mhz": 790, "cpu_pct": 3.5, "watts": 2.86, "rss_mb": 43}
{"t": 8, "temp_c": 53.0, "mhz": 878, "cpu_pct": 4.8, "watts": 3.03, "rss_mb": 43}
{"t": 9, "temp_c": 53.0, "mhz": 780, "cpu_pct": 3.5, "watts": 2.97, "rss_mb": 43}
{"t": 10, "temp_c": 53.0, "mhz": 774, "cpu_pct": 4.5, "watts": 2.97, "rss_mb": 43}
{"t": 11, "temp_c": 53.0, "mhz": 772, "cpu_pct": 4.8, "watts": 2.97, "rss_mb": 43}
{"t": 12, "temp_c": 52.0, "mhz": 614, "cpu_pct": 4.0, "watts": 2.93, "rss_mb": 43}
{"t": 13, "temp_c": 53.0, "mhz": 798, "cpu_pct": 4.0, "watts": 2.16, "rss_mb": 43}
{"t": 14, "temp_c": 54.0, "mhz": 2847, "cpu_pct": 5.1, "watts": 2.94, "rss_mb": 43}
{"t": 15, "temp_c": 52.0, "mhz": 784, "cpu_pct": 3.0, "watts": 2.94, "rss_mb": 43}
{"t": 16, "temp_c": 52.0, "mhz": 787, "cpu_pct": 3.5, "watts": 2.93, "rss_mb": 43}
{"t": 17, "temp_c": 52.0, "mhz": 786, "cpu_pct": 5.6, "watts": 3.09, "rss_mb": 43}
{"t": 18, "temp_c": 53.0, "mhz": 767, "cpu_pct": 4.5, "watts": 2.92, "rss_mb": 43}
{"t": 19, "temp_c": 52.0, "mhz": 800, "cpu_pct": 3.8, "watts": 2.14, "rss_mb": 43}
{"t": 20, "temp_c": 53.0, "mhz": 2853, "cpu_pct": 3.8, "watts": 3.02, "rss_mb": 43}
{"t": 21, "temp_c": 51.0, "mhz": 792, "cpu_pct": 3.0, "watts": 2.92, "rss_mb": 43}
{"t": 22, "temp_c": 52.0, "mhz": 800, "cpu_pct": 4.0, "watts": 2.93, "rss_mb": 43}
{"t": 23, "temp_c": 51.0, "mhz": 784, "cpu_pct": 5.5, "watts": 3.00, "rss_mb": 43}
{"t": 24, "temp_c": 52.0, "mhz": 793, "cpu_pct": 4.0, "watts": 2.96, "rss_mb": 43}
{"t": 25, "temp_c": 52.0, "mhz": 758, "cpu_pct": 4.0, "watts": 2.94, "rss_mb": 43}
{"t": 26, "temp_c": 54.0, "mhz": 2843, "cpu_pct": 4.8, "watts": 2.20, "rss_mb": 43}
{"t": 27, "temp_c": 51.0, "mhz": 796, "cpu_pct": 2.5, "watts": 2.92, "rss_mb": 43}
{"t": 28, "temp_c": 52.0, "mhz": 830, "cpu_pct": 4.5, "watts": 2.89, "rss_mb": 43}
{"t": 29, "temp_c": 54.0, "mhz": 737, "cpu_pct": 25.5, "watts": 4.67, "rss_mb": 43}
{"t": 30, "temp_c": 52.0, "mhz": 787, "cpu_pct": 4.3, "watts": 3.12, "rss_mb": 43}
{"t": 31, "temp_c": 52.0, "mhz": 891, "cpu_pct": 3.5, "watts": 2.85, "rss_mb": 43}
{"t": 32, "temp_c": 52.0, "mhz": 900, "cpu_pct": 4.1, "watts": 2.89, "rss_mb": 43}
{"t": 33, "temp_c": 51.0, "mhz": 799, "cpu_pct": 3.8, "watts": 2.27, "rss_mb": 43}
{"t": 34, "temp_c": 51.0, "mhz": 792, "cpu_pct": 3.8, "watts": 2.96, "rss_mb": 43}
{"t": 35, "temp_c": 52.0, "mhz": 791, "cpu_pct": 6.6, "watts": 3.07, "rss_mb": 43}
{"t": 36, "temp_c": 52.0, "mhz": 790, "cpu_pct": 4.5, "watts": 2.83, "rss_mb": 43}
{"t": 37, "temp_c": 52.0, "mhz": 800, "cpu_pct": 4.0, "watts": 2.80, "rss_mb": 43}
{"t": 38, "temp_c": 51.0, "mhz": 797, "cpu_pct": 3.3, "watts": 2.98, "rss_mb": 43}
{"t": 39, "temp_c": 52.0, "mhz": 767, "cpu_pct": 4.8, "watts": 2.97, "rss_mb": 43}
{"t": 40, "temp_c": 52.0, "mhz": 800, "cpu_pct": 4.0, "watts": 2.30, "rss_mb": 43}
{"t": 41, "temp_c": 51.0, "mhz": 784, "cpu_pct": 5.3, "watts": 2.92, "rss_mb": 43}
{"t": 42, "temp_c": 52.0, "mhz": 703, "cpu_pct": 3.8, "watts": 2.83, "rss_mb": 43}
{"t": 43, "temp_c": 52.0, "mhz": 754, "cpu_pct": 3.8, "watts": 2.90, "rss_mb": 43}
{"t": 44, "temp_c": 51.0, "mhz": 775, "cpu_pct": 3.5, "watts": 3.01, "rss_mb": 43}
{"t": 45, "temp_c": 51.0, "mhz": 791, "cpu_pct": 4.5, "watts": 2.94, "rss_mb": 43}
{"t": 46, "temp_c": 51.0, "mhz": 770, "cpu_pct": 3.8, "watts": 2.95, "rss_mb": 43}
{"t": 47, "temp_c": 51.0, "mhz": 800, "cpu_pct": 5.5, "watts": 2.17, "rss_mb": 43}
{"t": 48, "temp_c": 51.0, "mhz": 797, "cpu_pct": 4.0, "watts": 2.91, "rss_mb": 43}
{"t": 49, "temp_c": 52.0, "mhz": 1821, "cpu_pct": 4.3, "watts": 2.90, "rss_mb": 43}
{"t": 50, "temp_c": 51.0, "mhz": 750, "cpu_pct": 3.8, "watts": 2.97, "rss_mb": 43}
{"t": 51, "temp_c": 52.0, "mhz": 786, "cpu_pct": 3.8, "watts": 2.90, "rss_mb": 43}
{"t": 52, "temp_c": 51.0, "mhz": 800, "cpu_pct": 3.3, "watts": 2.92, "rss_mb": 43}
{"t": 53, "temp_c": 51.0, "mhz": 718, "cpu_pct": 6.3, "watts": 3.06, "rss_mb": 43}
{"t": 54, "temp_c": 52.0, "mhz": 758, "cpu_pct": 4.3, "watts": 2.13, "rss_mb": 43}
{"t": 55, "temp_c": 61.0, "mhz": 2800, "cpu_pct": 20.6, "watts": 3.91, "rss_mb": 43}
{"t": 56, "temp_c": 51.0, "mhz": 792, "cpu_pct": 5.0, "watts": 3.58, "rss_mb": 43}
{"t": 57, "temp_c": 51.0, "mhz": 757, "cpu_pct": 3.8, "watts": 2.91, "rss_mb": 43}
{"t": 58, "temp_c": 51.0, "mhz": 800, "cpu_pct": 3.8, "watts": 2.90, "rss_mb": 43}
{"t": 59, "temp_c": 52.0, "mhz": 794, "cpu_pct": 5.3, "watts": 2.97, "rss_mb": 43}
{"t": 60, "temp_c": 52.0, "mhz": 1399, "cpu_pct": 6.8, "watts": 3.10, "rss_mb": 43}
{"summary": "idle", "secs": 60, "temp_c_mean": 52.3, "temp_c_max": 61.0, "mhz_mean": 1016, "cpu_pct_mean": 5.0, "watts_mean": 2.92}

View File

@ -0,0 +1,121 @@
{"t": 1, "temp_c": 78.0, "mhz": 2700, "cpu_pct": 91.1, "watts": 9.43, "rss_mb": 543, "done": 0, "queue": 0}
{"t": 2, "temp_c": 68.0, "mhz": 2800, "cpu_pct": 70.2, "watts": 8.25, "rss_mb": 259, "done": 1, "queue": 0}
{"t": 3, "temp_c": 79.0, "mhz": 2507, "cpu_pct": 91.5, "watts": 7.15, "rss_mb": 622, "done": 1, "queue": 0}
{"t": 4, "temp_c": 72.0, "mhz": 2800, "cpu_pct": 69.2, "watts": 8.38, "rss_mb": 292, "done": 2, "queue": 0}
{"t": 5, "temp_c": 78.0, "mhz": 2600, "cpu_pct": 90.7, "watts": 9.03, "rss_mb": 643, "done": 2, "queue": 0}
{"t": 6, "temp_c": 68.0, "mhz": 2800, "cpu_pct": 66.5, "watts": 8.15, "rss_mb": 312, "done": 3, "queue": 0}
{"t": 7, "temp_c": 76.0, "mhz": 2700, "cpu_pct": 91.5, "watts": 9.05, "rss_mb": 579, "done": 3, "queue": 0}
{"t": 8, "temp_c": 71.0, "mhz": 2800, "cpu_pct": 68.1, "watts": 8.22, "rss_mb": 401, "done": 4, "queue": 0}
{"t": 9, "temp_c": 78.0, "mhz": 2500, "cpu_pct": 91.2, "watts": 9.22, "rss_mb": 699, "done": 4, "queue": 0}
{"t": 10, "temp_c": 74.0, "mhz": 2800, "cpu_pct": 67.8, "watts": 7.97, "rss_mb": 466, "done": 5, "queue": 0}
{"t": 11, "temp_c": 78.0, "mhz": 2500, "cpu_pct": 92.0, "watts": 6.97, "rss_mb": 707, "done": 5, "queue": 0}
{"t": 12, "temp_c": 77.0, "mhz": 2800, "cpu_pct": 66.3, "watts": 8.36, "rss_mb": 474, "done": 6, "queue": 0}
{"t": 13, "temp_c": 77.0, "mhz": 2200, "cpu_pct": 92.0, "watts": 8.96, "rss_mb": 698, "done": 6, "queue": 0}
{"t": 14, "temp_c": 73.0, "mhz": 2799, "cpu_pct": 64.8, "watts": 8.08, "rss_mb": 480, "done": 7, "queue": 0}
{"t": 15, "temp_c": 78.0, "mhz": 2600, "cpu_pct": 92.5, "watts": 9.09, "rss_mb": 701, "done": 7, "queue": 0}
{"t": 16, "temp_c": 76.0, "mhz": 2800, "cpu_pct": 67.7, "watts": 8.08, "rss_mb": 484, "done": 8, "queue": 0}
{"t": 17, "temp_c": 79.0, "mhz": 2436, "cpu_pct": 92.5, "watts": 9.03, "rss_mb": 705, "done": 8, "queue": 0}
{"t": 18, "temp_c": 76.0, "mhz": 2800, "cpu_pct": 66.4, "watts": 7.98, "rss_mb": 488, "done": 9, "queue": 0}
{"t": 19, "temp_c": 79.0, "mhz": 2500, "cpu_pct": 92.3, "watts": 9.24, "rss_mb": 712, "done": 9, "queue": 0}
{"t": 20, "temp_c": 80.0, "mhz": 2800, "cpu_pct": 68.6, "watts": 6.06, "rss_mb": 518, "done": 10, "queue": 0}
{"t": 21, "temp_c": 77.0, "mhz": 2600, "cpu_pct": 92.0, "watts": 9.08, "rss_mb": 714, "done": 10, "queue": 0}
{"t": 22, "temp_c": 79.0, "mhz": 2800, "cpu_pct": 67.2, "watts": 8.11, "rss_mb": 521, "done": 11, "queue": 0}
{"t": 23, "temp_c": 77.0, "mhz": 2756, "cpu_pct": 93.0, "watts": 8.98, "rss_mb": 715, "done": 11, "queue": 0}
{"t": 24, "temp_c": 80.0, "mhz": 2800, "cpu_pct": 67.2, "watts": 8.06, "rss_mb": 530, "done": 12, "queue": 0}
{"t": 25, "temp_c": 77.0, "mhz": 2700, "cpu_pct": 91.5, "watts": 9.08, "rss_mb": 724, "done": 12, "queue": 0}
{"t": 26, "temp_c": 81.0, "mhz": 2800, "cpu_pct": 67.2, "watts": 7.91, "rss_mb": 541, "done": 13, "queue": 0}
{"t": 27, "temp_c": 78.0, "mhz": 2600, "cpu_pct": 95.2, "watts": 6.97, "rss_mb": 725, "done": 13, "queue": 0}
{"t": 28, "temp_c": 80.0, "mhz": 2800, "cpu_pct": 74.8, "watts": 8.50, "rss_mb": 544, "done": 14, "queue": 0}
{"t": 29, "temp_c": 76.0, "mhz": 2701, "cpu_pct": 92.5, "watts": 8.90, "rss_mb": 726, "done": 14, "queue": 0}
{"t": 30, "temp_c": 83.0, "mhz": 2800, "cpu_pct": 68.0, "watts": 8.05, "rss_mb": 563, "done": 15, "queue": 0}
{"t": 31, "temp_c": 78.0, "mhz": 2700, "cpu_pct": 92.1, "watts": 8.87, "rss_mb": 727, "done": 15, "queue": 0}
{"t": 32, "temp_c": 84.0, "mhz": 2800, "cpu_pct": 66.1, "watts": 7.93, "rss_mb": 602, "done": 16, "queue": 0}
{"t": 33, "temp_c": 79.0, "mhz": 2400, "cpu_pct": 92.2, "watts": 9.04, "rss_mb": 727, "done": 16, "queue": 0}
{"t": 34, "temp_c": 85.0, "mhz": 2800, "cpu_pct": 66.7, "watts": 7.80, "rss_mb": 574, "done": 17, "queue": 0}
{"t": 35, "temp_c": 77.0, "mhz": 2586, "cpu_pct": 91.5, "watts": 9.18, "rss_mb": 745, "done": 17, "queue": 0}
{"t": 36, "temp_c": 86.0, "mhz": 2800, "cpu_pct": 69.3, "watts": 6.03, "rss_mb": 603, "done": 18, "queue": 0}
{"t": 37, "temp_c": 76.0, "mhz": 2800, "cpu_pct": 90.8, "watts": 8.86, "rss_mb": 731, "done": 18, "queue": 0}
{"t": 38, "temp_c": 85.0, "mhz": 2800, "cpu_pct": 67.2, "watts": 8.03, "rss_mb": 584, "done": 19, "queue": 0}
{"t": 39, "temp_c": 77.0, "mhz": 2550, "cpu_pct": 91.8, "watts": 8.73, "rss_mb": 747, "done": 19, "queue": 0}
{"t": 40, "temp_c": 82.0, "mhz": 2799, "cpu_pct": 67.2, "watts": 7.98, "rss_mb": 614, "done": 20, "queue": 0}
{"t": 41, "temp_c": 77.0, "mhz": 2600, "cpu_pct": 91.2, "watts": 8.95, "rss_mb": 748, "done": 20, "queue": 0}
{"t": 42, "temp_c": 86.0, "mhz": 2800, "cpu_pct": 67.2, "watts": 7.87, "rss_mb": 618, "done": 21, "queue": 0}
{"t": 43, "temp_c": 78.0, "mhz": 2600, "cpu_pct": 91.0, "watts": 8.96, "rss_mb": 753, "done": 21, "queue": 0}
{"t": 44, "temp_c": 85.0, "mhz": 2800, "cpu_pct": 67.6, "watts": 7.96, "rss_mb": 586, "done": 22, "queue": 0}
{"t": 45, "temp_c": 76.0, "mhz": 2464, "cpu_pct": 91.5, "watts": 6.90, "rss_mb": 759, "done": 22, "queue": 0}
{"t": 46, "temp_c": 86.0, "mhz": 2800, "cpu_pct": 68.6, "watts": 8.08, "rss_mb": 605, "done": 23, "queue": 0}
{"t": 47, "temp_c": 78.0, "mhz": 2700, "cpu_pct": 91.0, "watts": 8.67, "rss_mb": 743, "done": 23, "queue": 0}
{"t": 48, "temp_c": 85.0, "mhz": 2800, "cpu_pct": 67.8, "watts": 8.02, "rss_mb": 628, "done": 24, "queue": 0}
{"t": 49, "temp_c": 80.0, "mhz": 2787, "cpu_pct": 91.3, "watts": 8.87, "rss_mb": 743, "done": 24, "queue": 0}
{"t": 50, "temp_c": 88.0, "mhz": 2800, "cpu_pct": 67.9, "watts": 7.83, "rss_mb": 598, "done": 25, "queue": 0}
{"t": 51, "temp_c": 78.0, "mhz": 2642, "cpu_pct": 92.0, "watts": 8.89, "rss_mb": 762, "done": 25, "queue": 0}
{"t": 52, "temp_c": 84.0, "mhz": 2800, "cpu_pct": 69.5, "watts": 7.97, "rss_mb": 637, "done": 26, "queue": 0}
{"t": 53, "temp_c": 77.0, "mhz": 2716, "cpu_pct": 91.5, "watts": 6.79, "rss_mb": 746, "done": 26, "queue": 0}
{"t": 54, "temp_c": 81.0, "mhz": 2800, "cpu_pct": 68.5, "watts": 8.08, "rss_mb": 649, "done": 27, "queue": 0}
{"t": 55, "temp_c": 78.0, "mhz": 2800, "cpu_pct": 93.0, "watts": 8.69, "rss_mb": 751, "done": 27, "queue": 0}
{"t": 56, "temp_c": 87.0, "mhz": 2800, "cpu_pct": 68.5, "watts": 8.04, "rss_mb": 632, "done": 28, "queue": 0}
{"t": 57, "temp_c": 77.0, "mhz": 2701, "cpu_pct": 91.5, "watts": 8.92, "rss_mb": 751, "done": 28, "queue": 0}
{"t": 58, "temp_c": 83.0, "mhz": 2800, "cpu_pct": 69.1, "watts": 7.85, "rss_mb": 654, "done": 29, "queue": 0}
{"t": 59, "temp_c": 77.0, "mhz": 2470, "cpu_pct": 96.2, "watts": 9.05, "rss_mb": 751, "done": 29, "queue": 0}
{"t": 60, "temp_c": 84.0, "mhz": 2800, "cpu_pct": 70.9, "watts": 8.10, "rss_mb": 634, "done": 30, "queue": 0}
{"t": 61, "temp_c": 78.0, "mhz": 2701, "cpu_pct": 91.0, "watts": 6.80, "rss_mb": 752, "done": 30, "queue": 0}
{"t": 62, "temp_c": 79.0, "mhz": 2800, "cpu_pct": 68.4, "watts": 8.13, "rss_mb": 660, "done": 31, "queue": 0}
{"t": 63, "temp_c": 77.0, "mhz": 2500, "cpu_pct": 91.5, "watts": 8.87, "rss_mb": 754, "done": 31, "queue": 0}
{"t": 64, "temp_c": 86.0, "mhz": 2800, "cpu_pct": 67.5, "watts": 7.89, "rss_mb": 661, "done": 32, "queue": 0}
{"t": 65, "temp_c": 78.0, "mhz": 2585, "cpu_pct": 92.2, "watts": 8.98, "rss_mb": 755, "done": 32, "queue": 0}
{"t": 66, "temp_c": 80.0, "mhz": 2800, "cpu_pct": 67.4, "watts": 8.05, "rss_mb": 672, "done": 33, "queue": 0}
{"t": 67, "temp_c": 77.0, "mhz": 2600, "cpu_pct": 91.7, "watts": 9.02, "rss_mb": 757, "done": 33, "queue": 0}
{"t": 68, "temp_c": 80.0, "mhz": 2800, "cpu_pct": 66.9, "watts": 5.91, "rss_mb": 682, "done": 34, "queue": 0}
{"t": 69, "temp_c": 79.0, "mhz": 2778, "cpu_pct": 92.0, "watts": 8.82, "rss_mb": 773, "done": 34, "queue": 0}
{"t": 70, "temp_c": 84.0, "mhz": 2800, "cpu_pct": 68.5, "watts": 7.94, "rss_mb": 641, "done": 35, "queue": 0}
{"t": 71, "temp_c": 78.0, "mhz": 2544, "cpu_pct": 91.0, "watts": 8.87, "rss_mb": 759, "done": 35, "queue": 0}
{"t": 72, "temp_c": 78.0, "mhz": 2300, "cpu_pct": 68.2, "watts": 7.88, "rss_mb": 693, "done": 36, "queue": 0}
{"t": 73, "temp_c": 79.0, "mhz": 2304, "cpu_pct": 92.1, "watts": 8.81, "rss_mb": 759, "done": 36, "queue": 0}
{"t": 74, "temp_c": 79.0, "mhz": 2801, "cpu_pct": 69.2, "watts": 8.11, "rss_mb": 671, "done": 37, "queue": 0}
{"t": 75, "temp_c": 78.0, "mhz": 2600, "cpu_pct": 92.7, "watts": 8.81, "rss_mb": 761, "done": 37, "queue": 0}
{"t": 76, "temp_c": 79.0, "mhz": 2800, "cpu_pct": 69.2, "watts": 6.00, "rss_mb": 683, "done": 38, "queue": 0}
{"t": 77, "temp_c": 78.0, "mhz": 2500, "cpu_pct": 91.7, "watts": 8.64, "rss_mb": 761, "done": 38, "queue": 0}
{"t": 78, "temp_c": 80.0, "mhz": 2800, "cpu_pct": 68.4, "watts": 7.99, "rss_mb": 679, "done": 39, "queue": 0}
{"t": 79, "temp_c": 78.0, "mhz": 2473, "cpu_pct": 91.5, "watts": 8.81, "rss_mb": 761, "done": 39, "queue": 0}
{"t": 80, "temp_c": 79.0, "mhz": 2799, "cpu_pct": 67.4, "watts": 7.79, "rss_mb": 684, "done": 40, "queue": 0}
{"t": 81, "temp_c": 77.0, "mhz": 2500, "cpu_pct": 93.2, "watts": 8.92, "rss_mb": 761, "done": 40, "queue": 0}
{"t": 82, "temp_c": 78.0, "mhz": 2800, "cpu_pct": 69.0, "watts": 8.03, "rss_mb": 687, "done": 41, "queue": 0}
{"t": 83, "temp_c": 80.0, "mhz": 2400, "cpu_pct": 92.2, "watts": 8.87, "rss_mb": 761, "done": 41, "queue": 0}
{"t": 84, "temp_c": 79.0, "mhz": 2800, "cpu_pct": 67.5, "watts": 5.93, "rss_mb": 692, "done": 42, "queue": 0}
{"t": 85, "temp_c": 76.0, "mhz": 2700, "cpu_pct": 93.0, "watts": 8.62, "rss_mb": 761, "done": 42, "queue": 0}
{"t": 86, "temp_c": 82.0, "mhz": 2300, "cpu_pct": 67.9, "watts": 7.85, "rss_mb": 695, "done": 43, "queue": 0}
{"t": 87, "temp_c": 79.0, "mhz": 2500, "cpu_pct": 91.3, "watts": 8.62, "rss_mb": 761, "done": 43, "queue": 0}
{"t": 88, "temp_c": 83.0, "mhz": 2800, "cpu_pct": 68.9, "watts": 7.88, "rss_mb": 729, "done": 44, "queue": 0}
{"t": 89, "temp_c": 78.0, "mhz": 2400, "cpu_pct": 93.0, "watts": 8.75, "rss_mb": 779, "done": 44, "queue": 0}
{"t": 90, "temp_c": 80.0, "mhz": 2600, "cpu_pct": 82.7, "watts": 8.46, "rss_mb": 716, "done": 45, "queue": 0}
{"t": 91, "temp_c": 78.0, "mhz": 2500, "cpu_pct": 92.8, "watts": 8.71, "rss_mb": 779, "done": 45, "queue": 0}
{"t": 92, "temp_c": 79.0, "mhz": 2800, "cpu_pct": 67.8, "watts": 5.88, "rss_mb": 709, "done": 46, "queue": 0}
{"t": 93, "temp_c": 78.0, "mhz": 2478, "cpu_pct": 92.2, "watts": 8.65, "rss_mb": 779, "done": 46, "queue": 0}
{"t": 94, "temp_c": 81.0, "mhz": 2800, "cpu_pct": 69.4, "watts": 7.89, "rss_mb": 730, "done": 47, "queue": 0}
{"t": 95, "temp_c": 78.0, "mhz": 2500, "cpu_pct": 92.5, "watts": 8.80, "rss_mb": 762, "done": 47, "queue": 0}
{"t": 96, "temp_c": 86.0, "mhz": 2700, "cpu_pct": 67.1, "watts": 7.85, "rss_mb": 730, "done": 48, "queue": 0}
{"t": 97, "temp_c": 78.0, "mhz": 2600, "cpu_pct": 93.2, "watts": 8.69, "rss_mb": 779, "done": 48, "queue": 0}
{"t": 98, "temp_c": 86.0, "mhz": 2800, "cpu_pct": 66.8, "watts": 7.91, "rss_mb": 730, "done": 49, "queue": 0}
{"t": 99, "temp_c": 77.0, "mhz": 2400, "cpu_pct": 92.5, "watts": 8.69, "rss_mb": 779, "done": 49, "queue": 0}
{"t": 100, "temp_c": 81.0, "mhz": 2800, "cpu_pct": 68.2, "watts": 8.11, "rss_mb": 723, "done": 50, "queue": 0}
{"t": 101, "temp_c": 79.0, "mhz": 2319, "cpu_pct": 92.2, "watts": 6.39, "rss_mb": 779, "done": 50, "queue": 0}
{"t": 102, "temp_c": 82.0, "mhz": 2799, "cpu_pct": 68.9, "watts": 7.91, "rss_mb": 719, "done": 51, "queue": 0}
{"t": 103, "temp_c": 78.0, "mhz": 2582, "cpu_pct": 92.3, "watts": 8.73, "rss_mb": 779, "done": 51, "queue": 0}
{"t": 104, "temp_c": 86.0, "mhz": 2800, "cpu_pct": 68.5, "watts": 7.98, "rss_mb": 731, "done": 52, "queue": 0}
{"t": 105, "temp_c": 79.0, "mhz": 2400, "cpu_pct": 92.3, "watts": 8.83, "rss_mb": 779, "done": 52, "queue": 0}
{"t": 106, "temp_c": 80.0, "mhz": 2600, "cpu_pct": 66.5, "watts": 7.91, "rss_mb": 731, "done": 53, "queue": 0}
{"t": 107, "temp_c": 78.0, "mhz": 2700, "cpu_pct": 92.0, "watts": 8.43, "rss_mb": 763, "done": 53, "queue": 0}
{"t": 108, "temp_c": 84.0, "mhz": 2800, "cpu_pct": 67.9, "watts": 5.85, "rss_mb": 731, "done": 54, "queue": 0}
{"t": 109, "temp_c": 78.0, "mhz": 2500, "cpu_pct": 92.2, "watts": 8.63, "rss_mb": 779, "done": 54, "queue": 0}
{"t": 110, "temp_c": 83.0, "mhz": 2800, "cpu_pct": 68.8, "watts": 7.87, "rss_mb": 731, "done": 55, "queue": 0}
{"t": 111, "temp_c": 78.0, "mhz": 2700, "cpu_pct": 92.2, "watts": 8.77, "rss_mb": 763, "done": 55, "queue": 0}
{"t": 112, "temp_c": 86.0, "mhz": 2700, "cpu_pct": 68.9, "watts": 7.82, "rss_mb": 731, "done": 56, "queue": 0}
{"t": 113, "temp_c": 78.0, "mhz": 2600, "cpu_pct": 92.5, "watts": 8.60, "rss_mb": 763, "done": 56, "queue": 0}
{"t": 114, "temp_c": 84.0, "mhz": 2800, "cpu_pct": 67.3, "watts": 8.08, "rss_mb": 731, "done": 57, "queue": 0}
{"t": 115, "temp_c": 77.0, "mhz": 2325, "cpu_pct": 92.5, "watts": 8.57, "rss_mb": 763, "done": 57, "queue": 0}
{"t": 116, "temp_c": 80.0, "mhz": 2500, "cpu_pct": 68.6, "watts": 7.92, "rss_mb": 731, "done": 58, "queue": 0}
{"t": 117, "temp_c": 77.0, "mhz": 2500, "cpu_pct": 93.0, "watts": 6.32, "rss_mb": 763, "done": 58, "queue": 0}
{"t": 118, "temp_c": 85.0, "mhz": 2600, "cpu_pct": 71.0, "watts": 7.98, "rss_mb": 731, "done": 59, "queue": 0}
{"t": 119, "temp_c": 79.0, "mhz": 2400, "cpu_pct": 93.8, "watts": 8.70, "rss_mb": 781, "done": 59, "queue": 0}
{"t": 120, "temp_c": 73.0, "mhz": 2800, "cpu_pct": 64.8, "watts": 7.78, "rss_mb": 385, "done": 60, "queue": 0}
{"summary": "pipeline", "kind": "c12_ea", "workers": 1, "threads": 4, "effort": 3, "distance": 1.00, "period_ms": 2000, "secs": 120.0, "frames": 60, "frames_per_s": 0.500, "job_ms_p50": 1440, "latency_ms_p50": 1447, "latency_ms_p95": 1505, "latency_ms_max": 1563, "max_queue": 1, "backlog_at_end": 0, "cpu_s_per_frame": 2.302, "peak_rss_mb": 781, "temp_c_mean": 79.3, "temp_c_max": 88.0, "mhz_mean": 2663, "mhz_min": 2200, "cpu_pct_mean": 80.2, "watts_mean": 8.18}

View File

@ -0,0 +1,53 @@
16:07:41 cool-down 60 s
16:08:41 none: flat out 60 s
16:08:41 throttle counts: package 0 cores 0 0 0 0 temp 60000
16:09:42 none: paced 2000 ms 120 s
16:09:42 throttle counts: package 0 cores 0 0 0 0 temp 63000
16:11:43 throttle counts: package 0 cores 0 0 0 0 temp 59000
16:11:43 cool-down 60 s
every core capped at 1600 MHz ('/home/ggs/thermal-test/software/tools/thermal-sim/cap-cpu.sh restore' to undo)
16:12:43 cap1600: flat out 60 s
16:12:43 throttle counts: package 0 cores 0 0 0 0 temp 55000
16:13:45 cap1600: paced 2000 ms 120 s
16:13:45 throttle counts: package 0 cores 0 0 0 0 temp 54000
16:15:46 throttle counts: package 0 cores 0 0 0 0 temp 55000
CPU clock limits restored
16:15:46 cool-down 60 s
every core capped at 1200 MHz ('/home/ggs/thermal-test/software/tools/thermal-sim/cap-cpu.sh restore' to undo)
16:16:46 cap1200: flat out 60 s
16:16:46 throttle counts: package 0 cores 0 0 0 0 temp 51000
16:17:49 cap1200: paced 2000 ms 120 s
16:17:49 throttle counts: package 0 cores 0 0 0 0 temp 54000
16:19:51 throttle counts: package 0 cores 0 0 0 0 temp 54000
CPU clock limits restored
16:19:51 cool-down 60 s
every core capped at 800 MHz ('/home/ggs/thermal-test/software/tools/thermal-sim/cap-cpu.sh restore' to undo)
16:20:51 cap800: flat out 60 s
16:20:51 throttle counts: package 0 cores 0 0 0 0 temp 52000
16:21:54 cap800: paced 2000 ms 120 s
16:21:54 throttle counts: package 0 cores 0 0 0 0 temp 52000
16:23:59 throttle counts: package 0 cores 0 0 0 0 temp 53000
CPU clock limits restored
16:23:59 cool-down 60 s
package power capped at 6 W (was 10 W; '/home/ggs/thermal-test/software/tools/thermal-sim/cap-power.sh restore' to undo)
16:24:59 power6w: flat out 60 s
16:24:59 throttle counts: package 0 cores 0 0 0 0 temp 51000
16:26:01 power6w: paced 2000 ms 120 s
16:26:01 throttle counts: package 0 cores 0 0 0 0 temp 56000
16:28:02 throttle counts: package 0 cores 0 0 0 0 temp 58000
power limit restored to 10 W
16:28:02 cool-down 60 s
16:29:02 load2: 2 busy cores, paced 2000 ms 120 s
16:29:02 throttle counts: package 0 cores 0 0 0 0 temp 52000
nothing to restore (no cap set since boot)
nothing to restore (no cap set since boot)
16:51:52 throttle counts: package 0 cores 0 0 0 0 temp 54000
16:51:52 cool-down 60 s
every core capped at 800 MHz ('/home/ggs/thermal-test/software/tools/thermal-sim/cap-cpu.sh restore' to undo)
16:52:52 cap800+load2: paced 2000 ms 120 s
16:52:52 throttle counts: package 0 cores 0 0 0 0 temp 49000
16:54:57 throttle counts: package 0 cores 0 0 0 0 temp 52000
CPU clock limits restored
16:54:57 done
nothing to restore (no cap set since boot)
nothing to restore (no cap set since boot)

View File

@ -0,0 +1,78 @@
#!/bin/sh
# Throttling matrix on tower 111 (3 Delta, N5105): the 12-bit save pipeline under
# clock caps, a power cap and competing load. Tower program stopped. ~25 min.
# nohup sh ~/thermal-test/matrix.sh > ~/thermal-test/matrix.log 2>&1 &
set -u
cd ~/fgc-bench
R=~/thermal-test/results-tower111
O=/tmp/thermal-bench-out
B=./raw12_bench
SIM=~/thermal-test/software/tools/thermal-sim
mkdir -p "$R"
restore() {
sudo -n "$SIM/cap-cpu.sh" restore
sudo -n "$SIM/cap-power.sh" restore
pkill -f "stress-ng --cpu" 2>/dev/null
rm -f /dev/shm/fgc_rapl_run
rm -rf "$O"
}
trap restore EXIT INT TERM
touch /dev/shm/fgc_rapl_run
sudo -n sh -c 'while [ -e /dev/shm/fgc_rapl_run ]; do
cat /sys/class/powercap/intel-rapl:0/energy_uj > /dev/shm/fgc_rapl.tmp &&
chmod 644 /dev/shm/fgc_rapl.tmp && mv /dev/shm/fgc_rapl.tmp /dev/shm/fgc_rapl
sleep 0.25; done; rm -f /dev/shm/fgc_rapl' &
export FGC_RAPL=/dev/shm/fgc_rapl
sleep 1
step() { echo "$(date +%T) $*"; }
counts() {
echo "$(date +%T) throttle counts: package $(cat /sys/devices/system/cpu/cpu0/thermal_throttle/package_throttle_count)" \
"cores $(cat /sys/devices/system/cpu/cpu*/thermal_throttle/core_throttle_count | tr '\n' ' ')" \
"temp $(cat /sys/class/thermal/thermal_zone2/temp)"
}
# label: flat-out 60 s, then one frame per 2 s for 120 s
run() {
step "$1: flat out 60 s"; counts
$B pipeline synth $O c12_ea 1 4 60 0 3 1.0 > "$R/$1_flat.jsonl"
step "$1: paced 2000 ms 120 s"; counts
$B pipeline synth $O c12_ea 1 4 120 2000 3 1.0 > "$R/$1_paced.jsonl"
counts
}
cool() { step "cool-down $1 s"; $B idle synth $O "$1" > "$R/idle_$2.jsonl"; }
cool 60 start
run none
cool 60 a
for mhz in 1600 1200 800; do
sudo -n "$SIM/cap-cpu.sh" "$mhz"
run "cap${mhz}"
sudo -n "$SIM/cap-cpu.sh" restore
cool 60 "after${mhz}"
done
sudo -n "$SIM/cap-power.sh" 6
run power6w
sudo -n "$SIM/cap-power.sh" restore
cool 60 afterpower
step "load2: 2 busy cores, paced 2000 ms 120 s"; counts
stress-ng --cpu 2 --timeout 125s --quiet &
sp=$! # only this: a bare `wait` also waits for the power-reading loop, forever
sleep 2
$B pipeline synth $O c12_ea 1 4 120 2000 3 1.0 > "$R/load2_paced.jsonl"
wait "$sp"
counts
cool 60 afterload
sudo -n "$SIM/cap-cpu.sh" 800
step "cap800+load2: paced 2000 ms 120 s"; counts
stress-ng --cpu 2 --timeout 125s --quiet &
sp=$! # only this: a bare `wait` also waits for the power-reading loop, forever
sleep 2
$B pipeline synth $O c12_ea 1 4 120 2000 3 1.0 > "$R/cap800load2_paced.jsonl"
wait "$sp"
counts
sudo -n "$SIM/cap-cpu.sh" restore
step done

View File

@ -0,0 +1,61 @@
{"t": 1, "temp_c": 76.0, "mhz": 2848, "cpu_pct": 62.6, "watts": 8.44, "rss_mb": 535, "done": 0, "queue": 0}
{"t": 2, "temp_c": 74.0, "mhz": 2800, "cpu_pct": 61.8, "watts": 8.75, "rss_mb": 617, "done": 1, "queue": 0}
{"t": 3, "temp_c": 75.0, "mhz": 2800, "cpu_pct": 57.6, "watts": 8.43, "rss_mb": 639, "done": 2, "queue": 0}
{"t": 4, "temp_c": 76.0, "mhz": 2821, "cpu_pct": 59.0, "watts": 8.51, "rss_mb": 581, "done": 3, "queue": 0}
{"t": 5, "temp_c": 74.0, "mhz": 2800, "cpu_pct": 59.7, "watts": 8.71, "rss_mb": 686, "done": 4, "queue": 0}
{"t": 6, "temp_c": 82.0, "mhz": 2800, "cpu_pct": 68.8, "watts": 8.89, "rss_mb": 689, "done": 5, "queue": 0}
{"t": 7, "temp_c": 76.0, "mhz": 2874, "cpu_pct": 57.8, "watts": 6.11, "rss_mb": 681, "done": 6, "queue": 0}
{"t": 8, "temp_c": 70.0, "mhz": 2853, "cpu_pct": 60.6, "watts": 8.69, "rss_mb": 684, "done": 7, "queue": 0}
{"t": 9, "temp_c": 74.0, "mhz": 2831, "cpu_pct": 60.2, "watts": 8.79, "rss_mb": 688, "done": 8, "queue": 0}
{"t": 10, "temp_c": 72.0, "mhz": 2355, "cpu_pct": 60.1, "watts": 8.78, "rss_mb": 695, "done": 9, "queue": 0}
{"t": 11, "temp_c": 71.0, "mhz": 2801, "cpu_pct": 60.8, "watts": 8.76, "rss_mb": 697, "done": 10, "queue": 0}
{"t": 12, "temp_c": 75.0, "mhz": 2851, "cpu_pct": 60.5, "watts": 8.69, "rss_mb": 699, "done": 11, "queue": 0}
{"t": 13, "temp_c": 79.0, "mhz": 2500, "cpu_pct": 70.9, "watts": 9.14, "rss_mb": 701, "done": 12, "queue": 0}
{"t": 14, "temp_c": 66.0, "mhz": 1848, "cpu_pct": 59.6, "watts": 8.53, "rss_mb": 702, "done": 13, "queue": 0}
{"t": 15, "temp_c": 73.0, "mhz": 2800, "cpu_pct": 61.5, "watts": 8.77, "rss_mb": 704, "done": 14, "queue": 0}
{"t": 16, "temp_c": 79.0, "mhz": 2800, "cpu_pct": 61.6, "watts": 8.77, "rss_mb": 706, "done": 15, "queue": 0}
{"t": 17, "temp_c": 80.0, "mhz": 2800, "cpu_pct": 60.1, "watts": 8.63, "rss_mb": 706, "done": 16, "queue": 0}
{"t": 18, "temp_c": 79.0, "mhz": 2800, "cpu_pct": 61.0, "watts": 6.58, "rss_mb": 723, "done": 17, "queue": 0}
{"t": 19, "temp_c": 79.0, "mhz": 2800, "cpu_pct": 62.0, "watts": 8.73, "rss_mb": 708, "done": 18, "queue": 0}
{"t": 20, "temp_c": 77.0, "mhz": 2800, "cpu_pct": 59.8, "watts": 8.67, "rss_mb": 725, "done": 19, "queue": 0}
{"t": 21, "temp_c": 68.0, "mhz": 2346, "cpu_pct": 60.4, "watts": 8.69, "rss_mb": 727, "done": 20, "queue": 0}
{"t": 22, "temp_c": 72.0, "mhz": 2856, "cpu_pct": 59.9, "watts": 8.57, "rss_mb": 728, "done": 21, "queue": 0}
{"t": 23, "temp_c": 83.0, "mhz": 2800, "cpu_pct": 58.5, "watts": 8.44, "rss_mb": 729, "done": 22, "queue": 0}
{"t": 24, "temp_c": 84.0, "mhz": 2800, "cpu_pct": 61.8, "watts": 8.87, "rss_mb": 713, "done": 23, "queue": 0}
{"t": 25, "temp_c": 84.0, "mhz": 2800, "cpu_pct": 60.5, "watts": 8.65, "rss_mb": 713, "done": 24, "queue": 0}
{"t": 26, "temp_c": 83.0, "mhz": 2800, "cpu_pct": 60.8, "watts": 8.83, "rss_mb": 730, "done": 25, "queue": 0}
{"t": 27, "temp_c": 84.0, "mhz": 2800, "cpu_pct": 60.6, "watts": 8.71, "rss_mb": 715, "done": 26, "queue": 0}
{"t": 28, "temp_c": 86.0, "mhz": 2800, "cpu_pct": 60.7, "watts": 8.74, "rss_mb": 715, "done": 27, "queue": 0}
{"t": 29, "temp_c": 82.0, "mhz": 2800, "cpu_pct": 59.1, "watts": 8.59, "rss_mb": 715, "done": 28, "queue": 0}
{"t": 30, "temp_c": 85.0, "mhz": 2800, "cpu_pct": 62.7, "watts": 6.71, "rss_mb": 716, "done": 29, "queue": 0}
{"t": 31, "temp_c": 75.0, "mhz": 2850, "cpu_pct": 63.4, "watts": 9.06, "rss_mb": 716, "done": 30, "queue": 0}
{"t": 32, "temp_c": 84.0, "mhz": 2800, "cpu_pct": 60.5, "watts": 8.63, "rss_mb": 716, "done": 31, "queue": 0}
{"t": 33, "temp_c": 84.0, "mhz": 2800, "cpu_pct": 60.2, "watts": 8.64, "rss_mb": 716, "done": 32, "queue": 0}
{"t": 34, "temp_c": 84.0, "mhz": 2800, "cpu_pct": 60.2, "watts": 8.60, "rss_mb": 716, "done": 33, "queue": 0}
{"t": 35, "temp_c": 82.0, "mhz": 2854, "cpu_pct": 63.1, "watts": 8.86, "rss_mb": 732, "done": 34, "queue": 0}
{"t": 36, "temp_c": 79.0, "mhz": 2800, "cpu_pct": 60.2, "watts": 8.73, "rss_mb": 717, "done": 35, "queue": 0}
{"t": 37, "temp_c": 73.0, "mhz": 2804, "cpu_pct": 61.4, "watts": 8.82, "rss_mb": 717, "done": 36, "queue": 0}
{"t": 38, "temp_c": 75.0, "mhz": 2359, "cpu_pct": 60.7, "watts": 8.81, "rss_mb": 717, "done": 37, "queue": 0}
{"t": 39, "temp_c": 75.0, "mhz": 2876, "cpu_pct": 60.7, "watts": 8.87, "rss_mb": 717, "done": 38, "queue": 0}
{"t": 40, "temp_c": 76.0, "mhz": 2874, "cpu_pct": 61.1, "watts": 8.77, "rss_mb": 717, "done": 39, "queue": 0}
{"t": 41, "temp_c": 80.0, "mhz": 1841, "cpu_pct": 60.8, "watts": 6.49, "rss_mb": 717, "done": 40, "queue": 0}
{"t": 42, "temp_c": 78.0, "mhz": 2876, "cpu_pct": 60.4, "watts": 8.64, "rss_mb": 717, "done": 41, "queue": 0}
{"t": 43, "temp_c": 75.0, "mhz": 2850, "cpu_pct": 61.2, "watts": 8.78, "rss_mb": 718, "done": 42, "queue": 0}
{"t": 44, "temp_c": 80.0, "mhz": 2800, "cpu_pct": 72.2, "watts": 8.98, "rss_mb": 718, "done": 43, "queue": 0}
{"t": 45, "temp_c": 76.0, "mhz": 2800, "cpu_pct": 60.1, "watts": 8.55, "rss_mb": 734, "done": 44, "queue": 0}
{"t": 46, "temp_c": 72.0, "mhz": 2862, "cpu_pct": 61.7, "watts": 8.82, "rss_mb": 735, "done": 45, "queue": 0}
{"t": 47, "temp_c": 83.0, "mhz": 2800, "cpu_pct": 56.9, "watts": 8.28, "rss_mb": 735, "done": 46, "queue": 0}
{"t": 48, "temp_c": 84.0, "mhz": 2818, "cpu_pct": 60.3, "watts": 8.64, "rss_mb": 719, "done": 47, "queue": 0}
{"t": 49, "temp_c": 85.0, "mhz": 2800, "cpu_pct": 60.8, "watts": 8.68, "rss_mb": 717, "done": 48, "queue": 0}
{"t": 50, "temp_c": 85.0, "mhz": 2833, "cpu_pct": 60.9, "watts": 8.86, "rss_mb": 736, "done": 49, "queue": 0}
{"t": 51, "temp_c": 85.0, "mhz": 2800, "cpu_pct": 61.1, "watts": 8.66, "rss_mb": 723, "done": 50, "queue": 0}
{"t": 52, "temp_c": 80.0, "mhz": 2800, "cpu_pct": 60.1, "watts": 8.77, "rss_mb": 703, "done": 51, "queue": 0}
{"t": 53, "temp_c": 78.0, "mhz": 2800, "cpu_pct": 60.1, "watts": 6.81, "rss_mb": 691, "done": 52, "queue": 0}
{"t": 54, "temp_c": 78.0, "mhz": 2823, "cpu_pct": 61.7, "watts": 8.68, "rss_mb": 688, "done": 53, "queue": 0}
{"t": 55, "temp_c": 80.0, "mhz": 2800, "cpu_pct": 56.5, "watts": 8.64, "rss_mb": 589, "done": 54, "queue": 0}
{"t": 56, "temp_c": 80.0, "mhz": 2830, "cpu_pct": 59.9, "watts": 8.16, "rss_mb": 610, "done": 55, "queue": 0}
{"t": 57, "temp_c": 78.0, "mhz": 2872, "cpu_pct": 60.2, "watts": 8.80, "rss_mb": 608, "done": 56, "queue": 0}
{"t": 58, "temp_c": 75.0, "mhz": 2850, "cpu_pct": 60.8, "watts": 8.67, "rss_mb": 614, "done": 57, "queue": 0}
{"t": 59, "temp_c": 83.0, "mhz": 2800, "cpu_pct": 60.4, "watts": 8.71, "rss_mb": 592, "done": 58, "queue": 0}
{"t": 60, "temp_c": 61.0, "mhz": 757, "cpu_pct": 57.6, "watts": 8.60, "rss_mb": 392, "done": 59, "queue": 0}
{"summary": "pipeline", "kind": "c12_ea", "workers": 1, "threads": 4, "effort": 3, "distance": 1.00, "period_ms": 0, "secs": 60.0, "frames": 59, "frames_per_s": 0.983, "job_ms_p50": 994, "latency_ms_p50": 1009, "latency_ms_p95": 1094, "latency_ms_max": 1126, "max_queue": 0, "backlog_at_end": 0, "cpu_s_per_frame": 2.331, "peak_rss_mb": 736, "temp_c_mean": 78.0, "temp_c_max": 86.0, "mhz_mean": 2724, "mhz_min": 757, "cpu_pct_mean": 60.9, "watts_mean": 8.52}

View File

@ -0,0 +1,121 @@
{"t": 1, "temp_c": 80.0, "mhz": 2824, "cpu_pct": 62.4, "watts": 8.60, "rss_mb": 535, "done": 0, "queue": 0}
{"t": 2, "temp_c": 57.0, "mhz": 2805, "cpu_pct": 7.0, "watts": 3.96, "rss_mb": 247, "done": 1, "queue": 0}
{"t": 3, "temp_c": 66.0, "mhz": 2398, "cpu_pct": 61.0, "watts": 8.51, "rss_mb": 376, "done": 1, "queue": 0}
{"t": 4, "temp_c": 56.0, "mhz": 800, "cpu_pct": 6.1, "watts": 3.49, "rss_mb": 283, "done": 2, "queue": 0}
{"t": 5, "temp_c": 71.0, "mhz": 2801, "cpu_pct": 61.5, "watts": 8.65, "rss_mb": 397, "done": 2, "queue": 0}
{"t": 6, "temp_c": 56.0, "mhz": 800, "cpu_pct": 4.8, "watts": 2.27, "rss_mb": 304, "done": 3, "queue": 0}
{"t": 7, "temp_c": 77.0, "mhz": 2828, "cpu_pct": 61.6, "watts": 7.53, "rss_mb": 580, "done": 3, "queue": 0}
{"t": 8, "temp_c": 56.0, "mhz": 2700, "cpu_pct": 5.8, "watts": 4.39, "rss_mb": 395, "done": 4, "queue": 0}
{"t": 9, "temp_c": 63.0, "mhz": 1427, "cpu_pct": 60.5, "watts": 7.96, "rss_mb": 543, "done": 4, "queue": 0}
{"t": 10, "temp_c": 56.0, "mhz": 1135, "cpu_pct": 4.3, "watts": 3.73, "rss_mb": 450, "done": 5, "queue": 0}
{"t": 11, "temp_c": 63.0, "mhz": 961, "cpu_pct": 61.0, "watts": 8.18, "rss_mb": 517, "done": 5, "queue": 0}
{"t": 12, "temp_c": 55.0, "mhz": 782, "cpu_pct": 5.3, "watts": 3.37, "rss_mb": 462, "done": 6, "queue": 0}
{"t": 13, "temp_c": 65.0, "mhz": 2225, "cpu_pct": 61.7, "watts": 8.44, "rss_mb": 560, "done": 6, "queue": 0}
{"t": 14, "temp_c": 57.0, "mhz": 800, "cpu_pct": 21.2, "watts": 4.37, "rss_mb": 467, "done": 7, "queue": 0}
{"t": 15, "temp_c": 65.0, "mhz": 2900, "cpu_pct": 62.1, "watts": 6.43, "rss_mb": 562, "done": 7, "queue": 0}
{"t": 16, "temp_c": 56.0, "mhz": 2350, "cpu_pct": 6.0, "watts": 4.45, "rss_mb": 470, "done": 8, "queue": 0}
{"t": 17, "temp_c": 63.0, "mhz": 1287, "cpu_pct": 60.7, "watts": 7.77, "rss_mb": 473, "done": 9, "queue": 0}
{"t": 18, "temp_c": 56.0, "mhz": 800, "cpu_pct": 4.3, "watts": 3.61, "rss_mb": 473, "done": 9, "queue": 0}
{"t": 19, "temp_c": 64.0, "mhz": 1260, "cpu_pct": 60.6, "watts": 8.03, "rss_mb": 478, "done": 9, "queue": 0}
{"t": 20, "temp_c": 55.0, "mhz": 820, "cpu_pct": 3.5, "watts": 3.44, "rss_mb": 478, "done": 10, "queue": 0}
{"t": 21, "temp_c": 63.0, "mhz": 964, "cpu_pct": 60.9, "watts": 8.29, "rss_mb": 561, "done": 10, "queue": 0}
{"t": 22, "temp_c": 58.0, "mhz": 2025, "cpu_pct": 7.3, "watts": 3.33, "rss_mb": 479, "done": 11, "queue": 0}
{"t": 23, "temp_c": 63.0, "mhz": 1983, "cpu_pct": 60.6, "watts": 8.44, "rss_mb": 480, "done": 12, "queue": 0}
{"t": 24, "temp_c": 57.0, "mhz": 2801, "cpu_pct": 5.0, "watts": 3.12, "rss_mb": 480, "done": 12, "queue": 0}
{"t": 25, "temp_c": 63.0, "mhz": 1899, "cpu_pct": 60.3, "watts": 6.72, "rss_mb": 481, "done": 13, "queue": 0}
{"t": 26, "temp_c": 57.0, "mhz": 2800, "cpu_pct": 3.8, "watts": 3.97, "rss_mb": 490, "done": 13, "queue": 0}
{"t": 27, "temp_c": 61.0, "mhz": 988, "cpu_pct": 59.7, "watts": 7.83, "rss_mb": 484, "done": 14, "queue": 0}
{"t": 28, "temp_c": 55.0, "mhz": 1757, "cpu_pct": 5.1, "watts": 3.63, "rss_mb": 484, "done": 14, "queue": 0}
{"t": 29, "temp_c": 63.0, "mhz": 1505, "cpu_pct": 60.5, "watts": 8.21, "rss_mb": 485, "done": 15, "queue": 0}
{"t": 30, "temp_c": 56.0, "mhz": 1597, "cpu_pct": 4.8, "watts": 3.31, "rss_mb": 485, "done": 15, "queue": 0}
{"t": 31, "temp_c": 62.0, "mhz": 895, "cpu_pct": 60.2, "watts": 8.52, "rss_mb": 541, "done": 15, "queue": 0}
{"t": 32, "temp_c": 68.0, "mhz": 2800, "cpu_pct": 5.3, "watts": 2.99, "rss_mb": 509, "done": 16, "queue": 0}
{"t": 33, "temp_c": 60.0, "mhz": 1018, "cpu_pct": 58.5, "watts": 6.76, "rss_mb": 487, "done": 17, "queue": 0}
{"t": 34, "temp_c": 65.0, "mhz": 2800, "cpu_pct": 6.1, "watts": 4.11, "rss_mb": 519, "done": 17, "queue": 0}
{"t": 35, "temp_c": 61.0, "mhz": 1461, "cpu_pct": 59.6, "watts": 7.82, "rss_mb": 489, "done": 18, "queue": 0}
{"t": 36, "temp_c": 58.0, "mhz": 2800, "cpu_pct": 5.5, "watts": 3.75, "rss_mb": 503, "done": 18, "queue": 0}
{"t": 37, "temp_c": 61.0, "mhz": 1150, "cpu_pct": 59.9, "watts": 8.21, "rss_mb": 490, "done": 19, "queue": 0}
{"t": 38, "temp_c": 71.0, "mhz": 2800, "cpu_pct": 6.3, "watts": 3.14, "rss_mb": 541, "done": 19, "queue": 0}
{"t": 39, "temp_c": 61.0, "mhz": 770, "cpu_pct": 57.7, "watts": 8.57, "rss_mb": 490, "done": 20, "queue": 0}
{"t": 40, "temp_c": 62.0, "mhz": 2800, "cpu_pct": 7.3, "watts": 3.22, "rss_mb": 515, "done": 20, "queue": 0}
{"t": 41, "temp_c": 61.0, "mhz": 911, "cpu_pct": 59.5, "watts": 6.74, "rss_mb": 490, "done": 21, "queue": 0}
{"t": 42, "temp_c": 64.0, "mhz": 2800, "cpu_pct": 5.8, "watts": 4.02, "rss_mb": 523, "done": 21, "queue": 0}
{"t": 43, "temp_c": 62.0, "mhz": 1504, "cpu_pct": 60.1, "watts": 7.78, "rss_mb": 490, "done": 22, "queue": 0}
{"t": 44, "temp_c": 74.0, "mhz": 2800, "cpu_pct": 9.6, "watts": 3.88, "rss_mb": 568, "done": 22, "queue": 0}
{"t": 45, "temp_c": 75.0, "mhz": 2851, "cpu_pct": 73.9, "watts": 8.89, "rss_mb": 725, "done": 22, "queue": 0}
{"t": 46, "temp_c": 68.0, "mhz": 2800, "cpu_pct": 8.5, "watts": 4.03, "rss_mb": 542, "done": 23, "queue": 0}
{"t": 47, "temp_c": 61.0, "mhz": 897, "cpu_pct": 58.5, "watts": 8.44, "rss_mb": 492, "done": 24, "queue": 0}
{"t": 48, "temp_c": 70.0, "mhz": 2800, "cpu_pct": 6.8, "watts": 3.07, "rss_mb": 554, "done": 24, "queue": 0}
{"t": 49, "temp_c": 61.0, "mhz": 801, "cpu_pct": 58.5, "watts": 8.55, "rss_mb": 492, "done": 25, "queue": 0}
{"t": 50, "temp_c": 71.0, "mhz": 2823, "cpu_pct": 8.0, "watts": 2.18, "rss_mb": 592, "done": 25, "queue": 0}
{"t": 51, "temp_c": 61.0, "mhz": 859, "cpu_pct": 56.5, "watts": 7.96, "rss_mb": 493, "done": 26, "queue": 0}
{"t": 52, "temp_c": 71.0, "mhz": 2800, "cpu_pct": 7.0, "watts": 3.76, "rss_mb": 568, "done": 26, "queue": 0}
{"t": 53, "temp_c": 60.0, "mhz": 822, "cpu_pct": 57.4, "watts": 8.01, "rss_mb": 587, "done": 26, "queue": 0}
{"t": 54, "temp_c": 72.0, "mhz": 2800, "cpu_pct": 8.3, "watts": 3.49, "rss_mb": 582, "done": 27, "queue": 0}
{"t": 55, "temp_c": 60.0, "mhz": 797, "cpu_pct": 58.4, "watts": 8.50, "rss_mb": 587, "done": 27, "queue": 0}
{"t": 56, "temp_c": 72.0, "mhz": 2846, "cpu_pct": 8.6, "watts": 3.12, "rss_mb": 597, "done": 28, "queue": 0}
{"t": 57, "temp_c": 60.0, "mhz": 2797, "cpu_pct": 57.9, "watts": 8.48, "rss_mb": 495, "done": 29, "queue": 0}
{"t": 58, "temp_c": 66.0, "mhz": 2801, "cpu_pct": 8.3, "watts": 2.35, "rss_mb": 606, "done": 29, "queue": 0}
{"t": 59, "temp_c": 59.0, "mhz": 926, "cpu_pct": 56.4, "watts": 7.81, "rss_mb": 495, "done": 30, "queue": 0}
{"t": 60, "temp_c": 73.0, "mhz": 2825, "cpu_pct": 8.3, "watts": 3.74, "rss_mb": 591, "done": 30, "queue": 0}
{"t": 61, "temp_c": 60.0, "mhz": 791, "cpu_pct": 57.4, "watts": 8.06, "rss_mb": 496, "done": 31, "queue": 0}
{"t": 62, "temp_c": 70.0, "mhz": 2875, "cpu_pct": 7.8, "watts": 3.28, "rss_mb": 596, "done": 31, "queue": 0}
{"t": 63, "temp_c": 61.0, "mhz": 1015, "cpu_pct": 57.2, "watts": 8.50, "rss_mb": 496, "done": 32, "queue": 0}
{"t": 64, "temp_c": 70.0, "mhz": 2850, "cpu_pct": 8.0, "watts": 3.16, "rss_mb": 604, "done": 32, "queue": 0}
{"t": 65, "temp_c": 60.0, "mhz": 763, "cpu_pct": 57.2, "watts": 8.50, "rss_mb": 496, "done": 33, "queue": 0}
{"t": 66, "temp_c": 69.0, "mhz": 2832, "cpu_pct": 8.1, "watts": 3.24, "rss_mb": 598, "done": 33, "queue": 0}
{"t": 67, "temp_c": 60.0, "mhz": 781, "cpu_pct": 57.0, "watts": 6.83, "rss_mb": 496, "done": 34, "queue": 0}
{"t": 68, "temp_c": 70.0, "mhz": 2868, "cpu_pct": 8.3, "watts": 3.68, "rss_mb": 603, "done": 34, "queue": 0}
{"t": 69, "temp_c": 60.0, "mhz": 801, "cpu_pct": 56.8, "watts": 8.06, "rss_mb": 496, "done": 35, "queue": 0}
{"t": 70, "temp_c": 71.0, "mhz": 2846, "cpu_pct": 9.8, "watts": 3.73, "rss_mb": 596, "done": 35, "queue": 0}
{"t": 71, "temp_c": 59.0, "mhz": 870, "cpu_pct": 56.6, "watts": 8.29, "rss_mb": 496, "done": 36, "queue": 0}
{"t": 72, "temp_c": 66.0, "mhz": 2833, "cpu_pct": 7.8, "watts": 3.19, "rss_mb": 608, "done": 36, "queue": 0}
{"t": 73, "temp_c": 60.0, "mhz": 819, "cpu_pct": 57.3, "watts": 8.50, "rss_mb": 497, "done": 37, "queue": 0}
{"t": 74, "temp_c": 69.0, "mhz": 2868, "cpu_pct": 8.6, "watts": 3.09, "rss_mb": 610, "done": 37, "queue": 0}
{"t": 75, "temp_c": 66.0, "mhz": 2819, "cpu_pct": 64.2, "watts": 9.07, "rss_mb": 497, "done": 38, "queue": 0}
{"t": 76, "temp_c": 71.0, "mhz": 2800, "cpu_pct": 15.7, "watts": 3.92, "rss_mb": 609, "done": 38, "queue": 0}
{"t": 77, "temp_c": 59.0, "mhz": 744, "cpu_pct": 56.8, "watts": 6.68, "rss_mb": 497, "done": 39, "queue": 0}
{"t": 78, "temp_c": 66.0, "mhz": 2852, "cpu_pct": 8.8, "watts": 3.74, "rss_mb": 614, "done": 39, "queue": 0}
{"t": 79, "temp_c": 60.0, "mhz": 827, "cpu_pct": 57.5, "watts": 8.15, "rss_mb": 497, "done": 40, "queue": 0}
{"t": 80, "temp_c": 64.0, "mhz": 2850, "cpu_pct": 8.1, "watts": 3.40, "rss_mb": 619, "done": 40, "queue": 0}
{"t": 81, "temp_c": 59.0, "mhz": 813, "cpu_pct": 56.8, "watts": 8.41, "rss_mb": 497, "done": 41, "queue": 0}
{"t": 82, "temp_c": 69.0, "mhz": 2800, "cpu_pct": 9.1, "watts": 3.12, "rss_mb": 634, "done": 41, "queue": 0}
{"t": 83, "temp_c": 59.0, "mhz": 758, "cpu_pct": 55.6, "watts": 8.52, "rss_mb": 497, "done": 42, "queue": 0}
{"t": 84, "temp_c": 63.0, "mhz": 2847, "cpu_pct": 8.5, "watts": 3.40, "rss_mb": 642, "done": 42, "queue": 0}
{"t": 85, "temp_c": 60.0, "mhz": 778, "cpu_pct": 57.0, "watts": 6.78, "rss_mb": 497, "done": 43, "queue": 0}
{"t": 86, "temp_c": 63.0, "mhz": 2841, "cpu_pct": 9.0, "watts": 3.58, "rss_mb": 627, "done": 43, "queue": 0}
{"t": 87, "temp_c": 59.0, "mhz": 859, "cpu_pct": 57.6, "watts": 7.97, "rss_mb": 498, "done": 44, "queue": 0}
{"t": 88, "temp_c": 70.0, "mhz": 2849, "cpu_pct": 10.4, "watts": 3.53, "rss_mb": 620, "done": 44, "queue": 0}
{"t": 89, "temp_c": 60.0, "mhz": 927, "cpu_pct": 56.4, "watts": 8.37, "rss_mb": 499, "done": 45, "queue": 0}
{"t": 90, "temp_c": 62.0, "mhz": 2375, "cpu_pct": 8.8, "watts": 3.21, "rss_mb": 637, "done": 45, "queue": 0}
{"t": 91, "temp_c": 60.0, "mhz": 795, "cpu_pct": 57.9, "watts": 8.64, "rss_mb": 499, "done": 46, "queue": 0}
{"t": 92, "temp_c": 63.0, "mhz": 2375, "cpu_pct": 8.6, "watts": 3.36, "rss_mb": 633, "done": 46, "queue": 0}
{"t": 93, "temp_c": 60.0, "mhz": 800, "cpu_pct": 57.9, "watts": 6.65, "rss_mb": 500, "done": 47, "queue": 0}
{"t": 94, "temp_c": 64.0, "mhz": 2864, "cpu_pct": 9.1, "watts": 3.88, "rss_mb": 616, "done": 47, "queue": 0}
{"t": 95, "temp_c": 59.0, "mhz": 952, "cpu_pct": 56.4, "watts": 7.98, "rss_mb": 500, "done": 48, "queue": 0}
{"t": 96, "temp_c": 65.0, "mhz": 1850, "cpu_pct": 8.6, "watts": 3.57, "rss_mb": 641, "done": 48, "queue": 0}
{"t": 97, "temp_c": 59.0, "mhz": 836, "cpu_pct": 56.9, "watts": 8.34, "rss_mb": 501, "done": 49, "queue": 0}
{"t": 98, "temp_c": 63.0, "mhz": 1850, "cpu_pct": 9.6, "watts": 3.17, "rss_mb": 652, "done": 49, "queue": 0}
{"t": 99, "temp_c": 59.0, "mhz": 800, "cpu_pct": 56.4, "watts": 8.57, "rss_mb": 501, "done": 50, "queue": 0}
{"t": 100, "temp_c": 65.0, "mhz": 2824, "cpu_pct": 10.1, "watts": 3.21, "rss_mb": 653, "done": 50, "queue": 0}
{"t": 101, "temp_c": 59.0, "mhz": 800, "cpu_pct": 55.9, "watts": 8.28, "rss_mb": 501, "done": 51, "queue": 0}
{"t": 102, "temp_c": 61.0, "mhz": 2366, "cpu_pct": 9.1, "watts": 2.33, "rss_mb": 649, "done": 51, "queue": 0}
{"t": 103, "temp_c": 59.0, "mhz": 780, "cpu_pct": 56.8, "watts": 7.96, "rss_mb": 501, "done": 52, "queue": 0}
{"t": 104, "temp_c": 66.0, "mhz": 2367, "cpu_pct": 9.3, "watts": 3.59, "rss_mb": 653, "done": 52, "queue": 0}
{"t": 105, "temp_c": 59.0, "mhz": 768, "cpu_pct": 56.4, "watts": 8.32, "rss_mb": 501, "done": 53, "queue": 0}
{"t": 106, "temp_c": 76.0, "mhz": 2800, "cpu_pct": 28.1, "watts": 4.55, "rss_mb": 650, "done": 53, "queue": 0}
{"t": 107, "temp_c": 59.0, "mhz": 800, "cpu_pct": 56.3, "watts": 8.80, "rss_mb": 501, "done": 54, "queue": 0}
{"t": 108, "temp_c": 65.0, "mhz": 2301, "cpu_pct": 8.8, "watts": 3.16, "rss_mb": 657, "done": 54, "queue": 0}
{"t": 109, "temp_c": 60.0, "mhz": 780, "cpu_pct": 56.5, "watts": 8.40, "rss_mb": 502, "done": 55, "queue": 0}
{"t": 110, "temp_c": 62.0, "mhz": 2833, "cpu_pct": 8.6, "watts": 3.42, "rss_mb": 661, "done": 55, "queue": 0}
{"t": 111, "temp_c": 59.0, "mhz": 793, "cpu_pct": 56.0, "watts": 6.64, "rss_mb": 502, "done": 56, "queue": 0}
{"t": 112, "temp_c": 64.0, "mhz": 2324, "cpu_pct": 10.4, "watts": 3.61, "rss_mb": 652, "done": 56, "queue": 0}
{"t": 113, "temp_c": 59.0, "mhz": 776, "cpu_pct": 55.6, "watts": 8.26, "rss_mb": 502, "done": 57, "queue": 0}
{"t": 114, "temp_c": 63.0, "mhz": 2343, "cpu_pct": 8.8, "watts": 3.27, "rss_mb": 670, "done": 57, "queue": 0}
{"t": 115, "temp_c": 59.0, "mhz": 800, "cpu_pct": 56.6, "watts": 8.56, "rss_mb": 502, "done": 58, "queue": 0}
{"t": 116, "temp_c": 65.0, "mhz": 2859, "cpu_pct": 9.3, "watts": 3.13, "rss_mb": 669, "done": 58, "queue": 0}
{"t": 117, "temp_c": 59.0, "mhz": 875, "cpu_pct": 57.0, "watts": 8.51, "rss_mb": 502, "done": 59, "queue": 0}
{"t": 118, "temp_c": 62.0, "mhz": 2879, "cpu_pct": 10.1, "watts": 3.42, "rss_mb": 663, "done": 59, "queue": 0}
{"t": 119, "temp_c": 59.0, "mhz": 800, "cpu_pct": 56.2, "watts": 6.63, "rss_mb": 502, "done": 60, "queue": 0}
{"t": 120, "temp_c": 55.0, "mhz": 800, "cpu_pct": 4.5, "watts": 3.68, "rss_mb": 390, "done": 60, "queue": 0}
{"summary": "pipeline", "kind": "c12_ea", "workers": 1, "threads": 4, "effort": 3, "distance": 1.00, "period_ms": 2000, "secs": 120.0, "frames": 60, "frames_per_s": 0.500, "job_ms_p50": 1008, "latency_ms_p50": 1021, "latency_ms_p95": 1094, "latency_ms_max": 1140, "max_queue": 1, "backlog_at_end": 0, "cpu_s_per_frame": 2.343, "peak_rss_mb": 735, "temp_c_mean": 62.9, "temp_c_max": 80.0, "mhz_mean": 1816, "mhz_min": 744, "cpu_pct_mean": 33.4, "watts_mean": 5.75}

View File

@ -0,0 +1,62 @@
{"t": 1, "temp_c": 70.0, "mhz": 2803, "cpu_pct": 62.3, "watts": 8.25, "rss_mb": 536, "done": 0, "queue": 0}
{"t": 2, "temp_c": 72.0, "mhz": 2835, "cpu_pct": 60.7, "watts": 8.51, "rss_mb": 620, "done": 1, "queue": 0}
{"t": 3, "temp_c": 65.0, "mhz": 2376, "cpu_pct": 59.8, "watts": 8.64, "rss_mb": 633, "done": 2, "queue": 0}
{"t": 4, "temp_c": 76.0, "mhz": 2800, "cpu_pct": 59.4, "watts": 8.45, "rss_mb": 575, "done": 3, "queue": 0}
{"t": 5, "temp_c": 76.0, "mhz": 2800, "cpu_pct": 59.8, "watts": 8.59, "rss_mb": 681, "done": 4, "queue": 0}
{"t": 6, "temp_c": 76.0, "mhz": 2800, "cpu_pct": 60.7, "watts": 8.72, "rss_mb": 689, "done": 5, "queue": 0}
{"t": 7, "temp_c": 71.0, "mhz": 2800, "cpu_pct": 60.0, "watts": 8.68, "rss_mb": 681, "done": 6, "queue": 0}
{"t": 8, "temp_c": 69.0, "mhz": 2369, "cpu_pct": 60.2, "watts": 8.58, "rss_mb": 689, "done": 7, "queue": 0}
{"t": 9, "temp_c": 72.0, "mhz": 2874, "cpu_pct": 60.3, "watts": 8.77, "rss_mb": 690, "done": 8, "queue": 0}
{"t": 10, "temp_c": 77.0, "mhz": 2800, "cpu_pct": 61.7, "watts": 8.66, "rss_mb": 692, "done": 9, "queue": 0}
{"t": 11, "temp_c": 73.0, "mhz": 2798, "cpu_pct": 61.4, "watts": 6.51, "rss_mb": 697, "done": 10, "queue": 0}
{"t": 12, "temp_c": 77.0, "mhz": 2848, "cpu_pct": 61.1, "watts": 8.87, "rss_mb": 698, "done": 11, "queue": 0}
{"t": 13, "temp_c": 80.0, "mhz": 2800, "cpu_pct": 61.1, "watts": 8.74, "rss_mb": 700, "done": 12, "queue": 0}
{"t": 14, "temp_c": 69.0, "mhz": 2400, "cpu_pct": 59.6, "watts": 8.67, "rss_mb": 702, "done": 13, "queue": 0}
{"t": 15, "temp_c": 74.0, "mhz": 2800, "cpu_pct": 60.5, "watts": 8.54, "rss_mb": 703, "done": 14, "queue": 0}
{"t": 16, "temp_c": 78.0, "mhz": 2800, "cpu_pct": 61.2, "watts": 8.76, "rss_mb": 704, "done": 15, "queue": 0}
{"t": 17, "temp_c": 66.0, "mhz": 1325, "cpu_pct": 57.4, "watts": 8.54, "rss_mb": 704, "done": 16, "queue": 0}
{"t": 18, "temp_c": 70.0, "mhz": 2807, "cpu_pct": 60.7, "watts": 8.80, "rss_mb": 721, "done": 17, "queue": 0}
{"t": 19, "temp_c": 71.0, "mhz": 2867, "cpu_pct": 60.7, "watts": 8.75, "rss_mb": 705, "done": 18, "queue": 0}
{"t": 20, "temp_c": 76.0, "mhz": 2800, "cpu_pct": 60.2, "watts": 8.59, "rss_mb": 722, "done": 19, "queue": 0}
{"t": 21, "temp_c": 71.0, "mhz": 2867, "cpu_pct": 61.0, "watts": 8.77, "rss_mb": 724, "done": 20, "queue": 0}
{"t": 22, "temp_c": 71.0, "mhz": 2837, "cpu_pct": 60.5, "watts": 8.74, "rss_mb": 725, "done": 21, "queue": 0}
{"t": 23, "temp_c": 77.0, "mhz": 2800, "cpu_pct": 61.7, "watts": 6.56, "rss_mb": 725, "done": 22, "queue": 0}
{"t": 24, "temp_c": 76.0, "mhz": 2800, "cpu_pct": 60.9, "watts": 8.86, "rss_mb": 710, "done": 23, "queue": 0}
{"t": 25, "temp_c": 75.0, "mhz": 2800, "cpu_pct": 61.0, "watts": 8.67, "rss_mb": 710, "done": 24, "queue": 0}
{"t": 26, "temp_c": 78.0, "mhz": 2800, "cpu_pct": 70.9, "watts": 9.28, "rss_mb": 728, "done": 25, "queue": 0}
{"t": 27, "temp_c": 78.0, "mhz": 2800, "cpu_pct": 60.5, "watts": 8.68, "rss_mb": 712, "done": 26, "queue": 0}
{"t": 28, "temp_c": 77.0, "mhz": 2800, "cpu_pct": 60.3, "watts": 8.72, "rss_mb": 714, "done": 27, "queue": 0}
{"t": 29, "temp_c": 77.0, "mhz": 2800, "cpu_pct": 61.5, "watts": 8.90, "rss_mb": 714, "done": 28, "queue": 0}
{"t": 30, "temp_c": 77.0, "mhz": 2800, "cpu_pct": 60.4, "watts": 8.83, "rss_mb": 714, "done": 29, "queue": 0}
{"t": 31, "temp_c": 80.0, "mhz": 2812, "cpu_pct": 59.9, "watts": 8.63, "rss_mb": 715, "done": 30, "queue": 0}
{"t": 32, "temp_c": 78.0, "mhz": 2800, "cpu_pct": 61.8, "watts": 8.76, "rss_mb": 715, "done": 31, "queue": 0}
{"t": 33, "temp_c": 73.0, "mhz": 2825, "cpu_pct": 58.3, "watts": 8.44, "rss_mb": 715, "done": 32, "queue": 0}
{"t": 34, "temp_c": 74.0, "mhz": 2800, "cpu_pct": 60.4, "watts": 8.55, "rss_mb": 716, "done": 33, "queue": 0}
{"t": 35, "temp_c": 71.0, "mhz": 2894, "cpu_pct": 61.5, "watts": 6.49, "rss_mb": 732, "done": 34, "queue": 0}
{"t": 36, "temp_c": 81.0, "mhz": 2874, "cpu_pct": 60.2, "watts": 8.64, "rss_mb": 716, "done": 35, "queue": 0}
{"t": 37, "temp_c": 82.0, "mhz": 2868, "cpu_pct": 60.9, "watts": 8.85, "rss_mb": 717, "done": 36, "queue": 0}
{"t": 38, "temp_c": 81.0, "mhz": 2800, "cpu_pct": 61.0, "watts": 8.88, "rss_mb": 717, "done": 37, "queue": 0}
{"t": 39, "temp_c": 60.0, "mhz": 1700, "cpu_pct": 61.2, "watts": 7.48, "rss_mb": 717, "done": 38, "queue": 0}
{"t": 40, "temp_c": 59.0, "mhz": 1800, "cpu_pct": 58.8, "watts": 6.06, "rss_mb": 685, "done": 39, "queue": 0}
{"t": 41, "temp_c": 59.0, "mhz": 1800, "cpu_pct": 66.5, "watts": 5.80, "rss_mb": 717, "done": 39, "queue": 0}
{"t": 42, "temp_c": 59.0, "mhz": 1500, "cpu_pct": 60.5, "watts": 5.78, "rss_mb": 718, "done": 40, "queue": 0}
{"t": 43, "temp_c": 58.0, "mhz": 1800, "cpu_pct": 60.2, "watts": 5.61, "rss_mb": 686, "done": 41, "queue": 0}
{"t": 44, "temp_c": 59.0, "mhz": 1800, "cpu_pct": 67.2, "watts": 5.78, "rss_mb": 718, "done": 41, "queue": 0}
{"t": 45, "temp_c": 59.0, "mhz": 1800, "cpu_pct": 60.8, "watts": 4.23, "rss_mb": 718, "done": 42, "queue": 0}
{"t": 46, "temp_c": 59.0, "mhz": 1800, "cpu_pct": 59.6, "watts": 5.78, "rss_mb": 686, "done": 43, "queue": 0}
{"t": 47, "temp_c": 59.0, "mhz": 1900, "cpu_pct": 67.1, "watts": 6.01, "rss_mb": 718, "done": 43, "queue": 0}
{"t": 48, "temp_c": 58.0, "mhz": 1800, "cpu_pct": 59.9, "watts": 6.00, "rss_mb": 734, "done": 44, "queue": 0}
{"t": 49, "temp_c": 59.0, "mhz": 1800, "cpu_pct": 60.3, "watts": 5.83, "rss_mb": 688, "done": 45, "queue": 0}
{"t": 50, "temp_c": 59.0, "mhz": 1900, "cpu_pct": 65.8, "watts": 5.98, "rss_mb": 735, "done": 45, "queue": 0}
{"t": 51, "temp_c": 58.0, "mhz": 1624, "cpu_pct": 57.7, "watts": 5.98, "rss_mb": 736, "done": 46, "queue": 0}
{"t": 52, "temp_c": 59.0, "mhz": 1785, "cpu_pct": 62.8, "watts": 6.06, "rss_mb": 720, "done": 47, "queue": 0}
{"t": 53, "temp_c": 58.0, "mhz": 1900, "cpu_pct": 64.3, "watts": 4.53, "rss_mb": 720, "done": 47, "queue": 0}
{"t": 54, "temp_c": 59.0, "mhz": 1900, "cpu_pct": 60.4, "watts": 6.05, "rss_mb": 736, "done": 48, "queue": 0}
{"t": 55, "temp_c": 59.0, "mhz": 1800, "cpu_pct": 61.7, "watts": 6.02, "rss_mb": 736, "done": 49, "queue": 0}
{"t": 56, "temp_c": 60.0, "mhz": 1800, "cpu_pct": 69.3, "watts": 6.12, "rss_mb": 736, "done": 49, "queue": 0}
{"t": 57, "temp_c": 58.0, "mhz": 1025, "cpu_pct": 76.2, "watts": 6.44, "rss_mb": 737, "done": 50, "queue": 0}
{"t": 58, "temp_c": 58.0, "mhz": 1900, "cpu_pct": 59.0, "watts": 5.69, "rss_mb": 689, "done": 51, "queue": 0}
{"t": 59, "temp_c": 59.0, "mhz": 1800, "cpu_pct": 68.7, "watts": 6.05, "rss_mb": 737, "done": 51, "queue": 0}
{"t": 60, "temp_c": 58.0, "mhz": 1900, "cpu_pct": 58.4, "watts": 6.07, "rss_mb": 737, "done": 52, "queue": 0}
{"t": 61, "temp_c": 55.0, "mhz": 797, "cpu_pct": 48.0, "watts": 4.43, "rss_mb": 391, "done": 53, "queue": 0}
{"summary": "pipeline", "kind": "c12_ea", "workers": 1, "threads": 4, "effort": 3, "distance": 1.00, "period_ms": 0, "secs": 60.8, "frames": 53, "frames_per_s": 0.871, "job_ms_p50": 1006, "latency_ms_p50": 1019, "latency_ms_p95": 1519, "latency_ms_max": 1660, "max_queue": 0, "backlog_at_end": 0, "cpu_s_per_frame": 2.651, "peak_rss_mb": 737, "temp_c_mean": 68.6, "temp_c_max": 82.0, "mhz_mean": 2359, "mhz_min": 797, "cpu_pct_mean": 61.4, "watts_mean": 7.50}

View File

@ -0,0 +1,121 @@
{"t": 1, "temp_c": 60.0, "mhz": 2099, "cpu_pct": 61.9, "watts": 6.70, "rss_mb": 533, "done": 0, "queue": 0}
{"t": 2, "temp_c": 54.0, "mhz": 771, "cpu_pct": 23.0, "watts": 4.74, "rss_mb": 247, "done": 1, "queue": 0}
{"t": 3, "temp_c": 61.0, "mhz": 2300, "cpu_pct": 62.3, "watts": 7.22, "rss_mb": 613, "done": 1, "queue": 0}
{"t": 4, "temp_c": 54.0, "mhz": 800, "cpu_pct": 11.6, "watts": 3.98, "rss_mb": 282, "done": 2, "queue": 0}
{"t": 5, "temp_c": 67.0, "mhz": 2500, "cpu_pct": 62.6, "watts": 8.10, "rss_mb": 628, "done": 2, "queue": 0}
{"t": 6, "temp_c": 55.0, "mhz": 2847, "cpu_pct": 6.8, "watts": 3.31, "rss_mb": 297, "done": 3, "queue": 0}
{"t": 7, "temp_c": 71.0, "mhz": 2700, "cpu_pct": 60.6, "watts": 6.62, "rss_mb": 570, "done": 3, "queue": 0}
{"t": 8, "temp_c": 54.0, "mhz": 775, "cpu_pct": 5.3, "watts": 4.47, "rss_mb": 385, "done": 4, "queue": 0}
{"t": 9, "temp_c": 64.0, "mhz": 2017, "cpu_pct": 61.8, "watts": 7.52, "rss_mb": 534, "done": 4, "queue": 0}
{"t": 10, "temp_c": 54.0, "mhz": 795, "cpu_pct": 4.8, "watts": 4.12, "rss_mb": 442, "done": 5, "queue": 0}
{"t": 11, "temp_c": 63.0, "mhz": 1780, "cpu_pct": 61.2, "watts": 7.88, "rss_mb": 544, "done": 5, "queue": 0}
{"t": 12, "temp_c": 55.0, "mhz": 2800, "cpu_pct": 5.8, "watts": 3.56, "rss_mb": 452, "done": 6, "queue": 0}
{"t": 13, "temp_c": 61.0, "mhz": 1853, "cpu_pct": 59.2, "watts": 8.49, "rss_mb": 462, "done": 7, "queue": 0}
{"t": 14, "temp_c": 55.0, "mhz": 911, "cpu_pct": 4.5, "watts": 3.11, "rss_mb": 462, "done": 7, "queue": 0}
{"t": 15, "temp_c": 61.0, "mhz": 1000, "cpu_pct": 61.2, "watts": 8.52, "rss_mb": 465, "done": 8, "queue": 0}
{"t": 16, "temp_c": 55.0, "mhz": 799, "cpu_pct": 4.8, "watts": 2.21, "rss_mb": 465, "done": 8, "queue": 0}
{"t": 17, "temp_c": 61.0, "mhz": 1664, "cpu_pct": 60.5, "watts": 7.80, "rss_mb": 469, "done": 9, "queue": 0}
{"t": 18, "temp_c": 54.0, "mhz": 2847, "cpu_pct": 6.3, "watts": 3.86, "rss_mb": 469, "done": 9, "queue": 0}
{"t": 19, "temp_c": 61.0, "mhz": 1379, "cpu_pct": 59.9, "watts": 7.94, "rss_mb": 473, "done": 10, "queue": 0}
{"t": 20, "temp_c": 54.0, "mhz": 892, "cpu_pct": 4.5, "watts": 3.44, "rss_mb": 473, "done": 10, "queue": 0}
{"t": 21, "temp_c": 61.0, "mhz": 1106, "cpu_pct": 61.1, "watts": 8.26, "rss_mb": 518, "done": 10, "queue": 0}
{"t": 22, "temp_c": 55.0, "mhz": 940, "cpu_pct": 5.5, "watts": 3.27, "rss_mb": 474, "done": 11, "queue": 0}
{"t": 23, "temp_c": 61.0, "mhz": 1003, "cpu_pct": 60.2, "watts": 8.42, "rss_mb": 476, "done": 12, "queue": 0}
{"t": 24, "temp_c": 59.0, "mhz": 2800, "cpu_pct": 5.2, "watts": 2.19, "rss_mb": 488, "done": 12, "queue": 0}
{"t": 25, "temp_c": 74.0, "mhz": 2800, "cpu_pct": 64.7, "watts": 7.51, "rss_mb": 479, "done": 13, "queue": 0}
{"t": 26, "temp_c": 55.0, "mhz": 1949, "cpu_pct": 16.4, "watts": 5.30, "rss_mb": 479, "done": 13, "queue": 0}
{"t": 27, "temp_c": 61.0, "mhz": 1027, "cpu_pct": 60.4, "watts": 7.74, "rss_mb": 481, "done": 14, "queue": 0}
{"t": 28, "temp_c": 54.0, "mhz": 1430, "cpu_pct": 4.8, "watts": 3.59, "rss_mb": 481, "done": 14, "queue": 0}
{"t": 29, "temp_c": 61.0, "mhz": 1523, "cpu_pct": 59.8, "watts": 8.16, "rss_mb": 483, "done": 15, "queue": 0}
{"t": 30, "temp_c": 55.0, "mhz": 1811, "cpu_pct": 4.5, "watts": 3.40, "rss_mb": 483, "done": 15, "queue": 0}
{"t": 31, "temp_c": 60.0, "mhz": 1240, "cpu_pct": 59.9, "watts": 8.45, "rss_mb": 484, "done": 16, "queue": 0}
{"t": 32, "temp_c": 55.0, "mhz": 2798, "cpu_pct": 5.0, "watts": 3.06, "rss_mb": 484, "done": 16, "queue": 0}
{"t": 33, "temp_c": 60.0, "mhz": 1326, "cpu_pct": 60.3, "watts": 6.75, "rss_mb": 486, "done": 17, "queue": 0}
{"t": 34, "temp_c": 57.0, "mhz": 2800, "cpu_pct": 5.3, "watts": 3.94, "rss_mb": 499, "done": 17, "queue": 0}
{"t": 35, "temp_c": 61.0, "mhz": 951, "cpu_pct": 60.0, "watts": 7.83, "rss_mb": 489, "done": 18, "queue": 0}
{"t": 36, "temp_c": 67.0, "mhz": 2800, "cpu_pct": 8.3, "watts": 3.86, "rss_mb": 542, "done": 18, "queue": 0}
{"t": 37, "temp_c": 59.0, "mhz": 977, "cpu_pct": 58.4, "watts": 8.21, "rss_mb": 490, "done": 19, "queue": 0}
{"t": 38, "temp_c": 64.0, "mhz": 2800, "cpu_pct": 6.3, "watts": 3.20, "rss_mb": 525, "done": 19, "queue": 0}
{"t": 39, "temp_c": 60.0, "mhz": 1375, "cpu_pct": 58.6, "watts": 8.42, "rss_mb": 491, "done": 20, "queue": 0}
{"t": 40, "temp_c": 66.0, "mhz": 2800, "cpu_pct": 6.8, "watts": 3.10, "rss_mb": 535, "done": 20, "queue": 0}
{"t": 41, "temp_c": 60.0, "mhz": 800, "cpu_pct": 58.8, "watts": 8.57, "rss_mb": 491, "done": 21, "queue": 0}
{"t": 42, "temp_c": 71.0, "mhz": 2800, "cpu_pct": 7.3, "watts": 2.24, "rss_mb": 568, "done": 21, "queue": 0}
{"t": 43, "temp_c": 59.0, "mhz": 752, "cpu_pct": 56.8, "watts": 7.77, "rss_mb": 492, "done": 22, "queue": 0}
{"t": 44, "temp_c": 68.0, "mhz": 2800, "cpu_pct": 6.8, "watts": 3.67, "rss_mb": 553, "done": 22, "queue": 0}
{"t": 45, "temp_c": 60.0, "mhz": 913, "cpu_pct": 58.3, "watts": 8.04, "rss_mb": 493, "done": 23, "queue": 0}
{"t": 46, "temp_c": 70.0, "mhz": 2800, "cpu_pct": 7.3, "watts": 3.44, "rss_mb": 569, "done": 23, "queue": 0}
{"t": 47, "temp_c": 59.0, "mhz": 807, "cpu_pct": 57.7, "watts": 8.44, "rss_mb": 493, "done": 24, "queue": 0}
{"t": 48, "temp_c": 73.0, "mhz": 2800, "cpu_pct": 8.6, "watts": 2.98, "rss_mb": 573, "done": 24, "queue": 0}
{"t": 49, "temp_c": 60.0, "mhz": 868, "cpu_pct": 56.8, "watts": 8.58, "rss_mb": 494, "done": 25, "queue": 0}
{"t": 50, "temp_c": 72.0, "mhz": 2800, "cpu_pct": 7.8, "watts": 2.32, "rss_mb": 579, "done": 25, "queue": 0}
{"t": 51, "temp_c": 59.0, "mhz": 791, "cpu_pct": 57.8, "watts": 7.74, "rss_mb": 494, "done": 26, "queue": 0}
{"t": 52, "temp_c": 73.0, "mhz": 2800, "cpu_pct": 7.8, "watts": 3.75, "rss_mb": 584, "done": 26, "queue": 0}
{"t": 53, "temp_c": 60.0, "mhz": 1035, "cpu_pct": 58.4, "watts": 8.00, "rss_mb": 494, "done": 27, "queue": 0}
{"t": 54, "temp_c": 68.0, "mhz": 2850, "cpu_pct": 10.1, "watts": 3.53, "rss_mb": 599, "done": 27, "queue": 0}
{"t": 55, "temp_c": 60.0, "mhz": 794, "cpu_pct": 56.3, "watts": 8.46, "rss_mb": 495, "done": 28, "queue": 0}
{"t": 56, "temp_c": 57.0, "mhz": 1400, "cpu_pct": 18.4, "watts": 4.00, "rss_mb": 503, "done": 28, "queue": 0}
{"t": 57, "temp_c": 64.0, "mhz": 2526, "cpu_pct": 65.7, "watts": 8.73, "rss_mb": 589, "done": 28, "queue": 0}
{"t": 58, "temp_c": 70.0, "mhz": 2835, "cpu_pct": 8.8, "watts": 3.55, "rss_mb": 597, "done": 29, "queue": 0}
{"t": 59, "temp_c": 59.0, "mhz": 822, "cpu_pct": 56.9, "watts": 6.63, "rss_mb": 496, "done": 30, "queue": 0}
{"t": 60, "temp_c": 73.0, "mhz": 2843, "cpu_pct": 8.9, "watts": 3.74, "rss_mb": 593, "done": 30, "queue": 0}
{"t": 61, "temp_c": 59.0, "mhz": 868, "cpu_pct": 55.6, "watts": 8.02, "rss_mb": 496, "done": 31, "queue": 0}
{"t": 62, "temp_c": 68.0, "mhz": 2834, "cpu_pct": 8.6, "watts": 3.48, "rss_mb": 606, "done": 31, "queue": 0}
{"t": 63, "temp_c": 59.0, "mhz": 765, "cpu_pct": 56.4, "watts": 8.40, "rss_mb": 497, "done": 32, "queue": 0}
{"t": 64, "temp_c": 64.0, "mhz": 2849, "cpu_pct": 8.8, "watts": 3.13, "rss_mb": 615, "done": 32, "queue": 0}
{"t": 65, "temp_c": 59.0, "mhz": 744, "cpu_pct": 56.8, "watts": 8.58, "rss_mb": 497, "done": 33, "queue": 0}
{"t": 66, "temp_c": 70.0, "mhz": 2817, "cpu_pct": 9.5, "watts": 3.22, "rss_mb": 603, "done": 33, "queue": 0}
{"t": 67, "temp_c": 59.0, "mhz": 798, "cpu_pct": 56.8, "watts": 6.71, "rss_mb": 497, "done": 34, "queue": 0}
{"t": 68, "temp_c": 64.0, "mhz": 2838, "cpu_pct": 9.1, "watts": 3.80, "rss_mb": 616, "done": 34, "queue": 0}
{"t": 69, "temp_c": 59.0, "mhz": 777, "cpu_pct": 56.8, "watts": 8.05, "rss_mb": 497, "done": 35, "queue": 0}
{"t": 70, "temp_c": 63.0, "mhz": 2851, "cpu_pct": 8.8, "watts": 3.52, "rss_mb": 619, "done": 35, "queue": 0}
{"t": 71, "temp_c": 59.0, "mhz": 801, "cpu_pct": 56.8, "watts": 8.37, "rss_mb": 498, "done": 36, "queue": 0}
{"t": 72, "temp_c": 67.0, "mhz": 2848, "cpu_pct": 10.3, "watts": 3.19, "rss_mb": 629, "done": 36, "queue": 0}
{"t": 73, "temp_c": 59.0, "mhz": 775, "cpu_pct": 55.3, "watts": 8.54, "rss_mb": 498, "done": 37, "queue": 0}
{"t": 74, "temp_c": 64.0, "mhz": 2849, "cpu_pct": 8.4, "watts": 3.39, "rss_mb": 626, "done": 37, "queue": 0}
{"t": 75, "temp_c": 59.0, "mhz": 815, "cpu_pct": 56.0, "watts": 6.70, "rss_mb": 498, "done": 38, "queue": 0}
{"t": 76, "temp_c": 61.0, "mhz": 2900, "cpu_pct": 8.6, "watts": 3.59, "rss_mb": 631, "done": 38, "queue": 0}
{"t": 77, "temp_c": 59.0, "mhz": 868, "cpu_pct": 56.2, "watts": 8.16, "rss_mb": 499, "done": 39, "queue": 0}
{"t": 78, "temp_c": 65.0, "mhz": 2844, "cpu_pct": 10.1, "watts": 3.41, "rss_mb": 619, "done": 39, "queue": 0}
{"t": 79, "temp_c": 59.0, "mhz": 779, "cpu_pct": 56.0, "watts": 8.34, "rss_mb": 499, "done": 40, "queue": 0}
{"t": 80, "temp_c": 61.0, "mhz": 1843, "cpu_pct": 8.6, "watts": 3.26, "rss_mb": 657, "done": 40, "queue": 0}
{"t": 81, "temp_c": 58.0, "mhz": 762, "cpu_pct": 56.0, "watts": 8.56, "rss_mb": 499, "done": 41, "queue": 0}
{"t": 82, "temp_c": 62.0, "mhz": 2859, "cpu_pct": 9.0, "watts": 3.43, "rss_mb": 659, "done": 41, "queue": 0}
{"t": 83, "temp_c": 59.0, "mhz": 800, "cpu_pct": 56.5, "watts": 8.15, "rss_mb": 499, "done": 42, "queue": 0}
{"t": 84, "temp_c": 63.0, "mhz": 2370, "cpu_pct": 9.1, "watts": 2.25, "rss_mb": 648, "done": 42, "queue": 0}
{"t": 85, "temp_c": 59.0, "mhz": 800, "cpu_pct": 55.5, "watts": 8.12, "rss_mb": 499, "done": 43, "queue": 0}
{"t": 86, "temp_c": 63.0, "mhz": 2358, "cpu_pct": 8.6, "watts": 3.38, "rss_mb": 648, "done": 43, "queue": 0}
{"t": 87, "temp_c": 74.0, "mhz": 2737, "cpu_pct": 75.9, "watts": 8.89, "rss_mb": 648, "done": 43, "queue": 0}
{"t": 88, "temp_c": 63.0, "mhz": 1850, "cpu_pct": 10.4, "watts": 3.95, "rss_mb": 650, "done": 44, "queue": 0}
{"t": 89, "temp_c": 59.0, "mhz": 800, "cpu_pct": 56.0, "watts": 8.58, "rss_mb": 501, "done": 45, "queue": 0}
{"t": 90, "temp_c": 68.0, "mhz": 2823, "cpu_pct": 10.1, "watts": 3.37, "rss_mb": 663, "done": 45, "queue": 0}
{"t": 91, "temp_c": 58.0, "mhz": 800, "cpu_pct": 55.9, "watts": 8.16, "rss_mb": 501, "done": 46, "queue": 0}
{"t": 92, "temp_c": 61.0, "mhz": 1849, "cpu_pct": 8.8, "watts": 2.33, "rss_mb": 653, "done": 46, "queue": 0}
{"t": 93, "temp_c": 59.0, "mhz": 779, "cpu_pct": 57.1, "watts": 8.05, "rss_mb": 501, "done": 47, "queue": 0}
{"t": 94, "temp_c": 62.0, "mhz": 2889, "cpu_pct": 8.9, "watts": 3.48, "rss_mb": 657, "done": 47, "queue": 0}
{"t": 95, "temp_c": 59.0, "mhz": 789, "cpu_pct": 56.5, "watts": 8.39, "rss_mb": 502, "done": 48, "queue": 0}
{"t": 96, "temp_c": 65.0, "mhz": 2830, "cpu_pct": 11.9, "watts": 3.27, "rss_mb": 652, "done": 48, "queue": 0}
{"t": 97, "temp_c": 59.0, "mhz": 768, "cpu_pct": 55.6, "watts": 8.59, "rss_mb": 502, "done": 49, "queue": 0}
{"t": 98, "temp_c": 65.0, "mhz": 2834, "cpu_pct": 9.1, "watts": 3.43, "rss_mb": 662, "done": 49, "queue": 0}
{"t": 99, "temp_c": 59.0, "mhz": 800, "cpu_pct": 56.5, "watts": 8.15, "rss_mb": 502, "done": 50, "queue": 0}
{"t": 100, "temp_c": 61.0, "mhz": 1849, "cpu_pct": 8.8, "watts": 2.16, "rss_mb": 666, "done": 50, "queue": 0}
{"t": 101, "temp_c": 59.0, "mhz": 763, "cpu_pct": 56.3, "watts": 8.20, "rss_mb": 502, "done": 51, "queue": 0}
{"t": 102, "temp_c": 62.0, "mhz": 2859, "cpu_pct": 10.3, "watts": 3.42, "rss_mb": 655, "done": 51, "queue": 0}
{"t": 103, "temp_c": 59.0, "mhz": 796, "cpu_pct": 55.3, "watts": 8.46, "rss_mb": 502, "done": 52, "queue": 0}
{"t": 104, "temp_c": 61.0, "mhz": 2349, "cpu_pct": 9.3, "watts": 3.08, "rss_mb": 688, "done": 52, "queue": 0}
{"t": 105, "temp_c": 58.0, "mhz": 796, "cpu_pct": 55.5, "watts": 8.55, "rss_mb": 503, "done": 53, "queue": 0}
{"t": 106, "temp_c": 64.0, "mhz": 2360, "cpu_pct": 9.3, "watts": 3.44, "rss_mb": 677, "done": 53, "queue": 0}
{"t": 107, "temp_c": 59.0, "mhz": 800, "cpu_pct": 56.7, "watts": 8.07, "rss_mb": 503, "done": 54, "queue": 0}
{"t": 108, "temp_c": 62.0, "mhz": 2875, "cpu_pct": 10.9, "watts": 2.33, "rss_mb": 661, "done": 54, "queue": 0}
{"t": 109, "temp_c": 59.0, "mhz": 800, "cpu_pct": 55.5, "watts": 8.23, "rss_mb": 503, "done": 55, "queue": 0}
{"t": 110, "temp_c": 61.0, "mhz": 2884, "cpu_pct": 9.0, "watts": 3.26, "rss_mb": 682, "done": 55, "queue": 0}
{"t": 111, "temp_c": 59.0, "mhz": 749, "cpu_pct": 56.0, "watts": 8.41, "rss_mb": 503, "done": 56, "queue": 0}
{"t": 112, "temp_c": 62.0, "mhz": 2784, "cpu_pct": 9.8, "watts": 3.13, "rss_mb": 689, "done": 56, "queue": 0}
{"t": 113, "temp_c": 58.0, "mhz": 798, "cpu_pct": 54.4, "watts": 8.50, "rss_mb": 504, "done": 57, "queue": 0}
{"t": 114, "temp_c": 61.0, "mhz": 2871, "cpu_pct": 10.3, "watts": 3.38, "rss_mb": 689, "done": 57, "queue": 0}
{"t": 115, "temp_c": 59.0, "mhz": 2825, "cpu_pct": 55.1, "watts": 7.96, "rss_mb": 504, "done": 58, "queue": 0}
{"t": 116, "temp_c": 60.0, "mhz": 2878, "cpu_pct": 8.3, "watts": 2.31, "rss_mb": 689, "done": 58, "queue": 0}
{"t": 117, "temp_c": 59.0, "mhz": 800, "cpu_pct": 57.4, "watts": 8.26, "rss_mb": 506, "done": 59, "queue": 0}
{"t": 118, "temp_c": 63.0, "mhz": 2726, "cpu_pct": 27.6, "watts": 4.88, "rss_mb": 692, "done": 59, "queue": 0}
{"t": 119, "temp_c": 59.0, "mhz": 800, "cpu_pct": 55.3, "watts": 8.37, "rss_mb": 506, "done": 60, "queue": 0}
{"t": 120, "temp_c": 55.0, "mhz": 903, "cpu_pct": 5.6, "watts": 3.07, "rss_mb": 394, "done": 60, "queue": 0}
{"summary": "pipeline", "kind": "c12_ea", "workers": 1, "threads": 4, "effort": 3, "distance": 1.00, "period_ms": 2000, "secs": 120.0, "frames": 60, "frames_per_s": 0.500, "job_ms_p50": 1000, "latency_ms_p50": 1013, "latency_ms_p95": 1109, "latency_ms_max": 1395, "max_queue": 1, "backlog_at_end": 0, "cpu_s_per_frame": 2.353, "peak_rss_mb": 739, "temp_c_mean": 61.2, "temp_c_max": 74.0, "mhz_mean": 1765, "mhz_min": 744, "cpu_pct_mean": 33.6, "watts_mean": 5.72}

View File

@ -0,0 +1,34 @@
#!/bin/sh
# CPU the program spends while the camera streams and nothing is saved: the
# tower's installed build against the branch (buffer reuse). Manual mode, one
# snapshot to start the stream, then 60 s measured. ~5 min.
set -u
export GENICAM_GENTL64_PATH=/opt/VimbaX/cti # as scripts/fgc does
T=~/thermal-test
CFG=$T/manual-config.ini
# The tower's config, but starting in manual (still homing: a snapshot needs it).
sed 's/^mode = auto/mode = manual/' ~/.config/fire_gimbal_control/config.ini > "$CFG"
ln -sf ~/.config/fire_gimbal_control/scan.csv "$T/scan.csv"
ln -sfn ~/.config/fire_gimbal_control/camera_profiles "$T/camera_profiles"
HZ=$(getconf CLK_TCK)
measure() { # label binary
FIFO=$T/cmd2.fifo
rm -f "$FIFO"; mkfifo "$FIFO"
sleep 100000 > "$FIFO" &
holder=$!
"$2" -c "$CFG" --no-tui --no-mqtt --no-log-file < "$FIFO" > "$T/stream_$1.log" 2>&1 &
pid=$!
sleep 60 # start + homing
echo snapshot > "$FIFO"
sleep 15 # the snapshot saved; the stream keeps running
a=$(awk '{print $14 + $15}' /proc/$pid/stat)
sleep 60
b=$(awk '{print $14 + $15}' /proc/$pid/stat)
echo "$1: $(echo "scale=1; 100 * ($b - $a) / $HZ / 60" | bc) % of one core while streaming"
kill -TERM "$pid"; sleep 10; kill "$holder" 2>/dev/null; sleep 3
kill -0 "$pid" 2>/dev/null && kill -KILL "$pid"
rm -f "$FIFO"
}
measure installed ~/projects/fwt_2a/software/build/fire_gimbal_control
measure branch $T/software/build/fire_gimbal_control

38
tools/thermal-sim/cap-cpu.sh Executable file
View File

@ -0,0 +1,38 @@
#!/usr/bin/env bash
# Cap the CPU clock, to see how the program copes with a CPU slowed to stay cool.
#
# sudo tools/thermal-sim/cap-cpu.sh 800 # every core at most 800 MHz
# sudo tools/thermal-sim/cap-cpu.sh restore # back to what it was
#
# Writes scaling_max_freq on every core. The values found the first time are
# kept in /run/fgc-cap-cpu.saved, so `restore` puts back the real ones however
# many caps were set in between. A reboot also clears the cap.
set -euo pipefail
saved=/run/fgc-cap-cpu.saved
cpus=(/sys/devices/system/cpu/cpu[0-9]*/cpufreq)
usage() { echo "usage: $0 <MHz> | restore" >&2; exit 2; }
[[ $# -eq 1 ]] || usage
[[ $EUID -eq 0 ]] || { echo "$0: needs root (sudo)" >&2; exit 1; }
[[ -e ${cpus[0]}/scaling_max_freq ]] || { echo "$0: no cpufreq on this machine" >&2; exit 1; }
if [[ $1 == restore ]]; then
[[ -f $saved ]] || { echo "nothing to restore (no cap set since boot)"; exit 0; }
while read -r dir khz; do echo "$khz" > "$dir/scaling_max_freq"; done < "$saved"
rm -f "$saved"
echo "CPU clock limits restored"
exit 0
fi
[[ $1 =~ ^[0-9]+$ ]] || usage
khz=$(( $1 * 1000 ))
if [[ ! -f $saved ]]; then
for d in "${cpus[@]}"; do echo "$d $(cat "$d/scaling_max_freq")"; done > "$saved"
fi
for d in "${cpus[@]}"; do
min=$(cat "$d/cpuinfo_min_freq")
(( khz < min )) && { echo "$0: $1 MHz is under this CPU's minimum ($((min / 1000)) MHz)" >&2; exit 1; }
echo "$khz" > "$d/scaling_max_freq"
done
echo "every core capped at $1 MHz ('$0 restore' to undo)"

31
tools/thermal-sim/cap-power.sh Executable file
View File

@ -0,0 +1,31 @@
#!/usr/bin/env bash
# Cap the CPU package power, as a hot box or the 6 W TDP mode would.
#
# sudo tools/thermal-sim/cap-power.sh 6 # long-term limit 6 W
# sudo tools/thermal-sim/cap-power.sh restore
#
# Writes the RAPL long-term limit (constraint 0) of intel-rapl:0. The original is
# kept in /run/fgc-cap-power.saved. A reboot also clears it. Intel only.
set -euo pipefail
saved=/run/fgc-cap-power.saved
rapl=/sys/class/powercap/intel-rapl:0
limit=$rapl/constraint_0_power_limit_uw
usage() { echo "usage: $0 <watts> | restore" >&2; exit 2; }
[[ $# -eq 1 ]] || usage
[[ $EUID -eq 0 ]] || { echo "$0: needs root (sudo)" >&2; exit 1; }
[[ -w $limit ]] || { echo "$0: no writable RAPL limit at $limit" >&2; exit 1; }
if [[ $1 == restore ]]; then
[[ -f $saved ]] || { echo "nothing to restore (no cap set since boot)"; exit 0; }
cat "$saved" > "$limit"
rm -f "$saved"
echo "power limit restored to $(( $(cat "$limit") / 1000000 )) W"
exit 0
fi
[[ $1 =~ ^[0-9]+$ ]] || usage
[[ -f $saved ]] || cat "$limit" > "$saved"
echo $(( $1 * 1000000 )) > "$limit"
echo "package power capped at $1 W (was $(( $(cat "$saved") / 1000000 )) W; '$0 restore' to undo)"

77
tools/thermal-sim/fake-temp.sh Executable file
View File

@ -0,0 +1,77 @@
#!/usr/bin/env bash
# A fake /sys for the CPU guard, so heat can be simulated without heat. Point the
# program at it with [Thermal] sysfs_root = <root> (config.ini or hardware.ini)
# and change the temperature while it runs.
#
# tools/thermal-sim/fake-temp.sh <root> init # build the tree (4 cores, 3.6 GHz, 70 C)
# tools/thermal-sim/fake-temp.sh <root> <C> # set the CPU temperature
# tools/thermal-sim/fake-temp.sh <root> <C> throttle # ...and count one throttle event
# tools/thermal-sim/fake-temp.sh <root> clock <MHz> # set every core's clock
# tools/thermal-sim/fake-temp.sh <root> ramp <C> <C> <step> <secs-per-step>
# # walk the temperature, throttling
# # at 90 C and above
#
# The tree has no proc/stat, so the program reads the real /proc/stat: how busy
# the CPU is stays real (raise it with heat-load.sh).
set -euo pipefail
usage() { sed -n '2,15p' "$0" >&2; exit 2; }
[[ $# -ge 2 ]] || usage
root=$1; shift
cpu=$root/sys/devices/system/cpu
zone=$root/sys/class/thermal/thermal_zone0
init() {
rm -f "$root/proc/stat" # an older tree's frozen copy would hide the real one
mkdir -p "$zone"
echo x86_pkg_temp > "$zone/type"
echo 70000 > "$zone/temp"
for c in 0 1 2 3; do
mkdir -p "$cpu/cpu$c/cpufreq" "$cpu/cpu$c/thermal_throttle"
echo 2800000 > "$cpu/cpu$c/cpufreq/scaling_cur_freq"
echo 3600000 > "$cpu/cpu$c/cpufreq/cpuinfo_max_freq"
echo 3600000 > "$cpu/cpu$c/cpufreq/scaling_max_freq"
echo 0 > "$cpu/cpu$c/thermal_throttle/package_throttle_count"
echo 0 > "$cpu/cpu$c/thermal_throttle/core_throttle_count"
done
echo "fake tree ready at $root: 70 C, 2.8 of 3.6 GHz"
}
set_temp() { # <C> [throttle]
echo $(( $1 * 1000 )) > "$zone/temp"
if [[ ${2:-} == throttle ]]; then
f=$cpu/cpu0/thermal_throttle/package_throttle_count
echo $(( $(cat "$f") + 1 )) > "$f"
fi
}
[[ $1 == init ]] && { init; exit 0; }
[[ -d $zone ]] || { echo "$0: no tree at $root - run '$0 $root init' first" >&2; exit 1; }
case $1 in
clock)
[[ $# -eq 2 ]] || usage
for c in "$cpu"/cpu[0-9]*; do echo $(( $2 * 1000 )) > "$c/cpufreq/scaling_cur_freq"; done
echo "clock $2 MHz" ;;
ramp)
[[ $# -eq 5 ]] || usage
from=$2 to=$3 step=$4 secs=$5
(( from > to )) && step=$(( -step ))
t=$from
while :; do
echo "$(date +%T) $t C"
# Hold the step; at 90 C and up the CPU throttles, one counted
# event every 2 s.
for (( i = 0; i < secs; i += 2 )); do
if (( t >= 90 )); then set_temp "$t" throttle; else set_temp "$t"; fi
sleep 2
done
(( t == to )) && break
t=$(( t + step ))
(( (step > 0 && t > to) || (step < 0 && t < to) )) && t=$to
done ;;
*)
[[ $1 =~ ^[0-9]+$ ]] || usage
set_temp "$1" "${2:-}"
echo "CPU $1 C${2:+, one throttle event}" ;;
esac

26
tools/thermal-sim/heat-load.sh Executable file
View File

@ -0,0 +1,26 @@
#!/usr/bin/env bash
# Keep some cores busy, standing in for heat and work competing with the program
# (a hot afternoon, the modem, something else running).
#
# tools/thermal-sim/heat-load.sh 2 600 # 2 cores flat out for 10 minutes
#
# Uses stress-ng when installed; otherwise one busy shell loop per core. Ctrl-C
# stops it early. Needs no root.
set -euo pipefail
[[ $# -eq 2 && $1 =~ ^[0-9]+$ && $2 =~ ^[0-9]+$ ]] || {
echo "usage: $0 <cores> <seconds>" >&2; exit 2; }
cores=$1 secs=$2
if command -v stress-ng >/dev/null; then
exec stress-ng --cpu "$cores" --timeout "${secs}s" --metrics-brief
fi
echo "stress-ng not found; using $cores busy loop(s) for $secs s"
pids=()
trap 'kill "${pids[@]}" 2>/dev/null' EXIT INT TERM
for _ in $(seq "$cores"); do
( end=$((SECONDS + secs)); while (( SECONDS < end )); do :; done ) &
pids+=($!)
done
wait