companion-runtime-manager-performance.test.mjs file-level

at sha256:3 · View file ↗ · Intel ↗

History
1 files
1 commits
0 hotspots
0 🧊 dead
0 πŸ’₯ blast risk
sha256:9 feat(calendar): hosted bridge/gateway route parity and timeline noteRec… · aaronrene · Jun 19, 2026
1 /**
2 * Tier 6 β€” PERFORMANCE: lib/companion-runtime-manager.mjs
3 *
4 * Latency bounds for all decision functions. The runtime manager sits on the hot path
5 * for every inference request. Decisions must complete in sub-millisecond time to avoid
6 * adding measurable overhead to inference throughput.
7 *
8 * Bounds (conservative; well within what node:crypto + pure-JS can deliver):
9 * - Per-decision calls (evaluateRuntimeRequest, evaluateAdmission, etc.): mean < 0.1ms
10 * - 10k evaluateRuntimeRequest calls: total < 500ms
11 * - 10k lifecycle transitions: total < 200ms
12 * - Integrity accumulator: 100KB with 1-byte chunks: total < 500ms
13 *
14 * Reference: docs/COMPANION-APP-PHASE-4-RUNTIME-MANAGER.md Β§4 (backpressure).
15 */
16
17 import { describe, it } from 'node:test';
18 import assert from 'node:assert/strict';
19 import crypto from 'node:crypto';
20
21 import {
22 LIFECYCLE_STATES,
23 LIFECYCLE_EVENTS,
24 createLifecycleState,
25 transitionLifecycle,
26 canServeInference,
27 createAdmissionState,
28 evaluateAdmission,
29 recordInFlight,
30 recordCompletion,
31 createResourceLimits,
32 evaluateResourceLimits,
33 evaluateRuntimeRequest,
34 createIntegrityAccumulator,
35 verifyModelBytes,
36 validateSourceUrl,
37 } from '../lib/companion-runtime-manager.mjs';
38
39 function makeDigest(data) {
40 return crypto.createHash('sha256').update(data).digest('hex');
41 }
42
43 const ALLOWED_URLS = ['https://models.example.com/'];
44 const VALID_URL = 'https://models.example.com/model.gguf';
45 const READY = { state: LIFECYCLE_STATES.READY };
46 const VALID_LIMITS = createResourceLimits({ maxRamBytes: 8e9, maxVramBytes: 4e9, maxCpuPercent: 80 });
47 const VALID_OBS = { ramBytes: 1e9, vramBytes: 0.5e9, cpuPercent: 10 };
48 const VALID_ADMISSION = createAdmissionState({ maxInFlight: 100, queueBound: 200 });
49
50 // ── evaluateRuntimeRequest ────────────────────────────────────────────────────
51
52 describe('performance: evaluateRuntimeRequest', () => {
53 it('10k calls complete in < 500ms', () => {
54 const N = 10_000;
55 const start = performance.now();
56 for (let i = 0; i < N; i++) {
57 evaluateRuntimeRequest({
58 lifecycleState: READY,
59 admissionState: VALID_ADMISSION,
60 resourceObservation: VALID_OBS,
61 resourceLimits: VALID_LIMITS,
62 });
63 }
64 const elapsed = performance.now() - start;
65 assert.ok(elapsed < 500, `10k evaluateRuntimeRequest took ${elapsed.toFixed(1)}ms, expected < 500ms`);
66 });
67
68 it('mean per-call < 0.05ms (50ΞΌs)', () => {
69 const N = 10_000;
70 const start = performance.now();
71 for (let i = 0; i < N; i++) {
72 evaluateRuntimeRequest({
73 lifecycleState: READY,
74 admissionState: VALID_ADMISSION,
75 resourceObservation: VALID_OBS,
76 resourceLimits: VALID_LIMITS,
77 });
78 }
79 const mean = (performance.now() - start) / N;
80 assert.ok(mean < 0.05, `mean per-call ${mean.toFixed(4)}ms, expected < 0.05ms`);
81 });
82 });
83
84 // ── evaluateAdmission ─────────────────────────────────────────────────────────
85
86 describe('performance: evaluateAdmission', () => {
87 it('50k calls complete in < 500ms', () => {
88 const N = 50_000;
89 const s = { ...VALID_ADMISSION, inFlight: 1 };
90 const start = performance.now();
91 for (let i = 0; i < N; i++) evaluateAdmission(s);
92 const elapsed = performance.now() - start;
93 assert.ok(elapsed < 500, `50k evaluateAdmission took ${elapsed.toFixed(1)}ms, expected < 500ms`);
94 });
95 });
96
97 // ── evaluateResourceLimits ────────────────────────────────────────────────────
98
99 describe('performance: evaluateResourceLimits', () => {
100 it('50k calls complete in < 300ms', () => {
101 const N = 50_000;
102 const start = performance.now();
103 for (let i = 0; i < N; i++) evaluateResourceLimits(VALID_OBS, VALID_LIMITS);
104 const elapsed = performance.now() - start;
105 assert.ok(elapsed < 300, `50k evaluateResourceLimits took ${elapsed.toFixed(1)}ms, expected < 300ms`);
106 });
107 });
108
109 // ── Lifecycle transitions ────────────────────────────────────────────────────
110
111 describe('performance: lifecycle transitions', () => {
112 it('10k full round-trips (stopped→starting→ready→drain→stopped) < 200ms', () => {
113 const N = 10_000;
114 let lifecycle = createLifecycleState();
115 const start = performance.now();
116 for (let i = 0; i < N; i++) {
117 lifecycle = transitionLifecycle(lifecycle, LIFECYCLE_EVENTS.START).newState;
118 lifecycle = transitionLifecycle(lifecycle, LIFECYCLE_EVENTS.HEALTH_OK).newState;
119 lifecycle = transitionLifecycle(lifecycle, LIFECYCLE_EVENTS.DRAIN).newState;
120 lifecycle = transitionLifecycle(lifecycle, LIFECYCLE_EVENTS.STOPPED).newState;
121 }
122 const elapsed = performance.now() - start;
123 assert.ok(elapsed < 200, `10k lifecycle round-trips took ${elapsed.toFixed(1)}ms, expected < 200ms`);
124 });
125
126 it('canServeInference: 100k calls < 100ms', () => {
127 const N = 100_000;
128 const start = performance.now();
129 for (let i = 0; i < N; i++) canServeInference(READY);
130 const elapsed = performance.now() - start;
131 assert.ok(elapsed < 100, `100k canServeInference took ${elapsed.toFixed(1)}ms, expected < 100ms`);
132 });
133 });
134
135 // ── Integrity accumulator ────────────────────────────────────────────────────
136
137 describe('performance: integrity accumulator', () => {
138 it('100KB model data in 1-byte chunks completes in < 500ms', () => {
139 const data = crypto.randomBytes(100_000);
140 const digest = makeDigest(data);
141
142 const acc = createIntegrityAccumulator({
143 expectedDigest: digest, expectedSizeBytes: data.length,
144 sourceUrl: VALID_URL, allowedSourceUrls: ALLOWED_URLS,
145 });
146
147 const start = performance.now();
148 for (let i = 0; i < data.length; i++) {
149 acc.update(data.subarray(i, i + 1));
150 }
151 acc.finalize();
152 const elapsed = performance.now() - start;
153 assert.ok(elapsed < 500, `100KB 1-byte-chunk accumulation took ${elapsed.toFixed(1)}ms, expected < 500ms`);
154 });
155
156 it('1MB model data in 4KB chunks completes in < 200ms', () => {
157 const CHUNK = 4096;
158 const data = crypto.randomBytes(1024 * 1024);
159 const digest = makeDigest(data);
160
161 const acc = createIntegrityAccumulator({
162 expectedDigest: digest, expectedSizeBytes: data.length,
163 sourceUrl: VALID_URL, allowedSourceUrls: ALLOWED_URLS,
164 });
165
166 const start = performance.now();
167 for (let i = 0; i < data.length; i += CHUNK) {
168 acc.update(data.subarray(i, i + CHUNK));
169 }
170 acc.finalize();
171 const elapsed = performance.now() - start;
172 assert.ok(elapsed < 200, `1MB 4KB-chunk accumulation took ${elapsed.toFixed(1)}ms, expected < 200ms`);
173 });
174 });
175
176 // ── verifyModelBytes ─────────────────────────────────────────────────────────
177
178 describe('performance: verifyModelBytes', () => {
179 it('1000 calls on a 1KB buffer complete in < 300ms', () => {
180 const data = crypto.randomBytes(1024);
181 const digest = makeDigest(data);
182 const N = 1000;
183
184 const start = performance.now();
185 for (let i = 0; i < N; i++) {
186 verifyModelBytes({
187 fileData: data, expectedDigest: digest, expectedSizeBytes: data.length,
188 sourceUrl: VALID_URL, allowedSourceUrls: ALLOWED_URLS,
189 });
190 }
191 const elapsed = performance.now() - start;
192 assert.ok(elapsed < 300, `1000 verifyModelBytes took ${elapsed.toFixed(1)}ms, expected < 300ms`);
193 });
194 });
195
196 // ── validateSourceUrl (hot path for spec validation) ────────────────────────
197
198 describe('performance: validateSourceUrl', () => {
199 it('100k calls complete in < 500ms', () => {
200 const N = 100_000;
201 const start = performance.now();
202 for (let i = 0; i < N; i++) validateSourceUrl(VALID_URL, ALLOWED_URLS);
203 const elapsed = performance.now() - start;
204 assert.ok(elapsed < 500, `100k validateSourceUrl took ${elapsed.toFixed(1)}ms, expected < 500ms`);
205 });
206 });
207
208 // ── Admission record cycling ──────────────────────────────────────────────────
209
210 describe('performance: recordInFlight/recordCompletion cycling', () => {
211 it('10k recordInFlight + recordCompletion pairs < 100ms', () => {
212 const N = 10_000;
213 let s = createAdmissionState({ maxInFlight: N + 1, queueBound: N + 1 });
214 const start = performance.now();
215 for (let i = 0; i < N; i++) {
216 s = recordInFlight(s);
217 s = recordCompletion(s);
218 }
219 const elapsed = performance.now() - start;
220 assert.ok(elapsed < 100, `10k in-flight cycles took ${elapsed.toFixed(1)}ms, expected < 100ms`);
221 assert.equal(s.inFlight, 0); // net zero
222 });
223 });