Skip to content

Avoid division by zero and clock overflow in utilisation rate#478

Open
rocker-zhang wants to merge 1 commit into
Syllo:masterfrom
rocker-zhang:fix-utilrate-divide-by-zero
Open

Avoid division by zero and clock overflow in utilisation rate#478
rocker-zhang wants to merge 1 commit into
Syllo:masterfrom
rocker-zhang:fix-utilrate-divide-by-zero

Conversation

@rocker-zhang
Copy link
Copy Markdown

@rocker-zhang rocker-zhang commented Jun 5, 2026

gpuinfo_refresh_utilisation_rate() derives GPU utilisation from
drm-cycles and drm-maxfreq, and is used by the panfrost and panthor
backends. There are two problems in the same computation.

When the fdinfo has no drm-maxfreq key, gpu_clock_speed_max stays 0, so
max_freq_hz is 0 and the utilisation division has a zero denominator.
The double division yields infinity and the subsequent cast to
unsigned int is undefined behaviour. A zero sample delta or a reported
engine_count of 0 hit the same zero denominator. The fix returns early
when the denominator would be zero, which leaves gpu_util_rate unset so
the UI reports N/A rather than a bogus value, matching the existing
if (!gfx_total_process_cycles) return; guard above it.

gpu_clock_speed_max is an unsigned int in MHz; multiplying by 1000000
in unsigned int arithmetic overflows above ~4295 MHz before the result
is stored in the uint64_t max_freq_hz. Casting to uint64_t first keeps
the frequency correct (a 5000 MHz clock gave 705032704 Hz before, and
5000000000 Hz after).

Validation: under UBSan, the zero-frequency case reported
extract_gpuinfo.c: runtime error: division by zero before the guard and
returns cleanly after; a 5000 MHz clock with 2.5e9 cycles over 1 s now
yields 50% (it clamped to 100% before the cast). Built clean on x86_64
(all backends) and arm64, and the gtest suite passes.

gpuinfo_refresh_utilisation_rate() derives GPU usage from drm-cycles and
drm-maxfreq and is used by the panfrost and panthor backends.

When a backend does not report drm-maxfreq, gpu_clock_speed_max stays 0,
so max_freq_hz is 0 and the rate division has a zero denominator. The
double division yields infinity and casting that to unsigned int is
undefined behaviour. A zero sample delta or a reported engine_count of 0
produce the same zero denominator. Return early when the denominator
would be zero, leaving gpu_util_rate unset so the UI shows N/A, matching
the existing early return for a zero cycle count.

gpu_clock_speed_max (MHz, unsigned int) was also multiplied by 1000000 in
unsigned int arithmetic before being widened to the uint64_t max_freq_hz,
which overflows above ~4295 MHz. Cast to uint64_t before multiplying.
@rocker-zhang rocker-zhang force-pushed the fix-utilrate-divide-by-zero branch from c83a025 to 4a14751 Compare June 5, 2026 07:46
@rocker-zhang rocker-zhang changed the title Avoid division by zero in gpuinfo_refresh_utilisation_rate Avoid division by zero and clock overflow in utilisation rate Jun 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant