wardite 0.8.1 → 0.9.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.
- checksums.yaml +4 -4
- data/Rakefile +23 -0
- data/examples/i32_bench.html +482 -0
- data/examples/i32_bench.wat +137 -0
- data/examples/i32_bench_original.wat +314 -0
- data/examples/load_perf.rb +24 -0
- data/lib/wardite/alu_f32.generated.rb +12 -10
- data/lib/wardite/alu_f64.generated.rb +12 -10
- data/lib/wardite/alu_i32.generated.rb +24 -22
- data/lib/wardite/alu_i64.generated.rb +30 -28
- data/lib/wardite/cli/cli.rb +22 -0
- data/lib/wardite/convert.generated.rb +7 -5
- data/lib/wardite/instruction.rb +424 -64
- data/lib/wardite/leb128.rb +3 -6
- data/lib/wardite/load.rb +65 -26
- data/lib/wardite/revisitor.rb +12 -4
- data/lib/wardite/version.rb +1 -1
- data/lib/wardite.rb +53 -36
- data/rbs_collection.lock.yaml +24 -20
- data/scripts/gen_alu.rb +24 -24
- data/scripts/templates/alu_module.rb.tmpl +7 -5
- data/scripts/templates/conv_module.rb.tmpl +7 -5
- data/sig/generated/wardite/alu_f32.generated.rbs +4 -3
- data/sig/generated/wardite/alu_f64.generated.rbs +4 -3
- data/sig/generated/wardite/alu_i32.generated.rbs +4 -3
- data/sig/generated/wardite/alu_i64.generated.rbs +4 -3
- data/sig/generated/wardite/cli/cli.rbs +5 -0
- data/sig/generated/wardite/convert.generated.rbs +4 -3
- data/sig/generated/wardite/instruction.rbs +13 -9
- data/sig/generated/wardite/load.rbs +9 -9
- data/sig/generated/wardite.rbs +11 -7
- data/sig/vernier.rbs +3 -0
- metadata +8 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ed01a146affa721cec03c8751baded66418e2f62d6b42a878c6a8a60d8bdf270
|
4
|
+
data.tar.gz: 84fdcdfb8127d32a40f95f629065b6ce9c65f30e9f79c854003b9de05ee45b14
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 538b3e0a4b50fc5b4e109a39d1c243a5751d877859d1fe9942e8e5e52633ecf62ba55b2a99b0ffd80102c3b5cb7de258c8d0e878a8738b0bced8d4c9823e4052
|
7
|
+
data.tar.gz: 343459f70f34ebe76916058adc10d4db338d2594a39c4dca364fa8387b6c72393939e827517364965a8da14cf64ebf129198c9dbcfab9cf89dc0f17c766a752a
|
data/Rakefile
CHANGED
@@ -22,6 +22,29 @@ task :wasm, [:name] do |t, args|
|
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
25
|
+
desc "Run the official spec"
|
26
|
+
task :spec, [:name] do |t, args|
|
27
|
+
sh "which git && git clean -xf spec/ || true"
|
28
|
+
|
29
|
+
Dir.chdir "spec" do
|
30
|
+
sh "curl -L -o ./#{args.name}.wast https://raw.githubusercontent.com/WebAssembly/spec/refs/tags/wg-1.0/test/core/#{args.name}.wast"
|
31
|
+
sh "wast2json ./#{args.name}.wast"
|
32
|
+
sh "env JSON_PATH=./#{args.name}.json ruby ./runner.rb -v"
|
33
|
+
|
34
|
+
if File.exist?("./skip.txt")
|
35
|
+
puts
|
36
|
+
puts "\e[1;36mSkipped tests:\e[0m"
|
37
|
+
puts IO.read("./skip.txt")
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
desc "Run basic benchmark"
|
43
|
+
task :basic_benchmark do
|
44
|
+
sh "wasm-tools parse examples/i32_bench.wat -o examples/i32_bench.wasm"
|
45
|
+
sh "hyperfine --warmup 3 'bundle exec wardite --yjit --no-wasi --invoke detailed_arithmetic_loop examples/i32_bench.wasm'"
|
46
|
+
end
|
47
|
+
|
25
48
|
desc "Generate codes"
|
26
49
|
task :generate do
|
27
50
|
require_relative "scripts/gen_alu"
|
@@ -0,0 +1,482 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html lang="en">
|
3
|
+
<head>
|
4
|
+
<meta charset="UTF-8">
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
6
|
+
<title>WebAssembly Performance Test</title>
|
7
|
+
<style>
|
8
|
+
body {
|
9
|
+
font-family: 'Arial', sans-serif;
|
10
|
+
max-width: 1200px;
|
11
|
+
margin: 0 auto;
|
12
|
+
padding: 20px;
|
13
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
14
|
+
color: white;
|
15
|
+
min-height: 100vh;
|
16
|
+
}
|
17
|
+
|
18
|
+
.container {
|
19
|
+
background: rgba(255, 255, 255, 0.1);
|
20
|
+
border-radius: 15px;
|
21
|
+
padding: 30px;
|
22
|
+
backdrop-filter: blur(10px);
|
23
|
+
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
|
24
|
+
}
|
25
|
+
|
26
|
+
h1 {
|
27
|
+
text-align: center;
|
28
|
+
margin-bottom: 30px;
|
29
|
+
font-size: 2.5em;
|
30
|
+
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
|
31
|
+
}
|
32
|
+
|
33
|
+
.controls {
|
34
|
+
display: flex;
|
35
|
+
gap: 15px;
|
36
|
+
margin-bottom: 30px;
|
37
|
+
flex-wrap: wrap;
|
38
|
+
justify-content: center;
|
39
|
+
}
|
40
|
+
|
41
|
+
button {
|
42
|
+
padding: 12px 24px;
|
43
|
+
font-size: 16px;
|
44
|
+
border: none;
|
45
|
+
border-radius: 8px;
|
46
|
+
cursor: pointer;
|
47
|
+
background: linear-gradient(45deg, #ff6b6b, #ee5a24);
|
48
|
+
color: white;
|
49
|
+
font-weight: bold;
|
50
|
+
transition: all 0.3s ease;
|
51
|
+
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
|
52
|
+
}
|
53
|
+
|
54
|
+
button:hover {
|
55
|
+
transform: translateY(-2px);
|
56
|
+
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.3);
|
57
|
+
}
|
58
|
+
|
59
|
+
button:disabled {
|
60
|
+
background: #666;
|
61
|
+
cursor: not-allowed;
|
62
|
+
transform: none;
|
63
|
+
}
|
64
|
+
|
65
|
+
#fileInput {
|
66
|
+
padding: 8px;
|
67
|
+
border-radius: 5px;
|
68
|
+
border: 2px solid rgba(255, 255, 255, 0.3);
|
69
|
+
background: rgba(255, 255, 255, 0.1);
|
70
|
+
color: white;
|
71
|
+
}
|
72
|
+
|
73
|
+
.results {
|
74
|
+
display: grid;
|
75
|
+
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
76
|
+
gap: 20px;
|
77
|
+
margin-top: 30px;
|
78
|
+
}
|
79
|
+
|
80
|
+
.result-card {
|
81
|
+
background: rgba(255, 255, 255, 0.15);
|
82
|
+
padding: 20px;
|
83
|
+
border-radius: 10px;
|
84
|
+
border: 1px solid rgba(255, 255, 255, 0.2);
|
85
|
+
}
|
86
|
+
|
87
|
+
.result-card h3 {
|
88
|
+
margin-top: 0;
|
89
|
+
color: #ffd700;
|
90
|
+
font-size: 1.2em;
|
91
|
+
}
|
92
|
+
|
93
|
+
.metric {
|
94
|
+
display: flex;
|
95
|
+
justify-content: space-between;
|
96
|
+
margin: 10px 0;
|
97
|
+
padding: 5px 0;
|
98
|
+
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
|
99
|
+
}
|
100
|
+
|
101
|
+
.metric:last-child {
|
102
|
+
border-bottom: none;
|
103
|
+
}
|
104
|
+
|
105
|
+
.value {
|
106
|
+
font-weight: bold;
|
107
|
+
color: #90ee90;
|
108
|
+
}
|
109
|
+
|
110
|
+
.status {
|
111
|
+
text-align: center;
|
112
|
+
padding: 15px;
|
113
|
+
margin: 15px 0;
|
114
|
+
border-radius: 8px;
|
115
|
+
font-weight: bold;
|
116
|
+
}
|
117
|
+
|
118
|
+
.status.loading {
|
119
|
+
background: rgba(255, 193, 7, 0.3);
|
120
|
+
color: #ffc107;
|
121
|
+
}
|
122
|
+
|
123
|
+
.status.success {
|
124
|
+
background: rgba(40, 167, 69, 0.3);
|
125
|
+
color: #28a745;
|
126
|
+
}
|
127
|
+
|
128
|
+
.status.error {
|
129
|
+
background: rgba(220, 53, 69, 0.3);
|
130
|
+
color: #dc3545;
|
131
|
+
}
|
132
|
+
|
133
|
+
.comparison {
|
134
|
+
margin-top: 30px;
|
135
|
+
padding: 20px;
|
136
|
+
background: rgba(255, 255, 255, 0.1);
|
137
|
+
border-radius: 10px;
|
138
|
+
}
|
139
|
+
|
140
|
+
.progress-bar {
|
141
|
+
width: 100%;
|
142
|
+
height: 8px;
|
143
|
+
background: rgba(255, 255, 255, 0.2);
|
144
|
+
border-radius: 4px;
|
145
|
+
overflow: hidden;
|
146
|
+
margin: 10px 0;
|
147
|
+
}
|
148
|
+
|
149
|
+
.progress-fill {
|
150
|
+
height: 100%;
|
151
|
+
background: linear-gradient(90deg, #00d4ff, #090979);
|
152
|
+
width: 0%;
|
153
|
+
transition: width 0.3s ease;
|
154
|
+
}
|
155
|
+
</style>
|
156
|
+
</head>
|
157
|
+
<body>
|
158
|
+
<div class="container">
|
159
|
+
<h1>🚀 WebAssembly Performance Test</h1>
|
160
|
+
|
161
|
+
<div class="controls">
|
162
|
+
<input type="file" id="fileInput" accept=".wasm" />
|
163
|
+
<button id="loadBtn">Load WASM File</button>
|
164
|
+
<button id="runAllBtn" disabled>Run All Tests</button>
|
165
|
+
<button id="runSingleBtn" disabled>Single Test</button>
|
166
|
+
<button id="compareBtn" disabled>JS Comparison Test</button>
|
167
|
+
</div>
|
168
|
+
|
169
|
+
<div id="status" class="status loading" style="display: none;">
|
170
|
+
Preparing...
|
171
|
+
</div>
|
172
|
+
|
173
|
+
<div class="progress-bar" id="progressContainer" style="display: none;">
|
174
|
+
<div class="progress-fill" id="progressFill"></div>
|
175
|
+
</div>
|
176
|
+
|
177
|
+
<div class="results" id="results"></div>
|
178
|
+
|
179
|
+
<div class="comparison" id="comparison" style="display: none;">
|
180
|
+
<h3>📊 Performance Comparison</h3>
|
181
|
+
<div id="comparisonContent"></div>
|
182
|
+
</div>
|
183
|
+
</div>
|
184
|
+
|
185
|
+
<script>
|
186
|
+
let wasmModule = null;
|
187
|
+
|
188
|
+
// Get DOM elements
|
189
|
+
const fileInput = document.getElementById('fileInput');
|
190
|
+
const loadBtn = document.getElementById('loadBtn');
|
191
|
+
const runAllBtn = document.getElementById('runAllBtn');
|
192
|
+
const runSingleBtn = document.getElementById('runSingleBtn');
|
193
|
+
const compareBtn = document.getElementById('compareBtn');
|
194
|
+
const status = document.getElementById('status');
|
195
|
+
const results = document.getElementById('results');
|
196
|
+
const comparison = document.getElementById('comparison');
|
197
|
+
const comparisonContent = document.getElementById('comparisonContent');
|
198
|
+
const progressContainer = document.getElementById('progressContainer');
|
199
|
+
const progressFill = document.getElementById('progressFill');
|
200
|
+
|
201
|
+
// Status display function
|
202
|
+
function showStatus(message, type = 'loading') {
|
203
|
+
status.textContent = message;
|
204
|
+
status.className = `status ${type}`;
|
205
|
+
status.style.display = 'block';
|
206
|
+
}
|
207
|
+
|
208
|
+
function hideStatus() {
|
209
|
+
status.style.display = 'none';
|
210
|
+
}
|
211
|
+
|
212
|
+
// Progress bar update
|
213
|
+
function updateProgress(percent) {
|
214
|
+
progressFill.style.width = `${percent}%`;
|
215
|
+
}
|
216
|
+
|
217
|
+
function showProgress() {
|
218
|
+
progressContainer.style.display = 'block';
|
219
|
+
}
|
220
|
+
|
221
|
+
function hideProgress() {
|
222
|
+
progressContainer.style.display = 'none';
|
223
|
+
}
|
224
|
+
|
225
|
+
// Load WASM file
|
226
|
+
async function loadWasmFile(file) {
|
227
|
+
try {
|
228
|
+
showStatus('Loading WASM file...', 'loading');
|
229
|
+
|
230
|
+
const arrayBuffer = await file.arrayBuffer();
|
231
|
+
const wasmInstance = await WebAssembly.instantiate(arrayBuffer);
|
232
|
+
|
233
|
+
wasmModule = wasmInstance.instance;
|
234
|
+
|
235
|
+
showStatus('WASM file loaded successfully!', 'success');
|
236
|
+
|
237
|
+
// Enable buttons
|
238
|
+
runAllBtn.disabled = false;
|
239
|
+
runSingleBtn.disabled = false;
|
240
|
+
compareBtn.disabled = false;
|
241
|
+
|
242
|
+
setTimeout(hideStatus, 2000);
|
243
|
+
|
244
|
+
} catch (error) {
|
245
|
+
console.error('WASM loading error:', error);
|
246
|
+
showStatus(`Error: ${error.message}`, 'error');
|
247
|
+
}
|
248
|
+
}
|
249
|
+
|
250
|
+
// Execute performance test
|
251
|
+
function runPerformanceTest(testName, testFunction, iterations = 5) {
|
252
|
+
const times = [];
|
253
|
+
let result = null;
|
254
|
+
|
255
|
+
for (let i = 0; i < iterations; i++) {
|
256
|
+
const startTime = performance.now();
|
257
|
+
result = testFunction();
|
258
|
+
const endTime = performance.now();
|
259
|
+
times.push(endTime - startTime);
|
260
|
+
}
|
261
|
+
|
262
|
+
const avgTime = times.reduce((a, b) => a + b, 0) / times.length;
|
263
|
+
const minTime = Math.min(...times);
|
264
|
+
const maxTime = Math.max(...times);
|
265
|
+
|
266
|
+
return {
|
267
|
+
name: testName,
|
268
|
+
result: result,
|
269
|
+
avgTime: avgTime,
|
270
|
+
minTime: minTime,
|
271
|
+
maxTime: maxTime,
|
272
|
+
times: times
|
273
|
+
};
|
274
|
+
}
|
275
|
+
|
276
|
+
// Display results
|
277
|
+
function displayResult(testResult) {
|
278
|
+
const card = document.createElement('div');
|
279
|
+
card.className = 'result-card';
|
280
|
+
|
281
|
+
card.innerHTML = `
|
282
|
+
<h3>${testResult.name}</h3>
|
283
|
+
<div class="metric">
|
284
|
+
<span>Result Value:</span>
|
285
|
+
<span class="value">${testResult.result.toLocaleString()}</span>
|
286
|
+
</div>
|
287
|
+
<div class="metric">
|
288
|
+
<span>Average Execution Time:</span>
|
289
|
+
<span class="value">${testResult.avgTime.toFixed(3)} ms</span>
|
290
|
+
</div>
|
291
|
+
<div class="metric">
|
292
|
+
<span>Minimum Time:</span>
|
293
|
+
<span class="value">${testResult.minTime.toFixed(3)} ms</span>
|
294
|
+
</div>
|
295
|
+
<div class="metric">
|
296
|
+
<span>Maximum Time:</span>
|
297
|
+
<span class="value">${testResult.maxTime.toFixed(3)} ms</span>
|
298
|
+
</div>
|
299
|
+
<div class="metric">
|
300
|
+
<span>Number of Executions:</span>
|
301
|
+
<span class="value">${testResult.times.length} times</span>
|
302
|
+
</div>
|
303
|
+
`;
|
304
|
+
|
305
|
+
results.appendChild(card);
|
306
|
+
}
|
307
|
+
|
308
|
+
// JavaScript version of detailed arithmetic (for comparison)
|
309
|
+
function jsDetailedArithmetic(x, y) {
|
310
|
+
const sum = x + y;
|
311
|
+
const diff = x - y;
|
312
|
+
const product = x * y;
|
313
|
+
const quotient = y !== 0 ? Math.floor(x / y) : 0;
|
314
|
+
return sum + diff + product + quotient;
|
315
|
+
}
|
316
|
+
|
317
|
+
function jsDetailedArithmeticLoop() {
|
318
|
+
let totalResult = 0;
|
319
|
+
let x = 5;
|
320
|
+
let y = 2;
|
321
|
+
|
322
|
+
for (let i = 0; i < 100000; i++) {
|
323
|
+
const currentResult = jsDetailedArithmetic(x, y);
|
324
|
+
totalResult += currentResult;
|
325
|
+
|
326
|
+
x += 1;
|
327
|
+
y = (y * 2) % 17 + 1;
|
328
|
+
|
329
|
+
if (x > 1000) {
|
330
|
+
x = 1;
|
331
|
+
}
|
332
|
+
}
|
333
|
+
|
334
|
+
return totalResult;
|
335
|
+
}
|
336
|
+
|
337
|
+
// Run all tests
|
338
|
+
async function runAllTests() {
|
339
|
+
if (!wasmModule) return;
|
340
|
+
|
341
|
+
results.innerHTML = '';
|
342
|
+
showStatus('Running all tests...', 'loading');
|
343
|
+
showProgress();
|
344
|
+
|
345
|
+
const tests = [
|
346
|
+
{
|
347
|
+
name: '🔄 Basic 4-Operation Loop (10000 times)',
|
348
|
+
func: () => wasmModule.exports.arithmetic_loop()
|
349
|
+
},
|
350
|
+
{
|
351
|
+
name: '📊 Detailed Arithmetic Loop',
|
352
|
+
func: () => wasmModule.exports.detailed_arithmetic_loop()
|
353
|
+
},
|
354
|
+
{
|
355
|
+
name: '🎯 Complex Pattern Arithmetic Loop',
|
356
|
+
func: () => wasmModule.exports.detailed_arithmetic_complex_loop()
|
357
|
+
},
|
358
|
+
{
|
359
|
+
name: '🧮 Single Detailed Arithmetic (100, 7)',
|
360
|
+
func: () => wasmModule.exports.detailed_arithmetic(100, 7)
|
361
|
+
}
|
362
|
+
];
|
363
|
+
|
364
|
+
for (let i = 0; i < tests.length; i++) {
|
365
|
+
updateProgress((i / tests.length) * 100);
|
366
|
+
|
367
|
+
const testResult = runPerformanceTest(tests[i].name, tests[i].func, 10);
|
368
|
+
displayResult(testResult);
|
369
|
+
|
370
|
+
// Wait a bit to update UI
|
371
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
372
|
+
}
|
373
|
+
|
374
|
+
updateProgress(100);
|
375
|
+
showStatus('All tests completed!', 'success');
|
376
|
+
|
377
|
+
setTimeout(() => {
|
378
|
+
hideStatus();
|
379
|
+
hideProgress();
|
380
|
+
}, 2000);
|
381
|
+
}
|
382
|
+
|
383
|
+
// Run comparison test
|
384
|
+
async function runComparisonTest() {
|
385
|
+
if (!wasmModule) return;
|
386
|
+
|
387
|
+
showStatus('Running WebAssembly vs JavaScript comparison test...', 'loading');
|
388
|
+
showProgress();
|
389
|
+
|
390
|
+
updateProgress(25);
|
391
|
+
const wasmResult = runPerformanceTest('WebAssembly Version',
|
392
|
+
() => wasmModule.exports.detailed_arithmetic_loop(), 10);
|
393
|
+
|
394
|
+
updateProgress(75);
|
395
|
+
const jsResult = runPerformanceTest('JavaScript Version',
|
396
|
+
jsDetailedArithmeticLoop, 10);
|
397
|
+
|
398
|
+
updateProgress(100);
|
399
|
+
|
400
|
+
// Display comparison results
|
401
|
+
const speedup = jsResult.avgTime / wasmResult.avgTime;
|
402
|
+
const resultMatch = wasmResult.result === jsResult.result;
|
403
|
+
|
404
|
+
comparisonContent.innerHTML = `
|
405
|
+
<div class="metric">
|
406
|
+
<span>WebAssembly Average Time:</span>
|
407
|
+
<span class="value">${wasmResult.avgTime.toFixed(3)} ms</span>
|
408
|
+
</div>
|
409
|
+
<div class="metric">
|
410
|
+
<span>JavaScript Average Time:</span>
|
411
|
+
<span class="value">${jsResult.avgTime.toFixed(3)} ms</span>
|
412
|
+
</div>
|
413
|
+
<div class="metric">
|
414
|
+
<span>Speed Improvement:</span>
|
415
|
+
<span class="value">${speedup.toFixed(2)}x ${speedup > 1 ? 'faster' : 'slower'}</span>
|
416
|
+
</div>
|
417
|
+
<div class="metric">
|
418
|
+
<span>Result Match:</span>
|
419
|
+
<span class="value" style="color: ${resultMatch ? '#90ee90' : '#ff6b6b'}">
|
420
|
+
${resultMatch ? '✅ Match' : '❌ Mismatch'}
|
421
|
+
</span>
|
422
|
+
</div>
|
423
|
+
<div class="metric">
|
424
|
+
<span>WASM Result Value:</span>
|
425
|
+
<span class="value">${wasmResult.result.toLocaleString()}</span>
|
426
|
+
</div>
|
427
|
+
<div class="metric">
|
428
|
+
<span>JS Result Value:</span>
|
429
|
+
<span class="value">${jsResult.result.toLocaleString()}</span>
|
430
|
+
</div>
|
431
|
+
`;
|
432
|
+
|
433
|
+
comparison.style.display = 'block';
|
434
|
+
|
435
|
+
showStatus('Comparison test completed!', 'success');
|
436
|
+
|
437
|
+
setTimeout(() => {
|
438
|
+
hideStatus();
|
439
|
+
hideProgress();
|
440
|
+
}, 2000);
|
441
|
+
}
|
442
|
+
|
443
|
+
// Event listeners
|
444
|
+
loadBtn.addEventListener('click', () => {
|
445
|
+
const file = fileInput.files[0];
|
446
|
+
if (file) {
|
447
|
+
loadWasmFile(file);
|
448
|
+
} else {
|
449
|
+
showStatus('Please select a WASM file', 'error');
|
450
|
+
setTimeout(hideStatus, 2000);
|
451
|
+
}
|
452
|
+
});
|
453
|
+
|
454
|
+
runAllBtn.addEventListener('click', runAllTests);
|
455
|
+
runSingleBtn.addEventListener('click', () => {
|
456
|
+
if (!wasmModule) return;
|
457
|
+
results.innerHTML = '';
|
458
|
+
const testResult = runPerformanceTest('🎯 Single Test',
|
459
|
+
() => wasmModule.exports.detailed_arithmetic_loop(), 1);
|
460
|
+
displayResult(testResult);
|
461
|
+
});
|
462
|
+
compareBtn.addEventListener('click', runComparisonTest);
|
463
|
+
|
464
|
+
// File drag & drop support
|
465
|
+
document.addEventListener('dragover', (e) => {
|
466
|
+
e.preventDefault();
|
467
|
+
});
|
468
|
+
|
469
|
+
document.addEventListener('drop', (e) => {
|
470
|
+
e.preventDefault();
|
471
|
+
const file = e.dataTransfer.files[0];
|
472
|
+
if (file && file.name.endsWith('.wasm')) {
|
473
|
+
fileInput.files = e.dataTransfer.files;
|
474
|
+
loadWasmFile(file);
|
475
|
+
}
|
476
|
+
});
|
477
|
+
|
478
|
+
console.log('WebAssembly Performance Test Tool ready!');
|
479
|
+
console.log('Please select and load your bench.wasm file.');
|
480
|
+
</script>
|
481
|
+
</body>
|
482
|
+
</html>
|
@@ -0,0 +1,137 @@
|
|
1
|
+
(module
|
2
|
+
;; Detailed 4-operation arithmetic function (execute each operation individually)
|
3
|
+
(func $detailed_arithmetic (export "detailed_arithmetic") (param $x i32) (param $y i32) (result i32)
|
4
|
+
(local $sum i32)
|
5
|
+
(local $diff i32)
|
6
|
+
(local $product i32)
|
7
|
+
(local $quotient i32)
|
8
|
+
(local $final_result i32)
|
9
|
+
|
10
|
+
;; Addition
|
11
|
+
local.get $x
|
12
|
+
local.get $y
|
13
|
+
i32.add
|
14
|
+
local.set $sum
|
15
|
+
|
16
|
+
;; Subtraction
|
17
|
+
local.get $x
|
18
|
+
local.get $y
|
19
|
+
i32.sub
|
20
|
+
local.set $diff
|
21
|
+
|
22
|
+
;; Multiplication
|
23
|
+
local.get $x
|
24
|
+
local.get $y
|
25
|
+
i32.mul
|
26
|
+
local.set $product
|
27
|
+
|
28
|
+
;; Division (with zero division check)
|
29
|
+
local.get $y
|
30
|
+
i32.const 0
|
31
|
+
i32.eq
|
32
|
+
(if
|
33
|
+
(then
|
34
|
+
i32.const 0
|
35
|
+
local.set $quotient
|
36
|
+
)
|
37
|
+
(else
|
38
|
+
local.get $x
|
39
|
+
local.get $y
|
40
|
+
i32.div_s
|
41
|
+
local.set $quotient
|
42
|
+
)
|
43
|
+
)
|
44
|
+
|
45
|
+
;; Sum all results
|
46
|
+
local.get $sum
|
47
|
+
local.get $diff
|
48
|
+
i32.add
|
49
|
+
local.get $product
|
50
|
+
i32.add
|
51
|
+
local.get $quotient
|
52
|
+
i32.add
|
53
|
+
local.set $final_result
|
54
|
+
|
55
|
+
local.get $final_result
|
56
|
+
)
|
57
|
+
|
58
|
+
;; Execute detailed_arithmetic with changing numbers 10000 times
|
59
|
+
(func $detailed_arithmetic_loop (export "detailed_arithmetic_loop") (result i32)
|
60
|
+
(local $i i32) ;; Loop counter
|
61
|
+
(local $x i32) ;; First argument
|
62
|
+
(local $y i32) ;; Second argument
|
63
|
+
(local $total_result i32) ;; Accumulated result
|
64
|
+
(local $current_result i32) ;; Current arithmetic result
|
65
|
+
|
66
|
+
;; Initialize values
|
67
|
+
i32.const 0
|
68
|
+
local.set $i ;; i = 0
|
69
|
+
|
70
|
+
i32.const 5
|
71
|
+
local.set $x ;; x = 5 (initial value)
|
72
|
+
|
73
|
+
i32.const 2
|
74
|
+
local.set $y ;; y = 2 (initial value)
|
75
|
+
|
76
|
+
i32.const 0
|
77
|
+
local.set $total_result ;; total_result = 0
|
78
|
+
|
79
|
+
;; Start loop
|
80
|
+
(loop $detailed_loop
|
81
|
+
;; Call detailed_arithmetic function
|
82
|
+
local.get $x
|
83
|
+
local.get $y
|
84
|
+
call $detailed_arithmetic
|
85
|
+
local.set $current_result
|
86
|
+
|
87
|
+
;; Accumulate result
|
88
|
+
local.get $total_result
|
89
|
+
local.get $current_result
|
90
|
+
i32.add
|
91
|
+
local.set $total_result
|
92
|
+
|
93
|
+
;; Change x and y values (add variation)
|
94
|
+
;; x = x + 1
|
95
|
+
local.get $x
|
96
|
+
i32.const 1
|
97
|
+
i32.add
|
98
|
+
local.set $x
|
99
|
+
|
100
|
+
;; y = (y * 2) % 17 + 1 (cycle in range 1-17, avoid zero division)
|
101
|
+
local.get $y
|
102
|
+
i32.const 2
|
103
|
+
i32.mul
|
104
|
+
i32.const 17
|
105
|
+
i32.rem_s
|
106
|
+
i32.const 1
|
107
|
+
i32.add
|
108
|
+
local.set $y
|
109
|
+
|
110
|
+
;; Limit x to prevent overflow (overflow protection)
|
111
|
+
local.get $x
|
112
|
+
i32.const 1000
|
113
|
+
i32.gt_s
|
114
|
+
(if
|
115
|
+
(then
|
116
|
+
i32.const 1
|
117
|
+
local.set $x
|
118
|
+
)
|
119
|
+
)
|
120
|
+
|
121
|
+
;; Increment counter
|
122
|
+
local.get $i
|
123
|
+
i32.const 1
|
124
|
+
i32.add
|
125
|
+
local.set $i
|
126
|
+
|
127
|
+
;; Check loop continuation condition (i < 100000)
|
128
|
+
local.get $i
|
129
|
+
i32.const 100000
|
130
|
+
i32.lt_s
|
131
|
+
br_if $detailed_loop
|
132
|
+
)
|
133
|
+
|
134
|
+
;; Return accumulated result
|
135
|
+
local.get $total_result
|
136
|
+
)
|
137
|
+
)
|