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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b6ed5daed5c5abae915387734fb0d00b7da8d824de1b7f6de5f5d6a19e422daa
4
- data.tar.gz: f3299bc55ab918c9b01a9251a5c2f0c94ee23d01bb2b5838c6a48c06c221579c
3
+ metadata.gz: ed01a146affa721cec03c8751baded66418e2f62d6b42a878c6a8a60d8bdf270
4
+ data.tar.gz: 84fdcdfb8127d32a40f95f629065b6ce9c65f30e9f79c854003b9de05ee45b14
5
5
  SHA512:
6
- metadata.gz: b4dd3cf8d61266fe8a106f5aacabf5663bede6ea7eee83d18f7fedf3d599cb080e4b80bccb973fc39dc107100b57052d8c34d7d9a0d5c5b7862ba32834cf04bc
7
- data.tar.gz: 84a45746ca727e3f552e6bd389fe0a046dc76fb7afc7617a9214472cda3ca1a0eb5c1f087a644dcb65518f71825a778a611bc44d8108534df870b88996a3996c
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
+ )