@fraczak/k 8.0.0 → 8.1.0

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.
@@ -1,340 +0,0 @@
1
- import assert from "node:assert/strict";
2
- import fs from "node:fs";
3
- import os from "node:os";
4
- import path from "node:path";
5
- import { performance } from "node:perf_hooks";
6
- import { createState, evaluateInput } from "../repl.mjs";
7
- import * as djsonCodec from "../codecs/djson.mjs";
8
- import btrieCodec, { indexToBitPath } from "../codecs/djson-btrie.mjs";
9
- import ptrieCodec from "../codecs/djson-ptrie.mjs";
10
- import {
11
- compileWasmArtifactFromObject,
12
- instantiateWasmArtifact,
13
- writeValueToArena
14
- } from "../backends/wasm/src/wasm.mjs";
15
- import {
16
- compileCaseExecutable,
17
- prepareRelation,
18
- runExecutableMainBench,
19
- wireInput
20
- } from "../backends/llvm/tests/perf-support.mjs";
21
-
22
- const llvmCacheDir = fs.mkdtempSync(
23
- path.join(os.tmpdir(), "k-djson-bench-")
24
- );
25
-
26
- console.log("=== 1. Codec Round-Trip Verification ===");
27
- const sampleJson = {
28
- name: "Alice",
29
- age: 30,
30
- active: true,
31
- nothing: null,
32
- scores: [10, 20, 30, 40, 50],
33
- nested: { a: 1, ab: 2, abc: 3, abd: 4, z: 99 }
34
- };
35
- const sampleStr = JSON.stringify(sampleJson);
36
-
37
- for (const [label, c, pat] of [
38
- ["djson (cons-list)", djsonCodec, djsonCodec.DJSON_PATTERN],
39
- ["djson-btrie (bit-trie)", btrieCodec, btrieCodec.pattern],
40
- ["djson-ptrie (radix-trie)", ptrieCodec, ptrieCodec.pattern]
41
- ]) {
42
- const kVal = c.parse(sampleStr);
43
- const roundTrip = JSON.parse(c.print(kVal));
44
- assert.deepStrictEqual(
45
- roundTrip,
46
- sampleJson,
47
- `${label} round-trip failed`
48
- );
49
- console.log(
50
- ` [OK] ${label.padEnd(26)} pattern nodes: ${pat.length}`
51
- );
52
- }
53
-
54
- function indexToKLiteral(idx) {
55
- const bits = indexToBitPath(idx);
56
- const tags = bits.slice().reverse().map((b) => `|${b}`).join("");
57
- return `({}|_${tags})`;
58
- }
59
-
60
- async function setupBenchmarkState(kFile, benchSnippet) {
61
- const st = createState({ engine: "wasm" });
62
- await evaluateInput(`:load ${kFile}`, st);
63
- await evaluateInput(benchSnippet, st);
64
- return st;
65
- }
66
-
67
- async function benchRelationOnInput({
68
- state,
69
- relName,
70
- kInput,
71
- codec,
72
- expectedJson,
73
- calls = 1000
74
- }) {
75
- const wire = wireInput(kInput, codec.pattern);
76
- const wireBytes = wire.inputWire.length;
77
- const prepared = prepareRelation(state, relName);
78
-
79
- // 1. Wasm Compilation & Execution
80
- const tWasmComp0 = performance.now();
81
- const wasmBytes = await compileWasmArtifactFromObject(prepared.object, {
82
- relation: prepared.relationName,
83
- inputEnvelopePattern: wire.inputPattern,
84
- usePKIR: false
85
- });
86
- const runner = await instantiateWasmArtifact(wasmBytes);
87
- const wasmCompileMs = performance.now() - tWasmComp0;
88
-
89
- // Verify output once
90
- const outVal = runner.executeValue(kInput);
91
- assert(outVal !== undefined, `${relName} Wasm returned undefined`);
92
- assert.deepStrictEqual(
93
- JSON.parse(codec.print(outVal)),
94
- expectedJson,
95
- `Wasm output mismatch for ${relName}`
96
- );
97
-
98
- // Write input once to arena, then loop N calls resetting arena mark
99
- const ptrIn = writeValueToArena(
100
- runner.exports,
101
- kInput,
102
- runner.inputPattern,
103
- 0,
104
- new Map(),
105
- runner.tags,
106
- runner.metadata.inputPattern
107
- );
108
- const mark = runner.exports.arena_mark();
109
- const entryFn = runner.exports[runner.metadata.entry];
110
-
111
- // Warmup
112
- for (let i = 0; i < 20; i++) {
113
- runner.exports.arena_reset(mark);
114
- entryFn(ptrIn);
115
- }
116
-
117
- const tWasmExec0 = performance.now();
118
- for (let i = 0; i < calls; i++) {
119
- runner.exports.arena_reset(mark);
120
- entryFn(ptrIn);
121
- }
122
- const wasmExecNsPerCall =
123
- ((performance.now() - tWasmExec0) * 1e6) / calls;
124
-
125
- // 2. LLVM Compilation & Execution (-O3)
126
- const tLlvmComp0 = performance.now();
127
- const exePath = compileCaseExecutable({
128
- object: prepared.object,
129
- relationName: prepared.relationName,
130
- relHash: prepared.relHash,
131
- inputPattern: wire.inputPattern,
132
- cacheDir: llvmCacheDir,
133
- sourceLabel: relName,
134
- runtimeMode: "fast",
135
- clangOpt: "-O3",
136
- usePKIR: false
137
- });
138
- const llvmCompileMs = performance.now() - tLlvmComp0;
139
- const llvmRes = await runExecutableMainBench(
140
- exePath,
141
- wire.inputWire,
142
- calls
143
- );
144
-
145
- return {
146
- wireBytes,
147
- wasmBytes: wasmBytes.length,
148
- wasmCompileMs,
149
- wasmExecNsPerCall,
150
- llvmCompileMs,
151
- llvmExecNsPerCall: llvmRes.perCallNs
152
- };
153
- }
154
-
155
- const SCHEMAS = [
156
- {
157
- name: "djson (cons)",
158
- kFile: "Examples/djson.k",
159
- codec: { ...djsonCodec, pattern: djsonCodec.DJSON_PATTERN },
160
- dotExpr:
161
- "bench_dot = json? { " +
162
- "/list /cons .car /string key, " +
163
- "/list /cons .cdr /cons .car /object object } dot json?;"
164
- },
165
- {
166
- name: "djson-btrie",
167
- kFile: "Examples/djson-btrie.k",
168
- codec: btrieCodec,
169
- dotExpr:
170
- "bench_dot = json? { " +
171
- "{ 0 index, /list list } nth /string key, " +
172
- "{ 1 index, /list list } nth /object object } dot json?;"
173
- },
174
- {
175
- name: "djson-ptrie",
176
- kFile: "Examples/djson-ptrie.k",
177
- codec: ptrieCodec,
178
- dotExpr:
179
- "bench_dot = json? { " +
180
- "{ 0 index, /list list } nth /string key, " +
181
- "{ 1 index, /list list } nth /object object } dot json?;"
182
- }
183
- ];
184
-
185
- console.log(
186
- "\n=== 2A. Object Lookup (`dot`) — " +
187
- "Shared-Prefix Keys (Wasm vs LLVM -O3) ==="
188
- );
189
- for (const numKeys of [10, 100, 500]) {
190
- const obj = {};
191
- for (let i = 0; i < numKeys; i++) {
192
- const k = `field_prefix_${String(i).padStart(4, "0")}`;
193
- obj[k] = i * 10;
194
- }
195
- const targetKey =
196
- `field_prefix_${String(numKeys - 1).padStart(4, "0")}`;
197
- const expectedVal = (numKeys - 1) * 10;
198
- const inputJsonStr = JSON.stringify([targetKey, obj]);
199
-
200
- console.log(
201
- `\n--- Object with ${numKeys} shared-prefix keys ` +
202
- `(querying '${targetKey}') ---`
203
- );
204
- console.log(
205
- "Schema | Wire (B) | Wasm (B) | " +
206
- "Wasm Comp | LLVM Comp | Wasm (ns/call) | LLVM (ns/call)"
207
- );
208
- console.log(
209
- "----------------+----------+----------+-" +
210
- "----------+-----------+----------------+---------------"
211
- );
212
-
213
- for (const s of SCHEMAS) {
214
- const st = await setupBenchmarkState(s.kFile, s.dotExpr);
215
- const kInput = s.codec.parse(inputJsonStr);
216
- const res = await benchRelationOnInput({
217
- state: st,
218
- relName: "bench_dot",
219
- kInput,
220
- codec: s.codec,
221
- expectedJson: expectedVal,
222
- calls: 1000
223
- });
224
- console.log(
225
- `${s.name.padEnd(15)} | ${String(res.wireBytes).padStart(8)} | ` +
226
- `${String(res.wasmBytes).padStart(8)} | ` +
227
- `${res.wasmCompileMs.toFixed(0).padStart(7)}ms | ` +
228
- `${res.llvmCompileMs.toFixed(0).padStart(7)}ms | ` +
229
- `${res.wasmExecNsPerCall.toFixed(0).padStart(14)} | ` +
230
- `${res.llvmExecNsPerCall.toFixed(0).padStart(14)}`
231
- );
232
- }
233
- }
234
-
235
- console.log(
236
- "\n=== 2B. Object Lookup (`dot`) — " +
237
- "Distinct/Varied Keys (Wasm vs LLVM -O3) ==="
238
- );
239
- const WORDS = [
240
- "account", "balance", "category", "database", "endpoint",
241
- "filename", "geometry", "hostname", "identity", "journal",
242
- "keyboard", "language", "metadata", "network", "operator",
243
- "password", "quantity", "resource", "security", "template",
244
- "username", "validate", "workflow", "x509cert", "yearbook", "zoneinfo"
245
- ];
246
- for (const numKeys of [10, 100, 500]) {
247
- const obj = {};
248
- for (let i = 0; i < numKeys; i++) {
249
- const w1 = WORDS[i % WORDS.length];
250
- const w2 = WORDS[Math.floor(i / WORDS.length) % WORDS.length];
251
- const k = `${w1}_${i}_${w2}_attr`;
252
- obj[k] = i * 10;
253
- }
254
- const targetKey = Object.keys(obj).sort().at(-1);
255
- const expectedVal = obj[targetKey];
256
- const inputJsonStr = JSON.stringify([targetKey, obj]);
257
-
258
- console.log(
259
- `\n--- Object with ${numKeys} varied keys ` +
260
- `(querying '${targetKey}') ---`
261
- );
262
- console.log(
263
- "Schema | Wire (B) | Wasm (B) | " +
264
- "Wasm Comp | LLVM Comp | Wasm (ns/call) | LLVM (ns/call)"
265
- );
266
- console.log(
267
- "----------------+----------+----------+-" +
268
- "----------+-----------+----------------+---------------"
269
- );
270
-
271
- for (const s of SCHEMAS) {
272
- const st = await setupBenchmarkState(s.kFile, s.dotExpr);
273
- const kInput = s.codec.parse(inputJsonStr);
274
- const res = await benchRelationOnInput({
275
- state: st,
276
- relName: "bench_dot",
277
- kInput,
278
- codec: s.codec,
279
- expectedJson: expectedVal,
280
- calls: 1000
281
- });
282
- console.log(
283
- `${s.name.padEnd(15)} | ${String(res.wireBytes).padStart(8)} | ` +
284
- `${String(res.wasmBytes).padStart(8)} | ` +
285
- `${res.wasmCompileMs.toFixed(0).padStart(7)}ms | ` +
286
- `${res.llvmCompileMs.toFixed(0).padStart(7)}ms | ` +
287
- `${res.wasmExecNsPerCall.toFixed(0).padStart(14)} | ` +
288
- `${res.llvmExecNsPerCall.toFixed(0).padStart(14)}`
289
- );
290
- }
291
- }
292
-
293
- console.log(
294
- "\n=== 3. List Element Lookup (`nth`) Benchmark (Wasm vs LLVM -O3) ==="
295
- );
296
- for (const len of [10, 100, 500]) {
297
- const arr = Array.from({ length: len }, (_, i) => i * 3);
298
- const targetIdx = len - 1;
299
- const expectedVal = targetIdx * 3;
300
- const inputJsonStr = JSON.stringify(arr);
301
- const idxLit = indexToKLiteral(targetIdx);
302
- const nthExpr =
303
- `bench_nth = json? { ${idxLit} index, /list list } nth json?;`;
304
-
305
- console.log(
306
- `\n--- Array with ${len} elements ` +
307
- `(querying index ${targetIdx}) ---`
308
- );
309
- console.log(
310
- "Schema | Wire (B) | Wasm (B) | " +
311
- "Wasm Comp | LLVM Comp | Wasm (ns/call) | LLVM (ns/call)"
312
- );
313
- console.log(
314
- "----------------+----------+----------+-" +
315
- "----------+-----------+----------------+---------------"
316
- );
317
-
318
- for (const s of SCHEMAS) {
319
- const st = await setupBenchmarkState(s.kFile, nthExpr);
320
- const kInput = s.codec.parse(inputJsonStr);
321
- const res = await benchRelationOnInput({
322
- state: st,
323
- relName: "bench_nth",
324
- kInput,
325
- codec: s.codec,
326
- expectedJson: expectedVal,
327
- calls: 1000
328
- });
329
- console.log(
330
- `${s.name.padEnd(15)} | ${String(res.wireBytes).padStart(8)} | ` +
331
- `${String(res.wasmBytes).padStart(8)} | ` +
332
- `${res.wasmCompileMs.toFixed(0).padStart(7)}ms | ` +
333
- `${res.llvmCompileMs.toFixed(0).padStart(7)}ms | ` +
334
- `${res.wasmExecNsPerCall.toFixed(0).padStart(14)} | ` +
335
- `${res.llvmExecNsPerCall.toFixed(0).padStart(14)}`
336
- );
337
- }
338
- }
339
-
340
- fs.rmSync(llvmCacheDir, { recursive: true, force: true });