fix(engine): densify drawelement self-verify with parallel worker count

This commit is contained in:
Vance Ingalls
2026-07-11 14:14:08 -07:00
parent ddcd380a1a
commit 1b95af8bbb
4 changed files with 62 additions and 2 deletions
+3 -1
View File
@@ -3125,7 +3125,9 @@ async function captureDeVerificationFrames(
page: Page, page: Page,
logInitPhase: (phase: string) => void, logInitPhase: (phase: string) => void,
): Promise<void> { ): Promise<void> {
const kRaw = Number(process.env.HF_DE_VERIFY ?? "4"); // Explicit HF_DE_VERIFY wins; otherwise the session's own sample count
// (raised by the parallel coordinator for multi-worker DE), then default 4.
const kRaw = Number(process.env.HF_DE_VERIFY ?? session.options.deVerifySamples ?? "4");
const k = Number.isFinite(kRaw) ? Math.max(0, Math.min(8, Math.floor(kRaw))) : 4; const k = Number.isFinite(kRaw) ? Math.max(0, Math.min(8, Math.floor(kRaw))) : 4;
if (k === 0 || process.env.HF_FORCE_DRAWELEMENT === "1") return; if (k === 0 || process.env.HF_FORCE_DRAWELEMENT === "1") return;
if (session.options.format === "png") return; // worker-encode drain (the consumer) is jpeg-only if (session.options.format === "png") return; // worker-encode drain (the consumer) is jpeg-only
@@ -6,6 +6,7 @@ import {
selectWorkerDiagnostics, selectWorkerDiagnostics,
shouldDisableBrowserPoolForParallelWorker, shouldDisableBrowserPoolForParallelWorker,
shouldVerifyWorkerGpu, shouldVerifyWorkerGpu,
resolveParallelDeVerifySamples,
} from "./parallelCoordinator.js"; } from "./parallelCoordinator.js";
import type { EngineConfig } from "../config.js"; import type { EngineConfig } from "../config.js";
@@ -176,3 +177,24 @@ describe("shouldVerifyWorkerGpu", () => {
expect(shouldVerifyWorkerGpu(3, undefined)).toBe(false); expect(shouldVerifyWorkerGpu(3, undefined)).toBe(false);
}); });
}); });
describe("resolveParallelDeVerifySamples", () => {
it("densifies with worker count: 4 base + 2 per extra worker", () => {
expect(resolveParallelDeVerifySamples(undefined, 2)).toBe(6);
expect(resolveParallelDeVerifySamples(undefined, 3)).toBe(8);
});
it("clamps at the verify path's max of 8", () => {
expect(resolveParallelDeVerifySamples(undefined, 5)).toBe(8);
expect(resolveParallelDeVerifySamples(undefined, 16)).toBe(8);
});
it("leaves single-worker capture on the session default", () => {
expect(resolveParallelDeVerifySamples(undefined, 1)).toBeUndefined();
expect(resolveParallelDeVerifySamples(undefined, 0)).toBeUndefined();
});
it("passes a caller-set value through untouched", () => {
expect(resolveParallelDeVerifySamples(2, 3)).toBe(2);
});
});
@@ -459,6 +459,24 @@ async function executeWorkerTask(
} }
} }
/**
* drawElement self-verify sample count for multi-worker capture. Each worker
* arms the same shared sample grid but drains only ~1/N of it, and N
* concurrent hardware-GPU browsers are exactly where compositor-tile damage
* shows up (wild 0.7.52 black-slab report) so density rises with worker
* count: 4 base + 2 per extra worker, clamped to the verify path's max of 8.
* A caller-set value passes through untouched, and explicit HF_DE_VERIFY
* still overrides inside the session.
*/
export function resolveParallelDeVerifySamples(
callerValue: number | undefined,
workerCount: number,
): number | undefined {
if (callerValue !== undefined) return callerValue;
if (workerCount <= 1) return undefined;
return Math.min(8, 4 + 2 * (workerCount - 1));
}
export async function executeParallelCapture( export async function executeParallelCapture(
serverUrl: string, serverUrl: string,
workDir: string, workDir: string,
@@ -499,12 +517,20 @@ export async function executeParallelCapture(
}; };
const parallel = tasks.length > 1; const parallel = tasks.length > 1;
const deVerifySamples = resolveParallelDeVerifySamples(
captureOptions.deVerifySamples,
tasks.length,
);
const workerCaptureOptions: CaptureOptions =
deVerifySamples === captureOptions.deVerifySamples
? captureOptions
: { ...captureOptions, deVerifySamples };
const results = await Promise.all( const results = await Promise.all(
tasks.map((task) => tasks.map((task) =>
executeWorkerTask( executeWorkerTask(
task, task,
serverUrl, serverUrl,
captureOptions, workerCaptureOptions,
createBeforeCaptureHook, createBeforeCaptureHook,
signal, signal,
onFrameCaptured, onFrameCaptured,
+10
View File
@@ -158,6 +158,16 @@ export interface CaptureOptions {
* warmup loop). * warmup loop).
*/ */
lockWarmupTicks?: boolean; lockWarmupTicks?: boolean;
/**
* drawElement self-verify ground-truth sample count for this session.
* Overrides the HF_DE_VERIFY default (4). The parallel coordinator raises
* it for multi-worker drawElement capture N concurrent hardware-GPU
* browsers widen the damage surface (compositor tile eviction under
* GPU/memory pressure), and each worker only drains ~1/N of the shared
* sample grid, thinning effective coverage exactly when risk peaks.
* Clamped to 0..8 like the env knob; HF_DE_VERIFY, when set, still wins.
*/
deVerifySamples?: number;
} }
export interface CaptureVideoMetadataHint { export interface CaptureVideoMetadataHint {