@camstack/addon-pipeline 1.2.345 → 1.2.346
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-CrEsRBe_.js → custom-model-catalog-B0QdF7dJ.js} +2 -2
- package/dist/{custom-model-catalog-C7zLb7ze.mjs → custom-model-catalog-C4LhTrew.mjs} +2 -2
- package/dist/detection-pipeline/index.js +4 -4
- package/dist/detection-pipeline/index.mjs +8 -8
- package/dist/{dist-cT7hhXh9.mjs → dist-Dj26w1od.mjs} +2044 -60
- package/dist/{dist-_I6JkuJ8.js → dist-qBCVRsyf.js} +2073 -59
- package/dist/{model-catalogs-BrKLOMBe.js → model-catalogs-C6tbm7vF.js} +1 -1
- package/dist/{model-catalogs-CPAmiLRa.mjs → model-catalogs-CsxkEiiz.mjs} +1 -1
- package/dist/motion-wasm/index.js +1 -1
- package/dist/motion-wasm/index.mjs +1 -1
- package/dist/{node-Dmga8QNL.mjs → node-Cc9bQ8ZM.mjs} +1 -1
- package/dist/{node-6zL5ddry.js → node-DmCpPH58.js} +1 -1
- package/dist/pipeline-runner/index.js +733 -6
- package/dist/pipeline-runner/index.mjs +739 -12
- package/dist/{process-memory-DZcnBnb1.mjs → process-memory-BrI4evjl.mjs} +1 -1
- package/dist/{process-memory-CstCtC3A.js → process-memory-BxIflT01.js} +1 -1
- package/dist/recorder/index.js +25 -3
- package/dist/recorder/index.mjs +25 -3
- package/dist/{segment-demux-js-qzo-pQK7.mjs → segment-demux-js-CmuAuckE.mjs} +1 -1
- package/dist/{segment-demux-js-DPtDBph6.js → segment-demux-js-DCLzkQTf.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-BX73joE9.mjs} +2 -2
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-B38GLERV.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-pieGo_tC.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-DKWabjpO.mjs} +2 -2
- 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
|
@@ -3,15 +3,19 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
const require_chunk = require("../chunk-emK7D4bc.js");
|
|
6
|
-
const require_dist = require("../dist-
|
|
7
|
-
const require_node = require("../node-
|
|
8
|
-
const require_custom_model_catalog = require("../custom-model-catalog-
|
|
6
|
+
const require_dist = require("../dist-qBCVRsyf.js");
|
|
7
|
+
const require_node = require("../node-DmCpPH58.js");
|
|
8
|
+
const require_custom_model_catalog = require("../custom-model-catalog-B0QdF7dJ.js");
|
|
9
9
|
const require_hub_hostname = require("../hub-hostname-DAJXlOgV.js");
|
|
10
10
|
const require_lazy_sharp = require("../lazy-sharp-BuwKlQLR.js");
|
|
11
11
|
const require_restream_intent = require("../restream-intent-7uDNqMKs.js");
|
|
12
12
|
const require_remote_restream = require("../remote-restream-CO36Sr30.js");
|
|
13
13
|
let node_os = require("node:os");
|
|
14
14
|
node_os = require_chunk.__toESM(node_os);
|
|
15
|
+
let node_crypto = require("node:crypto");
|
|
16
|
+
let node_fs = require("node:fs");
|
|
17
|
+
let node_path = require("node:path");
|
|
18
|
+
node_path = require_chunk.__toESM(node_path);
|
|
15
19
|
let node_child_process = require("node:child_process");
|
|
16
20
|
let sharp = require("sharp");
|
|
17
21
|
sharp = require_chunk.__toESM(sharp);
|
|
@@ -3181,6 +3185,7 @@ async function executeCapacityRamp(opts) {
|
|
|
3181
3185
|
onMeasureStart: () => {
|
|
3182
3186
|
stallStart = opts.stallSnapshot();
|
|
3183
3187
|
rssStart = opts.rssMb();
|
|
3188
|
+
opts.onMeasureStartHook?.();
|
|
3184
3189
|
opts.onStep?.({
|
|
3185
3190
|
stepIndex,
|
|
3186
3191
|
cameras,
|
|
@@ -3189,15 +3194,25 @@ async function executeCapacityRamp(opts) {
|
|
|
3189
3194
|
}
|
|
3190
3195
|
});
|
|
3191
3196
|
const stall = diffStallWindow(stallStart, opts.stallSnapshot());
|
|
3192
|
-
const
|
|
3193
|
-
const
|
|
3197
|
+
const evaluated = evaluateCapacityStep(raw, stall, opts.slo);
|
|
3198
|
+
const base = {
|
|
3194
3199
|
cameras,
|
|
3195
3200
|
raw,
|
|
3196
3201
|
stall,
|
|
3197
|
-
verdict,
|
|
3202
|
+
verdict: evaluated,
|
|
3198
3203
|
rssStartMb: rssStart,
|
|
3199
3204
|
rssEndMb: opts.rssMb()
|
|
3200
3205
|
};
|
|
3206
|
+
const extra = opts.extraFailReasons?.(base) ?? [];
|
|
3207
|
+
const verdict = extra.length === 0 ? evaluated : {
|
|
3208
|
+
...evaluated,
|
|
3209
|
+
pass: false,
|
|
3210
|
+
failReasons: [...evaluated.failReasons, ...extra]
|
|
3211
|
+
};
|
|
3212
|
+
const step = {
|
|
3213
|
+
...base,
|
|
3214
|
+
verdict
|
|
3215
|
+
};
|
|
3201
3216
|
steps.push(step);
|
|
3202
3217
|
firstClass += raw.firstClassShed;
|
|
3203
3218
|
fallback += raw.fallbackShed;
|
|
@@ -7360,6 +7375,699 @@ async function runStatelessStep(deps, input) {
|
|
|
7360
7375
|
details
|
|
7361
7376
|
};
|
|
7362
7377
|
}
|
|
7378
|
+
//#endregion
|
|
7379
|
+
//#region src/pipeline-runner/node-bench/bench-frames.ts
|
|
7380
|
+
/**
|
|
7381
|
+
* The frames a node benchmark runs on (D791), decoded ONCE on the node into
|
|
7382
|
+
* RAM at the detection size — never shipped across a process per call (D9).
|
|
7383
|
+
*
|
|
7384
|
+
* Source, in order:
|
|
7385
|
+
* 1. the public bench clip (`camstack-bench-v1`, CC-licensed composite with
|
|
7386
|
+
* a synthetic plate — `docs/benchmarks/bench-clip.md`), downloaded once
|
|
7387
|
+
* into the runner's data dir and accepted ONLY when its sha256 matches
|
|
7388
|
+
* the pinned revision; decoded with the node's pinned ffmpeg;
|
|
7389
|
+
* 2. otherwise the executor's reference images (always on the node). The
|
|
7390
|
+
* run says which (`clip.id`), so a result never claims the clip it did
|
|
7391
|
+
* not use.
|
|
7392
|
+
*/
|
|
7393
|
+
/**
|
|
7394
|
+
* The published clip, pinned to the exact build uploaded to the HF dataset
|
|
7395
|
+
* repo (`scripts/bench-clip/build-bench-clip.sh` prints the hash). A download
|
|
7396
|
+
* that fails (not uploaded yet) or whose bytes differ falls back to the
|
|
7397
|
+
* reference images, and the run says so. `sha256: null` disables the clip.
|
|
7398
|
+
*/
|
|
7399
|
+
var BENCH_CLIP = {
|
|
7400
|
+
id: "camstack-bench-v1",
|
|
7401
|
+
revision: "v1",
|
|
7402
|
+
fileName: "camstack-bench-v1-h264-1080p.mp4",
|
|
7403
|
+
url: "https://huggingface.co/datasets/camstack/camstack-bench-clips/resolve/main/camstack-bench-v1/camstack-bench-v1-h264-1080p.mp4",
|
|
7404
|
+
sha256: "677eea6ccb5711dafe70ac7259aa152b8fad3e5704da1a8a8c66e6b1717f1434"
|
|
7405
|
+
};
|
|
7406
|
+
async function sha256Of(file) {
|
|
7407
|
+
const hash = (0, node_crypto.createHash)("sha256");
|
|
7408
|
+
for await (const chunk of (0, node_fs.createReadStream)(file)) hash.update(chunk);
|
|
7409
|
+
return hash.digest("hex");
|
|
7410
|
+
}
|
|
7411
|
+
/** The verified clip on disk, downloading it when absent or wrong. Null when unavailable. */
|
|
7412
|
+
async function ensureBenchClip(deps) {
|
|
7413
|
+
const clip = deps.clip ?? BENCH_CLIP;
|
|
7414
|
+
if (clip.sha256 === null) return null;
|
|
7415
|
+
const dir = node_path.default.join(deps.dataDir, "bench");
|
|
7416
|
+
const file = node_path.default.join(dir, clip.fileName);
|
|
7417
|
+
try {
|
|
7418
|
+
if (await sha256Of(file) === clip.sha256) return file;
|
|
7419
|
+
} catch {}
|
|
7420
|
+
await node_fs.promises.mkdir(dir, { recursive: true });
|
|
7421
|
+
const staged = `${file}.downloading`;
|
|
7422
|
+
const res = await deps.fetch(clip.url);
|
|
7423
|
+
if (!res.ok || res.body === null) throw new Error(`bench clip download: HTTP ${res.status}`);
|
|
7424
|
+
await node_fs.promises.writeFile(staged, new Uint8Array(await res.arrayBuffer()));
|
|
7425
|
+
const got = await sha256Of(staged);
|
|
7426
|
+
if (got !== clip.sha256) {
|
|
7427
|
+
await node_fs.promises.rm(staged, { force: true });
|
|
7428
|
+
throw new Error(`bench clip download: sha256 ${got} is not the pinned ${clip.sha256}`);
|
|
7429
|
+
}
|
|
7430
|
+
await node_fs.promises.rename(staged, file);
|
|
7431
|
+
return file;
|
|
7432
|
+
}
|
|
7433
|
+
/** Decode `count` evenly spread frames of `file` to raw RGB with the node's ffmpeg. */
|
|
7434
|
+
async function decodeClipFrames(ffmpeg, file, count) {
|
|
7435
|
+
const frameBytes = 640 * 360 * 3;
|
|
7436
|
+
const args = [
|
|
7437
|
+
"-v",
|
|
7438
|
+
"error",
|
|
7439
|
+
"-i",
|
|
7440
|
+
file,
|
|
7441
|
+
"-vf",
|
|
7442
|
+
`fps=1,scale=640:360`,
|
|
7443
|
+
"-frames:v",
|
|
7444
|
+
String(count),
|
|
7445
|
+
"-pix_fmt",
|
|
7446
|
+
"rgb24",
|
|
7447
|
+
"-f",
|
|
7448
|
+
"rawvideo",
|
|
7449
|
+
"pipe:1"
|
|
7450
|
+
];
|
|
7451
|
+
const chunks = [];
|
|
7452
|
+
const stderr = [];
|
|
7453
|
+
const code = await new Promise((resolve, reject) => {
|
|
7454
|
+
const child = (0, node_child_process.spawn)(ffmpeg, args, { stdio: [
|
|
7455
|
+
"ignore",
|
|
7456
|
+
"pipe",
|
|
7457
|
+
"pipe"
|
|
7458
|
+
] });
|
|
7459
|
+
child.stdout.on("data", (c) => chunks.push(c));
|
|
7460
|
+
child.stderr.on("data", (c) => stderr.push(c));
|
|
7461
|
+
child.on("error", reject);
|
|
7462
|
+
child.on("close", resolve);
|
|
7463
|
+
});
|
|
7464
|
+
if (code !== 0) throw new Error(`bench clip decode failed (${code}): ${Buffer.concat(stderr).toString().slice(0, 300)}`);
|
|
7465
|
+
const all = Buffer.concat(chunks);
|
|
7466
|
+
const frames = [];
|
|
7467
|
+
for (let off = 0; off + frameBytes <= all.length; off += frameBytes) frames.push({
|
|
7468
|
+
data: new Uint8Array(all.subarray(off, off + frameBytes)),
|
|
7469
|
+
width: 640,
|
|
7470
|
+
height: 360
|
|
7471
|
+
});
|
|
7472
|
+
return frames;
|
|
7473
|
+
}
|
|
7474
|
+
/** The clip's frames, else the reference images'. Throws only when neither yields a frame. */
|
|
7475
|
+
async function loadBenchFrames(deps) {
|
|
7476
|
+
const clip = deps.clip ?? BENCH_CLIP;
|
|
7477
|
+
try {
|
|
7478
|
+
const file = await ensureBenchClip(deps);
|
|
7479
|
+
if (file !== null) {
|
|
7480
|
+
const frames = await decodeClipFrames(await deps.ensureFfmpeg(), file, 120);
|
|
7481
|
+
if (frames.length > 0) return {
|
|
7482
|
+
frames,
|
|
7483
|
+
clip: {
|
|
7484
|
+
id: clip.id,
|
|
7485
|
+
revision: clip.revision,
|
|
7486
|
+
frames: frames.length,
|
|
7487
|
+
width: 640,
|
|
7488
|
+
height: 360
|
|
7489
|
+
}
|
|
7490
|
+
};
|
|
7491
|
+
} else deps.log("bench clip not published yet — measuring on the reference images");
|
|
7492
|
+
} catch (err) {
|
|
7493
|
+
deps.log("bench clip unavailable — measuring on the reference images", { error: err instanceof Error ? err.message : String(err) });
|
|
7494
|
+
}
|
|
7495
|
+
const frames = [];
|
|
7496
|
+
for (const jpeg of await deps.referenceImages()) try {
|
|
7497
|
+
frames.push(await deps.decodeJpeg(jpeg, 640));
|
|
7498
|
+
} catch {}
|
|
7499
|
+
if (frames.length === 0) throw new Error("node bench: neither the bench clip nor a reference image could be decoded");
|
|
7500
|
+
return {
|
|
7501
|
+
frames,
|
|
7502
|
+
clip: {
|
|
7503
|
+
id: "reference-images",
|
|
7504
|
+
revision: null,
|
|
7505
|
+
frames: frames.length,
|
|
7506
|
+
width: frames[0]?.width ?? 0,
|
|
7507
|
+
height: frames[0]?.height ?? 0
|
|
7508
|
+
}
|
|
7509
|
+
};
|
|
7510
|
+
}
|
|
7511
|
+
var WARMUP_CALLS = 3;
|
|
7512
|
+
var DETECTOR_STEP = "object-detection";
|
|
7513
|
+
function rootOnly(modelId) {
|
|
7514
|
+
return [{
|
|
7515
|
+
addonId: DETECTOR_STEP,
|
|
7516
|
+
modelId,
|
|
7517
|
+
enabled: true,
|
|
7518
|
+
children: []
|
|
7519
|
+
}];
|
|
7520
|
+
}
|
|
7521
|
+
/** Which limit a failing step hit first, from its reasons. */
|
|
7522
|
+
function limitOf(reasons) {
|
|
7523
|
+
const has = (prefix) => reasons.some((r) => r.startsWith(prefix));
|
|
7524
|
+
if (has("errors") || has("unresolved")) return "errors";
|
|
7525
|
+
if (has("cpu")) return "cpu";
|
|
7526
|
+
if (has("ram")) return "ram";
|
|
7527
|
+
if (has("event-loop")) return "stall";
|
|
7528
|
+
if (has("e2e p95")) return "p95";
|
|
7529
|
+
if (has("dropRatio")) return "drops";
|
|
7530
|
+
return "none";
|
|
7531
|
+
}
|
|
7532
|
+
function rampStepOf(step, measureSec, system) {
|
|
7533
|
+
return {
|
|
7534
|
+
load: step.cameras,
|
|
7535
|
+
pass: step.verdict.pass,
|
|
7536
|
+
p95Ms: Math.round(step.verdict.e2eMs.p95 * 10) / 10,
|
|
7537
|
+
dropRatio: Math.round(step.verdict.dropRatio * 1e4) / 1e4,
|
|
7538
|
+
fps: Math.round(step.raw.completed / Math.max(measureSec, 1e-9) * 10) / 10,
|
|
7539
|
+
cpuPct: system?.cpuPct ?? null,
|
|
7540
|
+
ramFreePct: system?.ramFreePct ?? null,
|
|
7541
|
+
failReasons: step.verdict.failReasons
|
|
7542
|
+
};
|
|
7543
|
+
}
|
|
7544
|
+
var NodeBenchDriver = class {
|
|
7545
|
+
deps;
|
|
7546
|
+
frameIndex = 0;
|
|
7547
|
+
cellsDone = 0;
|
|
7548
|
+
cellsTotal;
|
|
7549
|
+
constructor(deps) {
|
|
7550
|
+
this.deps = deps;
|
|
7551
|
+
const { input } = deps;
|
|
7552
|
+
const deviceCells = input.phases.includes("device") ? input.devices.reduce((n, d) => n + d.modelIds.length, 0) : 0;
|
|
7553
|
+
const pipelineCells = input.phases.includes("pipeline") ? input.devices.length : 0;
|
|
7554
|
+
this.cellsTotal = deviceCells + pipelineCells;
|
|
7555
|
+
}
|
|
7556
|
+
nextFrame() {
|
|
7557
|
+
const frames = this.deps.frames;
|
|
7558
|
+
const frame = frames[this.frameIndex % frames.length];
|
|
7559
|
+
this.frameIndex += 1;
|
|
7560
|
+
if (frame === void 0) throw new Error("node bench: no frames");
|
|
7561
|
+
return frame;
|
|
7562
|
+
}
|
|
7563
|
+
progress(p) {
|
|
7564
|
+
this.deps.onProgress({
|
|
7565
|
+
...p,
|
|
7566
|
+
cellsDone: this.cellsDone,
|
|
7567
|
+
cellsTotal: this.cellsTotal
|
|
7568
|
+
});
|
|
7569
|
+
}
|
|
7570
|
+
async warmup(steps, deviceKey, plane) {
|
|
7571
|
+
const t0 = this.deps.now();
|
|
7572
|
+
let firstMs = 0;
|
|
7573
|
+
for (let i = 0; i < WARMUP_CALLS; i++) {
|
|
7574
|
+
const started = this.deps.now();
|
|
7575
|
+
await this.deps.dispatch({
|
|
7576
|
+
steps,
|
|
7577
|
+
deviceKey,
|
|
7578
|
+
plane,
|
|
7579
|
+
frame: this.nextFrame()
|
|
7580
|
+
});
|
|
7581
|
+
if (i === 0) firstMs = this.deps.now() - started;
|
|
7582
|
+
}
|
|
7583
|
+
return Math.max(firstMs, 0) || this.deps.now() - t0;
|
|
7584
|
+
}
|
|
7585
|
+
ramp(opts) {
|
|
7586
|
+
const { input } = this.deps;
|
|
7587
|
+
const frameIntervalMs = 1e3 / input.fpsPerStream;
|
|
7588
|
+
const system = /* @__PURE__ */ new Map();
|
|
7589
|
+
const dispatch = async () => {
|
|
7590
|
+
const r = await this.deps.dispatch({
|
|
7591
|
+
steps: opts.steps,
|
|
7592
|
+
deviceKey: opts.deviceKey,
|
|
7593
|
+
plane: opts.plane,
|
|
7594
|
+
frame: this.nextFrame()
|
|
7595
|
+
});
|
|
7596
|
+
opts.onStepsRan?.(r.stepsRan);
|
|
7597
|
+
if (r.shed) return {
|
|
7598
|
+
kind: "shed",
|
|
7599
|
+
shedSignal: "first-class"
|
|
7600
|
+
};
|
|
7601
|
+
return {
|
|
7602
|
+
kind: "ok",
|
|
7603
|
+
inferMs: r.inferMs,
|
|
7604
|
+
predictMs: r.predictMs,
|
|
7605
|
+
detections: r.detections
|
|
7606
|
+
};
|
|
7607
|
+
};
|
|
7608
|
+
return executeCapacityRamp({
|
|
7609
|
+
ramp: opts.loads,
|
|
7610
|
+
fpsPerCamera: input.fpsPerStream,
|
|
7611
|
+
settleMs: input.settleSec * 1e3,
|
|
7612
|
+
measureMs: input.measureSec * 1e3,
|
|
7613
|
+
drainTimeoutMs: Math.max(5e3, frameIntervalMs * 20),
|
|
7614
|
+
slo: {
|
|
7615
|
+
dropRatioMax: .01,
|
|
7616
|
+
e2eP95MsMax: frameIntervalMs,
|
|
7617
|
+
stallsMax: 0
|
|
7618
|
+
},
|
|
7619
|
+
stopOnFirstFail: true,
|
|
7620
|
+
dispatch,
|
|
7621
|
+
now: this.deps.now,
|
|
7622
|
+
sleepUntil: this.deps.sleepUntil,
|
|
7623
|
+
shouldStop: this.deps.shouldStop,
|
|
7624
|
+
stallSnapshot: this.deps.stallSnapshot,
|
|
7625
|
+
rssMb: this.deps.rssMb,
|
|
7626
|
+
...opts.withSystemGate ? {
|
|
7627
|
+
extraFailReasons: (step) => {
|
|
7628
|
+
const s = this.deps.sampleSystem();
|
|
7629
|
+
system.set(step.cameras, s);
|
|
7630
|
+
const out = [];
|
|
7631
|
+
if (s.cpuPct > 85) out.push(`cpu ${Math.round(s.cpuPct)}% > 85%`);
|
|
7632
|
+
if (s.ramFreePct < 15) out.push(`ram free ${Math.round(s.ramFreePct)}% < 15%`);
|
|
7633
|
+
return out;
|
|
7634
|
+
},
|
|
7635
|
+
onMeasureStartHook: () => {
|
|
7636
|
+
this.deps.sampleSystem();
|
|
7637
|
+
}
|
|
7638
|
+
} : {},
|
|
7639
|
+
onStep: (info) => {
|
|
7640
|
+
if (info.phase === "done") return;
|
|
7641
|
+
this.progress({
|
|
7642
|
+
...opts.label,
|
|
7643
|
+
load: info.cameras,
|
|
7644
|
+
message: `${opts.label.phase === "device" ? "streams" : "sessions"} ${info.cameras} · ${info.phase}`
|
|
7645
|
+
});
|
|
7646
|
+
}
|
|
7647
|
+
}).then((outcome) => ({
|
|
7648
|
+
steps: [...outcome.steps],
|
|
7649
|
+
system,
|
|
7650
|
+
aborted: outcome.aborted
|
|
7651
|
+
}));
|
|
7652
|
+
}
|
|
7653
|
+
/** A cell whose ramp was cut short measured nothing reliable — null. */
|
|
7654
|
+
async measureDevice(deviceKey, modelId) {
|
|
7655
|
+
const steps = rootOnly(modelId);
|
|
7656
|
+
const label = {
|
|
7657
|
+
phase: "device",
|
|
7658
|
+
deviceKey,
|
|
7659
|
+
modelId
|
|
7660
|
+
};
|
|
7661
|
+
this.progress({
|
|
7662
|
+
...label,
|
|
7663
|
+
load: null,
|
|
7664
|
+
message: "loading the model"
|
|
7665
|
+
});
|
|
7666
|
+
const warmupMs = await this.warmup(steps, deviceKey, "frame");
|
|
7667
|
+
const { steps: ramp, aborted } = await this.ramp({
|
|
7668
|
+
loads: require_dist.DEVICE_RAMP,
|
|
7669
|
+
steps,
|
|
7670
|
+
deviceKey,
|
|
7671
|
+
plane: "frame",
|
|
7672
|
+
withSystemGate: false,
|
|
7673
|
+
label
|
|
7674
|
+
});
|
|
7675
|
+
if (aborted) return null;
|
|
7676
|
+
const last = ramp.filter((s) => s.verdict.pass).at(-1);
|
|
7677
|
+
const first = ramp[0];
|
|
7678
|
+
const failed = ramp.find((s) => !s.verdict.pass);
|
|
7679
|
+
const single = first?.raw.e2eMsList ?? [];
|
|
7680
|
+
return {
|
|
7681
|
+
phase: "device",
|
|
7682
|
+
deviceKey,
|
|
7683
|
+
modelId,
|
|
7684
|
+
p50Ms: Math.round(percentile(single, .5) * 10) / 10,
|
|
7685
|
+
p95Ms: Math.round(percentile(single, .95) * 10) / 10,
|
|
7686
|
+
p99Ms: Math.round(percentile(single, .99) * 10) / 10,
|
|
7687
|
+
fps: last === void 0 ? 0 : Math.round(last.raw.completed / this.deps.input.measureSec * 10) / 10,
|
|
7688
|
+
kMax: last?.cameras ?? 0,
|
|
7689
|
+
limitedBy: failed === void 0 ? "none" : limitOf(failed.verdict.failReasons),
|
|
7690
|
+
warmupMs: Math.round(warmupMs),
|
|
7691
|
+
ramp: ramp.map((s) => rampStepOf(s, this.deps.input.measureSec, null))
|
|
7692
|
+
};
|
|
7693
|
+
}
|
|
7694
|
+
async measurePipeline(deviceKey, modelId) {
|
|
7695
|
+
const steps = await this.deps.pipelineSteps(modelId);
|
|
7696
|
+
const label = {
|
|
7697
|
+
phase: "pipeline",
|
|
7698
|
+
deviceKey,
|
|
7699
|
+
modelId
|
|
7700
|
+
};
|
|
7701
|
+
this.progress({
|
|
7702
|
+
...label,
|
|
7703
|
+
load: null,
|
|
7704
|
+
message: "loading the pipeline"
|
|
7705
|
+
});
|
|
7706
|
+
const fired = /* @__PURE__ */ new Set();
|
|
7707
|
+
const warmupMs = await this.warmup(steps, deviceKey, "full");
|
|
7708
|
+
const { steps: ramp, system, aborted } = await this.ramp({
|
|
7709
|
+
loads: require_dist.PIPELINE_RAMP,
|
|
7710
|
+
steps,
|
|
7711
|
+
deviceKey,
|
|
7712
|
+
plane: "full",
|
|
7713
|
+
withSystemGate: true,
|
|
7714
|
+
onStepsRan: (ran) => {
|
|
7715
|
+
for (const s of ran) fired.add(s);
|
|
7716
|
+
},
|
|
7717
|
+
label
|
|
7718
|
+
});
|
|
7719
|
+
if (aborted) return null;
|
|
7720
|
+
const last = ramp.filter((s) => s.verdict.pass).at(-1);
|
|
7721
|
+
const failed = ramp.find((s) => !s.verdict.pass);
|
|
7722
|
+
return {
|
|
7723
|
+
phase: "pipeline",
|
|
7724
|
+
deviceKey,
|
|
7725
|
+
modelId,
|
|
7726
|
+
steps: this.deps.input.steps,
|
|
7727
|
+
maxSessions: last?.cameras ?? 0,
|
|
7728
|
+
limitedBy: failed === void 0 ? "none" : limitOf(failed.verdict.failReasons),
|
|
7729
|
+
stepsFired: this.deps.input.steps.filter((s) => fired.has(s)),
|
|
7730
|
+
warmupMs: Math.round(warmupMs),
|
|
7731
|
+
ramp: ramp.map((s) => rampStepOf(s, this.deps.input.measureSec, system.get(s.cameras) ?? null))
|
|
7732
|
+
};
|
|
7733
|
+
}
|
|
7734
|
+
/** Run every cell the input asks for; stops between steps when told to. */
|
|
7735
|
+
async run() {
|
|
7736
|
+
const { input } = this.deps;
|
|
7737
|
+
if (input.phases.includes("device")) for (const device of input.devices) for (const modelId of device.modelIds) {
|
|
7738
|
+
if (this.deps.shouldStop()) return;
|
|
7739
|
+
const cell = await this.measureDevice(device.deviceKey, modelId);
|
|
7740
|
+
this.cellsDone += 1;
|
|
7741
|
+
if (cell !== null) this.deps.onCell(cell);
|
|
7742
|
+
}
|
|
7743
|
+
if (input.phases.includes("pipeline")) for (const device of input.devices) {
|
|
7744
|
+
const modelId = device.modelIds[0];
|
|
7745
|
+
if (modelId === void 0 || this.deps.shouldStop()) return;
|
|
7746
|
+
const cell = await this.measurePipeline(device.deviceKey, modelId);
|
|
7747
|
+
this.cellsDone += 1;
|
|
7748
|
+
if (cell !== null) this.deps.onCell(cell);
|
|
7749
|
+
}
|
|
7750
|
+
}
|
|
7751
|
+
};
|
|
7752
|
+
//#endregion
|
|
7753
|
+
//#region src/pipeline-runner/node-bench/node-bench-host.ts
|
|
7754
|
+
/**
|
|
7755
|
+
* The runner side of the node benchmark (D791): one run per node, started
|
|
7756
|
+
* by the orchestrator through `nodePin`, answered at once and polled. Holds
|
|
7757
|
+
* the run's status in RAM (a restarted runner forgets it — the orchestrator
|
|
7758
|
+
* reads that as `runner-lost` and restores the cluster), stops itself at the
|
|
7759
|
+
* deadline whatever the hub does, and deletes the models it downloaded that
|
|
7760
|
+
* were not installed before (unless told to keep them).
|
|
7761
|
+
*/
|
|
7762
|
+
/** Node CPU % between two calls (all cores), and free RAM %. */
|
|
7763
|
+
function createSystemSampler() {
|
|
7764
|
+
const totals = () => node_os.default.cpus().reduce((acc, c) => {
|
|
7765
|
+
const t = c.times;
|
|
7766
|
+
return {
|
|
7767
|
+
idle: acc.idle + t.idle,
|
|
7768
|
+
total: acc.total + t.user + t.nice + t.sys + t.idle + t.irq
|
|
7769
|
+
};
|
|
7770
|
+
}, {
|
|
7771
|
+
idle: 0,
|
|
7772
|
+
total: 0
|
|
7773
|
+
});
|
|
7774
|
+
let prev = totals();
|
|
7775
|
+
return () => {
|
|
7776
|
+
const now = totals();
|
|
7777
|
+
const total = now.total - prev.total;
|
|
7778
|
+
const idle = now.idle - prev.idle;
|
|
7779
|
+
prev = now;
|
|
7780
|
+
return {
|
|
7781
|
+
cpuPct: total > 0 ? Math.round((1 - idle / total) * 1e3) / 10 : 0,
|
|
7782
|
+
ramFreePct: Math.round(node_os.default.freemem() / node_os.default.totalmem() * 1e3) / 10
|
|
7783
|
+
};
|
|
7784
|
+
};
|
|
7785
|
+
}
|
|
7786
|
+
/** Runs kept for status reads after they end. */
|
|
7787
|
+
var KEEP_FINISHED = 5;
|
|
7788
|
+
var NodeBenchHost = class {
|
|
7789
|
+
deps;
|
|
7790
|
+
runs = /* @__PURE__ */ new Map();
|
|
7791
|
+
constructor(deps) {
|
|
7792
|
+
this.deps = deps;
|
|
7793
|
+
}
|
|
7794
|
+
now() {
|
|
7795
|
+
return this.deps.now?.() ?? Date.now();
|
|
7796
|
+
}
|
|
7797
|
+
start(raw) {
|
|
7798
|
+
const input = require_dist.NodeBenchRunnerInputSchema.parse(raw);
|
|
7799
|
+
if (this.runs.get(input.runId) !== void 0) return {
|
|
7800
|
+
accepted: true,
|
|
7801
|
+
runId: input.runId
|
|
7802
|
+
};
|
|
7803
|
+
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`);
|
|
7804
|
+
const state = {
|
|
7805
|
+
stop: false,
|
|
7806
|
+
status: {
|
|
7807
|
+
runId: input.runId,
|
|
7808
|
+
nodeId: this.deps.nodeId,
|
|
7809
|
+
state: "running",
|
|
7810
|
+
progress: null,
|
|
7811
|
+
cells: [],
|
|
7812
|
+
fingerprint: null,
|
|
7813
|
+
clip: null,
|
|
7814
|
+
activeCameraIds: [...this.deps.activeCameraIds()],
|
|
7815
|
+
deletedModels: [],
|
|
7816
|
+
error: null,
|
|
7817
|
+
startedAtMs: this.now(),
|
|
7818
|
+
finishedAtMs: null
|
|
7819
|
+
}
|
|
7820
|
+
};
|
|
7821
|
+
this.runs.set(input.runId, state);
|
|
7822
|
+
this.prune();
|
|
7823
|
+
this.execute(input, state);
|
|
7824
|
+
return {
|
|
7825
|
+
accepted: true,
|
|
7826
|
+
runId: input.runId
|
|
7827
|
+
};
|
|
7828
|
+
}
|
|
7829
|
+
status(runId) {
|
|
7830
|
+
return this.runs.get(runId)?.status ?? null;
|
|
7831
|
+
}
|
|
7832
|
+
abort(runId) {
|
|
7833
|
+
const run = this.runs.get(runId);
|
|
7834
|
+
if (run === void 0 || run.status.state !== "running") return { aborted: false };
|
|
7835
|
+
run.stop = true;
|
|
7836
|
+
return { aborted: true };
|
|
7837
|
+
}
|
|
7838
|
+
prune() {
|
|
7839
|
+
const finished = [...this.runs.values()].filter((r) => r.status.state !== "running").toSorted((a, b) => b.status.startedAtMs - a.status.startedAtMs);
|
|
7840
|
+
for (const old of finished.slice(KEEP_FINISHED)) this.runs.delete(old.status.runId);
|
|
7841
|
+
}
|
|
7842
|
+
patch(state, patch) {
|
|
7843
|
+
state.status = {
|
|
7844
|
+
...state.status,
|
|
7845
|
+
...patch
|
|
7846
|
+
};
|
|
7847
|
+
}
|
|
7848
|
+
noteActiveCameras(state) {
|
|
7849
|
+
const seen = new Set([...state.status.activeCameraIds, ...this.deps.activeCameraIds()]);
|
|
7850
|
+
if (seen.size !== state.status.activeCameraIds.length) this.patch(state, { activeCameraIds: [...seen].toSorted((a, b) => a - b) });
|
|
7851
|
+
}
|
|
7852
|
+
async execute(input, state) {
|
|
7853
|
+
const shouldStop = () => state.stop || this.now() >= input.deadlineAtMs;
|
|
7854
|
+
const sampler = this.deps.startStallSampler();
|
|
7855
|
+
const installedBefore = await this.deps.installedDetectorModels().catch(() => null);
|
|
7856
|
+
try {
|
|
7857
|
+
this.patch(state, { progress: this.preparing(input, "decoding the bench frames") });
|
|
7858
|
+
const deviceKeys = input.devices.map((d) => d.deviceKey);
|
|
7859
|
+
const [frameSet, fingerprint] = await Promise.all([this.deps.loadFrames(), this.deps.fingerprint(deviceKeys).catch(() => null)]);
|
|
7860
|
+
this.patch(state, {
|
|
7861
|
+
clip: frameSet.clip,
|
|
7862
|
+
fingerprint
|
|
7863
|
+
});
|
|
7864
|
+
this.deps.log("info", "node bench start", {
|
|
7865
|
+
runId: input.runId,
|
|
7866
|
+
clip: frameSet.clip.id,
|
|
7867
|
+
frames: frameSet.frames.length,
|
|
7868
|
+
devices: deviceKeys,
|
|
7869
|
+
phases: input.phases
|
|
7870
|
+
});
|
|
7871
|
+
await new NodeBenchDriver({
|
|
7872
|
+
input,
|
|
7873
|
+
frames: frameSet.frames,
|
|
7874
|
+
dispatch: this.deps.dispatch,
|
|
7875
|
+
pipelineSteps: (modelId) => this.deps.pipelineSteps(modelId, input.steps),
|
|
7876
|
+
now: () => this.now(),
|
|
7877
|
+
sleepUntil: this.deps.sleepUntil ?? ((t) => new Promise((resolve) => {
|
|
7878
|
+
setTimeout(resolve, Math.max(0, t - this.now())).unref?.();
|
|
7879
|
+
})),
|
|
7880
|
+
shouldStop,
|
|
7881
|
+
stallSnapshot: sampler.snapshot,
|
|
7882
|
+
rssMb: () => Math.round(process.memoryUsage().rss / 1e6),
|
|
7883
|
+
sampleSystem: this.deps.sampleSystem ?? createSystemSampler(),
|
|
7884
|
+
onProgress: (progress) => {
|
|
7885
|
+
this.noteActiveCameras(state);
|
|
7886
|
+
this.patch(state, { progress });
|
|
7887
|
+
},
|
|
7888
|
+
onCell: (cell) => {
|
|
7889
|
+
this.patch(state, { cells: [...state.status.cells, cell] });
|
|
7890
|
+
this.deps.log("info", "node bench cell", {
|
|
7891
|
+
runId: input.runId,
|
|
7892
|
+
phase: cell.phase,
|
|
7893
|
+
deviceKey: cell.deviceKey,
|
|
7894
|
+
modelId: cell.modelId,
|
|
7895
|
+
...cell.phase === "device" ? {
|
|
7896
|
+
kMax: cell.kMax,
|
|
7897
|
+
fps: cell.fps,
|
|
7898
|
+
p95Ms: cell.p95Ms
|
|
7899
|
+
} : {
|
|
7900
|
+
maxSessions: cell.maxSessions,
|
|
7901
|
+
stepsFired: cell.stepsFired.join(",")
|
|
7902
|
+
},
|
|
7903
|
+
limitedBy: cell.limitedBy
|
|
7904
|
+
});
|
|
7905
|
+
}
|
|
7906
|
+
}).run();
|
|
7907
|
+
this.patch(state, { state: shouldStop() ? "aborted" : "done" });
|
|
7908
|
+
} catch (err) {
|
|
7909
|
+
const error = err instanceof Error ? err.message : String(err);
|
|
7910
|
+
this.deps.log("warn", "node bench failed", {
|
|
7911
|
+
runId: input.runId,
|
|
7912
|
+
error
|
|
7913
|
+
});
|
|
7914
|
+
this.patch(state, {
|
|
7915
|
+
state: "failed",
|
|
7916
|
+
error
|
|
7917
|
+
});
|
|
7918
|
+
} finally {
|
|
7919
|
+
sampler.stop();
|
|
7920
|
+
await this.cleanupModels(input, state, installedBefore);
|
|
7921
|
+
this.patch(state, {
|
|
7922
|
+
finishedAtMs: this.now(),
|
|
7923
|
+
progress: null
|
|
7924
|
+
});
|
|
7925
|
+
}
|
|
7926
|
+
}
|
|
7927
|
+
preparing(input, message) {
|
|
7928
|
+
return {
|
|
7929
|
+
phase: "preparing",
|
|
7930
|
+
deviceKey: null,
|
|
7931
|
+
modelId: null,
|
|
7932
|
+
load: null,
|
|
7933
|
+
cellsDone: 0,
|
|
7934
|
+
cellsTotal: (input.phases.includes("device") ? input.devices.reduce((n, d) => n + d.modelIds.length, 0) : 0) + (input.phases.includes("pipeline") ? input.devices.length : 0),
|
|
7935
|
+
message
|
|
7936
|
+
};
|
|
7937
|
+
}
|
|
7938
|
+
/** Delete the candidate detectors the run fetched that were not installed before. */
|
|
7939
|
+
async cleanupModels(input, state, before) {
|
|
7940
|
+
if (input.keepDownloadedModels || before === null) return;
|
|
7941
|
+
const after = await this.deps.installedDetectorModels().catch(() => null);
|
|
7942
|
+
if (after === null) return;
|
|
7943
|
+
const candidates = new Set(input.devices.flatMap((d) => d.modelIds));
|
|
7944
|
+
const fetched = [...after].filter((key) => candidates.has(key.split("/")[0] ?? "") && !before.has(key));
|
|
7945
|
+
const deleted = [];
|
|
7946
|
+
for (const key of fetched) try {
|
|
7947
|
+
await this.deps.deleteDetectorModel(key);
|
|
7948
|
+
deleted.push(key);
|
|
7949
|
+
} catch (err) {
|
|
7950
|
+
this.deps.log("warn", "node bench: could not delete a downloaded model", {
|
|
7951
|
+
model: key,
|
|
7952
|
+
error: err instanceof Error ? err.message : String(err)
|
|
7953
|
+
});
|
|
7954
|
+
}
|
|
7955
|
+
if (deleted.length > 0) this.patch(state, { deletedModels: deleted });
|
|
7956
|
+
}
|
|
7957
|
+
};
|
|
7958
|
+
//#endregion
|
|
7959
|
+
//#region src/pipeline-runner/node-bench/node-bench-wiring.ts
|
|
7960
|
+
/**
|
|
7961
|
+
* Binds the node benchmark host (D791) to the runner's in-process executor:
|
|
7962
|
+
* every call is pinned to THIS node, so the frame never leaves the process
|
|
7963
|
+
* group that owns it (D9) and the numbers are this node's.
|
|
7964
|
+
*/
|
|
7965
|
+
var DETECTOR_ADDON = "object-detection";
|
|
7966
|
+
/** A stall this long fails a ramp step (the frame interval at 4 fps). */
|
|
7967
|
+
var BENCH_STALL_MS = 250;
|
|
7968
|
+
function isModelFormat(value) {
|
|
7969
|
+
return require_dist.MODEL_FORMATS.includes(value);
|
|
7970
|
+
}
|
|
7971
|
+
function createNodeBenchHost(deps) {
|
|
7972
|
+
const api = () => {
|
|
7973
|
+
const a = deps.ctx().api;
|
|
7974
|
+
if (!a) throw new Error("node bench: ctx.api unavailable");
|
|
7975
|
+
return a;
|
|
7976
|
+
};
|
|
7977
|
+
const pin = () => require_dist.nodePin(deps.nodeId);
|
|
7978
|
+
const log = deps.ctx().logger;
|
|
7979
|
+
const decodeJpeg = async (jpeg, maxWidth) => {
|
|
7980
|
+
const { data, info } = await (await require_lazy_sharp.getSharp())(Buffer.from(jpeg)).resize({
|
|
7981
|
+
width: maxWidth,
|
|
7982
|
+
withoutEnlargement: true
|
|
7983
|
+
}).removeAlpha().raw().toBuffer({ resolveWithObject: true });
|
|
7984
|
+
return {
|
|
7985
|
+
data: new Uint8Array(data),
|
|
7986
|
+
width: info.width,
|
|
7987
|
+
height: info.height
|
|
7988
|
+
};
|
|
7989
|
+
};
|
|
7990
|
+
return new NodeBenchHost({
|
|
7991
|
+
nodeId: deps.nodeId,
|
|
7992
|
+
loadFrames: () => loadBenchFrames({
|
|
7993
|
+
dataDir: deps.ctx().dataDir,
|
|
7994
|
+
ensureFfmpeg: () => deps.ctx().deps.ensureFfmpeg(),
|
|
7995
|
+
fetch: globalThis.fetch,
|
|
7996
|
+
referenceImages: async () => {
|
|
7997
|
+
const list = await api().pipelineExecutor.listReferenceImages.query(void 0, pin());
|
|
7998
|
+
const out = [];
|
|
7999
|
+
for (const entry of list) {
|
|
8000
|
+
const img = await api().pipelineExecutor.getReferenceImage.query({ filename: entry.filename }, pin());
|
|
8001
|
+
if (img) out.push(new Uint8Array(Buffer.from(img.base64, "base64")));
|
|
8002
|
+
}
|
|
8003
|
+
return out;
|
|
8004
|
+
},
|
|
8005
|
+
decodeJpeg,
|
|
8006
|
+
log: (message, meta) => log.info(message, meta ? { meta } : void 0)
|
|
8007
|
+
}),
|
|
8008
|
+
dispatch: async ({ steps, deviceKey, plane, frame }) => {
|
|
8009
|
+
const result = await api().pipelineExecutor.runPipeline.mutate({
|
|
8010
|
+
steps: [...steps],
|
|
8011
|
+
frame: {
|
|
8012
|
+
data: frame.data,
|
|
8013
|
+
format: "rgb",
|
|
8014
|
+
width: frame.width,
|
|
8015
|
+
height: frame.height,
|
|
8016
|
+
timestamp: Date.now()
|
|
8017
|
+
},
|
|
8018
|
+
plane,
|
|
8019
|
+
deviceKey
|
|
8020
|
+
}, pin());
|
|
8021
|
+
return {
|
|
8022
|
+
shed: result.shed === true,
|
|
8023
|
+
detections: result.detections.length,
|
|
8024
|
+
inferMs: result.debug?.totalInferenceMs ?? 0,
|
|
8025
|
+
predictMs: result.debug?.predictMs ?? 0,
|
|
8026
|
+
stepsRan: [...new Set((result.debug?.stepTimings ?? []).filter((t) => t.ms > 0).map((t) => t.source))]
|
|
8027
|
+
};
|
|
8028
|
+
},
|
|
8029
|
+
pipelineSteps: async (rootModelId, stepIds) => {
|
|
8030
|
+
return require_dist.buildBenchStepTree(await api().pipelineExecutor.getSchema.query(void 0, pin()), rootModelId, stepIds);
|
|
8031
|
+
},
|
|
8032
|
+
fingerprint: async (deviceKeys) => {
|
|
8033
|
+
const pools = {};
|
|
8034
|
+
for (const deviceKey of deviceKeys) try {
|
|
8035
|
+
const t = await api().pipelineExecutor.getEffectiveTuning.query({ deviceKey }, pin());
|
|
8036
|
+
pools[deviceKey] = {
|
|
8037
|
+
runtime: t.runtime,
|
|
8038
|
+
numWorkers: t.numWorkers,
|
|
8039
|
+
concurrency: t.concurrency,
|
|
8040
|
+
batchMode: t.batchMode
|
|
8041
|
+
};
|
|
8042
|
+
} catch {}
|
|
8043
|
+
return {
|
|
8044
|
+
pipelineVersion: deps.pipelineVersion,
|
|
8045
|
+
cpuModel: node_os.default.cpus()[0]?.model?.trim() ?? null,
|
|
8046
|
+
ramGb: Math.round(node_os.default.totalmem() / 1e9),
|
|
8047
|
+
os: `${node_os.default.platform()}-${node_os.default.arch()}`,
|
|
8048
|
+
pools
|
|
8049
|
+
};
|
|
8050
|
+
},
|
|
8051
|
+
installedDetectorModels: async () => {
|
|
8052
|
+
const models = await api().pipelineExecutor.getAddonModels.query({ addonId: DETECTOR_ADDON }, pin());
|
|
8053
|
+
const out = /* @__PURE__ */ new Set();
|
|
8054
|
+
for (const m of models) for (const [format, status] of Object.entries(m.formats)) if (status?.downloaded === true) out.add(`${m.id}/${format}`);
|
|
8055
|
+
return out;
|
|
8056
|
+
},
|
|
8057
|
+
deleteDetectorModel: async (key) => {
|
|
8058
|
+
const [modelId = "", format = ""] = key.split("/");
|
|
8059
|
+
if (!isModelFormat(format)) return;
|
|
8060
|
+
await api().pipelineExecutor.deleteModel.mutate({
|
|
8061
|
+
addonId: DETECTOR_ADDON,
|
|
8062
|
+
modelId,
|
|
8063
|
+
format
|
|
8064
|
+
}, pin());
|
|
8065
|
+
},
|
|
8066
|
+
activeCameraIds: deps.activeCameraIds,
|
|
8067
|
+
startStallSampler: () => startStallSampler({ reportThresholdMs: BENCH_STALL_MS }),
|
|
8068
|
+
log: (level, message, meta) => log[level](message, meta ? { meta } : void 0)
|
|
8069
|
+
});
|
|
8070
|
+
}
|
|
7363
8071
|
/**
|
|
7364
8072
|
* Normalised boxes for the subjects worth a tile, highest confidence first,
|
|
7365
8073
|
* capped.
|
|
@@ -10010,6 +10718,25 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends require_dist.BaseAdd
|
|
|
10010
10718
|
* `executionFormat` reports — so the servability check and the dispatch
|
|
10011
10719
|
* cannot disagree about which format was verified.
|
|
10012
10720
|
*/
|
|
10721
|
+
nodeBenchHost = null;
|
|
10722
|
+
nodeBench() {
|
|
10723
|
+
this.nodeBenchHost ??= createNodeBenchHost({
|
|
10724
|
+
nodeId: this.nodeId,
|
|
10725
|
+
ctx: () => this.ctx,
|
|
10726
|
+
activeCameraIds: () => (this.runner?.getAllCameraMetrics() ?? []).filter((m) => m.phase !== "idle").map((m) => m.deviceId),
|
|
10727
|
+
pipelineVersion: null
|
|
10728
|
+
});
|
|
10729
|
+
return this.nodeBenchHost;
|
|
10730
|
+
}
|
|
10731
|
+
async startNodeBench(input) {
|
|
10732
|
+
return this.nodeBench().start(input);
|
|
10733
|
+
}
|
|
10734
|
+
async getNodeBenchStatus(input) {
|
|
10735
|
+
return this.nodeBench().status(input.runId);
|
|
10736
|
+
}
|
|
10737
|
+
async abortNodeBench(input) {
|
|
10738
|
+
return this.nodeBench().abort(input.runId);
|
|
10739
|
+
}
|
|
10013
10740
|
async runStatelessStep(input) {
|
|
10014
10741
|
const convention = await this.cropConvention.refresh(this.ctxIfReady?.api);
|
|
10015
10742
|
return runStatelessStep({
|