@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.
- package/DOCS/CODECS.md +258 -0
- package/DOCS/DICTIONARY.md +1172 -0
- package/DOCS/KIR_SPECIALIZATION_DESIGN.md +51 -46
- package/DOCS/KIR_V1.md +221 -0
- package/DOCS/KVM_EXECUTION_MODEL.md +56 -19
- package/DOCS/OBJECT_FILE_AND_PATTERN.md +2 -1
- package/DOCS/PROFILING_AND_TRACING.md +196 -0
- package/DOCS/REPL.md +61 -4
- package/DOCS/WEB_REPL_REQUIREMENTS.md +135 -0
- package/DOCS/dependency-graph.md +144 -0
- package/Examples/arithmetics.k +51 -48
- package/Examples/bnat.k +1 -1
- package/Examples/buda.k +44 -0
- package/Examples/ieee.k +300 -8671
- package/Examples/poly.k +67 -0
- package/README.md +68 -19
- package/augmentation.mjs +9 -7
- package/backend-api.mjs +11 -2
- package/backends/arm64/README.md +104 -0
- package/backends/arm64/bin/k-arm64-compile.mjs +101 -0
- package/backends/arm64/bin/k-arm64-run.mjs +58 -0
- package/backends/arm64/bin/k-arm64.mjs +88 -0
- package/backends/arm64/scripts/run-tests.mjs +41 -0
- package/backends/arm64/src/arm64.mjs +229 -0
- package/backends/arm64/src/cli.mjs +155 -0
- package/backends/arm64/src/kvm2arm64.mjs +906 -0
- package/backends/arm64/src/runtime.c +728 -0
- package/backends/arm64/tests/integration.sh +112 -0
- package/backends/arm64/tests/test-arm64.mjs +240 -0
- package/backends/llvm/README.md +135 -0
- package/backends/llvm/bin/k-llvm-build.mjs +71 -0
- package/backends/llvm/bin/k-llvm-compile.mjs +68 -0
- package/backends/llvm/bin/k-llvm-jit.mjs +160 -0
- package/backends/llvm/bin/k-llvm-run.mjs +90 -0
- package/backends/llvm/runtime/krt.c +1508 -0
- package/backends/llvm/runtime/krt.h +109 -0
- package/backends/llvm/scripts/conformance.mjs +76 -0
- package/backends/llvm/scripts/run-tests.mjs +28 -0
- package/backends/llvm/src/executable.mjs +562 -0
- package/backends/llvm/src/kvm2llvm.mjs +998 -0
- package/backends/llvm/src/llvm.mjs +1092 -0
- package/backends/llvm/tests/composition-driver.c +22 -0
- package/backends/llvm/tests/identity-driver.c +27 -0
- package/backends/llvm/tests/integration.sh +153 -0
- package/backends/llvm/tests/perf-support.mjs +735 -0
- package/backends/llvm/tests/product-driver.c +23 -0
- package/backends/llvm/tests/projection-driver.c +19 -0
- package/backends/llvm/tests/relation-driver.c +29 -0
- package/backends/llvm/tests/test-llvm.mjs +240 -0
- package/backends/llvm/tests/union-driver.c +31 -0
- package/backends/llvm/tests/variant-driver.c +19 -0
- package/backends/llvm/tests/variant-projection-driver.c +21 -0
- package/backends/wasm/DOCS/USE-WEB-ASSEMBLY.md +233 -0
- package/backends/wasm/README.md +97 -0
- package/backends/wasm/TECHNICAL-DEBT.md +60 -0
- package/backends/wasm/bin/k-wasm-compile.mjs +50 -0
- package/backends/wasm/bin/k-wasm-run.mjs +140 -0
- package/backends/wasm/bin/k-wasm.mjs +49 -0
- package/backends/wasm/demo_ieee.mjs +319 -0
- package/backends/wasm/runtime.wat +102 -0
- package/backends/wasm/scripts/run-tests.mjs +41 -0
- package/backends/wasm/src/cli.mjs +133 -0
- package/backends/wasm/src/kvm2wasm.mjs +661 -0
- package/backends/wasm/src/wasm.mjs +1010 -0
- package/backends/wasm/tests/integration.sh +182 -0
- package/backends/wasm/tests/perf-support.mjs +336 -0
- package/backends/wasm/tests/test-wasm.mjs +617 -0
- package/browser/repl-browser.mjs +1584 -0
- package/browser/shims/assert.mjs +19 -0
- package/browser/shims/buffer.mjs +224 -0
- package/browser/shims/crypto.mjs +103 -0
- package/browser/shims/fs.mjs +159 -0
- package/browser/shims/os.mjs +17 -0
- package/browser/shims/path.mjs +54 -0
- package/browser/shims/process.mjs +44 -0
- package/browser/shims/readline.mjs +11 -0
- package/browser/shims/url.mjs +12 -0
- package/browser/vfs-data.mjs +19 -0
- package/codecs/README.md +3 -0
- package/codecs/runtime/show-value.mjs +2 -2
- package/conformance/helper-reuse/case.json +8 -0
- package/conformance/helper-reuse/expected.kv +1 -0
- package/conformance/helper-reuse/input.kv +1 -0
- package/conformance/helper-reuse/program.k +2 -0
- package/conformance/identity/case.json +8 -0
- package/conformance/identity/expected.kv +1 -0
- package/conformance/identity/input.kv +1 -0
- package/conformance/identity/program.k +1 -0
- package/conformance/product-projection/case.json +8 -0
- package/conformance/product-projection/expected.kv +1 -0
- package/conformance/product-projection/input.kv +1 -0
- package/conformance/product-projection/program.k +1 -0
- package/conformance/run.mjs +149 -0
- package/conformance/variant-construction/case.json +8 -0
- package/conformance/variant-construction/expected.kv +1 -0
- package/conformance/variant-construction/input.kv +1 -0
- package/conformance/variant-construction/program.k +1 -0
- package/harness/adapters/arm64.mjs +105 -0
- package/harness/adapters/kvm.mjs +144 -0
- package/harness/adapters/llvm.mjs +118 -0
- package/harness/adapters/native.mjs +77 -0
- package/harness/adapters/wasm.mjs +169 -0
- package/harness/backend.mjs +95 -0
- package/harness/cli.mjs +130 -0
- package/harness/format.mjs +95 -0
- package/harness/index.mjs +25 -0
- package/harness/persistent.mjs +121 -0
- package/harness/registry.mjs +44 -0
- package/harness/suite.mjs +257 -0
- package/harness/suites/poly.mjs +156 -0
- package/harness/trace.mjs +50 -0
- package/harness/util.mjs +92 -0
- package/intrinsics.mjs +41 -0
- package/kir.mjs +399 -0
- package/kvm.mjs +585 -81
- package/objects/README.md +37 -3
- package/objects/compile.mjs +15 -22
- package/objects/inspect.mjs +96 -0
- package/objects/validate.mjs +415 -0
- package/package.json +51 -19
- package/repl-codecs.mjs +105 -6
- package/repl.mjs +335 -49
- package/run.mjs +2 -7
- package/scripts/benchmark.mjs +406 -22
- package/scripts/build-repl-html.mjs +1784 -0
- package/scripts/perf-ieee.mjs +586 -0
- package/scripts/perf-int.mjs +531 -0
- package/scripts/perf-poly.mjs +945 -0
- package/scripts/render-benchmark.mjs +12 -8
- package/scripts/run-tests.mjs +6 -0
- package/tests/integration.sh +19 -2
- package/tests/test-arithmetics.mjs +54 -0
- package/tests/test-ieee-arithmetic.mjs +4 -0
- package/tests/test-kir.mjs +85 -0
- package/tests/test-kvm-polymorphic.mjs +278 -0
- package/tests/test-kvm.mjs +25 -6
- package/tests/test-poly.mjs +129 -0
- package/tests/test-repl-html.mjs +303 -0
- package/tests/test-repl.mjs +144 -1
- package/tests/test-validate-object.mjs +40 -0
- package/a.klib +0 -1
- package/a.kvm +0 -142676
- package/a.wasm +0 -0
- package/benchmark-results.html +0 -532
- package/benchmark-results.json +0 -480
- package/k-vscode/.vscode/launch.json +0 -14
- package/k-vscode/README.md +0 -75
- package/k-vscode/extension.js +0 -273
- package/k-vscode/language-configuration.json +0 -42
- package/k-vscode/package.json +0 -79
- package/k-vscode/snippets/k.json +0 -92
- package/k-vscode/syntaxes/k.tmLanguage.json +0 -599
- package/k-vscode/test/background-ranges.test.js +0 -50
- package/k-vscode/themes/k-contrast-color-theme.json +0 -104
- package/scripts/git-hooks/pre-commit +0 -10
|
@@ -0,0 +1,586 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import wabtFactory from "wabt";
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
codes,
|
|
9
|
+
createState,
|
|
10
|
+
decodeWire,
|
|
11
|
+
evaluateInput,
|
|
12
|
+
executeKVM,
|
|
13
|
+
exportPatternGraph,
|
|
14
|
+
parseFloat64,
|
|
15
|
+
patternToPropertyList,
|
|
16
|
+
propertyListToPattern,
|
|
17
|
+
run,
|
|
18
|
+
run_converged,
|
|
19
|
+
valueForCode,
|
|
20
|
+
Value
|
|
21
|
+
} from "@fraczak/k/backend-api.mjs";
|
|
22
|
+
|
|
23
|
+
import {
|
|
24
|
+
csvEnv,
|
|
25
|
+
formatTiming,
|
|
26
|
+
createLLVMRunner,
|
|
27
|
+
createARM64Runner,
|
|
28
|
+
arm64LaneName,
|
|
29
|
+
llvmLaneName,
|
|
30
|
+
makeCacheDir,
|
|
31
|
+
parseNonNegativeIntEnv,
|
|
32
|
+
parsePositiveIntEnv,
|
|
33
|
+
prepareRelation,
|
|
34
|
+
printCompileFailures,
|
|
35
|
+
PersistentExecutable,
|
|
36
|
+
runExecutable,
|
|
37
|
+
runTimedIterations,
|
|
38
|
+
runTimedIterationsAsync,
|
|
39
|
+
shouldStrictFail,
|
|
40
|
+
toPlainObject,
|
|
41
|
+
tryCompileCase,
|
|
42
|
+
wireInput
|
|
43
|
+
} from "../backends/llvm/tests/perf-support.mjs";
|
|
44
|
+
|
|
45
|
+
import {
|
|
46
|
+
cleanName,
|
|
47
|
+
instantiateWasmModule,
|
|
48
|
+
readArenaValue,
|
|
49
|
+
writeValueToArena
|
|
50
|
+
} from "../backends/wasm/tests/perf-support.mjs";
|
|
51
|
+
|
|
52
|
+
import { compileWasmArtifactFromObject } from "../backends/wasm/src/wasm.mjs";
|
|
53
|
+
import { compileARM64ArtifactFromObject } from "../backends/arm64/src/arm64.mjs";
|
|
54
|
+
|
|
55
|
+
// Backend selection
|
|
56
|
+
const backendsEnv = process.env.BACKENDS?.toLowerCase();
|
|
57
|
+
const llvmOnly = process.env.LLVM_ONLY === "1" || backendsEnv === "llvm";
|
|
58
|
+
const wasmOnly = process.env.WASM_ONLY === "1" || backendsEnv === "wasm";
|
|
59
|
+
const arm64Only = process.env.ARM64_ONLY === "1" || backendsEnv === "arm64";
|
|
60
|
+
|
|
61
|
+
const isArm64Host = process.arch === "arm64" && process.platform === "linux";
|
|
62
|
+
const runARM64 = !wasmOnly && !llvmOnly && (isArm64Host || arm64Only);
|
|
63
|
+
const runLLVM = !wasmOnly && !arm64Only;
|
|
64
|
+
const runWasm = !llvmOnly && !arm64Only;
|
|
65
|
+
const runBaselines = !process.env.BACKENDS_ONLY && (process.env.LLVM_ONLY !== "1") && (process.env.WASM_ONLY !== "1") && (process.env.ARM64_ONLY !== "1");
|
|
66
|
+
|
|
67
|
+
const ops = ["add", "sub", "mul", "div"];
|
|
68
|
+
const values = csvEnv("VALUES", "0.5,-4,0,Infinity,-Infinity,NaN");
|
|
69
|
+
const iterations = parsePositiveIntEnv("ITERATIONS", 3);
|
|
70
|
+
|
|
71
|
+
// ARM64 options
|
|
72
|
+
const arm64WarmupIterations = parseNonNegativeIntEnv("ARM64_WARMUP_ITERATIONS", 1);
|
|
73
|
+
const arm64OptLevel = process.env.ARM64_OPT || "-O2";
|
|
74
|
+
|
|
75
|
+
// LLVM options
|
|
76
|
+
const llvmWarmupIterations = parseNonNegativeIntEnv("LLVM_WARMUP_ITERATIONS", 1);
|
|
77
|
+
const llvmRuntimeMode = process.env.K_LLVM_IEEE_RUNTIME_MODE || "compact";
|
|
78
|
+
|
|
79
|
+
function getClangOptLevels() {
|
|
80
|
+
for (const arg of process.argv.slice(2)) {
|
|
81
|
+
if (arg.startsWith("--opt=") || arg.startsWith("--opts=")) {
|
|
82
|
+
return arg.split("=")[1].split(",").map(s => s.trim()).filter(Boolean);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
const optIdx = process.argv.findIndex(arg => arg === "--opt" || arg === "--opts");
|
|
86
|
+
if (optIdx !== -1 && process.argv[optIdx + 1]) {
|
|
87
|
+
return process.argv[optIdx + 1].split(",").map(s => s.trim()).filter(Boolean);
|
|
88
|
+
}
|
|
89
|
+
const directFlags = [];
|
|
90
|
+
for (const flag of ["--O0", "--O1", "--O2", "--O3"]) {
|
|
91
|
+
if (process.argv.includes(flag)) {
|
|
92
|
+
directFlags.push(`-${flag.slice(2)}`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (directFlags.length > 0) return directFlags;
|
|
96
|
+
if (process.argv.includes("--full") || process.env.PERF_FULL === "1") {
|
|
97
|
+
return ["-O0", "-O1", "-O2"];
|
|
98
|
+
}
|
|
99
|
+
if (process.env.LLVM_OPTS) {
|
|
100
|
+
return csvEnv("LLVM_OPTS", "");
|
|
101
|
+
}
|
|
102
|
+
if (process.env.K_LLVM_IEEE_CLANG_OPT) {
|
|
103
|
+
return csvEnv("K_LLVM_IEEE_CLANG_OPT", "");
|
|
104
|
+
}
|
|
105
|
+
return ["-O1"];
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const llvmOptLevels = getClangOptLevels();
|
|
109
|
+
const cacheDir = makeCacheDir("k-llvm-ieee-perf-");
|
|
110
|
+
|
|
111
|
+
// Wasm options
|
|
112
|
+
const wasmWarmupIterations = parseNonNegativeIntEnv("WASM_WARMUP_ITERATIONS", 10);
|
|
113
|
+
const wasmReset = process.env.WASM_RESET !== "0";
|
|
114
|
+
const wasmPipe = process.env.WASM_PIPE === "0" || process.env.WASM_IN_PROCESS === "1" || process.argv.includes("--wasm-in-process")
|
|
115
|
+
? false
|
|
116
|
+
: true;
|
|
117
|
+
function wasmLaneName() {
|
|
118
|
+
const mode = wasmPipe ? "persistent" : "in-process";
|
|
119
|
+
return `WebAssembly (${mode})`;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
console.log("==> Initializing state and loading @fraczak/k/Examples/ieee.k");
|
|
123
|
+
const state = createState();
|
|
124
|
+
const ieeePath = fileURLToPath(import.meta.resolve("@fraczak/k/Examples/ieee.k"));
|
|
125
|
+
await evaluateInput(`:load ${ieeePath}`, state);
|
|
126
|
+
|
|
127
|
+
function generatePerfK(values) {
|
|
128
|
+
const paramFields = values.map((_, i) => ` float64 p${i}`).join(",\n");
|
|
129
|
+
const lines = [
|
|
130
|
+
`$params = {\n${paramFields}\n};`
|
|
131
|
+
];
|
|
132
|
+
for (const op of ops) {
|
|
133
|
+
lines.push(`perf_${op} =`);
|
|
134
|
+
lines.push(" {");
|
|
135
|
+
const cases = [];
|
|
136
|
+
for (let i = 0; i < values.length; i++) {
|
|
137
|
+
for (let j = 0; j < values.length; j++) {
|
|
138
|
+
cases.push(` {.p${i} x, .p${j} y} ${op} r_${i}_${j}`);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
lines.push(cases.join(",\n"));
|
|
142
|
+
lines.push(" };");
|
|
143
|
+
}
|
|
144
|
+
lines.push("perf_ieee = ?params");
|
|
145
|
+
lines.push(" {");
|
|
146
|
+
lines.push(" perf_add add,");
|
|
147
|
+
lines.push(" perf_sub sub,");
|
|
148
|
+
lines.push(" perf_mul mul,");
|
|
149
|
+
lines.push(" perf_div div");
|
|
150
|
+
lines.push(" };");
|
|
151
|
+
return lines.join("\n");
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const perfKSource = generatePerfK(values);
|
|
155
|
+
await evaluateInput(perfKSource, state);
|
|
156
|
+
|
|
157
|
+
const ieeeRaw = fs.readFileSync(ieeePath, "utf8");
|
|
158
|
+
// Exclude trailing unassigned expression and comment block to ensure clean parse
|
|
159
|
+
const ieeeBase = ieeeRaw.split("\n").slice(0, 15584).join("\n");
|
|
160
|
+
const fullSource = `${ieeeBase}\n${perfKSource}\nperf_ieee`;
|
|
161
|
+
|
|
162
|
+
console.log("==> Preparing relation perf_ieee");
|
|
163
|
+
const relation = prepareRelation(state, "perf_ieee", {
|
|
164
|
+
source: fullSource,
|
|
165
|
+
sourceLabel: "@fraczak/k/Examples/ieee.k#perf_ieee"
|
|
166
|
+
});
|
|
167
|
+
codes.load(state.codes);
|
|
168
|
+
|
|
169
|
+
const float64Hash = state.typeAliases.float64;
|
|
170
|
+
function float64(text) {
|
|
171
|
+
return valueForCode(parseFloat64(text), float64Hash, codes.find);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const paramsObj = {};
|
|
175
|
+
for (let i = 0; i < values.length; i++) {
|
|
176
|
+
paramsObj[`p${i}`] = float64(values[i]);
|
|
177
|
+
}
|
|
178
|
+
const rawProduct = Value.product(paramsObj);
|
|
179
|
+
const inputVal = valueForCode(rawProduct, state.typeAliases.params, codes.find);
|
|
180
|
+
const { inputWire, inputPattern } = wireInput(inputVal);
|
|
181
|
+
|
|
182
|
+
console.log("==> Computing expected results via Native JS");
|
|
183
|
+
run_converged.defs = state;
|
|
184
|
+
run.defs = state;
|
|
185
|
+
const expected = run_converged(codes.find, relation.relDef.def, inputVal, relation.relDef.typePatternGraph);
|
|
186
|
+
assert.ok(expected !== undefined, "Failed to compute expected results for perf_ieee");
|
|
187
|
+
const totalOps = ops.length * values.length * values.length;
|
|
188
|
+
|
|
189
|
+
// Setup LLVM
|
|
190
|
+
const llvmCasesByOpt = new Map();
|
|
191
|
+
if (runLLVM) {
|
|
192
|
+
for (const opt of llvmOptLevels) {
|
|
193
|
+
console.log(`==> Compiling LLVM executable (${opt})...`);
|
|
194
|
+
const llvm = tryCompileCase({
|
|
195
|
+
object: relation.object,
|
|
196
|
+
relationName: relation.relationName,
|
|
197
|
+
relHash: relation.relHash,
|
|
198
|
+
inputPattern,
|
|
199
|
+
cacheDir,
|
|
200
|
+
sourceLabel: "@fraczak/k/Examples/ieee.k#perf_ieee",
|
|
201
|
+
runtimeMode: llvmRuntimeMode,
|
|
202
|
+
clangOpt: opt
|
|
203
|
+
});
|
|
204
|
+
const singleCase = [{
|
|
205
|
+
op: "perf_ieee",
|
|
206
|
+
label: "params",
|
|
207
|
+
inputVal,
|
|
208
|
+
inputWire,
|
|
209
|
+
inputPattern,
|
|
210
|
+
expected,
|
|
211
|
+
llvm
|
|
212
|
+
}];
|
|
213
|
+
llvmCasesByOpt.set(opt, singleCase);
|
|
214
|
+
printCompileFailures(singleCase);
|
|
215
|
+
}
|
|
216
|
+
codes.load(state.codes);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// Setup Wasm
|
|
220
|
+
let wasmExports = null;
|
|
221
|
+
let wasmPtrIn = null;
|
|
222
|
+
let wasmOutputPattern = null;
|
|
223
|
+
let wasmOutputPatternPropertyList = null;
|
|
224
|
+
let wasmFuncName = null;
|
|
225
|
+
let wasmExePath = null;
|
|
226
|
+
let wasmCompileError = null;
|
|
227
|
+
|
|
228
|
+
if (runWasm) {
|
|
229
|
+
if (wasmPipe) {
|
|
230
|
+
console.log("==> Compiling WebAssembly executable (persistent runner)...");
|
|
231
|
+
try {
|
|
232
|
+
const wasmPath = path.join(cacheDir, "perf_ieee_wasm.wasm");
|
|
233
|
+
wasmExePath = path.join(cacheDir, "perf_ieee_wasm.exe");
|
|
234
|
+
const wasmBuf = await compileWasmArtifactFromObject(relation.object, {
|
|
235
|
+
entry: "__main__"
|
|
236
|
+
});
|
|
237
|
+
fs.writeFileSync(wasmPath, wasmBuf);
|
|
238
|
+
const runBin = fileURLToPath(import.meta.resolve("../backends/wasm/bin/k-wasm-run.mjs"));
|
|
239
|
+
fs.writeFileSync(wasmExePath, `#!/bin/sh\nexec node "${runBin}" "${wasmPath}" "$@"\n`, { mode: 0o755 });
|
|
240
|
+
} catch (error) {
|
|
241
|
+
wasmCompileError = error.stack || error.message || String(error);
|
|
242
|
+
console.log("WebAssembly compilation failed:");
|
|
243
|
+
console.log(wasmCompileError.split("\n").slice(0, 8).join("\n"));
|
|
244
|
+
}
|
|
245
|
+
} else {
|
|
246
|
+
console.log("==> Compiling WebAssembly module...");
|
|
247
|
+
const wabtInstance = await wabtFactory();
|
|
248
|
+
const wasmModule = await instantiateWasmModule([state.relAliases.perf_ieee], state, wabtInstance);
|
|
249
|
+
wasmExports = wasmModule.exports;
|
|
250
|
+
|
|
251
|
+
const relDef = relation.relDef;
|
|
252
|
+
const graph = relDef.typePatternGraph;
|
|
253
|
+
|
|
254
|
+
const inputPatternNodeId = graph.find(relDef.def.patterns[0]);
|
|
255
|
+
const inputPat = propertyListToPattern(patternToPropertyList(exportPatternGraph(graph, inputPatternNodeId)));
|
|
256
|
+
|
|
257
|
+
const outputPatternNodeId = graph.find(relDef.def.patterns[1]);
|
|
258
|
+
wasmOutputPatternPropertyList = patternToPropertyList(exportPatternGraph(graph, outputPatternNodeId));
|
|
259
|
+
wasmOutputPattern = propertyListToPattern(wasmOutputPatternPropertyList);
|
|
260
|
+
|
|
261
|
+
wasmPtrIn = writeValueToArena(wasmExports, inputVal, inputPat, 0);
|
|
262
|
+
wasmFuncName = cleanName(state.relAliases.perf_ieee);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// Setup ARM64
|
|
267
|
+
let arm64ExePath = null;
|
|
268
|
+
let arm64CompileError = null;
|
|
269
|
+
|
|
270
|
+
if (runARM64) {
|
|
271
|
+
console.log(`==> Compiling Linux ARM64 executable (${arm64OptLevel})...`);
|
|
272
|
+
try {
|
|
273
|
+
arm64ExePath = path.join(cacheDir, "perf_ieee_arm64");
|
|
274
|
+
compileARM64ArtifactFromObject(relation.object, {
|
|
275
|
+
entry: "__main__",
|
|
276
|
+
inputPattern,
|
|
277
|
+
outputPath: arm64ExePath,
|
|
278
|
+
optLevel: arm64OptLevel
|
|
279
|
+
});
|
|
280
|
+
} catch (error) {
|
|
281
|
+
arm64CompileError = error.stack || error.message || String(error);
|
|
282
|
+
console.log("Linux ARM64 compilation failed:");
|
|
283
|
+
console.log(arm64CompileError.split("\n").slice(0, 8).join("\n"));
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
function printBenchmarkDescription() {
|
|
288
|
+
const lanes = [];
|
|
289
|
+
if (runBaselines) {
|
|
290
|
+
lanes.push("Native JS (Envelope-Aware)");
|
|
291
|
+
lanes.push("Native JS (Envelope-Free)");
|
|
292
|
+
lanes.push("kVM Interpreter (Env-Free)");
|
|
293
|
+
}
|
|
294
|
+
if (runLLVM) {
|
|
295
|
+
for (const opt of llvmOptLevels) {
|
|
296
|
+
const mode = llvmLaneName().replace(/^LLVM Executable\\s*\\((.*)\\)$/, "$1");
|
|
297
|
+
lanes.push(llvmOptLevels.length > 1 ? `LLVM ${opt} (${mode})` : llvmLaneName());
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
if (runWasm) lanes.push(wasmLaneName());
|
|
301
|
+
if (runARM64) lanes.push(arm64LaneName(arm64OptLevel));
|
|
302
|
+
|
|
303
|
+
console.log("==> Benchmark description");
|
|
304
|
+
console.log(" source: @fraczak/k/Examples/ieee.k#perf_ieee (single program)");
|
|
305
|
+
console.log(` operations: ${ops.join(", ")}`);
|
|
306
|
+
console.log(` values: ${values.join(", ")}`);
|
|
307
|
+
console.log(` evaluation: 1 program call evaluating all ${totalOps} operations`);
|
|
308
|
+
if (runLLVM) {
|
|
309
|
+
console.log(` llvm warmup iterations: ${llvmWarmupIterations}`);
|
|
310
|
+
console.log(` llvm runtime mode: ${llvmRuntimeMode}`);
|
|
311
|
+
console.log(` llvm clang opts: ${llvmOptLevels.join(", ")}`);
|
|
312
|
+
console.log(` llvm cache dir: ${cacheDir}`);
|
|
313
|
+
}
|
|
314
|
+
if (runWasm) {
|
|
315
|
+
console.log(` wasm runner mode: ${wasmPipe ? "persistent pipe" : "in-process"}`);
|
|
316
|
+
console.log(` wasm warmup iterations: ${wasmWarmupIterations}`);
|
|
317
|
+
if (!wasmPipe) {
|
|
318
|
+
console.log(` wasm arena reset: ${wasmReset ? "yes" : "no"}`);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
if (runARM64) {
|
|
322
|
+
console.log(` arm64 warmup iterations: ${arm64WarmupIterations}`);
|
|
323
|
+
console.log(` arm64 opt level: ${arm64OptLevel}`);
|
|
324
|
+
console.log(` arm64 runner mode: ${process.env.ARM64_SPAWN_PER_CALL === "1" ? "spawn per call" : "persistent"}`);
|
|
325
|
+
}
|
|
326
|
+
console.log(` iterations: ${iterations}`);
|
|
327
|
+
console.log(` benchmark lanes: ${lanes.join("; ")}`);
|
|
328
|
+
console.log(" conformance: all outputs are compared to native expected values");
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
printBenchmarkDescription();
|
|
332
|
+
console.log(`==> Running IEEE Performance Test (1 program call / iteration, Iterations: ${iterations})...`);
|
|
333
|
+
|
|
334
|
+
// 1. Common baseline lanes (only run once!)
|
|
335
|
+
let nativeAwareResult = null;
|
|
336
|
+
let nativeFreeResult = null;
|
|
337
|
+
let kvmFreeResult = null;
|
|
338
|
+
|
|
339
|
+
if (runBaselines) {
|
|
340
|
+
console.log("==> Running Native JS (Envelope-Aware)...");
|
|
341
|
+
nativeAwareResult = runTimedIterations(iterations, () => {
|
|
342
|
+
const res = run(codes.find, relation.relDef.def, inputVal, relation.relDef.typePatternGraph);
|
|
343
|
+
if (res === undefined) throw new Error("Native JS (Envelope-Aware) returned undefined");
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
console.log("==> Running Native JS (Envelope-Free)...");
|
|
347
|
+
nativeFreeResult = runTimedIterations(iterations, () => {
|
|
348
|
+
const res = run_converged(codes.find, relation.relDef.def, inputVal, relation.relDef.typePatternGraph);
|
|
349
|
+
if (res === undefined) throw new Error("Native JS (Envelope-Free) returned undefined");
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
console.log("==> Running kVM Interpreter (Env-Free)...");
|
|
353
|
+
const contextFree = {
|
|
354
|
+
rels: state.rels,
|
|
355
|
+
findCode: codes.find,
|
|
356
|
+
options: { envelopeFree: true }
|
|
357
|
+
};
|
|
358
|
+
kvmFreeResult = runTimedIterations(iterations, () => {
|
|
359
|
+
const res = executeKVM(relation.kvmFunc, inputVal, contextFree);
|
|
360
|
+
if (res === undefined) throw new Error("kVM Interpreter returned undefined");
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
// 2. LLVM lanes
|
|
365
|
+
const llvmResults = new Map();
|
|
366
|
+
if (runLLVM) {
|
|
367
|
+
for (const opt of llvmOptLevels) {
|
|
368
|
+
const casesForOpt = llvmCasesByOpt.get(opt);
|
|
369
|
+
const llvmRunner = createLLVMRunner(casesForOpt);
|
|
370
|
+
try {
|
|
371
|
+
if (llvmWarmupIterations > 0) {
|
|
372
|
+
console.log(`==> Warming LLVM (${opt}) executable (${llvmWarmupIterations} iterations)...`);
|
|
373
|
+
await llvmRunner.run(llvmWarmupIterations);
|
|
374
|
+
}
|
|
375
|
+
console.log(`==> Running LLVM (${opt}) (${iterations} iterations)...`);
|
|
376
|
+
const result = await llvmRunner.run(iterations);
|
|
377
|
+
llvmResults.set(opt, result);
|
|
378
|
+
} finally {
|
|
379
|
+
llvmRunner.close();
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// 3. Wasm lane
|
|
385
|
+
let wasmResult = null;
|
|
386
|
+
if (runWasm) {
|
|
387
|
+
if (wasmPipe) {
|
|
388
|
+
if (wasmExePath) {
|
|
389
|
+
const server = new PersistentExecutable(wasmExePath);
|
|
390
|
+
try {
|
|
391
|
+
if (wasmWarmupIterations > 0) {
|
|
392
|
+
console.log(`==> Warming WebAssembly (${wasmWarmupIterations} iterations)...`);
|
|
393
|
+
for (let i = 0; i < wasmWarmupIterations; i++) {
|
|
394
|
+
await server.request(inputWire);
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
console.log(`==> Running WebAssembly (${iterations} iterations)...`);
|
|
398
|
+
wasmResult = await runTimedIterationsAsync(iterations, async () => {
|
|
399
|
+
await server.request(inputWire);
|
|
400
|
+
});
|
|
401
|
+
} finally {
|
|
402
|
+
server.close();
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
} else {
|
|
406
|
+
if (wasmWarmupIterations > 0) {
|
|
407
|
+
console.log(`==> Warming WebAssembly (${wasmWarmupIterations} iterations)...`);
|
|
408
|
+
for (let i = 0; i < wasmWarmupIterations; i++) {
|
|
409
|
+
const mark = wasmReset ? wasmExports.arena_mark() : 0;
|
|
410
|
+
const res = wasmExports[wasmFuncName](wasmPtrIn);
|
|
411
|
+
assert.ok(res[1] === 1);
|
|
412
|
+
if (wasmReset) wasmExports.arena_reset(mark);
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
console.log(`==> Running WebAssembly (${iterations} iterations)...`);
|
|
417
|
+
wasmResult = runTimedIterations(iterations, () => {
|
|
418
|
+
const mark = wasmReset ? wasmExports.arena_mark() : 0;
|
|
419
|
+
const res = wasmExports[wasmFuncName](wasmPtrIn);
|
|
420
|
+
assert.ok(res[1] === 1);
|
|
421
|
+
if (wasmReset) wasmExports.arena_reset(mark);
|
|
422
|
+
});
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
// 4. Linux ARM64 lane
|
|
427
|
+
let arm64Result = null;
|
|
428
|
+
if (runARM64 && arm64ExePath) {
|
|
429
|
+
const arm64Runner = createARM64Runner([{
|
|
430
|
+
op: "perf_ieee",
|
|
431
|
+
inputWire,
|
|
432
|
+
arm64: { status: "ok", exePath: arm64ExePath }
|
|
433
|
+
}]);
|
|
434
|
+
try {
|
|
435
|
+
if (arm64WarmupIterations > 0) {
|
|
436
|
+
console.log(`==> Warming Linux ARM64 (${arm64WarmupIterations} iterations)...`);
|
|
437
|
+
await arm64Runner.run(arm64WarmupIterations);
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
console.log(`==> Running Linux ARM64 (${iterations} iterations)...`);
|
|
441
|
+
arm64Result = await arm64Runner.run(iterations);
|
|
442
|
+
} finally {
|
|
443
|
+
arm64Runner.close();
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
console.log("\n=================== IEEE BENCHMARK RESULTS ===================");
|
|
448
|
+
console.log(`Program calls per iteration: 1 (${totalOps} IEEE operations evaluated inside)`);
|
|
449
|
+
console.log(`Total requested program calls: ${iterations} (${iterations * totalOps} equivalent IEEE operations)`);
|
|
450
|
+
console.log("--------------------------------------------------------------");
|
|
451
|
+
let laneIndex = 1;
|
|
452
|
+
if (runBaselines) {
|
|
453
|
+
console.log(`${laneIndex++}. Native JS (Envelope-Aware): ${formatTiming(nativeAwareResult)}`);
|
|
454
|
+
console.log(`${laneIndex++}. Native JS (Envelope-Free): ${formatTiming(nativeFreeResult)}`);
|
|
455
|
+
console.log(`${laneIndex++}. kVM Interpreter (Env-Free): ${formatTiming(kvmFreeResult)}`);
|
|
456
|
+
}
|
|
457
|
+
if (runLLVM) {
|
|
458
|
+
for (const opt of llvmOptLevels) {
|
|
459
|
+
const title = llvmOptLevels.length > 1
|
|
460
|
+
? `LLVM ${opt} (${llvmLaneName().replace(/^LLVM Executable\\s*\\((.*)\\)$/, "$1")})`
|
|
461
|
+
: llvmLaneName();
|
|
462
|
+
console.log(`${laneIndex++}. ${title.padEnd(29)} ${formatTiming(llvmResults.get(opt))}`);
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
if (runWasm) {
|
|
466
|
+
const timingStr = wasmResult ? formatTiming(wasmResult) : "compile failed";
|
|
467
|
+
console.log(`${laneIndex++}. ${wasmLaneName().padEnd(29)} ${timingStr}`);
|
|
468
|
+
}
|
|
469
|
+
if (runARM64) {
|
|
470
|
+
const timingStr = arm64Result ? formatTiming(arm64Result) : "compile failed";
|
|
471
|
+
console.log(`${laneIndex++}. ${arm64LaneName(arm64OptLevel).padEnd(29)} ${timingStr}`);
|
|
472
|
+
}
|
|
473
|
+
console.log("==============================================================\n");
|
|
474
|
+
|
|
475
|
+
// Conformance Validation
|
|
476
|
+
let kvmOk = false;
|
|
477
|
+
if (runBaselines) {
|
|
478
|
+
const contextFree = {
|
|
479
|
+
rels: state.rels,
|
|
480
|
+
findCode: codes.find,
|
|
481
|
+
options: { envelopeFree: true }
|
|
482
|
+
};
|
|
483
|
+
const kvmActual = executeKVM(relation.kvmFunc, inputVal, contextFree);
|
|
484
|
+
assert.deepEqual(toPlainObject(kvmActual), toPlainObject(expected));
|
|
485
|
+
kvmOk = true;
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
if (runLLVM) {
|
|
489
|
+
for (const opt of llvmOptLevels) {
|
|
490
|
+
const casesForOpt = llvmCasesByOpt.get(opt);
|
|
491
|
+
const tc = casesForOpt[0];
|
|
492
|
+
if (tc.llvm.status !== "ok") {
|
|
493
|
+
tc.llvmConformance = "compile-failed";
|
|
494
|
+
} else {
|
|
495
|
+
try {
|
|
496
|
+
const outputWire = await runExecutable(tc.llvm.exePath, tc.inputWire);
|
|
497
|
+
const actual = decodeWire(outputWire).value;
|
|
498
|
+
assert.deepEqual(toPlainObject(actual), toPlainObject(expected));
|
|
499
|
+
tc.llvmConformance = "ok";
|
|
500
|
+
} catch (error) {
|
|
501
|
+
tc.llvmConformance = "failed";
|
|
502
|
+
tc.llvm.error = error.stack || error.message || String(error);
|
|
503
|
+
console.log(`LLVM (${opt}) conformance failure:`);
|
|
504
|
+
console.log(tc.llvm.error.split("\n").slice(0, 8).join("\n"));
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
let wasmOk = false;
|
|
511
|
+
if (runWasm) {
|
|
512
|
+
if (wasmPipe) {
|
|
513
|
+
if (!wasmExePath) {
|
|
514
|
+
console.log("Wasm conformance failure: executable was not compiled");
|
|
515
|
+
} else {
|
|
516
|
+
try {
|
|
517
|
+
const outputWire = await runExecutable(wasmExePath, inputWire);
|
|
518
|
+
const actual = decodeWire(outputWire).value;
|
|
519
|
+
assert.deepEqual(toPlainObject(actual), toPlainObject(expected));
|
|
520
|
+
wasmOk = true;
|
|
521
|
+
} catch (error) {
|
|
522
|
+
console.log("Wasm conformance failure:", error.message || error);
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
} else {
|
|
526
|
+
try {
|
|
527
|
+
const mark = wasmReset ? wasmExports.arena_mark() : 0;
|
|
528
|
+
const res = wasmExports[wasmFuncName](wasmPtrIn);
|
|
529
|
+
assert.ok(res[1] === 1, `Wasm function ${wasmFuncName} execution failed`);
|
|
530
|
+
const actual = readArenaValue(
|
|
531
|
+
wasmExports,
|
|
532
|
+
res[0],
|
|
533
|
+
wasmOutputPattern,
|
|
534
|
+
0,
|
|
535
|
+
wasmOutputPatternPropertyList
|
|
536
|
+
);
|
|
537
|
+
if (wasmReset) wasmExports.arena_reset(mark);
|
|
538
|
+
assert.deepEqual(toPlainObject(actual), toPlainObject(expected));
|
|
539
|
+
wasmOk = true;
|
|
540
|
+
} catch (error) {
|
|
541
|
+
console.log("Wasm conformance failure:", error);
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
let arm64Ok = false;
|
|
547
|
+
if (runARM64) {
|
|
548
|
+
if (!arm64ExePath) {
|
|
549
|
+
console.log("Linux ARM64 conformance failure: executable was not compiled");
|
|
550
|
+
} else {
|
|
551
|
+
try {
|
|
552
|
+
const outputWire = await runExecutable(arm64ExePath, inputWire);
|
|
553
|
+
const actual = decodeWire(outputWire).value;
|
|
554
|
+
assert.deepEqual(toPlainObject(actual), toPlainObject(expected));
|
|
555
|
+
arm64Ok = true;
|
|
556
|
+
} catch (error) {
|
|
557
|
+
console.log("Linux ARM64 conformance failure:", error.message || error);
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
const validationSummary = [];
|
|
563
|
+
if (runBaselines && kvmOk) validationSummary.push(`kVM (all ${totalOps} ops)`);
|
|
564
|
+
if (runLLVM) {
|
|
565
|
+
for (const opt of llvmOptLevels) {
|
|
566
|
+
const casesForOpt = llvmCasesByOpt.get(opt);
|
|
567
|
+
const tc = casesForOpt[0];
|
|
568
|
+
validationSummary.push(`LLVM ${opt} (${tc.llvmConformance === "ok" ? `all ${totalOps} ops` : tc.llvmConformance})`);
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
if (runWasm) {
|
|
572
|
+
validationSummary.push(`Wasm (${wasmOk ? `all ${totalOps} ops` : "failed"})`);
|
|
573
|
+
}
|
|
574
|
+
if (runARM64) {
|
|
575
|
+
validationSummary.push(`Linux ARM64 (${arm64Ok ? `all ${totalOps} ops` : "failed"})`);
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
console.log(`Conformance validation: ${validationSummary.join(", ")} match expected values.`);
|
|
579
|
+
if (runLLVM) {
|
|
580
|
+
for (const opt of llvmOptLevels) {
|
|
581
|
+
const casesForOpt = llvmCasesByOpt.get(opt);
|
|
582
|
+
if (shouldStrictFail(casesForOpt)) process.exitCode = 1;
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
if (runWasm && !wasmOk) process.exitCode = 1;
|
|
586
|
+
if (runARM64 && !arm64Ok) process.exitCode = 1;
|