@fraczak/k 6.3.3 → 6.4.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.
Files changed (155) hide show
  1. package/DOCS/CODECS.md +258 -0
  2. package/DOCS/DICTIONARY.md +1172 -0
  3. package/DOCS/KIR_SPECIALIZATION_DESIGN.md +51 -46
  4. package/DOCS/KIR_V1.md +221 -0
  5. package/DOCS/KVM_EXECUTION_MODEL.md +56 -19
  6. package/DOCS/OBJECT_FILE_AND_PATTERN.md +2 -1
  7. package/DOCS/PROFILING_AND_TRACING.md +196 -0
  8. package/DOCS/REPL.md +61 -4
  9. package/DOCS/WEB_REPL_REQUIREMENTS.md +135 -0
  10. package/DOCS/dependency-graph.md +144 -0
  11. package/Examples/arithmetics.k +51 -48
  12. package/Examples/bnat.k +1 -1
  13. package/Examples/buda.k +44 -0
  14. package/Examples/ieee.k +300 -8671
  15. package/Examples/poly.k +67 -0
  16. package/README.md +68 -19
  17. package/augmentation.mjs +9 -7
  18. package/backend-api.mjs +11 -2
  19. package/backends/arm64/README.md +104 -0
  20. package/backends/arm64/bin/k-arm64-compile.mjs +101 -0
  21. package/backends/arm64/bin/k-arm64-run.mjs +58 -0
  22. package/backends/arm64/bin/k-arm64.mjs +88 -0
  23. package/backends/arm64/scripts/run-tests.mjs +41 -0
  24. package/backends/arm64/src/arm64.mjs +229 -0
  25. package/backends/arm64/src/cli.mjs +155 -0
  26. package/backends/arm64/src/kvm2arm64.mjs +906 -0
  27. package/backends/arm64/src/runtime.c +728 -0
  28. package/backends/arm64/tests/integration.sh +112 -0
  29. package/backends/arm64/tests/test-arm64.mjs +240 -0
  30. package/backends/llvm/README.md +135 -0
  31. package/backends/llvm/bin/k-llvm-build.mjs +71 -0
  32. package/backends/llvm/bin/k-llvm-compile.mjs +68 -0
  33. package/backends/llvm/bin/k-llvm-jit.mjs +160 -0
  34. package/backends/llvm/bin/k-llvm-run.mjs +90 -0
  35. package/backends/llvm/runtime/krt.c +1508 -0
  36. package/backends/llvm/runtime/krt.h +109 -0
  37. package/backends/llvm/scripts/conformance.mjs +76 -0
  38. package/backends/llvm/scripts/run-tests.mjs +28 -0
  39. package/backends/llvm/src/executable.mjs +562 -0
  40. package/backends/llvm/src/kvm2llvm.mjs +998 -0
  41. package/backends/llvm/src/llvm.mjs +1092 -0
  42. package/backends/llvm/tests/composition-driver.c +22 -0
  43. package/backends/llvm/tests/identity-driver.c +27 -0
  44. package/backends/llvm/tests/integration.sh +153 -0
  45. package/backends/llvm/tests/perf-support.mjs +735 -0
  46. package/backends/llvm/tests/product-driver.c +23 -0
  47. package/backends/llvm/tests/projection-driver.c +19 -0
  48. package/backends/llvm/tests/relation-driver.c +29 -0
  49. package/backends/llvm/tests/test-llvm.mjs +240 -0
  50. package/backends/llvm/tests/union-driver.c +31 -0
  51. package/backends/llvm/tests/variant-driver.c +19 -0
  52. package/backends/llvm/tests/variant-projection-driver.c +21 -0
  53. package/backends/wasm/DOCS/USE-WEB-ASSEMBLY.md +233 -0
  54. package/backends/wasm/README.md +97 -0
  55. package/backends/wasm/TECHNICAL-DEBT.md +60 -0
  56. package/backends/wasm/bin/k-wasm-compile.mjs +50 -0
  57. package/backends/wasm/bin/k-wasm-run.mjs +140 -0
  58. package/backends/wasm/bin/k-wasm.mjs +49 -0
  59. package/backends/wasm/demo_ieee.mjs +319 -0
  60. package/backends/wasm/runtime.wat +102 -0
  61. package/backends/wasm/scripts/run-tests.mjs +41 -0
  62. package/backends/wasm/src/cli.mjs +133 -0
  63. package/backends/wasm/src/kvm2wasm.mjs +661 -0
  64. package/backends/wasm/src/wasm.mjs +1010 -0
  65. package/backends/wasm/tests/integration.sh +182 -0
  66. package/backends/wasm/tests/perf-support.mjs +336 -0
  67. package/backends/wasm/tests/test-wasm.mjs +617 -0
  68. package/browser/repl-browser.mjs +1584 -0
  69. package/browser/shims/assert.mjs +19 -0
  70. package/browser/shims/buffer.mjs +224 -0
  71. package/browser/shims/crypto.mjs +103 -0
  72. package/browser/shims/fs.mjs +159 -0
  73. package/browser/shims/os.mjs +17 -0
  74. package/browser/shims/path.mjs +54 -0
  75. package/browser/shims/process.mjs +44 -0
  76. package/browser/shims/readline.mjs +11 -0
  77. package/browser/shims/url.mjs +12 -0
  78. package/browser/vfs-data.mjs +19 -0
  79. package/codecs/README.md +3 -0
  80. package/codecs/runtime/show-value.mjs +2 -2
  81. package/conformance/helper-reuse/case.json +8 -0
  82. package/conformance/helper-reuse/expected.kv +1 -0
  83. package/conformance/helper-reuse/input.kv +1 -0
  84. package/conformance/helper-reuse/program.k +2 -0
  85. package/conformance/identity/case.json +8 -0
  86. package/conformance/identity/expected.kv +1 -0
  87. package/conformance/identity/input.kv +1 -0
  88. package/conformance/identity/program.k +1 -0
  89. package/conformance/product-projection/case.json +8 -0
  90. package/conformance/product-projection/expected.kv +1 -0
  91. package/conformance/product-projection/input.kv +1 -0
  92. package/conformance/product-projection/program.k +1 -0
  93. package/conformance/run.mjs +149 -0
  94. package/conformance/variant-construction/case.json +8 -0
  95. package/conformance/variant-construction/expected.kv +1 -0
  96. package/conformance/variant-construction/input.kv +1 -0
  97. package/conformance/variant-construction/program.k +1 -0
  98. package/harness/adapters/arm64.mjs +105 -0
  99. package/harness/adapters/kvm.mjs +144 -0
  100. package/harness/adapters/llvm.mjs +118 -0
  101. package/harness/adapters/native.mjs +77 -0
  102. package/harness/adapters/wasm.mjs +169 -0
  103. package/harness/backend.mjs +95 -0
  104. package/harness/cli.mjs +130 -0
  105. package/harness/format.mjs +95 -0
  106. package/harness/index.mjs +25 -0
  107. package/harness/persistent.mjs +121 -0
  108. package/harness/registry.mjs +44 -0
  109. package/harness/suite.mjs +257 -0
  110. package/harness/suites/poly.mjs +156 -0
  111. package/harness/trace.mjs +50 -0
  112. package/harness/util.mjs +92 -0
  113. package/intrinsics.mjs +41 -0
  114. package/kir.mjs +399 -0
  115. package/kvm.mjs +585 -81
  116. package/objects/README.md +37 -3
  117. package/objects/compile.mjs +15 -22
  118. package/objects/inspect.mjs +96 -0
  119. package/objects/validate.mjs +415 -0
  120. package/package.json +51 -19
  121. package/repl-codecs.mjs +105 -6
  122. package/repl.mjs +335 -49
  123. package/run.mjs +2 -7
  124. package/scripts/benchmark.mjs +406 -22
  125. package/scripts/build-repl-html.mjs +1784 -0
  126. package/scripts/perf-ieee.mjs +586 -0
  127. package/scripts/perf-int.mjs +531 -0
  128. package/scripts/perf-poly.mjs +945 -0
  129. package/scripts/render-benchmark.mjs +12 -8
  130. package/scripts/run-tests.mjs +6 -0
  131. package/tests/integration.sh +19 -2
  132. package/tests/test-arithmetics.mjs +54 -0
  133. package/tests/test-ieee-arithmetic.mjs +4 -0
  134. package/tests/test-kir.mjs +85 -0
  135. package/tests/test-kvm-polymorphic.mjs +278 -0
  136. package/tests/test-kvm.mjs +25 -6
  137. package/tests/test-poly.mjs +129 -0
  138. package/tests/test-repl-html.mjs +303 -0
  139. package/tests/test-repl.mjs +144 -1
  140. package/tests/test-validate-object.mjs +40 -0
  141. package/a.klib +0 -1
  142. package/a.kvm +0 -142676
  143. package/a.wasm +0 -0
  144. package/benchmark-results.html +0 -532
  145. package/benchmark-results.json +0 -480
  146. package/k-vscode/.vscode/launch.json +0 -14
  147. package/k-vscode/README.md +0 -75
  148. package/k-vscode/extension.js +0 -273
  149. package/k-vscode/language-configuration.json +0 -42
  150. package/k-vscode/package.json +0 -79
  151. package/k-vscode/snippets/k.json +0 -92
  152. package/k-vscode/syntaxes/k.tmLanguage.json +0 -599
  153. package/k-vscode/test/background-ranges.test.js +0 -50
  154. package/k-vscode/themes/k-contrast-color-theme.json +0 -104
  155. package/scripts/git-hooks/pre-commit +0 -10
