Files
Robot_Arm/webapp/r4_probe.html
T
cbb b6141d237c fix: R4 探针页 tensor 复用(proxy 下 buffer 被 detach)+ pipeline.sh 7 处 GBK 读取 + r4 分支返回码;r4 端到端 rc=0
- webapp/r4_probe.html:feat 移进 run() 每次新建。proxy=1 时 ORT 把输入 transfer 给 Worker,旧写法第二次 run 报 Tensor size(83) vs data length(0),两种 proxy 配置全挂、r4.json pass=null。
- ml/pipeline.sh:7 处 json.load(open(...)) 补 encoding='utf-8'(:90 :110 :118 :127 :136 :138 :144)。r4.json 以 ensure_ascii=False 写出,Windows GBK 下 :110 实测 UnicodeDecodeError,命令替换为空会让上层分支走错。
- ml/pipeline.sh r4:末行 `[ "$r" = null ] && echo` 在 r=pass 时整体返回 1,set -e + EXIT trap 把通过的 r4 记成 rc=1(all 会因此停)→ 改 if/fi。
- 实测复跑两次:pass=true,部署口径(16 线程+proxy+enc_once)P99 10.22 / 11.25 ms,4 线程 13.58/13.64,无 proxy 9.28/10.92,webgpu 仍 backend not found。
- 文档同步:A 组两处标记已修,仅留 A-3(ortLocal+proxy 离线路径)交实现方。
2026-10-18 06:40:25 +08:00

44 lines
3.5 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!doctype html>
<meta charset="utf-8">
<title>R4 推理延迟探针</title>
<!-- 2026-10-18 第五轮:由 ml/eval/r4_probe.py 在无头浏览器里打开,测部署形态的单次推理(1 行特征 + K=8 条候选)。
参数:model= 模型 URL;ep=wasm|webgpu;threads=auto|N;proxy=0|1;n= 次数;ortLocal=1 用 vendor/ort/。
结果 POST 到 /r4/result;同时记录 20 ms 节拍的最大间隔(推理是否卡主线程)。也可手动打开看页面上的结果。 -->
<pre id="o">运行中…</pre>
<script>
(async () => {
const qs = new URLSearchParams(location.search), o = document.getElementById('o');
const res = { ep: qs.get('ep') || 'wasm', threadsArg: qs.get('threads') || 'auto', hc: navigator.hardwareConcurrency, coi: self.crossOriginIsolated, ua: navigator.userAgent };
const post = async () => { o.textContent = JSON.stringify(res, null, 1); try { await fetch('/r4/result', { method: 'POST', body: JSON.stringify(res) }); } catch (e) {} };
try {
const MODEL = qs.get('model'), N = +qs.get('n') || 150, K = 8, F = 83, H = 16;
const BASE = qs.get('ortLocal') === '1' ? '/webapp/vendor/ort/' : 'https://cdn.jsdelivr.net/npm/onnxruntime-web@1.20.1/dist/';
await new Promise((ok, no) => { const s = document.createElement('script'); s.src = BASE + 'ort.min.js'; s.onload = ok; s.onerror = () => no(new Error('加载 ort 失败:' + s.src)); document.head.appendChild(s); });
const meta = await (await fetch(MODEL.replace('.onnx', '.meta.json'))).json();
ort.env.wasm.wasmPaths = BASE;
// 与 ik-policy-glue.js 同一套默认值
ort.env.wasm.numThreads = !self.crossOriginIsolated ? 1 : (res.threadsArg === 'auto' ? Math.max(1, Math.min(16, Math.floor(res.hc * 0.6))) : +res.threadsArg);
res.threads = ort.env.wasm.numThreads;
res.proxy = res.ep === 'wasm' && qs.get('proxy') !== '0';
const opts = { executionProviders: res.ep === 'webgpu' ? ['webgpu'] : ['wasm'], graphOptimizationLevel: 'all' };
let sess = null;
if (res.proxy) { ort.env.wasm.proxy = true; try { sess = await ort.InferenceSession.create(MODEL, opts); } catch (e) { res.proxyError = String(e); res.proxy = false; ort.env.wasm.proxy = false; } }
if (!sess) sess = await ort.InferenceSession.create(MODEL, opts);
res.encOnce = !!meta.enc_once;
const z = () => new Float32Array(K * H * 6).map(() => Math.random() * 2 - 1);
/* proxy 模式下 ORT 会把输入 buffer 转移给 Worker(detach),feat 必须每次新建 */
const run = () => { const feat = new Float32Array((res.encOnce ? 1 : K) * F).map(() => Math.random() - 0.5);
return sess.run({ feat: new ort.Tensor('float32', feat, [res.encOnce ? 1 : K, F]), z: new ort.Tensor('float32', z(), [K, H, 6]) }); };
for (let i = 0; i < 10; i++) await run();
let last = performance.now(); const gaps = [];
const tk = setInterval(() => { const t = performance.now(); gaps.push(t - last); last = t; }, 20);
const ts = [];
for (let i = 0; i < N; i++) { const t = performance.now(); await run(); ts.push(performance.now() - t); await new Promise(r => setTimeout(r, 40)); }
clearInterval(tk);
const p = (a, x) => { const s = a.slice().sort((u, v) => u - v); return +s[Math.min(s.length - 1, Math.floor(s.length * x))].toFixed(2); };
Object.assign(res, { n: N, K, p50: p(ts, .5), p95: p(ts, .95), p99: p(ts, .99), tickGapP99: p(gaps, .99), tickGapMax: +Math.max(...gaps).toFixed(1) });
} catch (e) { res.error = String(e && e.message || e); }
await post();
})();
</script>