mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-10-30 09:16:55 +00:00
perf(engine): Macs with a hardware GPU render with more capture workers (#6636)
* perf(engine): Macs with a hardware GPU render with more capture workers * perf(engine): Apple-GPU worker sizing skips layered renders; fewer comment lines * test(producer): format
This commit is contained in:
@@ -310,6 +310,7 @@ export {
|
||||
type WorkerResult,
|
||||
type WorkerSizing,
|
||||
type WorkerSizingBound,
|
||||
type WorkerSizingConfig,
|
||||
type LandedFrame,
|
||||
type ParallelProgress,
|
||||
type ParallelWorkerPhaseDiagnostic,
|
||||
|
||||
@@ -167,6 +167,22 @@ describe("computeWorkerSizing", () => {
|
||||
expect(computeWorkerSizing(1300, undefined, { concurrency: "auto" }).workers).toBe(5);
|
||||
});
|
||||
|
||||
it("sizes Apple-GPU disk capture by its own heap and core budget", () => {
|
||||
vi.mocked(cpus).mockReturnValue(
|
||||
Array.from({ length: 14 }, () => ({}) as ReturnType<typeof cpus>[number]),
|
||||
);
|
||||
vi.mocked(totalmem).mockReturnValue(24 * 1024 ** 3);
|
||||
vi.mocked(getHeapStatistics).mockReturnValue({
|
||||
heap_size_limit: 4192 * 1024 ** 2,
|
||||
} as ReturnType<typeof getHeapStatistics>);
|
||||
const apple = { concurrency: "auto" as const, appleGpuDiskCapture: true };
|
||||
const sizing = computeWorkerSizing(1300, undefined, apple);
|
||||
expect(sizing.workers).toBe(8);
|
||||
expect(sizing.boundBy).toBe("memory");
|
||||
expect(sizing.exceedsHeapAdvisory).toBe(false);
|
||||
expect(computeWorkerSizing(1300, undefined, { ...apple, coresPerWorker: 4 }).workers).toBe(3);
|
||||
});
|
||||
|
||||
it("matches calculateOptimalWorkers and reports every constraint", () => {
|
||||
const config = { concurrency: "auto" as const };
|
||||
const sizing = computeWorkerSizing(900, undefined, config);
|
||||
|
||||
@@ -131,6 +131,8 @@ export interface WorkerSizingConfig extends Partial<
|
||||
* than a plain DOM screenshot. Explicit --workers requests ignore this hint.
|
||||
*/
|
||||
captureCostMultiplier?: number;
|
||||
/** macOS, hardware GPU, screenshot frames written to disk (not streamed through this process). */
|
||||
appleGpuDiskCapture?: boolean;
|
||||
}
|
||||
|
||||
type WorkerBrowserPoolDecision = {
|
||||
@@ -151,6 +153,10 @@ const HEAP_RESERVED_MB = 1024;
|
||||
// default heap ⇒ >~500MB/worker + base. Caps auto sizing; an explicit
|
||||
// `--workers N` is still the operator's call.
|
||||
const HEAP_PER_WORKER_MB = 640;
|
||||
// Apple-GPU disk capture measured ~15-25 MB parent heap per worker; 14 cores kept gaining to 8.
|
||||
const APPLE_DISK_HEAP_PER_WORKER_MB = 128;
|
||||
const APPLE_DISK_CORES_PER_WORKER = 1.75;
|
||||
const APPLE_DISK_MAX_WORKERS = 8;
|
||||
const MIN_WORKERS = 1;
|
||||
const MAX_WORKER_DIAGNOSTIC_LINES = 8;
|
||||
// Hard ceiling on explicit `--workers N` requests. Above this, the cost of
|
||||
@@ -321,9 +327,13 @@ export function computeWorkerSizing(
|
||||
// is immediately reclaimable.
|
||||
const totalMemoryMb = getSystemTotalMb();
|
||||
const heapLimitMb = Math.round(getHeapStatistics().heap_size_limit / (1024 * 1024));
|
||||
const appleDisk = config?.appleGpuDiskCapture === true;
|
||||
const heapBasedWorkers = Math.max(
|
||||
1,
|
||||
Math.floor((heapLimitMb - HEAP_RESERVED_MB) / HEAP_PER_WORKER_MB),
|
||||
Math.floor(
|
||||
(heapLimitMb - HEAP_RESERVED_MB) /
|
||||
(appleDisk ? APPLE_DISK_HEAP_PER_WORKER_MB : HEAP_PER_WORKER_MB),
|
||||
),
|
||||
);
|
||||
const cpuBasedWorkers = Math.max(1, cpuCount - 2);
|
||||
const memoryBasedWorkers = Math.max(1, Math.floor((totalMemoryMb * 0.5) / MEMORY_PER_WORKER_MB));
|
||||
@@ -362,9 +372,15 @@ export function computeWorkerSizing(
|
||||
if (concurrency !== "auto") {
|
||||
return Math.max(MIN_WORKERS, Math.min(ABSOLUTE_MAX_WORKERS, Math.floor(concurrency)));
|
||||
}
|
||||
return defaultSafeMaxWorkers();
|
||||
return appleDisk
|
||||
? Math.max(defaultSafeMaxWorkers(), APPLE_DISK_MAX_WORKERS)
|
||||
: defaultSafeMaxWorkers();
|
||||
})();
|
||||
const effectiveCoresPerWorker = config?.coresPerWorker ?? DEFAULT_CONFIG.coresPerWorker;
|
||||
const configuredCoresPerWorker = config?.coresPerWorker ?? DEFAULT_CONFIG.coresPerWorker;
|
||||
const effectiveCoresPerWorker =
|
||||
appleDisk && configuredCoresPerWorker === DEFAULT_CONFIG.coresPerWorker
|
||||
? APPLE_DISK_CORES_PER_WORKER
|
||||
: configuredCoresPerWorker;
|
||||
const effectiveMinParallelFrames = config?.minParallelFrames ?? DEFAULT_CONFIG.minParallelFrames;
|
||||
const effectiveLargeRenderThreshold =
|
||||
config?.largeRenderThreshold ?? DEFAULT_CONFIG.largeRenderThreshold;
|
||||
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
type CaptureSession,
|
||||
type EngineConfig,
|
||||
type WorkerSizing,
|
||||
type WorkerSizingConfig,
|
||||
calculateOptimalWorkers,
|
||||
captureFrameToBuffer,
|
||||
closeCaptureSession,
|
||||
@@ -138,7 +139,7 @@ export function buildHeapAdvisoryWarning(
|
||||
export function resolveRenderWorkerCount(
|
||||
totalFrames: number,
|
||||
requestedWorkers: number | undefined,
|
||||
cfg: EngineConfig,
|
||||
cfg: EngineConfig & Pick<WorkerSizingConfig, "appleGpuDiskCapture">,
|
||||
compiled: Pick<CompiledComposition, "hasShaderTransitions" | "renderModeHints">,
|
||||
log: ProducerLogger = defaultLogger,
|
||||
measuredCaptureCost?: CaptureCostEstimate,
|
||||
|
||||
@@ -64,6 +64,7 @@ import {
|
||||
SEGMENTED_MIN_SECONDS_AFTER_SOAK,
|
||||
resolveParallelCaptureMode,
|
||||
shouldStreamParallelCapture,
|
||||
isAppleGpuDiskCapture,
|
||||
shouldUseStreamingEncode,
|
||||
resolveObservedCaptureMode,
|
||||
createCaptureObservabilityUpdater,
|
||||
@@ -3665,6 +3666,23 @@ describe("calibrationCaptureConfig", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("isAppleGpuDiskCapture", () => {
|
||||
const disk = {
|
||||
platform: "darwin",
|
||||
browserGpuMode: "hardware",
|
||||
layered: false,
|
||||
parallelStream: false,
|
||||
} as const;
|
||||
|
||||
it("holds only for hardware-GPU Mac renders that write frames to disk", () => {
|
||||
expect(isAppleGpuDiskCapture(disk)).toBe(true);
|
||||
expect(isAppleGpuDiskCapture({ ...disk, layered: true })).toBe(false);
|
||||
expect(isAppleGpuDiskCapture({ ...disk, parallelStream: true })).toBe(false);
|
||||
expect(isAppleGpuDiskCapture({ ...disk, browserGpuMode: "software" })).toBe(false);
|
||||
expect(isAppleGpuDiskCapture({ ...disk, platform: "win32" })).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("shouldClampDefaultDrawElement (default-on drawElement clamp)", () => {
|
||||
const unverifiedParallel = {
|
||||
useDrawElement: true,
|
||||
|
||||
@@ -2797,6 +2797,21 @@ export function shouldSegmentCapture(args: {
|
||||
return args.durationSeconds >= resolveSegmentedMinSeconds(args.env);
|
||||
}
|
||||
|
||||
/** Worker sizing's Apple-GPU budget fits only frames written to disk by screenshot workers. */
|
||||
export function isAppleGpuDiskCapture(args: {
|
||||
platform: NodeJS.Platform;
|
||||
browserGpuMode: "software" | "hardware";
|
||||
layered: boolean;
|
||||
parallelStream: boolean;
|
||||
}): boolean {
|
||||
return (
|
||||
args.platform === "darwin" &&
|
||||
args.browserGpuMode === "hardware" &&
|
||||
!args.layered &&
|
||||
!args.parallelStream
|
||||
);
|
||||
}
|
||||
|
||||
export function shouldStreamParallelCapture(args: {
|
||||
/** Router switch for this render — see isCaptureParallelStreamRouterEnabled. */
|
||||
routerEnabled: boolean;
|
||||
@@ -4037,10 +4052,28 @@ async function executeRenderPipeline(input: {
|
||||
|
||||
// Low-memory safe-mode's single-worker pin lives inside
|
||||
// resolveRenderWorkerCount so its "why workers=N" logging stays coherent.
|
||||
const appleGpuDiskCapture = isAppleGpuDiskCapture({
|
||||
platform: process.platform,
|
||||
browserGpuMode: resolvedBrowserGpuMode,
|
||||
layered: shouldUseLayeredComposite({
|
||||
hasHdrContent,
|
||||
hasShaderTransitions: compiled.hasShaderTransitions && !isGif,
|
||||
isPngSequence,
|
||||
}),
|
||||
parallelStream: isCaptureParallelStreamRouterEnabled(
|
||||
process.env,
|
||||
resolveParallelCaptureMode({
|
||||
platform: process.platform,
|
||||
headlessShellPath: resolveHeadlessShellPath(cfg),
|
||||
forceScreenshot: captureForceScreenshot,
|
||||
deviceScaleFactor: captureOptions.deviceScaleFactor,
|
||||
}),
|
||||
),
|
||||
});
|
||||
workerCount = resolveRenderWorkerCount(
|
||||
totalFrames,
|
||||
job.config.workers,
|
||||
cfg,
|
||||
{ ...cfg, appleGpuDiskCapture },
|
||||
compiled,
|
||||
log,
|
||||
captureCalibration?.estimate,
|
||||
|
||||
Reference in New Issue
Block a user