Skip to content

Commit 10cd296

Browse files
authored
Added some more features to benchmarking App (#274)
* Added support for other cores * Configured wasmboy with some peromance options (to at least somewhat compete with other cores) * Show output as each core finished running * Fixed some bugs * Enabled sourcemaps for cores # Example ![othercoresbenchmark](https://user-images.githubusercontent.com/1448289/53397107-18a84980-395b-11e9-97a9-20bf496a6f04.gif)
1 parent 82d6b12 commit 10cd296

File tree

14 files changed

+10895
-28
lines changed

14 files changed

+10895
-28
lines changed

demo/benchmark/benchmarkResults.js

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -47,20 +47,19 @@ export default class BenchmarkRunner extends Component {
4747
return responses;
4848
}
4949

50-
generateTable(WasmBoyCoreObjects) {
51-
if (!WasmBoyCoreObjects || WasmBoyCoreObjects <= 0) {
50+
generateTable(coreObjects) {
51+
if (!coreObjects || coreObjects.length <= 0) {
5252
return <table />;
5353
}
5454

55-
const shouldReturnEmptyTable = WasmBoyCoreObjects.some(wasmboyCoreObject => {
56-
if (!wasmboyCoreObject.resultTimes || wasmboyCoreObject.resultTimes.length <= 0) {
57-
return true;
55+
const WasmBoyCoreObjects = [];
56+
coreObjects.forEach(coreObject => {
57+
if (coreObject.resultTimes && coreObject.resultTimes.length > 0) {
58+
WasmBoyCoreObjects.push(coreObject);
5859
}
59-
60-
return false;
6160
});
6261

63-
if (shouldReturnEmptyTable) {
62+
if (WasmBoyCoreObjects.length === 0) {
6463
return <table />;
6564
}
6665

@@ -81,6 +80,30 @@ export default class BenchmarkRunner extends Component {
8180
return <td>{coreObject.resultTimes.length}</td>;
8281
})}
8382
</tr>
83+
<tr>
84+
<td>Fastest Frame Time</td>
85+
{this.getInfoFromCoreObjects(WasmBoyCoreObjects, coreObject => {
86+
const sortedTimes = [...coreObject.resultTimes];
87+
sortedTimes.sort((a, b) => {
88+
if (a < b) return -1;
89+
if (a > b) return 1;
90+
return;
91+
});
92+
return <td>{sortedTimes[0]}</td>;
93+
})}
94+
</tr>
95+
<tr>
96+
<td>Slowest Frame Time</td>
97+
{this.getInfoFromCoreObjects(WasmBoyCoreObjects, coreObject => {
98+
const sortedTimes = [...coreObject.resultTimes];
99+
sortedTimes.sort((a, b) => {
100+
if (a < b) return -1;
101+
if (a > b) return 1;
102+
return;
103+
});
104+
return <td>{sortedTimes[sortedTimes.length - 1]}</td>;
105+
})}
106+
</tr>
84107
<tr>
85108
<td>Sum</td>
86109
{this.getInfoFromCoreObjects(WasmBoyCoreObjects, coreObject => {

demo/benchmark/benchmarkRunner.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,19 @@ export default class BenchmarkRunner extends Component {
116116
times = times.slice(times.length * 0.15);
117117
coreObject.resultTimes = coreObject.resultTimes.concat(times);
118118
});
119+
120+
this.props.running(false);
121+
122+
// Wait a little bit, and start running again
123+
const timeoutPromise = new Promise(resolve => {
124+
setTimeout(() => {
125+
resolve();
126+
}, 10);
127+
});
128+
129+
await timeoutPromise;
130+
131+
this.props.running(true);
119132
}
120133

121134
this.benchmarkComplete();

demo/benchmark/binjgb/0.1.3/binjgb.js

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
/*
2+
* Copyright (C) 2019 Ben Smith
3+
*
4+
* This software may be modified and distributed under the terms
5+
* of the MIT license. See the LICENSE file for details.
6+
*/
7+
8+
// Modified to import wasm through rollup
9+
// And export the binjgb object
10+
11+
import binjgbWasmUrl from './binjgb.wasm';
12+
13+
const Binjgb = async function() {
14+
// Must match values defined in generated binjgb.js
15+
const TABLE_SIZE = 34;
16+
const TOTAL_MEMORY = 16777216;
17+
const STATIC_BUMP = 17264;
18+
const TOTAL_STACK = 5242880;
19+
20+
const pageSize = 65536;
21+
const totalPages = TOTAL_MEMORY / pageSize;
22+
const wasmFile = binjgbWasmUrl;
23+
const memory = new WebAssembly.Memory({ initial: totalPages, maximum: totalPages });
24+
const buffer = memory.buffer;
25+
const u8a = new Uint8Array(buffer);
26+
const u32a = new Uint32Array(buffer);
27+
28+
const GLOBAL_BASE = 1024;
29+
const STATIC_BASE = GLOBAL_BASE;
30+
let STATICTOP = STATIC_BASE + STATIC_BUMP;
31+
const alignMemory = size => {
32+
return (size + 15) & -16;
33+
};
34+
const staticAlloc = size => {
35+
const ret = STATICTOP;
36+
STATICTOP = alignMemory(STATICTOP + size);
37+
return ret;
38+
};
39+
40+
const DYNAMICTOP_PTR = staticAlloc(4);
41+
const STACK_BASE = alignMemory(STATICTOP);
42+
const STACKTOP = STACK_BASE;
43+
const STACK_MAX = alignMemory(STACK_BASE + TOTAL_STACK);
44+
const DYNAMIC_BASE = alignMemory(STACK_MAX);
45+
u32a[DYNAMICTOP_PTR >> 2] = DYNAMIC_BASE;
46+
47+
const abort = what => {
48+
throw `abort(${what}).`;
49+
};
50+
const abortOnCannotGrowMemory = () => {
51+
abort('Cannot enlarge memory.');
52+
};
53+
const enlargeMemory = abortOnCannotGrowMemory;
54+
const getTotalMemory = () => {
55+
return TOTAL_MEMORY;
56+
};
57+
const ___setErrNo = v => {
58+
return v;
59+
};
60+
const ___syscall140 = (which, varargs) => {
61+
return 0;
62+
};
63+
const streams = {
64+
1: { buffer: [], out: console.log.bind(console) },
65+
2: { buffer: [], out: console.error.bind(console) }
66+
};
67+
const decoder = new TextDecoder('utf8');
68+
const ___syscall146 = (which, varargs) => {
69+
const get = () => {
70+
varargs += 4;
71+
return u32a[(varargs - 4) >> 2];
72+
};
73+
const { buffer, out } = streams[get()];
74+
const flush = () => {
75+
out(decoder.decode(new Uint8Array(buffer)));
76+
buffer.length = 0;
77+
};
78+
const iov = get();
79+
const iovcnt = get();
80+
const printChar = c => {
81+
if (c === 0 || c === 10) {
82+
flush();
83+
} else {
84+
buffer.push(c);
85+
}
86+
};
87+
let ret = 0;
88+
for (let i = 0; i < iovcnt; ++i) {
89+
const ptr = u32a[(iov + i * 8) >> 2];
90+
const len = u32a[(iov + (i * 8 + 4)) >> 2];
91+
for (let j = 0; j < len; ++j) {
92+
printChar(u8a[ptr + j]);
93+
}
94+
ret += len;
95+
}
96+
return ret;
97+
};
98+
const ___syscall54 = (which, varargs) => {
99+
return 0;
100+
};
101+
const ___syscall6 = (which, varargs) => {
102+
return 0;
103+
};
104+
const _emscripten_memcpy_big = (dest, src, num) => {
105+
u8a.set(u8a.subarray(src, src + num), dest);
106+
return dest;
107+
};
108+
const _exit = status => {};
109+
const __table_base = 0;
110+
const table = new WebAssembly.Table({ initial: TABLE_SIZE, maximum: TABLE_SIZE, element: 'anyfunc' });
111+
112+
const importObject = {
113+
env: {
114+
abort,
115+
enlargeMemory,
116+
getTotalMemory,
117+
abortOnCannotGrowMemory,
118+
___setErrNo,
119+
___syscall140,
120+
___syscall146,
121+
___syscall54,
122+
___syscall6,
123+
_emscripten_memcpy_big,
124+
_exit,
125+
__table_base,
126+
DYNAMICTOP_PTR,
127+
STACKTOP,
128+
STACK_MAX,
129+
memory,
130+
table
131+
}
132+
};
133+
134+
const response = fetch(wasmFile);
135+
if (WebAssembly.instantiateStreaming) {
136+
try {
137+
var { instance } = await WebAssembly.instantiateStreaming(response, importObject);
138+
} catch (_) {}
139+
}
140+
if (!instance) {
141+
var { instance } = await WebAssembly.instantiate(await (await response).arrayBuffer(), importObject);
142+
}
143+
144+
const ret = {};
145+
for (let name in instance.exports) {
146+
ret[name] = instance.exports[name];
147+
}
148+
ret.buffer = memory.buffer;
149+
return ret;
150+
};
151+
152+
export default Binjgb;
116 KB
Binary file not shown.
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
// File to export a final wasmboy-like core
2+
3+
// Alot of logic taken from: https://github.com/binji/binjgb/blob/master/demo/demo.js
4+
5+
const RESULT_OK = 0;
6+
const RESULT_ERROR = 1;
7+
const SCREEN_WIDTH = 160;
8+
const SCREEN_HEIGHT = 144;
9+
const AUDIO_FRAMES = 4096;
10+
const AUDIO_LATENCY_SEC = 0.1;
11+
const MAX_UPDATE_SEC = 5 / 60;
12+
const CPU_TICKS_PER_SECOND = 4194304;
13+
const EVENT_NEW_FRAME = 1;
14+
const EVENT_AUDIO_BUFFER_FULL = 2;
15+
const EVENT_UNTIL_TICKS = 4;
16+
const REWIND_FRAMES_PER_BASE_STATE = 45;
17+
const REWIND_BUFFER_CAPACITY = 4 * 1024 * 1024;
18+
const REWIND_FACTOR = 1.5;
19+
const REWIND_UPDATE_MS = 16;
20+
const BUILTIN_PALETTES = 83; // See builtin-palettes.def.
21+
22+
import Binjgb from './binjgb';
23+
24+
function makeWasmBuffer(module, ptr, size) {
25+
return new Uint8Array(module.buffer, ptr, size);
26+
}
27+
28+
const CPU_TICKS_PER_FRAME = 70224;
29+
let framesRun = 0;
30+
31+
export default async function getBinjgbCore() {
32+
// Get our binjgb module
33+
const module = await Binjgb();
34+
35+
// Create our byteMemory
36+
37+
// Let's assume 8MB ROM
38+
const romBufferByteLength = 262144 * 10;
39+
const romDataPtr = module._malloc(romBufferByteLength);
40+
const romByteMemory = makeWasmBuffer(module, romDataPtr, romBufferByteLength);
41+
42+
// set a placeholder for our emulator
43+
let e;
44+
45+
// set a placehodler for our graphics memory
46+
let graphicsByteMemory;
47+
48+
// Create an array for our RGB buffer, that wasmboy will convert to rgba
49+
const rgbMemory = new Uint8ClampedArray(SCREEN_HEIGHT * SCREEN_WIDTH * 3);
50+
51+
let core = {};
52+
core = {
53+
byteMemory: romByteMemory,
54+
instance: {
55+
exports: {
56+
CARTRIDGE_ROM_LOCATION: 0,
57+
FRAME_LOCATION: 0,
58+
FRAME_SIZE: 0x016c00,
59+
config: () => {
60+
// Rom is now loaded.
61+
62+
// Create a new simple emulator?
63+
e = module._emulator_new_simple(romDataPtr, romBufferByteLength, 44100, AUDIO_FRAMES);
64+
if (e == 0) {
65+
throw new Error('Invalid ROM.');
66+
}
67+
68+
graphicsByteMemory = makeWasmBuffer(module, module._get_frame_buffer_ptr(e), module._get_frame_buffer_size(e));
69+
70+
// Now that we have our rom loaded, simply swap the byte memory for our purposes ;)
71+
core.byteMemory = rgbMemory;
72+
},
73+
executeFrame: () => {
74+
while (true) {
75+
const event = module._emulator_run_until_f64(e, CPU_TICKS_PER_FRAME * framesRun);
76+
if (event & EVENT_NEW_FRAME) {
77+
// Output Graphics (normally here, but doing later for perf)
78+
// Convert the graphics memory to our rgb Memory
79+
for (let i = 0; i < SCREEN_HEIGHT * SCREEN_WIDTH; i++) {
80+
let rgbIndex = i * 3;
81+
let rgbaIndex = i * 4;
82+
83+
rgbMemory[rgbIndex + 0] = graphicsByteMemory[rgbaIndex + 0];
84+
rgbMemory[rgbIndex + 1] = graphicsByteMemory[rgbaIndex + 1];
85+
rgbMemory[rgbIndex + 2] = graphicsByteMemory[rgbaIndex + 2];
86+
}
87+
}
88+
if (event & EVENT_AUDIO_BUFFER_FULL) {
89+
}
90+
if (event & EVENT_UNTIL_TICKS) {
91+
framesRun++;
92+
break;
93+
}
94+
}
95+
}
96+
}
97+
}
98+
};
99+
100+
return core;
101+
}

0 commit comments

Comments
 (0)