diff --git a/src/renderer/src/lib/browser-history-match-budget.ts b/src/renderer/src/lib/browser-history-match-budget.ts index 2f6468948d7..79e84e2c8ba 100644 --- a/src/renderer/src/lib/browser-history-match-budget.ts +++ b/src/renderer/src/lib/browser-history-match-budget.ts @@ -4,18 +4,18 @@ * These are ceilings for catching order-of-magnitude regressions, not targets — * the measured numbers on a developer machine sit far under each one. * - * The ceilings are asserted against the *fastest* sample of a batch, never the - * slowest: a vitest worker sharing cores with the rest of the suite gets - * preempted mid-measurement, so the slowest sample measures the machine while - * the fastest still approximates the matcher. + * The ceilings are asserted against the *lower quartile* of a batch, never the + * slowest sample: a vitest worker sharing cores with the rest of the suite gets + * preempted mid-measurement, so the slow tail measures the machine. A quartile + * rather than the minimum keeps one lucky sample from carrying a regressed batch. * * Raising any value requires a fresh measurement recorded in the PR. */ export const BROWSER_HISTORY_MATCH_BUDGET = { /** Entries prepared in one omnibox open. Tracks MAX_BROWSER_HISTORY_ENTRIES. */ candidateCount: 200, - /** Milliseconds to prepare the whole corpus once (cold open), fastest sample. Measured 0.08 ms. */ + /** Milliseconds to prepare the whole corpus once (cold open), lower quartile. Measured 0.07 ms. */ prepareMs: 2, - /** Milliseconds to match the prepared corpus against one query, fastest sample. Measured 0.03 ms. */ + /** Milliseconds to match the prepared corpus against one query, lower quartile. Measured 0.03 ms. */ matchMs: 2 } as const diff --git a/src/renderer/src/lib/browser-history-match.performance.test.ts b/src/renderer/src/lib/browser-history-match.performance.test.ts index 0ec2925530d..f40ed3e29b1 100644 --- a/src/renderer/src/lib/browser-history-match.performance.test.ts +++ b/src/renderer/src/lib/browser-history-match.performance.test.ts @@ -25,13 +25,19 @@ const entries = Array.from({ length: candidateCount }, (_, index) => makeEntry(i const WORST_QUERY = 'observability rollout' /** - * Why the fastest sample and not p95: this runs in a vitest worker competing for - * cores with the rest of the suite, so a slow sample records a preemption rather - * than the matcher. Measured across idle and full-suite runs, the fastest sample - * moved 0.05 ms -> 0.08 ms while p95 of the same batches swung 0.09 ms -> 0.50 ms. + * Why the lower quartile and not p95 or the minimum: this runs in a vitest worker + * competing for cores with the rest of the suite, so a slow sample records a + * preemption rather than the matcher, while a single fastest sample would pass + * with the other 19 runs over budget. Requiring a quarter of the batch inside the + * ceiling still discards the preempted tail: measured for preparation, the lower + * quartile moved 0.07 ms -> 0.15 ms between idle and 4x core oversubscription, + * while p95 of those same batches swung 0.10 ms -> 0.81 ms and the slowest sample + * reached 6.9 ms. */ -function fastestSample(samples: readonly number[]): number { - return Math.min(...samples) +function lowerQuartileSample(samples: readonly number[]): number { + const sorted = [...samples].sort((a, b) => a - b) + // Nearest-rank p25: ceil(n*0.25)-1, so 20 samples pick the 5th fastest. + return sorted[Math.max(0, Math.ceil(sorted.length * 0.25) - 1)] } describe('browser history match performance budget', () => { @@ -51,7 +57,7 @@ describe('browser history match performance budget', () => { prepareBrowserHistoryEntries(entries.slice()) samples.push(performance.now() - start) } - expect(fastestSample(samples)).toBeLessThan(prepareMs) + expect(lowerQuartileSample(samples)).toBeLessThan(prepareMs) }) it('matches one query against the prepared corpus within budget', () => { @@ -67,6 +73,6 @@ describe('browser history match performance budget', () => { run() samples.push(performance.now() - start) } - expect(fastestSample(samples)).toBeLessThan(matchMs) + expect(lowerQuartileSample(samples)).toBeLessThan(matchMs) }) })