Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion packages/engine/src/services/frameCapture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3125,7 +3125,9 @@ async function captureDeVerificationFrames(
page: Page,
logInitPhase: (phase: string) => 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;
if (k === 0 || process.env.HF_FORCE_DRAWELEMENT === "1") return;
if (session.options.format === "png") return; // worker-encode drain (the consumer) is jpeg-only
Expand Down
22 changes: 22 additions & 0 deletions packages/engine/src/services/parallelCoordinator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
selectWorkerDiagnostics,
shouldDisableBrowserPoolForParallelWorker,
shouldVerifyWorkerGpu,
resolveParallelDeVerifySamples,
} from "./parallelCoordinator.js";
import type { EngineConfig } from "../config.js";

Expand Down Expand Up @@ -176,3 +177,24 @@ describe("shouldVerifyWorkerGpu", () => {
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);
});
});
28 changes: 27 additions & 1 deletion packages/engine/src/services/parallelCoordinator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(
serverUrl: string,
workDir: string,
Expand Down Expand Up @@ -499,12 +517,20 @@ export async function executeParallelCapture(
};

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(
tasks.map((task) =>
executeWorkerTask(
task,
serverUrl,
captureOptions,
workerCaptureOptions,
createBeforeCaptureHook,
signal,
onFrameCaptured,
Expand Down
10 changes: 10 additions & 0 deletions packages/engine/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,16 @@ export interface CaptureOptions {
* warmup loop).
*/
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 {
Expand Down
Loading