|
<!DOCTYPE html> |
|
<html> |
|
<script> |
|
const base64 = { |
|
whole: { |
|
optimal: "AGFzbQEAAAABEgRgAX8AYAAAYAABf2ACf38BfwIPAQdjb25zb2xlA2xvZwAAAwYFAQIDAAAFBAEBAgIGBgF/AUEACwcrBQVyZXNldAABBm5ld05pbAACB25ld0NvbnMAAwVwcmludAAEBHNvcnQABQrgAQUGAEEAJAALGQEBfyMAIQAgAEEANgIAIABBBGokACAADwsnAQF/IwAhAiACQQE2AgAgAiAANgIEIAIgATYCCCACQQxqJAAgAg8LJgACQAJAAkAgACgCAA4CAgEACwALIAAoAgQQACAAKAIIEAQPCw8LbgEEfwNAQQAgACgCAEYEQA8LIAAoAgQhASAAIQIgAigCCCEDA0BBACADKAIARgRAIAIgAEYEQCAAKAIIIQALDAILIAMoAgQhBCAEIAFJBEAgAyABNgIEIAIgBDYCBCADIQILIAMoAgghAwwACwsL", |
|
unguarded: "AGFzbQEAAAABHAZgAX8AYAAAYAABf2ACf38Bf2ABfwF/YAJ/fwACDwEHY29uc29sZQNsb2cAAAMKCQECAwQEBAUAAAUEAQECAgYGAX8BQQALBysFBXJlc2V0AAEGbmV3TmlsAAIHbmV3Q29ucwADBXByaW50AAgEc29ydAAJCvkBCQYAQQAkAAsZAQF/IwAhACAAQQA2AgAgAEEEaiQAIAAPCycBAX8jACECIAJBATYCACACIAA2AgQgAiABNgIIIAJBDGokACACDwsLAEEAIAAoAgBGDwsIACAAKAIEDwsIACAAKAIIDwsJACAAIAE2AgQLJgACQAJAAkAgACgCAA4CAgEACwALIAAoAgQQACAAKAIIEAgPCw8LXwEEfwNAIAAQBARADwsgABAFIQEgACECIAIQBiEDA0AgAxAEBEAgAiAARgRAIAAQBiEACwwCCyADEAUhBCAEIAFJBEAgAyABEAcgAiAEEAcgAyECCyADEAYhAwwACwsL", |
|
switch: "AGFzbQEAAAABHAZgAX8AYAAAYAABf2ACf38Bf2ABfwF/YAJ/fwACDwEHY29uc29sZQNsb2cAAAMKCQECAwQEBAUAAAUEAQECAgYGAX8BQQALBysFBXJlc2V0AAEGbmV3TmlsAAIHbmV3Q29ucwADBXByaW50AAgEc29ydAAJCsoCCQYAQQAkAAsZAQF/IwAhACAAQQA2AgAgAEEEaiQAIAAPCycBAX8jACECIAJBATYCACACIAA2AgQgAiABNgIIIAJBDGokACACDwscAAJAAkACQCAAKAIADgICAQALAAtBAA8LQQEPCx0AAkACQAJAIAAoAgAOAgIBAAsACyAAKAIEDwsACx0AAkACQAJAIAAoAgAOAgIBAAsACyAAKAIIDwsACx8AAkACQAJAIAAoAgAOAgIBAAsACyAAIAE2AgQPCwALJgACQAJAAkAgACgCAA4CAgEACwALIAAoAgQQACAAKAIIEAgPCw8LXwEEfwNAIAAQBARADwsgABAFIQEgACECIAIQBiEDA0AgAxAEBEAgAiAARgRAIAAQBiEACwwCCyADEAUhBCAEIAFJBEAgAyABEAcgAiAEEAcgAyECCyADEAYhAwwACwsL", |
|
vtable: "AGFzbQEAAAABHAZgAX8AYAAAYAABf2ACf38Bf2ABfwF/YAJ/fwACDwEHY29uc29sZQNsb2cAAAMQDwECAwQEBAQEBAUFAAAAAAQFAXABCgoFBAEBAgIGBgF/AUEACwcrBQVyZXNldAABBm5ld05pbAACB25ld0NvbnMAAwVwcmludAAOBHNvcnQADwkQAQBBAAsKBAYKCAwFBwsJDQrSAg8GAEEAJAALGQEBfyMAIQAgAEEANgIAIABBBGokACAADwsnAQF/IwAhAiACQQU2AgAgAiAANgIEIAIgATYCCCACQQxqJAAgAg8LBQBBAQ8LBQBBAA8LAwAACwgAIAAoAgQPCwMAAAsJACAAKAIIDwALAwAACwoAIAAgATYCBA8LAwAPCxEAIAAoAgQQACAAKAIIEA4PCw8AIABBBCAAKAIAahEAAAuqAQEEfwNAIAAgACgCABEEAARADwsgAEEBIAAoAgBqEQQAIQEgACECIAJBAyACKAIAahEEACEDA0AgAyADKAIAEQQABEAgAiAARgRAIABBAyAAKAIAahEEACEACwwCCyADQQEgAygCAGoRBAAhBCAEIAFJBEAgAyABQQIgAygCAGoRBQAgAiAEQQIgAigCAGoRBQAgAyECCyADQQMgAygCAGoRBAAhAwwACwsL" |
|
}, |
|
separate: { |
|
direct: { |
|
list: { |
|
unguarded: "AGFzbQEAAAABHAZgAX8AYAAAYAABf2ACf38Bf2ABfwF/YAJ/fwACDwEHY29uc29sZQNsb2cAAAMJCAECAwQEBAUABQQBAQICBgYBfwFBAAsHWQkGbWVtb3J5AgAFcmVzZXQAAQZuZXdOaWwAAgduZXdDb25zAAMFaXNOaWwABApnZXRFbGVtZW50AAUHZ2V0TmV4dAAGCnNldEVsZW1lbnQABwVwcmludAAICpkBCAYAQQAkAAsZAQF/IwAhACAAQQA2AgAgAEEEaiQAIAAPCycBAX8jACECIAJBATYCACACIAA2AgQgAiABNgIIIAJBDGokACACDwsLAEEAIAAoAgBGDwsIACAAKAIEDwsIACAAKAIIDwsJACAAIAE2AgQLJgACQAJAAkAgACgCAA4CAgEACwALIAAoAgQQACAAKAIIEAgPCw8L", |
|
switch: "AGFzbQEAAAABHAZgAX8AYAAAYAABf2ACf38Bf2ABfwF/YAJ/fwACDwEHY29uc29sZQNsb2cAAAMJCAECAwQEBAUABQQBAQICBgYBfwFBAAsHWQkGbWVtb3J5AgAFcmVzZXQAAQZuZXdOaWwAAgduZXdDb25zAAMFaXNOaWwABApnZXRFbGVtZW50AAUHZ2V0TmV4dAAGCnNldEVsZW1lbnQABwVwcmludAAICuoBCAYAQQAkAAsZAQF/IwAhACAAQQA2AgAgAEEEaiQAIAAPCycBAX8jACECIAJBATYCACACIAA2AgQgAiABNgIIIAJBDGokACACDwscAAJAAkACQCAAKAIADgICAQALAAtBAA8LQQEPCx0AAkACQAJAIAAoAgAOAgIBAAsACyAAKAIEDwsACx0AAkACQAJAIAAoAgAOAgIBAAsACyAAKAIIDwsACx8AAkACQAJAIAAoAgAOAgIBAAsACyAAIAE2AgQPCwALJgACQAJAAkAgACgCAA4CAgEACwALIAAoAgQQACAAKAIIEAgPCw8L" |
|
}, |
|
sort: "AGFzbQEAAAABDwNgAX8Bf2ACf38AYAF/AAJQBQRsaXN0Bm1lbW9yeQIAAQRsaXN0BWlzTmlsAAAEbGlzdApnZXRFbGVtZW50AAAEbGlzdAdnZXROZXh0AAAEbGlzdApzZXRFbGVtZW50AAEDAgECBwgBBHNvcnQABAphAV8BBH8DQCAAEAAEQA8LIAAQASEBIAAhAiACEAIhAwNAIAMQAARAIAIgAEYEQCAAEAIhAAsMAgsgAxABIQQgBCABSQRAIAMgARADIAIgBBADIAMhAgsgAxACIQMMAAsLCw==" |
|
}, |
|
vtable: { |
|
list: "AGFzbQEAAAABHAZgAX8AYAAAYAABf2ACf38Bf2ABfwF/YAJ/fwACDwEHY29uc29sZQNsb2cAAAMPDgECAwQEBAQEBAUFAAAABAUBcAEKCgUEAQECAgYfBn8AQQALfwBBAQt/AEECC38AQQMLfwBBBAt/AUEACweIAQsLaXNOaWxPZmZzZXQDABBnZXRFbGVtZW50T2Zmc2V0AwEQc2V0RWxlbWVudE9mZnNldAMCDWdldE5leHRPZmZzZXQDAwtwcmludE9mZnNldAMEBm1lbW9yeQIABnZ0YWJsZQEABXJlc2V0AAEGbmV3TmlsAAIHbmV3Q29ucwADBXByaW50AA4JEAEAQQALCgQGCggMBQcLCQ0KpgEOBgBBACQFCxkBAX8jBSEAIABBADYCACAAQQRqJAUgAA8LJwEBfyMFIQIgAkEFNgIAIAIgADYCBCACIAE2AgggAkEMaiQFIAIPCwUAQQEPCwUAQQAPCwMAAAsIACAAKAIEDwsDAAALCQAgACgCCA8ACwMAAAsKACAAIAE2AgQPCwMADwsRACAAKAIEEAAgACgCCBAODwsPACAAIwQgACgCAGoRAAAL", |
|
sort: { |
|
constant: "AGFzbQEAAAABDwNgAX8AYAF/AX9gAn9/AAIgAgRsaXN0Bm1lbW9yeQIAAQRsaXN0BnZ0YWJsZQFwAAADAgEABwgBBHNvcnQAAAqtAQGqAQEEfwNAIAAgACgCABEBAARADwsgAEEBIAAoAgBqEQEAIQEgACECIAJBAyACKAIAahEBACEDA0AgAyADKAIAEQEABEAgAiAARgRAIABBAyAAKAIAahEBACEACwwCCyADQQEgAygCAGoRAQAhBCAEIAFJBEAgAyABQQIgAygCAGoRAgAgAiAEQQIgAigCAGoRAgAgAyECCyADQQMgAygCAGoRAQAhAwwACwsL", |
|
extern: "AGFzbQEAAAABDwNgAX8AYAF/AX9gAn9/AAJkBgRsaXN0BWlzTmlsA38ABGxpc3QKZ2V0RWxlbWVudAN/AARsaXN0CnNldEVsZW1lbnQDfwAEbGlzdAdnZXROZXh0A38ABGxpc3QGbWVtb3J5AgABBGxpc3QGdnRhYmxlAXAAAAMCAQAHCAEEc29ydAAACrMBAbABAQR/A0AgACMAIAAoAgBqEQEABEAPCyAAIwEgACgCAGoRAQAhASAAIQIgAiMDIAIoAgBqEQEAIQMDQCADIwAgAygCAGoRAQAEQCACIABGBEAgACMDIAAoAgBqEQEAIQALDAILIAMjASADKAIAahEBACEEIAQgAUkEQCADIAEjAiADKAIAahECACACIAQjAiACKAIAahECACADIQILIAMjAyADKAIAahEBACEDDAALCws=" |
|
} |
|
} |
|
}, |
|
} |
|
|
|
function base64ToArrayBuffer(base64) { |
|
var binary_string = window.atob(base64); |
|
var len = binary_string.length; |
|
var bytes = new Uint8Array(len); |
|
for (var i = 0; i < len; i++) { |
|
bytes[i] = binary_string.charCodeAt(i); |
|
} |
|
return bytes.buffer; |
|
} |
|
function log(text) { |
|
document.getElementById("console").innerHTML += text + "</br>"; |
|
} |
|
function clearConsole() { |
|
document.getElementById("console").innerHTML = ""; |
|
} |
|
|
|
const instances = {} |
|
|
|
function instantiateWhole(wasm_base64) { |
|
return WebAssembly.instantiate(base64ToArrayBuffer(wasm_base64), |
|
{console: {log: log}} |
|
).then((wasm) => { |
|
const { newNil: newNil, newCons: newCons, print: print, reset: reset, sort: sort } = wasm.instance.exports; |
|
return { newNil: newNil, newCons: newCons, print: print, reset: reset, sort: sort }; |
|
}); |
|
} |
|
|
|
function instantiateSeparateDirect(list_base64, sort_base64) { |
|
return WebAssembly.instantiate(base64ToArrayBuffer(list_base64), |
|
{console: {log: log}} |
|
).then((list_wasm) => { |
|
const { newNil: newNil, newCons: newCons, print: print, reset: reset, memory: memory, |
|
isNil: isNil, getElement: getElement, setElement: setElement, getNext: getNext |
|
} = list_wasm.instance.exports; |
|
return WebAssembly.instantiate(base64ToArrayBuffer(sort_base64), |
|
{list: {memory: memory, isNil: isNil, getElement: getElement, setElement: setElement, getNext: getNext}} |
|
).then((sort_wasm) => { |
|
const { sort: sort } = sort_wasm.instance.exports; |
|
return { newNil: newNil, newCons: newCons, print: print, reset: reset, sort: sort }; |
|
}); |
|
}); |
|
} |
|
|
|
function instantiateSeparateVtable(list_base64, sort_base64) { |
|
return WebAssembly.instantiate(base64ToArrayBuffer(list_base64), |
|
{console: {log: log}} |
|
).then((list_wasm) => { |
|
const { newNil: newNil, newCons: newCons, print: print, reset: reset, memory: memory, vtable: vtable, |
|
isNilOffset: isNilOffset, getElementOffset: getElementOffset, setElementOffset: setElementOffset, getNextOffset: getNextOffset |
|
} = list_wasm.instance.exports; |
|
return WebAssembly.instantiate(base64ToArrayBuffer(sort_base64), |
|
{list: {memory: memory, vtable: vtable, isNil: isNilOffset, getElement: getElementOffset, setElement: setElementOffset, getNext: getNextOffset}} |
|
).then((sort_wasm) => { |
|
const { sort: sort } = sort_wasm.instance.exports; |
|
return { newNil: newNil, newCons: newCons, print: print, reset: reset, sort: sort }; |
|
}); |
|
}); |
|
} |
|
|
|
function instantiateJavascript() { |
|
class Node { |
|
//isNil() |
|
//getElement() : Int16 |
|
//setElement(Int16) |
|
//getNext() : Node |
|
//print() |
|
} |
|
|
|
class Nil extends Node { |
|
isNil() { return true; } |
|
print() { } |
|
} |
|
|
|
class Cons extends Node { |
|
element; |
|
next; |
|
constructor(element, next) { super(); this.element = element; this.next = next; } |
|
isNil() { return false; } |
|
getElement() { return this.element; } |
|
setElement(element) { this.element = element; } |
|
getNext() { return this.next; } |
|
print() { log(this.element); this.next.print(); } |
|
} |
|
|
|
function sort(head) { |
|
while (!head.isNil()) { |
|
element = head.getElement(); |
|
old = head; |
|
node = old.getNext(); |
|
while (!node.isNil()) { |
|
value = node.getElement(); |
|
if (value < element) { |
|
node.setElement(element); |
|
old.setElement(value); |
|
old = node; |
|
} |
|
node = node.getNext(); |
|
} |
|
if (old === head) { |
|
head = head.getNext(); |
|
} |
|
} |
|
} |
|
function newNil() { return new Nil(); } |
|
function newCons(element, next) { return new Cons(element, next); } |
|
function print(node) { node.print(); } |
|
function reset() {} |
|
|
|
return Promise.resolve({ newNil: newNil, newCons: newCons, print: print, reset: reset, sort: sort }); |
|
} |
|
|
|
const instantiators = { |
|
wholeOptimal: () => instantiateWhole(base64.whole.optimal), |
|
wholeUnguarded: () => instantiateWhole(base64.whole.unguarded), |
|
wholeSwitch: () => instantiateWhole(base64.whole.switch), |
|
wholeVtable: () => instantiateWhole(base64.whole.vtable), |
|
separateDirectUnguarded: () => instantiateSeparateDirect(base64.separate.direct.list.unguarded, base64.separate.direct.sort), |
|
separateDirectSwitch: () => instantiateSeparateDirect(base64.separate.direct.list.switch, base64.separate.direct.sort), |
|
separateVtableConstant: () => instantiateSeparateVtable(base64.separate.vtable.list, base64.separate.vtable.sort.constant), |
|
separateVtableExtern: () => instantiateSeparateVtable(base64.separate.vtable.list, base64.separate.vtable.sort.extern), |
|
javascript: instantiateJavascript, |
|
}; |
|
|
|
function runEvaluation() { |
|
const selector = document.getElementById("selection"); |
|
const name = selector.options[selector.selectedIndex].innerHTML; |
|
const selection = selector.value; |
|
if (selection in instances) { |
|
log(name + " already instantiated"); |
|
} else { |
|
log("instantiating " + name); |
|
instances[selection] = instantiators[selection](); |
|
} |
|
|
|
instances[selection].then((sorter) => { |
|
log("starting " + name); |
|
|
|
const { newNil: newNil, newCons: newCons, print: print, reset: reset, sort: sort } = sorter; |
|
|
|
times = 5; |
|
|
|
function runOnce() { |
|
size = 10000; |
|
|
|
reset(); |
|
list = newNil(); |
|
element = 17; |
|
for (i = 0; i < size; i++) { |
|
list = newCons(element, list); |
|
element = (element * 115249) % 16777213; |
|
} |
|
start = performance.now(); |
|
sort(list); |
|
log(performance.now() - start); |
|
|
|
if (--times > 0) |
|
window.setTimeout(runOnce, 0); |
|
else { |
|
log(name + " done"); |
|
log(""); |
|
} |
|
} |
|
|
|
window.setTimeout(runOnce, 0); |
|
}); |
|
} |
|
|
|
function checkCorrectness() { |
|
const selector = document.getElementById("selection"); |
|
const name = selector.options[selector.selectedIndex].innerHTML; |
|
const selection = selector.value; |
|
if (selection in instances) { |
|
log(name + " already instantiated"); |
|
} else { |
|
log("instantiating " + name); |
|
instances[selection] = instantiators[selection](); |
|
} |
|
|
|
instances[selection].then((sorter) => { |
|
log("starting " + name); |
|
|
|
const { newNil: newNil, newCons: newCons, print: print, reset: reset, sort: sort } = sorter; |
|
|
|
size = 5; |
|
|
|
reset(); |
|
list = newNil(); |
|
element = 17; |
|
for (i = 0; i < size; i++) { |
|
list = newCons(element, list); |
|
element = (element * 115249) % 16777213; |
|
} |
|
log("unsorted"); |
|
print(list); |
|
log("sorted"); |
|
sort(list); |
|
print(list); |
|
log(name + " done"); |
|
log(""); |
|
}); |
|
} |
|
</script> |
|
<body> |
|
|
|
<h1>WebAssembly Performance</h1> |
|
<select id="selection"> |
|
<option value="wholeOptimal">whole-optimal: Fully Inlined without Tests</option> |
|
<option value="wholeUnguarded">whole-unguarded: Direct Calls without Tests</option> |
|
<option value="wholeSwitch">whole-switch: Direct Calls using Switch Tables</option> |
|
<option value="wholeVtable">whole-vtable: Indirect Calls</option> |
|
<option value="separateDirectUnguarded">separate-direct-unguarded: Separately Compiled using Direct Calls without Tests</option> |
|
<option value="separateDirectSwitch">separate-direct-switch: Separately Compiled using Direct Calls using Switch Tables</option> |
|
<option value="separateVtableConstant">separate-vtable-constant: Separately Compiled using Indirect Calls at Predetermined Method Offsets</option> |
|
<option value="separateVtableExtern">separate-vtable-extern: Separately Compiled using Indirect Calls at Imported Method Offsets</option> |
|
<option value="javascript">JavaScript Classes using only Methods</option> |
|
</select> |
|
<input type="button" value="Run" onclick="runEvaluation()"/> |
|
<input type="button" value="Test" onclick="checkCorrectness()"/> |
|
<input type="button" value="Clear" onclick="clearConsole()"/> |
|
<p id="console"></p> |
|
|
|
</body> |
|
</html> |