Timing results
Looks like WebAssembly in Chromium is about 35% faster, but the Javascript engine in Firefox is another 59% faster
This commit is contained in:
parent
7a8b1baa25
commit
f683961af8
@ -6,10 +6,84 @@
|
|||||||
<body>
|
<body>
|
||||||
<h1>Buffer</h1>
|
<h1>Buffer</h1>
|
||||||
|
|
||||||
<a href="index.html">List</a> - <a href="crc32.py.html">Source</a> - <a href="crc32.wat.html">WebAssembly</a>
|
<a href="index.html">List</a> - <a href="crc32.py.html">Source</a> - <a href="crc32.wat.html">WebAssembly</a><br />
|
||||||
|
<br />
|
||||||
|
Note: This tests performs some timing comparison, please wait a few seconds for the results.<br />
|
||||||
<div style="white-space: pre;" id="results"></div>
|
<div style="white-space: pre;" id="results"></div>
|
||||||
|
|
||||||
|
<h2>Measurement log</h2>
|
||||||
|
<h3>AMD Ryzen 7 3700X 8-Core, Ubuntu 20.04, Linux 5.4.0-124-generic</h3>
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td>Test</td>
|
||||||
|
<td>Interpreter</td>
|
||||||
|
<td>Setup</td>
|
||||||
|
<td>WebAssembly</td>
|
||||||
|
<td>Javascript</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Lynx * 65536</td>
|
||||||
|
<td>Chromium 104.0.5112.101</td>
|
||||||
|
<td>DevTools closed</td>
|
||||||
|
<td>9.35</td>
|
||||||
|
<td>12.56</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Lynx * 65536</td>
|
||||||
|
<td>Chromium 104.0.5112.101</td>
|
||||||
|
<td>DevTools open</td>
|
||||||
|
<td>14.71</td>
|
||||||
|
<td>12.72</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Lynx * 65536</td>
|
||||||
|
<td>Chromium 104.0.5112.101</td>
|
||||||
|
<td>Record page load</td>
|
||||||
|
<td>9.44</td>
|
||||||
|
<td>12.69</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Lynx * 65536</td>
|
||||||
|
<td>Firefox 103</td>
|
||||||
|
<td>DevTools closed</td>
|
||||||
|
<td>9.02</td>
|
||||||
|
<td>5.86</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Lynx * 65536</td>
|
||||||
|
<td>Firefox 103</td>
|
||||||
|
<td>DevTools open</td>
|
||||||
|
<td>9.01</td>
|
||||||
|
<td>5.83</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Lynx * 65536</td>
|
||||||
|
<td>Firefox 103</td>
|
||||||
|
<td>Record page load</td>
|
||||||
|
<td>72.41</td>
|
||||||
|
<td>5.85</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>Lynx * 1048576</td>
|
||||||
|
<td>Chromium 104.0.5112.101</td>
|
||||||
|
<td>DevTools closed</td>
|
||||||
|
<td>149.24</td>
|
||||||
|
<td>202.36</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Lynx * 1048576</td>
|
||||||
|
<td>Firefox 103</td>
|
||||||
|
<td>DevTools closed</td>
|
||||||
|
<td>145.01</td>
|
||||||
|
<td>91.44</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
Notes:<br />
|
||||||
|
- Firefox seems faster than Chromium in my setup for Javascript, WebAssembly seems about the same.<br />
|
||||||
|
- Having DevTools open in Chromium seems to slow down the WebAssembly by about 30%, but not when doing a recording of the page load.<br />
|
||||||
|
- WebAssembly in Firefox seems to slow down when doing a recording of the page load, which makes sense, but the Javascript does not.<br />
|
||||||
|
|
||||||
<script type="text/javascript" src="./include.js"></script>
|
<script type="text/javascript" src="./include.js"></script>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
@ -32,6 +106,8 @@ var makeCRCTable = function(){
|
|||||||
window.crcTable = makeCRCTable();
|
window.crcTable = makeCRCTable();
|
||||||
|
|
||||||
var crc32_js = function(i8arr) {
|
var crc32_js = function(i8arr) {
|
||||||
|
// console.log('crc32_js', i8arr.length);
|
||||||
|
|
||||||
var crcTable = window.crcTable;
|
var crcTable = window.crcTable;
|
||||||
var crc = 0 ^ (-1);
|
var crc = 0 ^ (-1);
|
||||||
|
|
||||||
@ -43,34 +119,68 @@ var crc32_js = function(i8arr) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Run a single test
|
// Run a single test
|
||||||
function run_test(app, str)
|
function run_test(app, str, str_repeat)
|
||||||
{
|
{
|
||||||
// Cast to Uint32 in Javascript
|
// Cast to Uint32 in Javascript
|
||||||
let crc32_wasm = (offset) => (app.instance.exports.crc32(offset) >>> 0);
|
let crc32_wasm = function(offset) {
|
||||||
|
// console.log('crc32_wasm', str.length);
|
||||||
|
return app.instance.exports.crc32(offset) >>> 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
let orig_str = str;
|
||||||
|
if( str_repeat ) {
|
||||||
|
str = str.repeat(str_repeat);
|
||||||
|
} else {
|
||||||
|
str_repeat = 1;
|
||||||
|
}
|
||||||
|
|
||||||
let data = Uint8Array.from(str.split('').map(x => x.charCodeAt()));
|
let data = Uint8Array.from(str.split('').map(x => x.charCodeAt()));
|
||||||
|
|
||||||
offset = alloc_bytes(app, data);
|
offset = alloc_bytes(app, data);
|
||||||
|
|
||||||
|
let tweak = () => {
|
||||||
|
data[0] = data[0] + 1;
|
||||||
|
|
||||||
|
let i8arr = new Uint8Array(app.instance.exports.memory.buffer, offset + 4, data.length);
|
||||||
|
i8arr[0] = i8arr[0] + 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
let tweak_reset = () => {
|
||||||
|
data[0] = 'T'.charCodeAt(0);
|
||||||
|
|
||||||
|
let i8arr = new Uint8Array(app.instance.exports.memory.buffer, offset + 4, data.length);
|
||||||
|
i8arr[0] = 'T'.charCodeAt(0);
|
||||||
|
};
|
||||||
|
|
||||||
// Run once to get the result
|
// Run once to get the result
|
||||||
// For some reason, the JS version takes 2ms on the first run
|
// For some reason, the JS version takes 2ms on the first run
|
||||||
let wasm_result = crc32_wasm(offset);
|
// let wasm_result = crc32_wasm(offset);
|
||||||
let js_result = crc32_js(data);
|
// let js_result = crc32_js(data);
|
||||||
|
|
||||||
let wasm_time = run_times(100, () => crc32_wasm(offset));
|
let wasm_timing = run_times(100, () => crc32_wasm(offset));
|
||||||
let js_time = run_times(100, () => crc32_js(data));
|
let js_timing = run_times(100, () => crc32_js(data));
|
||||||
|
|
||||||
test_result((js_result == wasm_result) && ((js_time == 0) || (wasm_time < js_time)), {
|
let wasm_time = wasm_timing.avg;
|
||||||
|
let js_time = js_timing.avg;
|
||||||
|
|
||||||
|
let check = wasm_timing.values.every(function(value, index) {
|
||||||
|
return value.result === js_timing.values[index].result;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Don't test speedup for small strings, it varies a lot
|
||||||
|
let speedup = str.length < 16 ? 1 : (js_time == wasm_time ? 1 : js_time / wasm_time);
|
||||||
|
|
||||||
|
test_result(check && 0.999 < speedup, { // At least as fast as Javascript
|
||||||
'summary': 'crc32(' + (str
|
'summary': 'crc32(' + (str
|
||||||
? (str.length < 64 ? '"' + str + '"' : '"' + str.substring(0, 64) + '..." (' + str.length + ')')
|
? (str.length < 64 ? '"' + str + '"' : '"' + str.substring(0, 64) + '..." (' + str.length + ')')
|
||||||
: '""') + ')',
|
: '""') + ')',
|
||||||
'attributes': {
|
'attributes': {
|
||||||
'str': str,
|
'str': orig_str,
|
||||||
'wasm_result': wasm_result,
|
'str_repeat': str_repeat,
|
||||||
'wasm_time': wasm_time,
|
'wasm_timing': wasm_timing,
|
||||||
'js_result': js_result,
|
'js_timing': js_timing,
|
||||||
'js_time': js_time,
|
'check': check,
|
||||||
'speedup': (js_time == wasm_time) ? '-' : (js_time / wasm_time),
|
'speedup': speedup,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -78,13 +188,16 @@ function run_test(app, str)
|
|||||||
// Load WebAssembly, and run all tests
|
// Load WebAssembly, and run all tests
|
||||||
WebAssembly.instantiateStreaming(fetch('crc32.wasm'), importObject)
|
WebAssembly.instantiateStreaming(fetch('crc32.wasm'), importObject)
|
||||||
.then(app => {
|
.then(app => {
|
||||||
|
app.instance.exports.memory.grow(640);
|
||||||
|
|
||||||
run_test(app, "");
|
run_test(app, "");
|
||||||
run_test(app, "a");
|
run_test(app, "a");
|
||||||
run_test(app, "Z");
|
run_test(app, "Z");
|
||||||
run_test(app, "ab");
|
run_test(app, "ab");
|
||||||
run_test(app, "abcdefghijklmnopqrstuvwxyz");
|
run_test(app, "abcdefghijklmnopqrstuvwxyz");
|
||||||
run_test(app, "The quick brown fox jumps over the lazy dog");
|
run_test(app, "The quick brown fox jumps over the lazy dog");
|
||||||
run_test(app, "The quick brown fox jumps over the lazy dog".repeat(1024)); // FIXME: Too slow :(
|
run_test(app, "The quick brown fox jumps over the lazy dog", 1024);
|
||||||
|
run_test(app, "Lynx c.q. vos prikt bh: dag zwemjuf!", 1048576);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@ -14,17 +14,33 @@ function alloc_bytes(app, data)
|
|||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
function run_times(times, callback)
|
function run_times(times, callback, tweak)
|
||||||
{
|
{
|
||||||
let sum = 0;
|
let sum = 0;
|
||||||
|
let max = 0;
|
||||||
|
let min = 1000000000000000000;
|
||||||
|
let values = [];
|
||||||
for(let idx = 0; idx < times; idx += 1) {
|
for(let idx = 0; idx < times; idx += 1) {
|
||||||
|
if( tweak ) {
|
||||||
|
tweak();
|
||||||
|
}
|
||||||
|
|
||||||
const t0 = performance.now();
|
const t0 = performance.now();
|
||||||
callback();
|
let result = callback();
|
||||||
const t1 = performance.now();
|
const t1 = performance.now();
|
||||||
sum += t1 - t0;
|
let time = t1 - t0;
|
||||||
|
sum += time;
|
||||||
|
values.push({'time': time, 'result': result});
|
||||||
|
max = max < time ? time : max;
|
||||||
|
min = min > time ? time : min;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
'min': min,
|
||||||
|
'avg': sum / times,
|
||||||
|
'max': max,
|
||||||
|
'sum': sum,
|
||||||
|
'values': values,
|
||||||
}
|
}
|
||||||
console.log(sum);
|
|
||||||
return sum / times;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function test_result(is_pass, data)
|
function test_result(is_pass, data)
|
||||||
@ -42,23 +58,41 @@ function test_result(is_pass, data)
|
|||||||
result_details.appendChild(result_summary);
|
result_details.appendChild(result_summary);
|
||||||
|
|
||||||
if( data.attributes ) {
|
if( data.attributes ) {
|
||||||
let table = document.createElement('table');
|
result_table(data, result_details);
|
||||||
|
|
||||||
Object.keys(data.attributes).forEach(idx => {
|
|
||||||
let td0 = document.createElement('td');
|
|
||||||
td0.textContent = idx;
|
|
||||||
let td1 = document.createElement('td');
|
|
||||||
td1.textContent = data.attributes[idx];
|
|
||||||
|
|
||||||
let tr = document.createElement('tr');
|
|
||||||
tr.appendChild(td0);
|
|
||||||
tr.appendChild(td1);
|
|
||||||
|
|
||||||
table.appendChild(tr);
|
|
||||||
});
|
|
||||||
result_details.append(table);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let results = document.getElementById('results');
|
let results = document.getElementById('results');
|
||||||
results.appendChild(result_details);
|
results.appendChild(result_details);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function result_table(attributes, parent)
|
||||||
|
{
|
||||||
|
let table = document.createElement('table');
|
||||||
|
|
||||||
|
Object.keys(attributes).forEach(idx => {
|
||||||
|
let td0 = document.createElement('td');
|
||||||
|
td0.setAttribute('style', 'vertical-align: top;');
|
||||||
|
td0.textContent = idx;
|
||||||
|
let td1 = document.createElement('td');
|
||||||
|
if( typeof(attributes[idx]) == 'object' ) {
|
||||||
|
let result_details = document.createElement('details');
|
||||||
|
|
||||||
|
let result_summary = document.createElement('summary');
|
||||||
|
result_summary.textContent = 'Show me';
|
||||||
|
result_details.appendChild(result_summary);
|
||||||
|
|
||||||
|
result_table(attributes[idx], result_details);
|
||||||
|
|
||||||
|
td1.appendChild(result_details);
|
||||||
|
} else {
|
||||||
|
td1.textContent = attributes[idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
let tr = document.createElement('tr');
|
||||||
|
tr.appendChild(td0);
|
||||||
|
tr.appendChild(td1);
|
||||||
|
|
||||||
|
table.appendChild(tr);
|
||||||
|
});
|
||||||
|
parent.append(table);
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user