ENGINEERING NOTE / DEVICE QUALIFICATION

Decoder performance testing

Updated 2026-09-07. This engineering note records a device-state limitation found while qualifying CQFTx's FT8 decoder on the Lenovo TB305FU tablet. It is intended to keep future performance campaigns from mistaking a tablet power or frequency state for a decoder regression.

Bottom line

The measured slowdown was not caused by Android sending CQFTx's decoder to efficiency cores or starving it as background work. The real decoder worker ran on the tablet's two highest-capacity cores, kept them fully utilized, and had negligible scheduler wait in both visible-app and foreground-service tests.

Those cores were instead held at an effective 850 MHz minimum and maximum for the entire experiment, although their advertised operating points extend to 2.0 GHz. Historical EARLY decoding averaged about 62 ms; the same fixed decode took about 140 ms in the capped state. Multiple current and historical decoder binaries reproduced the slowdown, so rolling back decoder code did not recover performance.

This is a verified state of the tested tablet, not a permanent specification for every TB305FU. Subsequent recovery testing isolated the cap to Lenovo's com.zui.pp package: disabling that package through ADB removed the cap on the large-core cluster and restored access to higher operating points. Treat this as an advanced, device- and firmware-specific workaround; vendor updates may change the package or behavior, and disabling it may affect Lenovo power or performance features outside CQFTx.

What the scheduler experiment established

The same frozen websdr_test6 EARLY capture was decoded in alternating contexts using the production worker and optimized native decoder:

Context Runs Native time Median
Visible activity, initial 3 150.567, 139.878, 139.095 ms 139.878 ms
Foreground service 3 141.365, 139.113, 138.751 ms 139.113 ms
Visible activity with service 3 142.374, 139.907, 139.664 ms 139.907 ms
Foreground service, repeated 3 141.534, 139.403, 139.593 ms 139.593 ms
Standalone shell control 6 145, 144, 142, 143, 143, 143 ms 143 ms

Excluding the first cold decode, the visible-app and foreground-service means differed by only 0.224 ms, or 0.16%. All 18 decodes returned the same 17 messages and the same complete-output fingerprint.

Perfetto and process diagnostics showed:

The current production path deliberately confines the native decode call to CPUs 6 and 7. These findings therefore establish behavior for that path on the tested tablet; they do not predict placement for a future un-affined decoder or for another device.

Limits on interpretation

The tablet model, firmware fingerprint, charger state, and temperature do not by themselves define a comparable performance environment.

The observed owner was Lenovo's com.zui.pp package, acting through the vendor power-management stack below the PowerHAL request. The exact internal frequency-QoS or MediaTek PPM mechanism remains implementation-specific.

Mandatory TB305FU preflight

Run this preflight before and after every baseline/candidate campaign, and repeat it after a reboot, shutdown, charger or power-mode transition, long sleep, or unexplained latency change.

  1. Record the APK and native-library hashes, corpus and fixture hashes, Android build fingerprint, boot identifier or uptime, power source, battery level and temperature, Android thermal status, and relevant power settings.
  2. Run three to six identical websdr_test6 EARLY sentinels using the preserved binary, fixed 12.85-second capture, 200--3000 Hz search, and 450 ms native deadline. Retain each latency, message set, complete-output fingerprint, affinity diagnostic, and performance-cluster residency delta.
  3. Trace at least the initial baseline sentinel with scheduler slices, actual CPU frequency, and CPU frequency limits. For installed-app tests, also record process importance, process and decoder-thread cgroups, allowed CPUs, and actual foreground or background-service state.
  4. Interleave candidate and baseline trials only while the measured frequency limit, residency signature, process context, capture profile, power state, thermal start band, and background-load condition remain comparable.
  5. Repeat the sentinels after the test blocks. If frequency state, process context, fixture output, or any required condition changed, keep the raw observation but invalidate the comparison and rerun it under one stable state.
  6. Label a run platform-capped when the performance cluster remains fixed at 850 MHz. Do not present that run as evidence of a decoder regression against the historical approximately 62 ms result.

Passing a recall floor alone does not establish an improvement. Report exact paired additions and losses, fixed-deadline behavior, repeated fingerprints, and latency distributions against a control rerun on the same platform in the same classified state.

Controlled recovery sequence

A reboot is a recovery experiment, not a way to normalize results after the fact.

  1. Capture a pre-reboot sentinel and its frequency evidence.
  2. Reboot the tablet.
  3. Before changing charger or application settings, run three to six identical sentinels and record uptime, frequency limits, residency, latency, messages, and fingerprint.
  4. Treat recovery as established only when the policy maximum rises above 850 MHz, decode-time residency accumulates above 850 MHz, and latency moves materially toward the historical result.
  5. If recovery occurs, run matched current/baseline corpus blocks, then vary charger transitions, screen sleep and wake, long uptime, and power modes one at a time to isolate the trigger.
  6. If a warm reboot does not recover the cluster, perform a true shutdown with external power disconnected and repeat the sentinel. If that fails, compare another TB305FU or firmware build and obtain privileged diagnostics for the active governor, maximum-frequency constraints, frequency-QoS owners, MediaTek PPM limits, and cooling-device state.

Do not compensate for a capped platform by raising Java priority, adding decoder workers, extending deadlines, adding artificial warm-up load, or moving decoding between lifecycle contexts. Those changes cannot exceed a kernel maximum and would weaken the real-time and recall guarantees. Native decoder optimization remains useful engineering work, but it is mitigation for a slow device rather than recovery from this device state.