@camstack/addon-pipeline 1.2.345 → 1.2.347
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/audio-analyzer/index.js +3 -3
- package/dist/audio-analyzer/index.mjs +3 -3
- package/dist/{custom-model-catalog-C7zLb7ze.mjs → custom-model-catalog-B_3TaGyS.mjs} +2 -2
- package/dist/{custom-model-catalog-CrEsRBe_.js → custom-model-catalog-VPiA2VLl.js} +2 -2
- package/dist/detection-pipeline/index.js +4 -4
- package/dist/detection-pipeline/index.mjs +8 -8
- package/dist/{dist-_I6JkuJ8.js → dist-BK74zWWV.js} +3774 -111
- package/dist/{dist-cT7hhXh9.mjs → dist-mCRj-pzB.mjs} +3745 -112
- package/dist/{model-catalogs-BrKLOMBe.js → model-catalogs-0h3q8aik.js} +15 -4
- package/dist/{model-catalogs-CPAmiLRa.mjs → model-catalogs-CwzQMyNC.mjs} +15 -4
- package/dist/motion-wasm/index.js +1 -1
- package/dist/motion-wasm/index.mjs +1 -1
- package/dist/{node-Dmga8QNL.mjs → node-BbmYK6W-.mjs} +1 -1
- package/dist/{node-6zL5ddry.js → node-BdTn3tlc.js} +1 -1
- package/dist/pipeline-runner/index.js +733 -6
- package/dist/pipeline-runner/index.mjs +739 -12
- package/dist/{process-memory-CstCtC3A.js → process-memory-CnZ_X4eQ.js} +1 -1
- package/dist/{process-memory-DZcnBnb1.mjs → process-memory-bOQf34ya.mjs} +1 -1
- package/dist/recorder/index.js +27 -7
- package/dist/recorder/index.mjs +27 -7
- package/dist/{segment-demux-js-qzo-pQK7.mjs → segment-demux-js-5MO-ia8o.mjs} +1 -1
- package/dist/{segment-demux-js-DPtDBph6.js → segment-demux-js-C4jnKQoX.js} +1 -1
- package/dist/stream-broker/_stub.js +2 -2
- package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-Drg8iwTA.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-C8GBSIhY.mjs} +3 -3
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-CNhTe1NS.mjs +26 -0
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-uvybMzaE.mjs +26 -0
- package/dist/stream-broker/demux-worker-child.js +1 -1
- package/dist/stream-broker/demux-worker-child.mjs +1 -1
- package/dist/stream-broker/{hostInit-Bz5eB0VL.mjs → hostInit-IWX_cy7U.mjs} +3 -3
- package/dist/stream-broker/index.js +3 -3
- package/dist/stream-broker/index.mjs +5 -5
- package/dist/stream-broker/remoteEntry.js +1 -1
- package/package.json +1 -1
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-C2VoXjqc.mjs +0 -26
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-DATpA6mb.mjs +0 -26
|
@@ -1,12 +1,16 @@
|
|
|
1
|
-
import { $ as
|
|
2
|
-
import { i as NO_COST_CLAIM, t as ChildCostRegistry } from "../node-
|
|
3
|
-
import { a as stepsForElectedPool, b as getStepDefinition, d as rootObjectGate, f as localFrameRegistry, h as resolveFrameViewGeometry, i as placeDetailStep, l as resolveDefaultDetectionModel, m as createSessionDecodeCoordinator, p as isSessionDecodeReadGone, s as resolveDeviceEngine, t as CustomModelCatalog, u as macroGateVerdict, y as getStep } from "../custom-model-catalog-
|
|
1
|
+
import { $t as pipelineRunnerCapability, Bn as defineCustomActions, E as FailureCounters, Et as failureContributionCapability, Ft as linkedStepOf, I as PIPELINE_RAMP, It as loadContributionCapability, Kn as nodePin, M as NativeLeaseAdmissionSchema, Mn as errMsg, N as NativeLeaseSettingsSchema, P as NodeBenchRunnerInputSchema, Pn as BaseAddon, Qn as boolean, Rn as createEvent, U as ROOT_SUPPLIABLE_STEP_IDS, Xn as _enum, Xt as pickDetailCropConvention, Z as allowedSuppliedEffect, Zn as array, Zt as pickNativeLeaseOverride, _ as DEFAULT_DETAIL_CROP_CONVENTION, _t as deriveRootFaceRefineRect, a as BackgroundRunRegistry, cr as EventCategory, er as lazy, fn as resolveRootSupply, ht as deriveDetailCropRect, it as cameraOwnsMotionViaSensor, j as MODEL_FORMATS, ln as resolveModelBoundSetting, m as CROP_SUPPLY_SOURCES, nr as number, or as string, pn as rootSuppliesOf, rr as object, rt as buildBenchStepTree, tr as literal, x as DEVICE_RAMP, y as DEFAULT_NATIVE_LEASE_SETTINGS, zn as customAction } from "../dist-mCRj-pzB.mjs";
|
|
2
|
+
import { i as NO_COST_CLAIM, t as ChildCostRegistry } from "../node-BbmYK6W-.mjs";
|
|
3
|
+
import { a as stepsForElectedPool, b as getStepDefinition, d as rootObjectGate, f as localFrameRegistry, h as resolveFrameViewGeometry, i as placeDetailStep, l as resolveDefaultDetectionModel, m as createSessionDecodeCoordinator, p as isSessionDecodeReadGone, s as resolveDeviceEngine, t as CustomModelCatalog, u as macroGateVerdict, y as getStep } from "../custom-model-catalog-B_3TaGyS.mjs";
|
|
4
4
|
import { t as resolveHubHostname } from "../hub-hostname-cCknRYKj.mjs";
|
|
5
5
|
import { t as getSharp } from "../lazy-sharp-DXsqwpph.mjs";
|
|
6
6
|
import { c as withDetectionIntent, o as preRollRequestOf, t as DETECTION_PRE_ROLL_REQUEST_MS } from "../restream-intent-DyGmLAU9.mjs";
|
|
7
7
|
import { n as profileForStreamId, t as isRemoteRestream } from "../remote-restream-BeHi78PZ.mjs";
|
|
8
|
-
import * as os from "node:os";
|
|
9
|
-
import
|
|
8
|
+
import * as os$1 from "node:os";
|
|
9
|
+
import os from "node:os";
|
|
10
|
+
import { createHash } from "node:crypto";
|
|
11
|
+
import { createReadStream, promises } from "node:fs";
|
|
12
|
+
import path from "node:path";
|
|
13
|
+
import { fork, spawn } from "node:child_process";
|
|
10
14
|
import sharp from "sharp";
|
|
11
15
|
import { fileURLToPath } from "node:url";
|
|
12
16
|
import { PerformanceObserver } from "node:perf_hooks";
|
|
@@ -3173,6 +3177,7 @@ async function executeCapacityRamp(opts) {
|
|
|
3173
3177
|
onMeasureStart: () => {
|
|
3174
3178
|
stallStart = opts.stallSnapshot();
|
|
3175
3179
|
rssStart = opts.rssMb();
|
|
3180
|
+
opts.onMeasureStartHook?.();
|
|
3176
3181
|
opts.onStep?.({
|
|
3177
3182
|
stepIndex,
|
|
3178
3183
|
cameras,
|
|
@@ -3181,15 +3186,25 @@ async function executeCapacityRamp(opts) {
|
|
|
3181
3186
|
}
|
|
3182
3187
|
});
|
|
3183
3188
|
const stall = diffStallWindow(stallStart, opts.stallSnapshot());
|
|
3184
|
-
const
|
|
3185
|
-
const
|
|
3189
|
+
const evaluated = evaluateCapacityStep(raw, stall, opts.slo);
|
|
3190
|
+
const base = {
|
|
3186
3191
|
cameras,
|
|
3187
3192
|
raw,
|
|
3188
3193
|
stall,
|
|
3189
|
-
verdict,
|
|
3194
|
+
verdict: evaluated,
|
|
3190
3195
|
rssStartMb: rssStart,
|
|
3191
3196
|
rssEndMb: opts.rssMb()
|
|
3192
3197
|
};
|
|
3198
|
+
const extra = opts.extraFailReasons?.(base) ?? [];
|
|
3199
|
+
const verdict = extra.length === 0 ? evaluated : {
|
|
3200
|
+
...evaluated,
|
|
3201
|
+
pass: false,
|
|
3202
|
+
failReasons: [...evaluated.failReasons, ...extra]
|
|
3203
|
+
};
|
|
3204
|
+
const step = {
|
|
3205
|
+
...base,
|
|
3206
|
+
verdict
|
|
3207
|
+
};
|
|
3193
3208
|
steps.push(step);
|
|
3194
3209
|
firstClass += raw.firstClassShed;
|
|
3195
3210
|
fallback += raw.fallbackShed;
|
|
@@ -4526,7 +4541,7 @@ function selectExecutorFrameSource(coLocated, frameRef, inlineFrame) {
|
|
|
4526
4541
|
* device balancer weights on. A null probe means "could not tell", which reports
|
|
4527
4542
|
* as `false` — the same conservative floor the engine cascade takes.
|
|
4528
4543
|
*/
|
|
4529
|
-
function summarizeRunnerHardware(hardware, cpuCores = os.cpus().length) {
|
|
4544
|
+
function summarizeRunnerHardware(hardware, cpuCores = os$1.cpus().length) {
|
|
4530
4545
|
return {
|
|
4531
4546
|
hasGpu: hardware?.gpu != null,
|
|
4532
4547
|
cpuCores
|
|
@@ -7352,6 +7367,699 @@ async function runStatelessStep(deps, input) {
|
|
|
7352
7367
|
details
|
|
7353
7368
|
};
|
|
7354
7369
|
}
|
|
7370
|
+
//#endregion
|
|
7371
|
+
//#region src/pipeline-runner/node-bench/bench-frames.ts
|
|
7372
|
+
/**
|
|
7373
|
+
* The frames a node benchmark runs on (D791), decoded ONCE on the node into
|
|
7374
|
+
* RAM at the detection size — never shipped across a process per call (D9).
|
|
7375
|
+
*
|
|
7376
|
+
* Source, in order:
|
|
7377
|
+
* 1. the public bench clip (`camstack-bench-v1`, CC-licensed composite with
|
|
7378
|
+
* a synthetic plate — `docs/benchmarks/bench-clip.md`), downloaded once
|
|
7379
|
+
* into the runner's data dir and accepted ONLY when its sha256 matches
|
|
7380
|
+
* the pinned revision; decoded with the node's pinned ffmpeg;
|
|
7381
|
+
* 2. otherwise the executor's reference images (always on the node). The
|
|
7382
|
+
* run says which (`clip.id`), so a result never claims the clip it did
|
|
7383
|
+
* not use.
|
|
7384
|
+
*/
|
|
7385
|
+
/**
|
|
7386
|
+
* The published clip, pinned to the exact build uploaded to the HF dataset
|
|
7387
|
+
* repo (`scripts/bench-clip/build-bench-clip.sh` prints the hash). A download
|
|
7388
|
+
* that fails (not uploaded yet) or whose bytes differ falls back to the
|
|
7389
|
+
* reference images, and the run says so. `sha256: null` disables the clip.
|
|
7390
|
+
*/
|
|
7391
|
+
var BENCH_CLIP = {
|
|
7392
|
+
id: "camstack-bench-v1",
|
|
7393
|
+
revision: "v1",
|
|
7394
|
+
fileName: "camstack-bench-v1-h264-1080p.mp4",
|
|
7395
|
+
url: "https://huggingface.co/datasets/camstack/camstack-bench-clips/resolve/main/camstack-bench-v1/camstack-bench-v1-h264-1080p.mp4",
|
|
7396
|
+
sha256: "677eea6ccb5711dafe70ac7259aa152b8fad3e5704da1a8a8c66e6b1717f1434"
|
|
7397
|
+
};
|
|
7398
|
+
async function sha256Of(file) {
|
|
7399
|
+
const hash = createHash("sha256");
|
|
7400
|
+
for await (const chunk of createReadStream(file)) hash.update(chunk);
|
|
7401
|
+
return hash.digest("hex");
|
|
7402
|
+
}
|
|
7403
|
+
/** The verified clip on disk, downloading it when absent or wrong. Null when unavailable. */
|
|
7404
|
+
async function ensureBenchClip(deps) {
|
|
7405
|
+
const clip = deps.clip ?? BENCH_CLIP;
|
|
7406
|
+
if (clip.sha256 === null) return null;
|
|
7407
|
+
const dir = path.join(deps.dataDir, "bench");
|
|
7408
|
+
const file = path.join(dir, clip.fileName);
|
|
7409
|
+
try {
|
|
7410
|
+
if (await sha256Of(file) === clip.sha256) return file;
|
|
7411
|
+
} catch {}
|
|
7412
|
+
await promises.mkdir(dir, { recursive: true });
|
|
7413
|
+
const staged = `${file}.downloading`;
|
|
7414
|
+
const res = await deps.fetch(clip.url);
|
|
7415
|
+
if (!res.ok || res.body === null) throw new Error(`bench clip download: HTTP ${res.status}`);
|
|
7416
|
+
await promises.writeFile(staged, new Uint8Array(await res.arrayBuffer()));
|
|
7417
|
+
const got = await sha256Of(staged);
|
|
7418
|
+
if (got !== clip.sha256) {
|
|
7419
|
+
await promises.rm(staged, { force: true });
|
|
7420
|
+
throw new Error(`bench clip download: sha256 ${got} is not the pinned ${clip.sha256}`);
|
|
7421
|
+
}
|
|
7422
|
+
await promises.rename(staged, file);
|
|
7423
|
+
return file;
|
|
7424
|
+
}
|
|
7425
|
+
/** Decode `count` evenly spread frames of `file` to raw RGB with the node's ffmpeg. */
|
|
7426
|
+
async function decodeClipFrames(ffmpeg, file, count) {
|
|
7427
|
+
const frameBytes = 640 * 360 * 3;
|
|
7428
|
+
const args = [
|
|
7429
|
+
"-v",
|
|
7430
|
+
"error",
|
|
7431
|
+
"-i",
|
|
7432
|
+
file,
|
|
7433
|
+
"-vf",
|
|
7434
|
+
`fps=1,scale=640:360`,
|
|
7435
|
+
"-frames:v",
|
|
7436
|
+
String(count),
|
|
7437
|
+
"-pix_fmt",
|
|
7438
|
+
"rgb24",
|
|
7439
|
+
"-f",
|
|
7440
|
+
"rawvideo",
|
|
7441
|
+
"pipe:1"
|
|
7442
|
+
];
|
|
7443
|
+
const chunks = [];
|
|
7444
|
+
const stderr = [];
|
|
7445
|
+
const code = await new Promise((resolve, reject) => {
|
|
7446
|
+
const child = spawn(ffmpeg, args, { stdio: [
|
|
7447
|
+
"ignore",
|
|
7448
|
+
"pipe",
|
|
7449
|
+
"pipe"
|
|
7450
|
+
] });
|
|
7451
|
+
child.stdout.on("data", (c) => chunks.push(c));
|
|
7452
|
+
child.stderr.on("data", (c) => stderr.push(c));
|
|
7453
|
+
child.on("error", reject);
|
|
7454
|
+
child.on("close", resolve);
|
|
7455
|
+
});
|
|
7456
|
+
if (code !== 0) throw new Error(`bench clip decode failed (${code}): ${Buffer.concat(stderr).toString().slice(0, 300)}`);
|
|
7457
|
+
const all = Buffer.concat(chunks);
|
|
7458
|
+
const frames = [];
|
|
7459
|
+
for (let off = 0; off + frameBytes <= all.length; off += frameBytes) frames.push({
|
|
7460
|
+
data: new Uint8Array(all.subarray(off, off + frameBytes)),
|
|
7461
|
+
width: 640,
|
|
7462
|
+
height: 360
|
|
7463
|
+
});
|
|
7464
|
+
return frames;
|
|
7465
|
+
}
|
|
7466
|
+
/** The clip's frames, else the reference images'. Throws only when neither yields a frame. */
|
|
7467
|
+
async function loadBenchFrames(deps) {
|
|
7468
|
+
const clip = deps.clip ?? BENCH_CLIP;
|
|
7469
|
+
try {
|
|
7470
|
+
const file = await ensureBenchClip(deps);
|
|
7471
|
+
if (file !== null) {
|
|
7472
|
+
const frames = await decodeClipFrames(await deps.ensureFfmpeg(), file, 120);
|
|
7473
|
+
if (frames.length > 0) return {
|
|
7474
|
+
frames,
|
|
7475
|
+
clip: {
|
|
7476
|
+
id: clip.id,
|
|
7477
|
+
revision: clip.revision,
|
|
7478
|
+
frames: frames.length,
|
|
7479
|
+
width: 640,
|
|
7480
|
+
height: 360
|
|
7481
|
+
}
|
|
7482
|
+
};
|
|
7483
|
+
} else deps.log("bench clip not published yet — measuring on the reference images");
|
|
7484
|
+
} catch (err) {
|
|
7485
|
+
deps.log("bench clip unavailable — measuring on the reference images", { error: err instanceof Error ? err.message : String(err) });
|
|
7486
|
+
}
|
|
7487
|
+
const frames = [];
|
|
7488
|
+
for (const jpeg of await deps.referenceImages()) try {
|
|
7489
|
+
frames.push(await deps.decodeJpeg(jpeg, 640));
|
|
7490
|
+
} catch {}
|
|
7491
|
+
if (frames.length === 0) throw new Error("node bench: neither the bench clip nor a reference image could be decoded");
|
|
7492
|
+
return {
|
|
7493
|
+
frames,
|
|
7494
|
+
clip: {
|
|
7495
|
+
id: "reference-images",
|
|
7496
|
+
revision: null,
|
|
7497
|
+
frames: frames.length,
|
|
7498
|
+
width: frames[0]?.width ?? 0,
|
|
7499
|
+
height: frames[0]?.height ?? 0
|
|
7500
|
+
}
|
|
7501
|
+
};
|
|
7502
|
+
}
|
|
7503
|
+
var WARMUP_CALLS = 3;
|
|
7504
|
+
var DETECTOR_STEP = "object-detection";
|
|
7505
|
+
function rootOnly(modelId) {
|
|
7506
|
+
return [{
|
|
7507
|
+
addonId: DETECTOR_STEP,
|
|
7508
|
+
modelId,
|
|
7509
|
+
enabled: true,
|
|
7510
|
+
children: []
|
|
7511
|
+
}];
|
|
7512
|
+
}
|
|
7513
|
+
/** Which limit a failing step hit first, from its reasons. */
|
|
7514
|
+
function limitOf(reasons) {
|
|
7515
|
+
const has = (prefix) => reasons.some((r) => r.startsWith(prefix));
|
|
7516
|
+
if (has("errors") || has("unresolved")) return "errors";
|
|
7517
|
+
if (has("cpu")) return "cpu";
|
|
7518
|
+
if (has("ram")) return "ram";
|
|
7519
|
+
if (has("event-loop")) return "stall";
|
|
7520
|
+
if (has("e2e p95")) return "p95";
|
|
7521
|
+
if (has("dropRatio")) return "drops";
|
|
7522
|
+
return "none";
|
|
7523
|
+
}
|
|
7524
|
+
function rampStepOf(step, measureSec, system) {
|
|
7525
|
+
return {
|
|
7526
|
+
load: step.cameras,
|
|
7527
|
+
pass: step.verdict.pass,
|
|
7528
|
+
p95Ms: Math.round(step.verdict.e2eMs.p95 * 10) / 10,
|
|
7529
|
+
dropRatio: Math.round(step.verdict.dropRatio * 1e4) / 1e4,
|
|
7530
|
+
fps: Math.round(step.raw.completed / Math.max(measureSec, 1e-9) * 10) / 10,
|
|
7531
|
+
cpuPct: system?.cpuPct ?? null,
|
|
7532
|
+
ramFreePct: system?.ramFreePct ?? null,
|
|
7533
|
+
failReasons: step.verdict.failReasons
|
|
7534
|
+
};
|
|
7535
|
+
}
|
|
7536
|
+
var NodeBenchDriver = class {
|
|
7537
|
+
deps;
|
|
7538
|
+
frameIndex = 0;
|
|
7539
|
+
cellsDone = 0;
|
|
7540
|
+
cellsTotal;
|
|
7541
|
+
constructor(deps) {
|
|
7542
|
+
this.deps = deps;
|
|
7543
|
+
const { input } = deps;
|
|
7544
|
+
const deviceCells = input.phases.includes("device") ? input.devices.reduce((n, d) => n + d.modelIds.length, 0) : 0;
|
|
7545
|
+
const pipelineCells = input.phases.includes("pipeline") ? input.devices.length : 0;
|
|
7546
|
+
this.cellsTotal = deviceCells + pipelineCells;
|
|
7547
|
+
}
|
|
7548
|
+
nextFrame() {
|
|
7549
|
+
const frames = this.deps.frames;
|
|
7550
|
+
const frame = frames[this.frameIndex % frames.length];
|
|
7551
|
+
this.frameIndex += 1;
|
|
7552
|
+
if (frame === void 0) throw new Error("node bench: no frames");
|
|
7553
|
+
return frame;
|
|
7554
|
+
}
|
|
7555
|
+
progress(p) {
|
|
7556
|
+
this.deps.onProgress({
|
|
7557
|
+
...p,
|
|
7558
|
+
cellsDone: this.cellsDone,
|
|
7559
|
+
cellsTotal: this.cellsTotal
|
|
7560
|
+
});
|
|
7561
|
+
}
|
|
7562
|
+
async warmup(steps, deviceKey, plane) {
|
|
7563
|
+
const t0 = this.deps.now();
|
|
7564
|
+
let firstMs = 0;
|
|
7565
|
+
for (let i = 0; i < WARMUP_CALLS; i++) {
|
|
7566
|
+
const started = this.deps.now();
|
|
7567
|
+
await this.deps.dispatch({
|
|
7568
|
+
steps,
|
|
7569
|
+
deviceKey,
|
|
7570
|
+
plane,
|
|
7571
|
+
frame: this.nextFrame()
|
|
7572
|
+
});
|
|
7573
|
+
if (i === 0) firstMs = this.deps.now() - started;
|
|
7574
|
+
}
|
|
7575
|
+
return Math.max(firstMs, 0) || this.deps.now() - t0;
|
|
7576
|
+
}
|
|
7577
|
+
ramp(opts) {
|
|
7578
|
+
const { input } = this.deps;
|
|
7579
|
+
const frameIntervalMs = 1e3 / input.fpsPerStream;
|
|
7580
|
+
const system = /* @__PURE__ */ new Map();
|
|
7581
|
+
const dispatch = async () => {
|
|
7582
|
+
const r = await this.deps.dispatch({
|
|
7583
|
+
steps: opts.steps,
|
|
7584
|
+
deviceKey: opts.deviceKey,
|
|
7585
|
+
plane: opts.plane,
|
|
7586
|
+
frame: this.nextFrame()
|
|
7587
|
+
});
|
|
7588
|
+
opts.onStepsRan?.(r.stepsRan);
|
|
7589
|
+
if (r.shed) return {
|
|
7590
|
+
kind: "shed",
|
|
7591
|
+
shedSignal: "first-class"
|
|
7592
|
+
};
|
|
7593
|
+
return {
|
|
7594
|
+
kind: "ok",
|
|
7595
|
+
inferMs: r.inferMs,
|
|
7596
|
+
predictMs: r.predictMs,
|
|
7597
|
+
detections: r.detections
|
|
7598
|
+
};
|
|
7599
|
+
};
|
|
7600
|
+
return executeCapacityRamp({
|
|
7601
|
+
ramp: opts.loads,
|
|
7602
|
+
fpsPerCamera: input.fpsPerStream,
|
|
7603
|
+
settleMs: input.settleSec * 1e3,
|
|
7604
|
+
measureMs: input.measureSec * 1e3,
|
|
7605
|
+
drainTimeoutMs: Math.max(5e3, frameIntervalMs * 20),
|
|
7606
|
+
slo: {
|
|
7607
|
+
dropRatioMax: .01,
|
|
7608
|
+
e2eP95MsMax: frameIntervalMs,
|
|
7609
|
+
stallsMax: 0
|
|
7610
|
+
},
|
|
7611
|
+
stopOnFirstFail: true,
|
|
7612
|
+
dispatch,
|
|
7613
|
+
now: this.deps.now,
|
|
7614
|
+
sleepUntil: this.deps.sleepUntil,
|
|
7615
|
+
shouldStop: this.deps.shouldStop,
|
|
7616
|
+
stallSnapshot: this.deps.stallSnapshot,
|
|
7617
|
+
rssMb: this.deps.rssMb,
|
|
7618
|
+
...opts.withSystemGate ? {
|
|
7619
|
+
extraFailReasons: (step) => {
|
|
7620
|
+
const s = this.deps.sampleSystem();
|
|
7621
|
+
system.set(step.cameras, s);
|
|
7622
|
+
const out = [];
|
|
7623
|
+
if (s.cpuPct > 85) out.push(`cpu ${Math.round(s.cpuPct)}% > 85%`);
|
|
7624
|
+
if (s.ramFreePct < 15) out.push(`ram free ${Math.round(s.ramFreePct)}% < 15%`);
|
|
7625
|
+
return out;
|
|
7626
|
+
},
|
|
7627
|
+
onMeasureStartHook: () => {
|
|
7628
|
+
this.deps.sampleSystem();
|
|
7629
|
+
}
|
|
7630
|
+
} : {},
|
|
7631
|
+
onStep: (info) => {
|
|
7632
|
+
if (info.phase === "done") return;
|
|
7633
|
+
this.progress({
|
|
7634
|
+
...opts.label,
|
|
7635
|
+
load: info.cameras,
|
|
7636
|
+
message: `${opts.label.phase === "device" ? "streams" : "sessions"} ${info.cameras} · ${info.phase}`
|
|
7637
|
+
});
|
|
7638
|
+
}
|
|
7639
|
+
}).then((outcome) => ({
|
|
7640
|
+
steps: [...outcome.steps],
|
|
7641
|
+
system,
|
|
7642
|
+
aborted: outcome.aborted
|
|
7643
|
+
}));
|
|
7644
|
+
}
|
|
7645
|
+
/** A cell whose ramp was cut short measured nothing reliable — null. */
|
|
7646
|
+
async measureDevice(deviceKey, modelId) {
|
|
7647
|
+
const steps = rootOnly(modelId);
|
|
7648
|
+
const label = {
|
|
7649
|
+
phase: "device",
|
|
7650
|
+
deviceKey,
|
|
7651
|
+
modelId
|
|
7652
|
+
};
|
|
7653
|
+
this.progress({
|
|
7654
|
+
...label,
|
|
7655
|
+
load: null,
|
|
7656
|
+
message: "loading the model"
|
|
7657
|
+
});
|
|
7658
|
+
const warmupMs = await this.warmup(steps, deviceKey, "frame");
|
|
7659
|
+
const { steps: ramp, aborted } = await this.ramp({
|
|
7660
|
+
loads: DEVICE_RAMP,
|
|
7661
|
+
steps,
|
|
7662
|
+
deviceKey,
|
|
7663
|
+
plane: "frame",
|
|
7664
|
+
withSystemGate: false,
|
|
7665
|
+
label
|
|
7666
|
+
});
|
|
7667
|
+
if (aborted) return null;
|
|
7668
|
+
const last = ramp.filter((s) => s.verdict.pass).at(-1);
|
|
7669
|
+
const first = ramp[0];
|
|
7670
|
+
const failed = ramp.find((s) => !s.verdict.pass);
|
|
7671
|
+
const single = first?.raw.e2eMsList ?? [];
|
|
7672
|
+
return {
|
|
7673
|
+
phase: "device",
|
|
7674
|
+
deviceKey,
|
|
7675
|
+
modelId,
|
|
7676
|
+
p50Ms: Math.round(percentile(single, .5) * 10) / 10,
|
|
7677
|
+
p95Ms: Math.round(percentile(single, .95) * 10) / 10,
|
|
7678
|
+
p99Ms: Math.round(percentile(single, .99) * 10) / 10,
|
|
7679
|
+
fps: last === void 0 ? 0 : Math.round(last.raw.completed / this.deps.input.measureSec * 10) / 10,
|
|
7680
|
+
kMax: last?.cameras ?? 0,
|
|
7681
|
+
limitedBy: failed === void 0 ? "none" : limitOf(failed.verdict.failReasons),
|
|
7682
|
+
warmupMs: Math.round(warmupMs),
|
|
7683
|
+
ramp: ramp.map((s) => rampStepOf(s, this.deps.input.measureSec, null))
|
|
7684
|
+
};
|
|
7685
|
+
}
|
|
7686
|
+
async measurePipeline(deviceKey, modelId) {
|
|
7687
|
+
const steps = await this.deps.pipelineSteps(modelId);
|
|
7688
|
+
const label = {
|
|
7689
|
+
phase: "pipeline",
|
|
7690
|
+
deviceKey,
|
|
7691
|
+
modelId
|
|
7692
|
+
};
|
|
7693
|
+
this.progress({
|
|
7694
|
+
...label,
|
|
7695
|
+
load: null,
|
|
7696
|
+
message: "loading the pipeline"
|
|
7697
|
+
});
|
|
7698
|
+
const fired = /* @__PURE__ */ new Set();
|
|
7699
|
+
const warmupMs = await this.warmup(steps, deviceKey, "full");
|
|
7700
|
+
const { steps: ramp, system, aborted } = await this.ramp({
|
|
7701
|
+
loads: PIPELINE_RAMP,
|
|
7702
|
+
steps,
|
|
7703
|
+
deviceKey,
|
|
7704
|
+
plane: "full",
|
|
7705
|
+
withSystemGate: true,
|
|
7706
|
+
onStepsRan: (ran) => {
|
|
7707
|
+
for (const s of ran) fired.add(s);
|
|
7708
|
+
},
|
|
7709
|
+
label
|
|
7710
|
+
});
|
|
7711
|
+
if (aborted) return null;
|
|
7712
|
+
const last = ramp.filter((s) => s.verdict.pass).at(-1);
|
|
7713
|
+
const failed = ramp.find((s) => !s.verdict.pass);
|
|
7714
|
+
return {
|
|
7715
|
+
phase: "pipeline",
|
|
7716
|
+
deviceKey,
|
|
7717
|
+
modelId,
|
|
7718
|
+
steps: this.deps.input.steps,
|
|
7719
|
+
maxSessions: last?.cameras ?? 0,
|
|
7720
|
+
limitedBy: failed === void 0 ? "none" : limitOf(failed.verdict.failReasons),
|
|
7721
|
+
stepsFired: this.deps.input.steps.filter((s) => fired.has(s)),
|
|
7722
|
+
warmupMs: Math.round(warmupMs),
|
|
7723
|
+
ramp: ramp.map((s) => rampStepOf(s, this.deps.input.measureSec, system.get(s.cameras) ?? null))
|
|
7724
|
+
};
|
|
7725
|
+
}
|
|
7726
|
+
/** Run every cell the input asks for; stops between steps when told to. */
|
|
7727
|
+
async run() {
|
|
7728
|
+
const { input } = this.deps;
|
|
7729
|
+
if (input.phases.includes("device")) for (const device of input.devices) for (const modelId of device.modelIds) {
|
|
7730
|
+
if (this.deps.shouldStop()) return;
|
|
7731
|
+
const cell = await this.measureDevice(device.deviceKey, modelId);
|
|
7732
|
+
this.cellsDone += 1;
|
|
7733
|
+
if (cell !== null) this.deps.onCell(cell);
|
|
7734
|
+
}
|
|
7735
|
+
if (input.phases.includes("pipeline")) for (const device of input.devices) {
|
|
7736
|
+
const modelId = device.modelIds[0];
|
|
7737
|
+
if (modelId === void 0 || this.deps.shouldStop()) return;
|
|
7738
|
+
const cell = await this.measurePipeline(device.deviceKey, modelId);
|
|
7739
|
+
this.cellsDone += 1;
|
|
7740
|
+
if (cell !== null) this.deps.onCell(cell);
|
|
7741
|
+
}
|
|
7742
|
+
}
|
|
7743
|
+
};
|
|
7744
|
+
//#endregion
|
|
7745
|
+
//#region src/pipeline-runner/node-bench/node-bench-host.ts
|
|
7746
|
+
/**
|
|
7747
|
+
* The runner side of the node benchmark (D791): one run per node, started
|
|
7748
|
+
* by the orchestrator through `nodePin`, answered at once and polled. Holds
|
|
7749
|
+
* the run's status in RAM (a restarted runner forgets it — the orchestrator
|
|
7750
|
+
* reads that as `runner-lost` and restores the cluster), stops itself at the
|
|
7751
|
+
* deadline whatever the hub does, and deletes the models it downloaded that
|
|
7752
|
+
* were not installed before (unless told to keep them).
|
|
7753
|
+
*/
|
|
7754
|
+
/** Node CPU % between two calls (all cores), and free RAM %. */
|
|
7755
|
+
function createSystemSampler() {
|
|
7756
|
+
const totals = () => os.cpus().reduce((acc, c) => {
|
|
7757
|
+
const t = c.times;
|
|
7758
|
+
return {
|
|
7759
|
+
idle: acc.idle + t.idle,
|
|
7760
|
+
total: acc.total + t.user + t.nice + t.sys + t.idle + t.irq
|
|
7761
|
+
};
|
|
7762
|
+
}, {
|
|
7763
|
+
idle: 0,
|
|
7764
|
+
total: 0
|
|
7765
|
+
});
|
|
7766
|
+
let prev = totals();
|
|
7767
|
+
return () => {
|
|
7768
|
+
const now = totals();
|
|
7769
|
+
const total = now.total - prev.total;
|
|
7770
|
+
const idle = now.idle - prev.idle;
|
|
7771
|
+
prev = now;
|
|
7772
|
+
return {
|
|
7773
|
+
cpuPct: total > 0 ? Math.round((1 - idle / total) * 1e3) / 10 : 0,
|
|
7774
|
+
ramFreePct: Math.round(os.freemem() / os.totalmem() * 1e3) / 10
|
|
7775
|
+
};
|
|
7776
|
+
};
|
|
7777
|
+
}
|
|
7778
|
+
/** Runs kept for status reads after they end. */
|
|
7779
|
+
var KEEP_FINISHED = 5;
|
|
7780
|
+
var NodeBenchHost = class {
|
|
7781
|
+
deps;
|
|
7782
|
+
runs = /* @__PURE__ */ new Map();
|
|
7783
|
+
constructor(deps) {
|
|
7784
|
+
this.deps = deps;
|
|
7785
|
+
}
|
|
7786
|
+
now() {
|
|
7787
|
+
return this.deps.now?.() ?? Date.now();
|
|
7788
|
+
}
|
|
7789
|
+
start(raw) {
|
|
7790
|
+
const input = NodeBenchRunnerInputSchema.parse(raw);
|
|
7791
|
+
if (this.runs.get(input.runId) !== void 0) return {
|
|
7792
|
+
accepted: true,
|
|
7793
|
+
runId: input.runId
|
|
7794
|
+
};
|
|
7795
|
+
for (const [id, run] of this.runs) if (run.status.state === "running") throw new Error(`node bench: run ${id} is measuring this node — one at a time`);
|
|
7796
|
+
const state = {
|
|
7797
|
+
stop: false,
|
|
7798
|
+
status: {
|
|
7799
|
+
runId: input.runId,
|
|
7800
|
+
nodeId: this.deps.nodeId,
|
|
7801
|
+
state: "running",
|
|
7802
|
+
progress: null,
|
|
7803
|
+
cells: [],
|
|
7804
|
+
fingerprint: null,
|
|
7805
|
+
clip: null,
|
|
7806
|
+
activeCameraIds: [...this.deps.activeCameraIds()],
|
|
7807
|
+
deletedModels: [],
|
|
7808
|
+
error: null,
|
|
7809
|
+
startedAtMs: this.now(),
|
|
7810
|
+
finishedAtMs: null
|
|
7811
|
+
}
|
|
7812
|
+
};
|
|
7813
|
+
this.runs.set(input.runId, state);
|
|
7814
|
+
this.prune();
|
|
7815
|
+
this.execute(input, state);
|
|
7816
|
+
return {
|
|
7817
|
+
accepted: true,
|
|
7818
|
+
runId: input.runId
|
|
7819
|
+
};
|
|
7820
|
+
}
|
|
7821
|
+
status(runId) {
|
|
7822
|
+
return this.runs.get(runId)?.status ?? null;
|
|
7823
|
+
}
|
|
7824
|
+
abort(runId) {
|
|
7825
|
+
const run = this.runs.get(runId);
|
|
7826
|
+
if (run === void 0 || run.status.state !== "running") return { aborted: false };
|
|
7827
|
+
run.stop = true;
|
|
7828
|
+
return { aborted: true };
|
|
7829
|
+
}
|
|
7830
|
+
prune() {
|
|
7831
|
+
const finished = [...this.runs.values()].filter((r) => r.status.state !== "running").toSorted((a, b) => b.status.startedAtMs - a.status.startedAtMs);
|
|
7832
|
+
for (const old of finished.slice(KEEP_FINISHED)) this.runs.delete(old.status.runId);
|
|
7833
|
+
}
|
|
7834
|
+
patch(state, patch) {
|
|
7835
|
+
state.status = {
|
|
7836
|
+
...state.status,
|
|
7837
|
+
...patch
|
|
7838
|
+
};
|
|
7839
|
+
}
|
|
7840
|
+
noteActiveCameras(state) {
|
|
7841
|
+
const seen = new Set([...state.status.activeCameraIds, ...this.deps.activeCameraIds()]);
|
|
7842
|
+
if (seen.size !== state.status.activeCameraIds.length) this.patch(state, { activeCameraIds: [...seen].toSorted((a, b) => a - b) });
|
|
7843
|
+
}
|
|
7844
|
+
async execute(input, state) {
|
|
7845
|
+
const shouldStop = () => state.stop || this.now() >= input.deadlineAtMs;
|
|
7846
|
+
const sampler = this.deps.startStallSampler();
|
|
7847
|
+
const installedBefore = await this.deps.installedDetectorModels().catch(() => null);
|
|
7848
|
+
try {
|
|
7849
|
+
this.patch(state, { progress: this.preparing(input, "decoding the bench frames") });
|
|
7850
|
+
const deviceKeys = input.devices.map((d) => d.deviceKey);
|
|
7851
|
+
const [frameSet, fingerprint] = await Promise.all([this.deps.loadFrames(), this.deps.fingerprint(deviceKeys).catch(() => null)]);
|
|
7852
|
+
this.patch(state, {
|
|
7853
|
+
clip: frameSet.clip,
|
|
7854
|
+
fingerprint
|
|
7855
|
+
});
|
|
7856
|
+
this.deps.log("info", "node bench start", {
|
|
7857
|
+
runId: input.runId,
|
|
7858
|
+
clip: frameSet.clip.id,
|
|
7859
|
+
frames: frameSet.frames.length,
|
|
7860
|
+
devices: deviceKeys,
|
|
7861
|
+
phases: input.phases
|
|
7862
|
+
});
|
|
7863
|
+
await new NodeBenchDriver({
|
|
7864
|
+
input,
|
|
7865
|
+
frames: frameSet.frames,
|
|
7866
|
+
dispatch: this.deps.dispatch,
|
|
7867
|
+
pipelineSteps: (modelId) => this.deps.pipelineSteps(modelId, input.steps),
|
|
7868
|
+
now: () => this.now(),
|
|
7869
|
+
sleepUntil: this.deps.sleepUntil ?? ((t) => new Promise((resolve) => {
|
|
7870
|
+
setTimeout(resolve, Math.max(0, t - this.now())).unref?.();
|
|
7871
|
+
})),
|
|
7872
|
+
shouldStop,
|
|
7873
|
+
stallSnapshot: sampler.snapshot,
|
|
7874
|
+
rssMb: () => Math.round(process.memoryUsage().rss / 1e6),
|
|
7875
|
+
sampleSystem: this.deps.sampleSystem ?? createSystemSampler(),
|
|
7876
|
+
onProgress: (progress) => {
|
|
7877
|
+
this.noteActiveCameras(state);
|
|
7878
|
+
this.patch(state, { progress });
|
|
7879
|
+
},
|
|
7880
|
+
onCell: (cell) => {
|
|
7881
|
+
this.patch(state, { cells: [...state.status.cells, cell] });
|
|
7882
|
+
this.deps.log("info", "node bench cell", {
|
|
7883
|
+
runId: input.runId,
|
|
7884
|
+
phase: cell.phase,
|
|
7885
|
+
deviceKey: cell.deviceKey,
|
|
7886
|
+
modelId: cell.modelId,
|
|
7887
|
+
...cell.phase === "device" ? {
|
|
7888
|
+
kMax: cell.kMax,
|
|
7889
|
+
fps: cell.fps,
|
|
7890
|
+
p95Ms: cell.p95Ms
|
|
7891
|
+
} : {
|
|
7892
|
+
maxSessions: cell.maxSessions,
|
|
7893
|
+
stepsFired: cell.stepsFired.join(",")
|
|
7894
|
+
},
|
|
7895
|
+
limitedBy: cell.limitedBy
|
|
7896
|
+
});
|
|
7897
|
+
}
|
|
7898
|
+
}).run();
|
|
7899
|
+
this.patch(state, { state: shouldStop() ? "aborted" : "done" });
|
|
7900
|
+
} catch (err) {
|
|
7901
|
+
const error = err instanceof Error ? err.message : String(err);
|
|
7902
|
+
this.deps.log("warn", "node bench failed", {
|
|
7903
|
+
runId: input.runId,
|
|
7904
|
+
error
|
|
7905
|
+
});
|
|
7906
|
+
this.patch(state, {
|
|
7907
|
+
state: "failed",
|
|
7908
|
+
error
|
|
7909
|
+
});
|
|
7910
|
+
} finally {
|
|
7911
|
+
sampler.stop();
|
|
7912
|
+
await this.cleanupModels(input, state, installedBefore);
|
|
7913
|
+
this.patch(state, {
|
|
7914
|
+
finishedAtMs: this.now(),
|
|
7915
|
+
progress: null
|
|
7916
|
+
});
|
|
7917
|
+
}
|
|
7918
|
+
}
|
|
7919
|
+
preparing(input, message) {
|
|
7920
|
+
return {
|
|
7921
|
+
phase: "preparing",
|
|
7922
|
+
deviceKey: null,
|
|
7923
|
+
modelId: null,
|
|
7924
|
+
load: null,
|
|
7925
|
+
cellsDone: 0,
|
|
7926
|
+
cellsTotal: (input.phases.includes("device") ? input.devices.reduce((n, d) => n + d.modelIds.length, 0) : 0) + (input.phases.includes("pipeline") ? input.devices.length : 0),
|
|
7927
|
+
message
|
|
7928
|
+
};
|
|
7929
|
+
}
|
|
7930
|
+
/** Delete the candidate detectors the run fetched that were not installed before. */
|
|
7931
|
+
async cleanupModels(input, state, before) {
|
|
7932
|
+
if (input.keepDownloadedModels || before === null) return;
|
|
7933
|
+
const after = await this.deps.installedDetectorModels().catch(() => null);
|
|
7934
|
+
if (after === null) return;
|
|
7935
|
+
const candidates = new Set(input.devices.flatMap((d) => d.modelIds));
|
|
7936
|
+
const fetched = [...after].filter((key) => candidates.has(key.split("/")[0] ?? "") && !before.has(key));
|
|
7937
|
+
const deleted = [];
|
|
7938
|
+
for (const key of fetched) try {
|
|
7939
|
+
await this.deps.deleteDetectorModel(key);
|
|
7940
|
+
deleted.push(key);
|
|
7941
|
+
} catch (err) {
|
|
7942
|
+
this.deps.log("warn", "node bench: could not delete a downloaded model", {
|
|
7943
|
+
model: key,
|
|
7944
|
+
error: err instanceof Error ? err.message : String(err)
|
|
7945
|
+
});
|
|
7946
|
+
}
|
|
7947
|
+
if (deleted.length > 0) this.patch(state, { deletedModels: deleted });
|
|
7948
|
+
}
|
|
7949
|
+
};
|
|
7950
|
+
//#endregion
|
|
7951
|
+
//#region src/pipeline-runner/node-bench/node-bench-wiring.ts
|
|
7952
|
+
/**
|
|
7953
|
+
* Binds the node benchmark host (D791) to the runner's in-process executor:
|
|
7954
|
+
* every call is pinned to THIS node, so the frame never leaves the process
|
|
7955
|
+
* group that owns it (D9) and the numbers are this node's.
|
|
7956
|
+
*/
|
|
7957
|
+
var DETECTOR_ADDON = "object-detection";
|
|
7958
|
+
/** A stall this long fails a ramp step (the frame interval at 4 fps). */
|
|
7959
|
+
var BENCH_STALL_MS = 250;
|
|
7960
|
+
function isModelFormat(value) {
|
|
7961
|
+
return MODEL_FORMATS.includes(value);
|
|
7962
|
+
}
|
|
7963
|
+
function createNodeBenchHost(deps) {
|
|
7964
|
+
const api = () => {
|
|
7965
|
+
const a = deps.ctx().api;
|
|
7966
|
+
if (!a) throw new Error("node bench: ctx.api unavailable");
|
|
7967
|
+
return a;
|
|
7968
|
+
};
|
|
7969
|
+
const pin = () => nodePin(deps.nodeId);
|
|
7970
|
+
const log = deps.ctx().logger;
|
|
7971
|
+
const decodeJpeg = async (jpeg, maxWidth) => {
|
|
7972
|
+
const { data, info } = await (await getSharp())(Buffer.from(jpeg)).resize({
|
|
7973
|
+
width: maxWidth,
|
|
7974
|
+
withoutEnlargement: true
|
|
7975
|
+
}).removeAlpha().raw().toBuffer({ resolveWithObject: true });
|
|
7976
|
+
return {
|
|
7977
|
+
data: new Uint8Array(data),
|
|
7978
|
+
width: info.width,
|
|
7979
|
+
height: info.height
|
|
7980
|
+
};
|
|
7981
|
+
};
|
|
7982
|
+
return new NodeBenchHost({
|
|
7983
|
+
nodeId: deps.nodeId,
|
|
7984
|
+
loadFrames: () => loadBenchFrames({
|
|
7985
|
+
dataDir: deps.ctx().dataDir,
|
|
7986
|
+
ensureFfmpeg: () => deps.ctx().deps.ensureFfmpeg(),
|
|
7987
|
+
fetch: globalThis.fetch,
|
|
7988
|
+
referenceImages: async () => {
|
|
7989
|
+
const list = await api().pipelineExecutor.listReferenceImages.query(void 0, pin());
|
|
7990
|
+
const out = [];
|
|
7991
|
+
for (const entry of list) {
|
|
7992
|
+
const img = await api().pipelineExecutor.getReferenceImage.query({ filename: entry.filename }, pin());
|
|
7993
|
+
if (img) out.push(new Uint8Array(Buffer.from(img.base64, "base64")));
|
|
7994
|
+
}
|
|
7995
|
+
return out;
|
|
7996
|
+
},
|
|
7997
|
+
decodeJpeg,
|
|
7998
|
+
log: (message, meta) => log.info(message, meta ? { meta } : void 0)
|
|
7999
|
+
}),
|
|
8000
|
+
dispatch: async ({ steps, deviceKey, plane, frame }) => {
|
|
8001
|
+
const result = await api().pipelineExecutor.runPipeline.mutate({
|
|
8002
|
+
steps: [...steps],
|
|
8003
|
+
frame: {
|
|
8004
|
+
data: frame.data,
|
|
8005
|
+
format: "rgb",
|
|
8006
|
+
width: frame.width,
|
|
8007
|
+
height: frame.height,
|
|
8008
|
+
timestamp: Date.now()
|
|
8009
|
+
},
|
|
8010
|
+
plane,
|
|
8011
|
+
deviceKey
|
|
8012
|
+
}, pin());
|
|
8013
|
+
return {
|
|
8014
|
+
shed: result.shed === true,
|
|
8015
|
+
detections: result.detections.length,
|
|
8016
|
+
inferMs: result.debug?.totalInferenceMs ?? 0,
|
|
8017
|
+
predictMs: result.debug?.predictMs ?? 0,
|
|
8018
|
+
stepsRan: [...new Set((result.debug?.stepTimings ?? []).filter((t) => t.ms > 0).map((t) => t.source))]
|
|
8019
|
+
};
|
|
8020
|
+
},
|
|
8021
|
+
pipelineSteps: async (rootModelId, stepIds) => {
|
|
8022
|
+
return buildBenchStepTree(await api().pipelineExecutor.getSchema.query(void 0, pin()), rootModelId, stepIds);
|
|
8023
|
+
},
|
|
8024
|
+
fingerprint: async (deviceKeys) => {
|
|
8025
|
+
const pools = {};
|
|
8026
|
+
for (const deviceKey of deviceKeys) try {
|
|
8027
|
+
const t = await api().pipelineExecutor.getEffectiveTuning.query({ deviceKey }, pin());
|
|
8028
|
+
pools[deviceKey] = {
|
|
8029
|
+
runtime: t.runtime,
|
|
8030
|
+
numWorkers: t.numWorkers,
|
|
8031
|
+
concurrency: t.concurrency,
|
|
8032
|
+
batchMode: t.batchMode
|
|
8033
|
+
};
|
|
8034
|
+
} catch {}
|
|
8035
|
+
return {
|
|
8036
|
+
pipelineVersion: deps.pipelineVersion,
|
|
8037
|
+
cpuModel: os.cpus()[0]?.model?.trim() ?? null,
|
|
8038
|
+
ramGb: Math.round(os.totalmem() / 1e9),
|
|
8039
|
+
os: `${os.platform()}-${os.arch()}`,
|
|
8040
|
+
pools
|
|
8041
|
+
};
|
|
8042
|
+
},
|
|
8043
|
+
installedDetectorModels: async () => {
|
|
8044
|
+
const models = await api().pipelineExecutor.getAddonModels.query({ addonId: DETECTOR_ADDON }, pin());
|
|
8045
|
+
const out = /* @__PURE__ */ new Set();
|
|
8046
|
+
for (const m of models) for (const [format, status] of Object.entries(m.formats)) if (status?.downloaded === true) out.add(`${m.id}/${format}`);
|
|
8047
|
+
return out;
|
|
8048
|
+
},
|
|
8049
|
+
deleteDetectorModel: async (key) => {
|
|
8050
|
+
const [modelId = "", format = ""] = key.split("/");
|
|
8051
|
+
if (!isModelFormat(format)) return;
|
|
8052
|
+
await api().pipelineExecutor.deleteModel.mutate({
|
|
8053
|
+
addonId: DETECTOR_ADDON,
|
|
8054
|
+
modelId,
|
|
8055
|
+
format
|
|
8056
|
+
}, pin());
|
|
8057
|
+
},
|
|
8058
|
+
activeCameraIds: deps.activeCameraIds,
|
|
8059
|
+
startStallSampler: () => startStallSampler({ reportThresholdMs: BENCH_STALL_MS }),
|
|
8060
|
+
log: (level, message, meta) => log[level](message, meta ? { meta } : void 0)
|
|
8061
|
+
});
|
|
8062
|
+
}
|
|
7355
8063
|
/**
|
|
7356
8064
|
* Normalised boxes for the subjects worth a tile, highest confidence first,
|
|
7357
8065
|
* capped.
|
|
@@ -8357,7 +9065,7 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends BaseAddon {
|
|
|
8357
9065
|
budgetSource: decodeLimits.budgetSource,
|
|
8358
9066
|
maxWorkers: decodeLimits.maxWorkers,
|
|
8359
9067
|
maxWorkersSource: decodeLimits.maxWorkersSource,
|
|
8360
|
-
totalMemMb: Math.round(os.totalmem() / 1048576)
|
|
9068
|
+
totalMemMb: Math.round(os$1.totalmem() / 1048576)
|
|
8361
9069
|
} });
|
|
8362
9070
|
this.liveWorkers = new LiveDecodeWorkerAdmission({
|
|
8363
9071
|
limit: decodeLimits.maxWorkers,
|
|
@@ -10002,6 +10710,25 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends BaseAddon {
|
|
|
10002
10710
|
* `executionFormat` reports — so the servability check and the dispatch
|
|
10003
10711
|
* cannot disagree about which format was verified.
|
|
10004
10712
|
*/
|
|
10713
|
+
nodeBenchHost = null;
|
|
10714
|
+
nodeBench() {
|
|
10715
|
+
this.nodeBenchHost ??= createNodeBenchHost({
|
|
10716
|
+
nodeId: this.nodeId,
|
|
10717
|
+
ctx: () => this.ctx,
|
|
10718
|
+
activeCameraIds: () => (this.runner?.getAllCameraMetrics() ?? []).filter((m) => m.phase !== "idle").map((m) => m.deviceId),
|
|
10719
|
+
pipelineVersion: null
|
|
10720
|
+
});
|
|
10721
|
+
return this.nodeBenchHost;
|
|
10722
|
+
}
|
|
10723
|
+
async startNodeBench(input) {
|
|
10724
|
+
return this.nodeBench().start(input);
|
|
10725
|
+
}
|
|
10726
|
+
async getNodeBenchStatus(input) {
|
|
10727
|
+
return this.nodeBench().status(input.runId);
|
|
10728
|
+
}
|
|
10729
|
+
async abortNodeBench(input) {
|
|
10730
|
+
return this.nodeBench().abort(input.runId);
|
|
10731
|
+
}
|
|
10005
10732
|
async runStatelessStep(input) {
|
|
10006
10733
|
const convention = await this.cropConvention.refresh(this.ctxIfReady?.api);
|
|
10007
10734
|
return runStatelessStep({
|
|
@@ -10218,7 +10945,7 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends BaseAddon {
|
|
|
10218
10945
|
defaultBudgetMb: DEFAULT_CONFIG.nodeDecodeBudgetMb,
|
|
10219
10946
|
defaultMaxWorkers: DEFAULT_CONFIG.maxLiveDecodeWorkers,
|
|
10220
10947
|
node: this.nodeLimits?.current() ?? {},
|
|
10221
|
-
totalMemMb: Math.round(os.totalmem() / 1048576)
|
|
10948
|
+
totalMemMb: Math.round(os$1.totalmem() / 1048576)
|
|
10222
10949
|
});
|
|
10223
10950
|
}
|
|
10224
10951
|
/** Resize the admission to the resolved limits; one info line per change. */
|
|
@@ -10235,7 +10962,7 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends BaseAddon {
|
|
|
10235
10962
|
budgetSource: limits.budgetSource,
|
|
10236
10963
|
maxWorkers: limits.maxWorkers,
|
|
10237
10964
|
maxWorkersSource: limits.maxWorkersSource,
|
|
10238
|
-
totalMemMb: Math.round(os.totalmem() / 1048576),
|
|
10965
|
+
totalMemMb: Math.round(os$1.totalmem() / 1048576),
|
|
10239
10966
|
decodeCeilingInForce: this.liveWorkers?.ceiling
|
|
10240
10967
|
} });
|
|
10241
10968
|
}
|