Spaces:
Running
Running
Update via HuggingBot
Browse files
bench.mjs
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env node
|
| 2 |
+
// OpenJev CPU smoke-bench: warmup, 1-question latency x N, 10-question batch, ops.
|
| 3 |
+
// Usage: node bench.mjs http://localhost:7860 [--batch 1 --n 5 --token x]
|
| 4 |
+
|
| 5 |
+
const BASE = process.argv[1] ?? "http://localhost:7860";
|
| 6 |
+
const args = process.argv.slice(2);
|
| 7 |
+
const opt = (k, d) => { const i = args.indexOf(k); return i >= 0 ? Number(args[i + 1] ?? d) : d; };
|
| 8 |
+
const N = opt("--n", 5);
|
| 9 |
+
const B = opt("--batch", 10);
|
| 10 |
+
|
| 11 |
+
const token = (() => { const i = args.indexOf("--token"); return i >= 0 ? args[i + 1] : ""; })();
|
| 12 |
+
const headers = { "Content-Type": "application/json", ...(token ? { Authorization: `Bearer ${token}` } : {}) };
|
| 13 |
+
const baseQ = (suffix) => ({
|
| 14 |
+
state: `Customer message: I was charged twice for my order last week${suffix}`,
|
| 15 |
+
questions: {
|
| 16 |
+
route: { type: "choice", instructions: "Which team should handle this?",
|
| 17 |
+
criteria: { billing: null, shipping: null, technical: null } },
|
| 18 |
+
angry: { type: "noul", instructions: "Is the customer angry?" },
|
| 19 |
+
urgency: { type: "score", instructions: "How urgent is this?",
|
| 20 |
+
criteria: ["can wait", "this week", "today", "right now"] },
|
| 21 |
+
},
|
| 22 |
+
});
|
| 23 |
+
|
| 24 |
+
async function post(path, body) {
|
| 25 |
+
const t0 = Date.now();
|
| 26 |
+
const r = await fetch(BASE + path, { method: "POST", headers, body: JSON.stringify(body) });
|
| 27 |
+
const ms = Date.now() - t0;
|
| 28 |
+
const json = await r.json();
|
| 29 |
+
if (!r.ok) { console.error(`HTTP ${r.status} ${path}:`, JSON.stringify(json).slice(0, 300)); process.exit(1); }
|
| 30 |
+
return { ms, json };
|
| 31 |
+
}
|
| 32 |
+
const mean = (a) => a.reduce((x, y) => x + y, 0) / a.length;
|
| 33 |
+
const sleep = (s) => new Promise((r) => setTimeout(r, s * 1000));
|
| 34 |
+
|
| 35 |
+
const { ms } = await post("/v1/healthz", {});
|
| 36 |
+
console.log(`healthz ${ms} ms`);
|
| 37 |
+
const v = await fetch(BASE + "/v1/version").then((r) => r.json());
|
| 38 |
+
console.log(`version: backend=${v?.backend} model=${v?.model_dir} profile=${v?.profile} T=${v?.T}`);
|
| 39 |
+
|
| 40 |
+
// warmup (first call pays cold model load if the Space just woke)
|
| 41 |
+
const w = await post("/v1/systemone", baseQ(" and nobody replied."));
|
| 42 |
+
console.log(`warmup: ${w.ms} ms -> ${w.json?.answers?.route?.choice}`);
|
| 43 |
+
|
| 44 |
+
// single-question latency
|
| 45 |
+
const lat = [];
|
| 46 |
+
for (let i = 0; i < N; i++) {
|
| 47 |
+
const r = await post("/v1/systemone", baseQ(` and nobody replied (${i}).`));
|
| 48 |
+
lat.push(r.ms); const a = r.json.answers;
|
| 49 |
+
console.log(`q${i}: ${r.ms} ms route=${a.route.choice} angry=${a.angry.noul.toFixed(2)} score=${a.urgency.score.toFixed(2)} tok=${r.json.usage.input_tokens}`);
|
| 50 |
+
await sleep(0.2);
|
| 51 |
+
}
|
| 52 |
+
|
| 53 |
+
// batched (one pass, many questions)
|
| 54 |
+
const multi = { state: baseQ(".").state, questions: {} };
|
| 55 |
+
for (let i = 0; i < B; i++) multi.questions[`q${i}`] = { type: "choice", instructions: `Pick a team for case ${i}.`, criteria: { billing: null, shipping: null, technical: null } };
|
| 56 |
+
const b = await post("/v1/systemone", multi);
|
| 57 |
+
console.log(`\nbatch ${B} questions: ${b.ms} ms (${(b.ms - w.ms).toFixed(0)} ms extra vs warmup single)`);
|
| 58 |
+
|
| 59 |
+
console.log(`\nsummary: single-question mean ${Math.round(mean(lat))} ms over ${N} | batch(${B}) ${b.ms} ms`);
|