fix: benchmark scores clamped to 0% for below-average hardware

The log2 normalization formula `50 * (1 + log2(ratio))` produces negative
values (clamped to 0) whenever the measured value is less than half the
reference. For example, a CPU scoring 1993 events/sec against a 5000
reference gives ratio=0.4, log2(0.4)=-1.32, score=-16 -> 0%.

Fix by dividing log2 by 3 to widen the usable range. This preserves the
50% score at the reference value while allowing below-average hardware
to receive proportional non-zero scores (e.g., 28% for the CPU above).

Also adds debug logging for CPU sysbench output parsing to aid future
diagnosis of parsing issues.

Fixes #415
This commit is contained in:
Bortlesboat 2026-03-21 09:34:09 -04:00 committed by Jake Turner
parent 78c0b1d24d
commit 4642dee6ce

View File

@ -571,10 +571,10 @@ export class BenchmarkService {
*/
private _normalizeScore(value: number, reference: number): number {
if (value <= 0) return 0
// Log scale: score = 50 * (1 + log2(value/reference))
// This gives 50 at reference value, scales logarithmically
// Log scale with widened range: dividing log2 by 3 prevents scores from
// clamping to 0% for below-average hardware. Gives 50% at reference value.
const ratio = value / reference
const score = 50 * (1 + Math.log2(Math.max(0.01, ratio)))
const score = 50 * (1 + Math.log2(Math.max(0.01, ratio)) / 3)
return Math.min(100, Math.max(0, score)) / 100
}
@ -583,9 +583,9 @@ export class BenchmarkService {
*/
private _normalizeScoreInverse(value: number, reference: number): number {
if (value <= 0) return 1
// Inverse: lower values = higher scores
// Inverse: lower values = higher scores, with widened log range
const ratio = reference / value
const score = 50 * (1 + Math.log2(Math.max(0.01, ratio)))
const score = 50 * (1 + Math.log2(Math.max(0.01, ratio)) / 3)
return Math.min(100, Math.max(0, score)) / 100
}
@ -619,6 +619,7 @@ export class BenchmarkService {
const eventsMatch = output.match(/events per second:\s*([\d.]+)/i)
const totalTimeMatch = output.match(/total time:\s*([\d.]+)s/i)
const totalEventsMatch = output.match(/total number of events:\s*(\d+)/i)
logger.debug(`[BenchmarkService] CPU output parsing - events/s: ${eventsMatch?.[1]}, total_time: ${totalTimeMatch?.[1]}, total_events: ${totalEventsMatch?.[1]}`)
return {
events_per_second: eventsMatch ? parseFloat(eventsMatch[1]) : 0,