@@ -0,0 +1,77 @@
1
+ import {
2
+ codes,
3
+ decodeWire,
4
+ encodeToWire,
5
+ run,
6
+ run_converged
7
+ } from "../../backend-api.mjs";
8
+ import { BackendAdapter, BackendRunner } from "../backend.mjs";
9
+
10
+ class NativeRunner extends BackendRunner {
11
+ constructor(backendId, mode, state) {
12
+ super(backendId);
13
+ this.mode = mode; // "aware" or "free"
14
+ this.state = state;
15
+ }
16
+
17
+ async runSingle(testCase, options = {}) {
18
+ const relDef = testCase.relDef;
19
+ const inputVal = testCase.inputVal;
20
+ const findCode = codes.find;
21
+
22
+ if (this.mode === "free") {
23
+ run_converged.defs = this.state;
24
+ }
25
+
26
+ const t0 = process.hrtime.bigint();
27
+ const result = this.mode === "aware"
28
+ ? run(findCode, relDef.def, inputVal, relDef.typePatternGraph)
29
+ : run_converged(findCode, relDef.def, inputVal, relDef.typePatternGraph);
30
+ const t1 = process.hrtime.bigint();
31
+
32
+ const evalNs = Number(t1 - t0);
33
+
34
+ const trace = options.trace ? {
35
+ ipcReadNs: 0,
36
+ decodeNs: 0,
37
+ flatInNs: 0,
38
+ evalNs,
39
+ flatOutNs: 0,
40
+ encodeNs: 0,
41
+ ipcWriteNs: 0,
42
+ totalNs: evalNs
43
+ } : null;
44
+
45
+ return {
46
+ outputVal: result,
47
+ trace
48
+ };
49
+ }
50
+ }
51
+
52
+ export class NativeAdapter extends BackendAdapter {
53
+ constructor(mode = "free", state = null) {
54
+ const id = mode === "aware" ? "native-aware" : "native-free";
55
+ const name = mode === "aware" ? "Native JS (Envelope-Aware)" : "Native JS (Envelope-Free)";
56
+ super(id, name);
57
+ this.mode = mode;
58
+ this.state = state;
59
+ }
60
+
61
+ setState(state) {
62
+ this.state = state;
63
+ }
64
+
65
+ async compile(testCase) {
66
+ return {
67
+ status: "ok",
68
+ relDef: testCase.relDef,
69
+ inputVal: testCase.inputVal,
70
+ outputPattern: testCase.outputPattern
71
+ };
72
+ }
73
+
74
+ async createRunner(compiledCases) {
75
+ return new NativeRunner(this.id, this.mode, this.state);
76
+ }
77
+ }
@@ -0,0 +1,169 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import { BackendAdapter, BackendRunner } from "../backend.mjs";
5
+ import { PersistentExecutable } from "../persistent.mjs";
6
+ import {
7
+ compileWasmArtifactFromObject,
8
+ instantiateWasmArtifact
9
+ } from "../../backends/wasm/src/wasm.mjs";
10
+ import { decodeWire } from "../../backend-api.mjs";
11
+
12
+ class WasmInProcessRunner extends BackendRunner {
13
+ constructor(backendId) {
14
+ super(backendId);
15
+ }
16
+
17
+ async runSingle(testCase, options = {}) {
18
+ const runner = testCase.runner;
19
+ if (options.trace) {
20
+ const res = runner.execute(testCase.inputWire, { trace: true });
21
+ const decoded = decodeWire(res.outputWire);
22
+ return {
23
+ outputWire: res.outputWire,
24
+ outputVal: decoded.value,
25
+ outputPattern: decoded.pattern,
26
+ trace: {
27
+ ipcReadNs: 0,
28
+ decodeNs: res.trace.decodeNs,
29
+ flatInNs: res.trace.flatInNs,
30
+ evalNs: res.trace.evalNs,
31
+ flatOutNs: res.trace.flatOutNs,
32
+ encodeNs: res.trace.encodeNs,
33
+ ipcWriteNs: 0,
34
+ totalNs: res.trace.totalNs
35
+ }
36
+ };
37
+ } else {
38
+ const outWire = runner.execute(testCase.inputWire);
39
+ const decoded = decodeWire(outWire);
40
+ return {
41
+ outputWire: outWire,
42
+ outputVal: decoded.value,
43
+ outputPattern: decoded.pattern
44
+ };
45
+ }
46
+ }
47
+
48
+ async runBatch(compiledCases) {
49
+ for (const c of compiledCases) {
50
+ c.runner.execute(c.inputWire);
51
+ }
52
+ }
53
+
54
+ async close() {}
55
+ }
56
+
57
+ class WasmPipeRunner extends BackendRunner {
58
+ constructor(backendId, servers = new Map()) {
59
+ super(backendId);
60
+ this.servers = servers;
61
+ }
62
+
63
+ getServer(exePath) {
64
+ let server = this.servers.get(exePath);
65
+ if (!server) {
66
+ server = new PersistentExecutable(exePath);
67
+ this.servers.set(exePath, server);
68
+ }
69
+ return server;
70
+ }
71
+
72
+ async runSingle(testCase, options = {}) {
73
+ const server = this.getServer(testCase.exePath);
74
+ if (options.trace) {
75
+ const res = await server.requestWithTrace(testCase.inputWire);
76
+ const decoded = decodeWire(res.payload);
77
+ return {
78
+ outputWire: res.payload,
79
+ outputVal: decoded.value,
80
+ outputPattern: decoded.pattern,
81
+ trace: res.trace,
82
+ profile: res.trace?.profile
83
+ };
84
+ } else {
85
+ const payload = await server.request(testCase.inputWire);
86
+ const decoded = decodeWire(payload);
87
+ return {
88
+ outputWire: payload,
89
+ outputVal: decoded.value,
90
+ outputPattern: decoded.pattern
91
+ };
92
+ }
93
+ }
94
+
95
+ async runBatch(compiledCases) {
96
+ for (const c of compiledCases) {
97
+ const server = this.getServer(c.exePath);
98
+ await server.request(c.inputWire);
99
+ }
100
+ }
101
+
102
+ async close() {
103
+ for (const server of this.servers.values()) {
104
+ server.close();
105
+ }
106
+ this.servers.clear();
107
+ }
108
+ }
109
+
110
+ export class WasmAdapter extends BackendAdapter {
111
+ constructor(options = {}) {
112
+ const mode = options.mode || "pipe"; // "pipe" or "in-process"
113
+ const id = options.id || (mode === "in-process" ? "wasm-in-process" : "wasm");
114
+ const name = options.name || `WebAssembly (${mode === "pipe" ? "persistent pipe" : "in-process"})`;
115
+ super(id, name, options);
116
+ this.mode = mode;
117
+ }
118
+
119
+ isAvailable() {
120
+ return true; // Runs in Node.js via WABT / V8 Wasm
121
+ }
122
+
123
+ async compile(testCase, options = {}) {
124
+ const cacheDir = options.cacheDir || path.join(process.cwd(), ".cache");
125
+ fs.mkdirSync(cacheDir, { recursive: true });
126
+ const name = testCase.op || testCase.relName || "case";
127
+ const wasmPath = path.join(cacheDir, `harness_wasm_${name}.wasm`);
128
+ const exePath = path.join(cacheDir, `harness_wasm_${name}.exe`);
129
+
130
+ try {
131
+ const entry = testCase.relHash || testCase.relName || testCase.op;
132
+ const wasmBuf = await compileWasmArtifactFromObject(testCase.object, {
133
+ entry,
134
+ profile: Boolean(options.profile)
135
+ });
136
+ fs.writeFileSync(wasmPath, wasmBuf);
137
+
138
+ const runBin = fileURLToPath(import.meta.resolve("../../backends/wasm/bin/k-wasm-run.mjs"));
139
+ fs.writeFileSync(exePath, `#!/bin/sh\nexec node "${runBin}" "${wasmPath}" "$@"\n`, { mode: 0o755 });
140
+
141
+ let inProcessRunner = null;
142
+ if (this.mode === "in-process") {
143
+ inProcessRunner = await instantiateWasmArtifact(wasmBuf);
144
+ }
145
+
146
+ return {
147
+ status: "ok",
148
+ wasmPath,
149
+ exePath,
150
+ runner: inProcessRunner,
151
+ inputWire: testCase.inputWire,
152
+ inputVal: testCase.inputVal,
153
+ outputPattern: testCase.outputPattern
154
+ };
155
+ } catch (error) {
156
+ return {
157
+ status: "failed",
158
+ error: error.stack || error.message || String(error)
159
+ };
160
+ }
161
+ }
162
+
163
+ async createRunner(compiledCases) {
164
+ if (this.mode === "in-process") {
165
+ return new WasmInProcessRunner(this.id);
166
+ }
167
+ return new WasmPipeRunner(this.id);
168
+ }
169
+ }
@@ -0,0 +1,95 @@
1
+ // Base class for all backend adapters
2
+
3
+ export class BackendAdapter {
4
+ constructor(id, name, options = {}) {
5
+ this.id = id;
6
+ this.name = name;
7
+ this.options = options;
8
+ }
9
+
10
+ isAvailable() {
11
+ return true;
12
+ }
13
+
14
+ getLaneName() {
15
+ return this.name;
16
+ }
17
+
18
+ /**
19
+ * Compiles or prepares a test case for execution.
20
+ * @param {object} testCase
21
+ * @param {object} options
22
+ * @returns {Promise<object>} compiled artifact/handle
23
+ */
24
+ async compile(testCase, options = {}) {
25
+ throw new Error(`compile() not implemented for backend '${this.id}'`);
26
+ }
27
+
28
+ /**
29
+ * Creates a runner for a suite of compiled cases.
30
+ * @param {Array<object>} compiledCases
31
+ * @param {object} options
32
+ * @returns {Promise<BackendRunner>}
33
+ */
34
+ async createRunner(compiledCases, options = {}) {
35
+ throw new Error(`createRunner() not implemented for backend '${this.id}'`);
36
+ }
37
+ }
38
+
39
+ export class BackendRunner {
40
+ constructor(backendId, options = {}) {
41
+ this.backendId = backendId;
42
+ this.options = options;
43
+ }
44
+
45
+ /**
46
+ * Run a single case.
47
+ * @param {object} compiledCase
48
+ * @param {object} options { trace?: boolean, profile?: boolean }
49
+ * @returns {Promise<{ outputWire?: Buffer, outputVal?: any, trace?: object, profile?: object }>}
50
+ */
51
+ async runSingle(compiledCase, options = {}) {
52
+ throw new Error(`runSingle() not implemented for runner '${this.backendId}'`);
53
+ }
54
+
55
+ /**
56
+ * Run all cases once.
57
+ * @param {Array<object>} compiledCases
58
+ * @returns {Promise<void>}
59
+ */
60
+ async runBatch(compiledCases) {
61
+ for (const c of compiledCases) {
62
+ await this.runSingle(c);
63
+ }
64
+ }
65
+
66
+ /**
67
+ * Run timed iterations over all cases.
68
+ * @param {Array<object>} compiledCases
69
+ * @param {number} iterations
70
+ * @returns {Promise<{ totalNs: number, perIterationMs: number, iterationTimes: number[] }>}
71
+ */
72
+ async runIterations(compiledCases, iterations) {
73
+ const iterationTimes = [];
74
+ let totalNs = 0;
75
+
76
+ for (let i = 0; i < iterations; i++) {
77
+ const t0 = process.hrtime.bigint();
78
+ await this.runBatch(compiledCases);
79
+ const t1 = process.hrtime.bigint();
80
+ const diffNs = Number(t1 - t0);
81
+ totalNs += diffNs;
82
+ iterationTimes.push(diffNs / 1000000);
83
+ }
84
+
85
+ return {
86
+ totalNs,
87
+ perIterationMs: iterations > 0 ? (totalNs / iterations / 1000000) : 0,
88
+ iterationTimes
89
+ };
90
+ }
91
+
92
+ async close() {
93
+ // Optional cleanup
94
+ }
95
+ }
@@ -0,0 +1,130 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { parseArgs } from "node:util";
4
+ import { createPolySuite } from "./suites/poly.mjs";
5
+ import {
6
+ formatPhaseTable,
7
+ formatProfileTable,
8
+ formatBenchmarkTable
9
+ } from "./format.mjs";
10
+
11
+ async function main() {
12
+ const options = {
13
+ suite: { type: "string", default: "poly" },
14
+ backends: { type: "string", short: "b" },
15
+ iterations: { type: "string", short: "i", default: "3" },
16
+ warmup: { type: "string", short: "w", default: "1" },
17
+ trace: { type: "boolean", default: false },
18
+ profile: { type: "boolean", default: false },
19
+ conformance: { type: "boolean", default: false },
20
+ all: { type: "boolean", default: false },
21
+ format: { type: "string", default: "text" },
22
+ listLength: { type: "string", default: "40" },
23
+ help: { type: "boolean", short: "h", default: false }
24
+ };
25
+
26
+ const { values } = parseArgs({ options, allowPositionals: true });
27
+
28
+ if (values.help) {
29
+ console.log(`Usage: node harness/cli.mjs [options]
30
+
31
+ Options:
32
+ --suite <name> Benchmark suite: poly (default: poly)
33
+ -b, --backends <csv> Comma-separated backends (default: all available)
34
+ -i, --iterations <n> Measured iterations (default: 3)
35
+ -w, --warmup <n> Warmup iterations (default: 1)
36
+ --trace Measure 7-phase nanosecond execution timing
37
+ --profile Measure per-function call count profiling
38
+ --conformance Verify output equality across all backends
39
+ --all Run conformance, profile, trace, and benchmark
40
+ --format <fmt> Output format: text, json (default: text)
41
+ --listLength <n> Workload size for list operations (default: 40)
42
+ -h, --help Show this help message
43
+ `);
44
+ return;
45
+ }
46
+
47
+ const listLength = parseInt(values.listLength, 10);
48
+ const iterations = parseInt(values.iterations, 10);
49
+ const warmup = parseInt(values.warmup, 10);
50
+ const doTrace = values.trace || values.all;
51
+ const doProfile = values.profile || values.all;
52
+ const doConformance = values.conformance || values.all;
53
+ const doBenchmark = !values.trace && !values.profile && !values.conformance ? true : values.all;
54
+
55
+ console.log(`==> Initializing test suite: ${values.suite} (listLength=${listLength})...`);
56
+ let suite;
57
+ if (values.suite === "poly") {
58
+ suite = await createPolySuite({ listLength });
59
+ } else {
60
+ throw new Error(`Unknown suite: ${values.suite}`);
61
+ }
62
+
63
+ const available = suite.getAvailableBackendIds();
64
+ const selectedBackends = values.backends
65
+ ? values.backends.split(",").map(b => b.trim()).filter(Boolean)
66
+ : available;
67
+
68
+ console.log(`==> Target backends: ${selectedBackends.join(", ")}`);
69
+ console.log(`==> Compiling test cases for backends...`);
70
+ const compileResults = await suite.compileAll(selectedBackends, {
71
+ profile: doProfile,
72
+ trace: doTrace
73
+ });
74
+
75
+ for (const [id, res] of Object.entries(compileResults)) {
76
+ console.log(` [${id}] ${res.status}: ${res.ready}/${res.total} cases ready`);
77
+ if (res.status !== "ok" && res.error) {
78
+ console.log(` Error: ${res.error.split("\n")[0]}`);
79
+ }
80
+ }
81
+
82
+ const readyBackends = selectedBackends.filter(id => compileResults[id]?.status === "ok");
83
+
84
+ try {
85
+ // 1. Conformance
86
+ if (doConformance) {
87
+ console.log("\n==> Running Conformance Verification...");
88
+ const confResults = await suite.checkConformance(readyBackends);
89
+ let allPassed = true;
90
+ for (const r of confResults) {
91
+ const statuses = Object.entries(r.conformance).map(([id, c]) => `${id}:${c.status}`).join(" ");
92
+ console.log(` ${r.name.padEnd(15)} -> ${statuses}`);
93
+ if (!r.passed) allPassed = false;
94
+ }
95
+ console.log(allPassed ? " All backends conform!" : " Conformance failure detected!");
96
+ }
97
+
98
+ // 2. Profile
99
+ if (doProfile) {
100
+ console.log("\n==> Running Per-Function Call Profiling...");
101
+ const profResults = await suite.runProfile(readyBackends);
102
+ console.log(formatProfileTable(profResults, readyBackends));
103
+ }
104
+
105
+ // 3. Trace
106
+ if (doTrace) {
107
+ console.log("\n==> Running 7-Phase Execution Tracing...");
108
+ const traceResults = await suite.runTrace(readyBackends, 3);
109
+ console.log(formatPhaseTable(traceResults, readyBackends));
110
+ }
111
+
112
+ // 4. Benchmark
113
+ if (doBenchmark) {
114
+ console.log(`\n==> Running Benchmark (${iterations} iterations, ${warmup} warmup)...`);
115
+ const benchResults = await suite.runBenchmark(readyBackends, { warmup, iterations });
116
+ if (values.format === "json") {
117
+ console.log(JSON.stringify(benchResults, null, 2));
118
+ } else {
119
+ console.log(formatBenchmarkTable(benchResults));
120
+ }
121
+ }
122
+ } finally {
123
+ await suite.close();
124
+ }
125
+ }
126
+
127
+ main().catch(err => {
128
+ console.error("Harness error:", err);
129
+ process.exit(1);
130
+ });
@@ -0,0 +1,95 @@
1
+ import { PHASES, formatUs } from "./trace.mjs";
2
+
3
+ export function formatPhaseTable(phaseResults, backendIds = ["arm64", "llvm", "wasm", "kvm"]) {
4
+ const lines = [];
5
+
6
+ for (const item of phaseResults) {
7
+ lines.push(`\n--- Operation: ${item.op || item.name} (${item.label || ""}) ---`);
8
+ const header = ["Phase".padEnd(25), ...backendIds.map(id => id.padEnd(14))].join(" | ");
9
+ lines.push(header);
10
+ lines.push("-".repeat(header.length));
11
+
12
+ for (const phase of PHASES) {
13
+ if (phase.isTotal) {
14
+ lines.push("-".repeat(header.length));
15
+ }
16
+ const pName = phase.name.padEnd(25);
17
+ const cols = backendIds.map(id => {
18
+ const val = item[id]?.[phase.key];
19
+ return formatUs(val).padEnd(14);
20
+ });
21
+ lines.push([pName, ...cols].join(" | "));
22
+ }
23
+ }
24
+
25
+ return lines.join("\n");
26
+ }
27
+
28
+ export function formatProfileTable(profileResults, backendIds = ["arm64", "wasm", "kvm"]) {
29
+ const lines = [];
30
+
31
+ for (const item of profileResults) {
32
+ lines.push(`\nFunction Call Profile: ${item.op || item.name}`);
33
+ const header = ["Function Name".padEnd(30), ...backendIds.map(id => `${id} Calls`.padEnd(18))].join(" | ");
34
+ lines.push(header);
35
+ lines.push("-".repeat(header.length));
36
+
37
+ const funcNames = new Set();
38
+ for (const id of backendIds) {
39
+ const prof = item[id] || {};
40
+ for (const fn of Object.keys(prof)) funcNames.add(fn);
41
+ }
42
+
43
+ const sortedFuncs = [...funcNames].sort();
44
+ const totals = Object.fromEntries(backendIds.map(id => [id, 0]));
45
+
46
+ for (const fn of sortedFuncs) {
47
+ const rowCols = backendIds.map(id => {
48
+ const count = item[id]?.[fn];
49
+ if (count != null) {
50
+ totals[id] += count;
51
+ return String(count).padStart(18);
52
+ }
53
+ return " - ".padStart(18);
54
+ });
55
+ lines.push([fn.padEnd(30), ...rowCols].join(" | "));
56
+ }
57
+
58
+ lines.push("-".repeat(header.length));
59
+ const totalRow = backendIds.map(id => String(totals[id]).padStart(18));
60
+ lines.push(["Total Calls".padEnd(30), ...totalRow].join(" | "));
61
+ }
62
+
63
+ return lines.join("\n");
64
+ }
65
+
66
+ export function formatBenchmarkTable(benchResults) {
67
+ const lines = [];
68
+ const hasPureEval = benchResults.some(r => r.pureEvalMs != null);
69
+ const header = [
70
+ "Backend".padEnd(35),
71
+ "Mean (ms/iter)".padStart(15),
72
+ ...(hasPureEval ? ["Pure Eval (ms)".padStart(15)] : []),
73
+ "Min (ms)".padStart(12),
74
+ "Max (ms)".padStart(12),
75
+ "Samples".padStart(10)
76
+ ].join(" | ");
77
+
78
+ lines.push(header);
79
+ lines.push("-".repeat(header.length));
80
+
81
+ for (const res of benchResults) {
82
+ const name = (res.name || res.id).padEnd(35);
83
+ const mean = (res.perIterationMs != null ? res.perIterationMs.toFixed(3) : "N/A").padStart(15);
84
+ const pureEval = hasPureEval
85
+ ? (res.pureEvalMs != null ? res.pureEvalMs.toFixed(3) : "-").padStart(15)
86
+ : null;
87
+ const min = (res.minMs != null ? res.minMs.toFixed(3) : "-").padStart(12);
88
+ const max = (res.maxMs != null ? res.maxMs.toFixed(3) : "-").padStart(12);
89
+ const samples = (res.samples != null ? String(res.samples) : "0").padStart(10);
90
+ const cols = [name, mean, ...(pureEval ? [pureEval] : []), min, max, samples];
91
+ lines.push(cols.join(" | "));
92
+ }
93
+
94
+ return lines.join("\n");
95
+ }
@@ -0,0 +1,25 @@
1
+ export { BenchmarkSuite } from "./suite.mjs";
2
+ export { createRegistry } from "./registry.mjs";
3
+ export { BackendAdapter, BackendRunner } from "./backend.mjs";
4
+ export { PersistentExecutable } from "./persistent.mjs";
5
+ export {
6
+ safeDeepEqual,
7
+ toPlainObject,
8
+ average,
9
+ stdDev,
10
+ min,
11
+ max,
12
+ formatTiming,
13
+ makeCacheDir
14
+ } from "./util.mjs";
15
+ export {
16
+ PHASES,
17
+ parseTraceLine,
18
+ averageTrace,
19
+ formatUs
20
+ } from "./trace.mjs";
21
+ export {
22
+ formatPhaseTable,
23
+ formatProfileTable,
24
+ formatBenchmarkTable
25
+ } from "./format.mjs";