@camstack/addon-pipeline 1.1.26 → 1.1.27
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/constants-CAqYVigN.js +6615 -0
- package/dist/constants-oYgW36Ty.mjs +3587 -0
- package/dist/decoder-ffmpeg/index.js +33 -272
- package/dist/decoder-ffmpeg/index.mjs +32 -271
- package/dist/decoder-nodeav/index.js +1213 -0
- package/dist/decoder-nodeav/index.mjs +1205 -0
- package/dist/dist-D3Ytt-_Y.js +41111 -0
- package/dist/dist-DluJuxV5.mjs +37976 -0
- package/dist/frame-ring-sink-B_NvPTJZ.mjs +316 -0
- package/dist/frame-ring-sink-BbzrqTWj.js +339 -0
- package/dist/stream-broker/index.js +20 -15
- package/dist/stream-broker/index.mjs +20 -15
- package/package.json +31 -3
- package/python/inference_pool.py +34 -38
- package/python/test_inference_pool_device_selection.py +9 -10
- package/python/yamnet_audio.py +1 -1
|
@@ -17799,30 +17799,35 @@ var FfmpegDecoderSession = class {
|
|
|
17799
17799
|
this.outputBuffer = Buffer.alloc(0);
|
|
17800
17800
|
this.cachedWidth = 0;
|
|
17801
17801
|
this.cachedHeight = 0;
|
|
17802
|
-
const
|
|
17803
|
-
this.process =
|
|
17804
|
-
|
|
17805
|
-
|
|
17806
|
-
this.handleOutputData(chunk);
|
|
17802
|
+
const child = (0, node_child_process.spawn)("ffmpeg", buildFfmpegArgs(this.config));
|
|
17803
|
+
this.process = child;
|
|
17804
|
+
child.stdin?.on("error", () => {});
|
|
17805
|
+
child.stdout?.on("data", (chunk) => {
|
|
17806
|
+
if (child === this.process) this.handleOutputData(chunk);
|
|
17807
17807
|
});
|
|
17808
|
-
|
|
17808
|
+
child.stderr?.on("data", (data) => {
|
|
17809
|
+
if (child !== this.process) return;
|
|
17809
17810
|
const line = data.toString().trim();
|
|
17810
17811
|
if (line) this.logger.debug("ffmpeg stderr", { meta: { line } });
|
|
17811
17812
|
});
|
|
17812
|
-
|
|
17813
|
+
child.on("error", (err) => {
|
|
17814
|
+
if (child !== this.process) return;
|
|
17813
17815
|
this.logger.error("FFmpeg decoder spawn error", { meta: { error: err.message } });
|
|
17814
17816
|
});
|
|
17815
|
-
|
|
17816
|
-
if (!this.destroyed) this.process = null;
|
|
17817
|
+
child.on("close", (_code, _signal) => {
|
|
17818
|
+
if (child === this.process && !this.destroyed) this.process = null;
|
|
17817
17819
|
});
|
|
17818
17820
|
}
|
|
17819
17821
|
killFfmpeg() {
|
|
17820
|
-
|
|
17821
|
-
|
|
17822
|
-
|
|
17823
|
-
|
|
17824
|
-
|
|
17825
|
-
|
|
17822
|
+
const child = this.process;
|
|
17823
|
+
if (!child) return;
|
|
17824
|
+
this.process = null;
|
|
17825
|
+
child.stdout?.removeAllListeners("data");
|
|
17826
|
+
child.stderr?.removeAllListeners("data");
|
|
17827
|
+
child.removeAllListeners("close");
|
|
17828
|
+
try {
|
|
17829
|
+
child.kill("SIGKILL");
|
|
17830
|
+
} catch {}
|
|
17826
17831
|
}
|
|
17827
17832
|
handleOutputData(chunk) {
|
|
17828
17833
|
this.outputBuffer = Buffer.concat([this.outputBuffer, chunk]);
|
|
@@ -17795,30 +17795,35 @@ var FfmpegDecoderSession = class {
|
|
|
17795
17795
|
this.outputBuffer = Buffer.alloc(0);
|
|
17796
17796
|
this.cachedWidth = 0;
|
|
17797
17797
|
this.cachedHeight = 0;
|
|
17798
|
-
const
|
|
17799
|
-
this.process =
|
|
17800
|
-
|
|
17801
|
-
|
|
17802
|
-
this.handleOutputData(chunk);
|
|
17798
|
+
const child = spawn("ffmpeg", buildFfmpegArgs(this.config));
|
|
17799
|
+
this.process = child;
|
|
17800
|
+
child.stdin?.on("error", () => {});
|
|
17801
|
+
child.stdout?.on("data", (chunk) => {
|
|
17802
|
+
if (child === this.process) this.handleOutputData(chunk);
|
|
17803
17803
|
});
|
|
17804
|
-
|
|
17804
|
+
child.stderr?.on("data", (data) => {
|
|
17805
|
+
if (child !== this.process) return;
|
|
17805
17806
|
const line = data.toString().trim();
|
|
17806
17807
|
if (line) this.logger.debug("ffmpeg stderr", { meta: { line } });
|
|
17807
17808
|
});
|
|
17808
|
-
|
|
17809
|
+
child.on("error", (err) => {
|
|
17810
|
+
if (child !== this.process) return;
|
|
17809
17811
|
this.logger.error("FFmpeg decoder spawn error", { meta: { error: err.message } });
|
|
17810
17812
|
});
|
|
17811
|
-
|
|
17812
|
-
if (!this.destroyed) this.process = null;
|
|
17813
|
+
child.on("close", (_code, _signal) => {
|
|
17814
|
+
if (child === this.process && !this.destroyed) this.process = null;
|
|
17813
17815
|
});
|
|
17814
17816
|
}
|
|
17815
17817
|
killFfmpeg() {
|
|
17816
|
-
|
|
17817
|
-
|
|
17818
|
-
|
|
17819
|
-
|
|
17820
|
-
|
|
17821
|
-
|
|
17818
|
+
const child = this.process;
|
|
17819
|
+
if (!child) return;
|
|
17820
|
+
this.process = null;
|
|
17821
|
+
child.stdout?.removeAllListeners("data");
|
|
17822
|
+
child.stderr?.removeAllListeners("data");
|
|
17823
|
+
child.removeAllListeners("close");
|
|
17824
|
+
try {
|
|
17825
|
+
child.kill("SIGKILL");
|
|
17826
|
+
} catch {}
|
|
17822
17827
|
}
|
|
17823
17828
|
handleOutputData(chunk) {
|
|
17824
17829
|
this.outputBuffer = Buffer.concat([this.outputBuffer, chunk]);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camstack/addon-pipeline",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.27",
|
|
4
4
|
"description": "CamStack Pipeline bundle — runner, detection, motion, decoders, audio + stream broker. Multi-entry npm package shipping 7 addons under a single bundle.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"camstack",
|
|
@@ -36,6 +36,10 @@
|
|
|
36
36
|
"import": "./dist/decoder-ffmpeg/index.mjs",
|
|
37
37
|
"require": "./dist/decoder-ffmpeg/index.js"
|
|
38
38
|
},
|
|
39
|
+
"./decoder-nodeav": {
|
|
40
|
+
"import": "./dist/decoder-nodeav/index.mjs",
|
|
41
|
+
"require": "./dist/decoder-nodeav/index.js"
|
|
42
|
+
},
|
|
39
43
|
"./audio-codec-ffmpeg": {
|
|
40
44
|
"import": "./dist/audio-codec-ffmpeg/index.mjs",
|
|
41
45
|
"require": "./dist/audio-codec-ffmpeg/index.js"
|
|
@@ -149,7 +153,7 @@
|
|
|
149
153
|
"category": "pipeline",
|
|
150
154
|
"name": "Decoder (ffmpeg)",
|
|
151
155
|
"version": "0.1.0",
|
|
152
|
-
"description": "Out-of-process video decoder spawning an ffmpeg subprocess —
|
|
156
|
+
"description": "Out-of-process video decoder spawning an ffmpeg subprocess — a decode crash is isolated to the child, never taking down the runner. The DEFAULT decoder backend: it registers the decoder cap only when the node's `decoder` settings section selects `ffmpeg` (the default). ffmpeg is provisioned per node via ctx.deps.ensureFfmpeg().",
|
|
153
157
|
"entry": "./dist/decoder-ffmpeg/index.js",
|
|
154
158
|
"execution": {
|
|
155
159
|
"placement": "any-node",
|
|
@@ -157,7 +161,30 @@
|
|
|
157
161
|
},
|
|
158
162
|
"capabilities": [
|
|
159
163
|
{
|
|
160
|
-
"name": "decoder"
|
|
164
|
+
"name": "decoder",
|
|
165
|
+
"optional": true
|
|
166
|
+
}
|
|
167
|
+
],
|
|
168
|
+
"passive": true,
|
|
169
|
+
"protected": true,
|
|
170
|
+
"icon": "assets/icon.svg",
|
|
171
|
+
"color": "#0ea5e9"
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
"id": "decoder-nodeav",
|
|
175
|
+
"category": "pipeline",
|
|
176
|
+
"name": "Decoder (node-av)",
|
|
177
|
+
"version": "0.1.0",
|
|
178
|
+
"description": "In-process video decoder using FFmpeg native bindings (node-av) — no subprocess lifecycle (nothing to spawn, supervise, or leak). Registers the decoder cap only when the node's `decoder` settings section selects `nodeav`; decoder-ffmpeg is the default backend.",
|
|
179
|
+
"entry": "./dist/decoder-nodeav/index.js",
|
|
180
|
+
"execution": {
|
|
181
|
+
"placement": "any-node",
|
|
182
|
+
"heapProfile": "heavy"
|
|
183
|
+
},
|
|
184
|
+
"capabilities": [
|
|
185
|
+
{
|
|
186
|
+
"name": "decoder",
|
|
187
|
+
"optional": true
|
|
161
188
|
}
|
|
162
189
|
],
|
|
163
190
|
"passive": true,
|
|
@@ -299,6 +326,7 @@
|
|
|
299
326
|
"@camstack/system": "*",
|
|
300
327
|
"lucide-react": "^0.511.0",
|
|
301
328
|
"mp4box": "0.5.4",
|
|
329
|
+
"node-av": "^6.0.0",
|
|
302
330
|
"sharp": "^0.35.2",
|
|
303
331
|
"zod": "^4.3.6"
|
|
304
332
|
},
|
package/python/inference_pool.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
"""Async inference pool — request_id multiplexed, per-runtime concurrency.
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
Per-runtime ML backends (coreml / openvino / onnx):
|
|
5
5
|
- asyncio main loop reads requests from stdin; inference is dispatched
|
|
6
6
|
onto a runtime-specific executor so the reader never blocks.
|
|
7
7
|
- Each request carries a 32-bit id; responses are tagged with the same
|
|
@@ -76,7 +76,7 @@ MSG_INFER_RAW = 0x02
|
|
|
76
76
|
# Each item is dispatched concurrently via asyncio.gather so the
|
|
77
77
|
# predict pool's existing parallelism applies; the saving over N
|
|
78
78
|
# separate calls is one IPC round-trip per item collapsed to one,
|
|
79
|
-
#
|
|
79
|
+
# with batch=4 semantics for fair benchmarking.
|
|
80
80
|
MSG_INFER_BATCH = 0x03
|
|
81
81
|
MSG_CACHE_FRAME = 0x04
|
|
82
82
|
MSG_INFER_CACHED = 0x05
|
|
@@ -172,22 +172,21 @@ _ov_optimal_reqs: int = 0
|
|
|
172
172
|
# query the device's optimal request count). ≈ measured optimal on Intel
|
|
173
173
|
# CPU/iGPU/NPU (4-5). Threads idle-block on infer, so over-provisioning is cheap.
|
|
174
174
|
OV_DEFAULT_CONCURRENCY: int = 4
|
|
175
|
-
# OpenVINO device-mode decision
|
|
176
|
-
# device
|
|
177
|
-
#
|
|
178
|
-
#
|
|
179
|
-
#
|
|
180
|
-
#
|
|
181
|
-
# output ports ("Cannot find tensor for port opset1::Result score_8").
|
|
175
|
+
# OpenVINO device-mode decision. AUTO mode can hide errors / cause conflicts
|
|
176
|
+
# with NPU and GPU, so we resolve an explicit device and fall back accordingly.
|
|
177
|
+
# The intel-iGPU-only case (the N100) compiles explicit "GPU" — the exact host
|
|
178
|
+
# where the AUTO plugin's mid-flight CPU-helper -> GPU handover invalidated
|
|
179
|
+
# in-flight InferRequest output ports ("Cannot find tensor for port
|
|
180
|
+
# opset1::Result score_8").
|
|
182
181
|
|
|
183
182
|
|
|
184
183
|
def _resolve_ov_mode(available: list[str], full_names: dict[str, str]) -> str:
|
|
185
|
-
"""
|
|
184
|
+
"""Resolve the device-mode string for an AUTO/default device request.
|
|
186
185
|
|
|
187
186
|
`available` is `core.available_devices`; `full_names` maps each device to
|
|
188
187
|
its FULL_DEVICE_NAME property (entries whose property query failed are
|
|
189
|
-
absent —
|
|
190
|
-
|
|
188
|
+
absent — a device whose FULL_DEVICE_NAME probe failed is not classified).
|
|
189
|
+
The branch matrix:
|
|
191
190
|
|
|
192
191
|
npu & gpu -> "AUTO:NPU,GPU,CPU"
|
|
193
192
|
npu & !gpu -> "AUTO:NPU,CPU"
|
|
@@ -217,8 +216,8 @@ def _resolve_ov_mode(available: list[str], full_names: dict[str, str]) -> str:
|
|
|
217
216
|
mode = "AUTO:NPU,CPU"
|
|
218
217
|
elif len(dgpus):
|
|
219
218
|
mode = f"AUTO:{','.join(dgpus)},CPU"
|
|
220
|
-
# forcing GPU can
|
|
221
|
-
#
|
|
219
|
+
# forcing GPU can crash on older GPUs — the GPU-mode compile failure falls
|
|
220
|
+
# back to AUTO in the compile loop below.
|
|
222
221
|
elif gpu:
|
|
223
222
|
mode = "GPU"
|
|
224
223
|
return mode
|
|
@@ -239,8 +238,7 @@ def _resolve_onnx_providers(
|
|
|
239
238
|
) -> list:
|
|
240
239
|
"""Ordered ONNX Runtime providers — hardware first, CPU always last.
|
|
241
240
|
|
|
242
|
-
|
|
243
|
-
for the AUTO/default case:
|
|
241
|
+
Ordering for the AUTO/default case:
|
|
244
242
|
|
|
245
243
|
darwin -> CoreMLExecutionProvider
|
|
246
244
|
linux/win on x86_64/AMD64 -> ("CUDAExecutionProvider", {"device_id": N})
|
|
@@ -253,8 +251,8 @@ def _resolve_onnx_providers(
|
|
|
253
251
|
(ort.get_available_providers()) are dropped — camstack ships the
|
|
254
252
|
plain `onnxruntime` wheel on most nodes, and requesting an EP the
|
|
255
253
|
build lacks raises at session creation instead of falling back.
|
|
256
|
-
- platform match uses startswith so
|
|
257
|
-
|
|
254
|
+
- platform match uses startswith so a substring test on "win" never
|
|
255
|
+
wrongly matches "darwin".
|
|
258
256
|
"""
|
|
259
257
|
dev = (device or "").strip().lower()
|
|
260
258
|
ordered: list = []
|
|
@@ -265,7 +263,7 @@ def _resolve_onnx_providers(
|
|
|
265
263
|
elif dev == "cpu":
|
|
266
264
|
pass # explicit CPU pin — no hardware EPs
|
|
267
265
|
else:
|
|
268
|
-
# AUTO/default —
|
|
266
|
+
# AUTO/default — platform-driven ordering.
|
|
269
267
|
if plat == "darwin":
|
|
270
268
|
ordered.append(ONNX_COREML_EP)
|
|
271
269
|
if plat.startswith(("linux", "win")) and machine in ("x86_64", "AMD64"):
|
|
@@ -281,8 +279,8 @@ def _resolve_onnx_providers(
|
|
|
281
279
|
# ---------------------------------------------------------------------------
|
|
282
280
|
# CoreML persistent compiled-model cache
|
|
283
281
|
# ---------------------------------------------------------------------------
|
|
284
|
-
# macOS
|
|
285
|
-
#
|
|
282
|
+
# Known macOS behavior: the OS-level compiled-model cache is NOT reused across
|
|
283
|
+
# process restarts — every
|
|
286
284
|
# `ct.models.MLModel(.mlpackage)` load RECOMPILES the model, and the stale OS
|
|
287
285
|
# cache is only cleared on reboot. camstack loads the .mlpackage on every pool
|
|
288
286
|
# spawn, so each spawn paid the full recompile. Fix: after the first compile,
|
|
@@ -472,9 +470,9 @@ def _load_model(slot: ModelSlot, config: dict) -> None:
|
|
|
472
470
|
"ane": ct.ComputeUnit.CPU_AND_NE,
|
|
473
471
|
"all": ct.ComputeUnit.ALL,
|
|
474
472
|
}
|
|
475
|
-
# NOTE
|
|
476
|
-
#
|
|
477
|
-
#
|
|
473
|
+
# NOTE: a macOS behavior can cause the .mlpackage to be RECOMPILED on
|
|
474
|
+
# every load with the compiled cache not reused until reboot. camstack
|
|
475
|
+
# loads the .mlpackage on
|
|
478
476
|
# every pool spawn, so it was exposed to the same trap.
|
|
479
477
|
# _acquire_coreml_model routes through a persistent `.coreml-cache`
|
|
480
478
|
# of the compiled `.mlmodelc` (CompiledMLModel on hit, plain MLModel
|
|
@@ -526,11 +524,10 @@ def _load_model(slot: ModelSlot, config: dict) -> None:
|
|
|
526
524
|
elif _runtime == "openvino":
|
|
527
525
|
core = _runtime_lib
|
|
528
526
|
ov_device = str(config.get("device", "AUTO")).upper()
|
|
529
|
-
#
|
|
530
|
-
#
|
|
531
|
-
#
|
|
532
|
-
#
|
|
533
|
-
# gpu/cpu/npu) is honored unchanged — compiled directly.
|
|
527
|
+
# Device switch (see _resolve_ov_mode above): an AUTO/default request
|
|
528
|
+
# classifies the enumerated devices by their FULL_DEVICE_NAME and
|
|
529
|
+
# builds an explicit mode string. An operator-pinned device (config
|
|
530
|
+
# "device" = gpu/cpu/npu) is honored unchanged — compiled directly.
|
|
534
531
|
if ov_device in ("AUTO", "DEFAULT", ""):
|
|
535
532
|
available = list(core.available_devices)
|
|
536
533
|
full_names: dict[str, str] = {}
|
|
@@ -565,11 +562,10 @@ def _load_model(slot: ModelSlot, config: dict) -> None:
|
|
|
565
562
|
ov_config["CACHE_DIR"] = _cache_dir
|
|
566
563
|
except OSError:
|
|
567
564
|
pass
|
|
568
|
-
# Compile the resolved mode. Failure fallback
|
|
569
|
-
#
|
|
570
|
-
#
|
|
571
|
-
#
|
|
572
|
-
# load/replace error handler reports the failure.
|
|
565
|
+
# Compile the resolved mode. Failure fallback: any mode containing
|
|
566
|
+
# "GPU" reverts to plain "AUTO" and recompiles once; if THAT also
|
|
567
|
+
# fails (or the mode had no GPU), re-raise — the existing load/replace
|
|
568
|
+
# error handler reports the failure.
|
|
573
569
|
candidates = [ov_device]
|
|
574
570
|
if "GPU" in ov_device:
|
|
575
571
|
candidates.append("AUTO")
|
|
@@ -591,7 +587,7 @@ def _load_model(slot: ModelSlot, config: dict) -> None:
|
|
|
591
587
|
raise last_exc
|
|
592
588
|
raise RuntimeError("OpenVINO: no device available to compile the model")
|
|
593
589
|
# Name the resolved mode + what OpenVINO actually placed the model on
|
|
594
|
-
# (
|
|
590
|
+
# (the EXECUTION_DEVICES property) so a silent CPU
|
|
595
591
|
# placement is visible in the pool stderr.
|
|
596
592
|
try:
|
|
597
593
|
_exec_devices = compiled.get_property("EXECUTION_DEVICES")
|
|
@@ -646,7 +642,7 @@ def _load_model(slot: ModelSlot, config: dict) -> None:
|
|
|
646
642
|
elif _runtime == "onnxruntime":
|
|
647
643
|
ort = _runtime_lib
|
|
648
644
|
ort_device = str(config.get("device", "") or "")
|
|
649
|
-
#
|
|
645
|
+
# Ordered providers — hardware EP first, CPU LAST as
|
|
650
646
|
# fallback (see _resolve_onnx_providers): a "cuda"/"coreml" pin puts
|
|
651
647
|
# that EP first, a "cpu" pin compiles CPU only, and the AUTO/default
|
|
652
648
|
# case derives the hardware EP from the platform.
|
|
@@ -658,8 +654,8 @@ def _load_model(slot: ModelSlot, config: dict) -> None:
|
|
|
658
654
|
ort_device, sys.platform, platform.machine(), available_eps,
|
|
659
655
|
)
|
|
660
656
|
session = ort.InferenceSession(path, providers=providers)
|
|
661
|
-
# Report the EP that ACTUALLY initialized
|
|
662
|
-
#
|
|
657
|
+
# Report the EP that ACTUALLY initialized (CPU stripped from the log)
|
|
658
|
+
# so a silent CPU fallback is visible.
|
|
663
659
|
_active_eps = [p for p in session.get_providers() if p != ONNX_CPU_EP]
|
|
664
660
|
_requested = [p[0] if isinstance(p, tuple) else p for p in providers]
|
|
665
661
|
sys.stderr.write(
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
"""Unit tests for the runtime device/provider selection in inference_pool.
|
|
2
2
|
|
|
3
3
|
Covers:
|
|
4
|
-
- _resolve_ov_mode —
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
(scrypted-onnx-init.py:95-109) with camstack's pin + availability filter.
|
|
4
|
+
- _resolve_ov_mode — the OpenVINO device-mode branch matrix.
|
|
5
|
+
- _resolve_onnx_providers — the ONNX execution-provider ordering
|
|
6
|
+
with camstack's pin + availability filter.
|
|
8
7
|
|
|
9
8
|
Pure-python: stubs numpy / PIL / postprocessors in sys.modules so the module
|
|
10
9
|
imports without the ML runtime installed (inference_pool uses
|
|
@@ -47,10 +46,10 @@ from inference_pool import (
|
|
|
47
46
|
|
|
48
47
|
|
|
49
48
|
class ResolveOvModeTest(unittest.TestCase):
|
|
50
|
-
"""Branch matrix of
|
|
49
|
+
"""Branch matrix of the OpenVINO device switch."""
|
|
51
50
|
|
|
52
51
|
def test_n100_intel_igpu_and_cpu_is_explicit_gpu(self) -> None:
|
|
53
|
-
# Intel iGPU + CPU, no NPU, no dGPU —
|
|
52
|
+
# Intel iGPU + CPU, no NPU, no dGPU — compiles explicit GPU.
|
|
54
53
|
self.assertEqual(
|
|
55
54
|
_resolve_ov_mode(
|
|
56
55
|
["CPU", "GPU"],
|
|
@@ -127,7 +126,7 @@ class ResolveOvModeTest(unittest.TestCase):
|
|
|
127
126
|
)
|
|
128
127
|
|
|
129
128
|
def test_npu_wins_over_nvidia_dgpu(self) -> None:
|
|
130
|
-
#
|
|
129
|
+
# npu is checked FIRST — dGPUs only matter when no NPU exists.
|
|
131
130
|
self.assertEqual(
|
|
132
131
|
_resolve_ov_mode(
|
|
133
132
|
["CPU", "GPU.0", "NPU"],
|
|
@@ -150,7 +149,7 @@ class ResolveOvModeTest(unittest.TestCase):
|
|
|
150
149
|
self.assertEqual(_resolve_ov_mode([], {}), "AUTO")
|
|
151
150
|
|
|
152
151
|
def test_device_without_full_name_is_not_classified(self) -> None:
|
|
153
|
-
#
|
|
152
|
+
# A device whose
|
|
154
153
|
# FULL_DEVICE_NAME query failed is skipped entirely.
|
|
155
154
|
self.assertEqual(
|
|
156
155
|
_resolve_ov_mode(["CPU", "GPU"], {"CPU": "Intel(R) N100"}),
|
|
@@ -159,7 +158,7 @@ class ResolveOvModeTest(unittest.TestCase):
|
|
|
159
158
|
|
|
160
159
|
|
|
161
160
|
class ResolveOnnxProvidersTest(unittest.TestCase):
|
|
162
|
-
"""
|
|
161
|
+
"""ONNX EP ordering + camstack's pin/availability filter."""
|
|
163
162
|
|
|
164
163
|
def test_darwin_auto_prefers_coreml_cpu_last(self) -> None:
|
|
165
164
|
self.assertEqual(
|
|
@@ -203,7 +202,7 @@ class ResolveOnnxProvidersTest(unittest.TestCase):
|
|
|
203
202
|
|
|
204
203
|
def test_darwin_never_matches_win_substring(self) -> None:
|
|
205
204
|
# "win" in "darwin" is True — the helper must NOT add CUDA on an
|
|
206
|
-
# Intel Mac (
|
|
205
|
+
# Intel Mac (a substring "win" in platform check would misfire).
|
|
207
206
|
self.assertEqual(
|
|
208
207
|
_resolve_onnx_providers(
|
|
209
208
|
"", "darwin", "x86_64",
|
package/python/yamnet_audio.py
CHANGED
|
@@ -54,7 +54,7 @@ def main() -> None:
|
|
|
54
54
|
# YAMNet is a tiny model — ONNX Runtime otherwise defaults intra_op threads to the CPU core
|
|
55
55
|
# count, so every short inference spins up N threads whose coordination overhead dwarfs the
|
|
56
56
|
# actual compute (observed: ~1000% CPU across a handful of always-on audio streams). Cap to a
|
|
57
|
-
# single op thread
|
|
57
|
+
# single op thread; overridable via --threads for large hosts.
|
|
58
58
|
ap.add_argument("--threads", type=int, default=1)
|
|
59
59
|
args = ap.parse_args()
|
|
60
60
|
|