Significantly improve speed of nasm tests

- Reuse v86 instances (in particular, memory allocation and wasm
loading)
- Reduce memory size from default (64M) to 2M
This commit is contained in:
Fabian 2017-07-27 12:25:36 +02:00
parent 4871e5a288
commit 3014f95359
5 changed files with 166 additions and 139 deletions

View file

@ -615,6 +615,8 @@ function V86Starter(options)
{ {
this.bus.send("cpu-run"); this.bus.send("cpu-run");
} }
this.emulator_bus.send("emulator-loaded");
}.bind(this), 0); }.bind(this), 0);
}.bind(this), 0); }.bind(this), 0);
} }

View file

@ -7,7 +7,7 @@ function BusConnector()
{ {
this.listeners = {}; this.listeners = {};
this.pair = undefined; this.pair = undefined;
}; }
/** /**
* @param {string} name * @param {string} name
@ -46,7 +46,7 @@ BusConnector.prototype.unregister = function(name, fn)
this.listeners[name] = listeners.filter(function(l) this.listeners[name] = listeners.filter(function(l)
{ {
return l.fn !== fn return l.fn !== fn;
}); });
}; };

View file

@ -603,6 +603,11 @@ CPU.prototype.reset = function()
this.fw_value[0] = 0; this.fw_value[0] = 0;
}; };
CPU.prototype.reset_memory = function()
{
this.mem8.fill(0);
};
/** @export */ /** @export */
CPU.prototype.create_memory = function(size) CPU.prototype.create_memory = function(size)
{ {
@ -1267,13 +1272,19 @@ CPU.prototype.run_prefix_instruction = function()
CPU.prototype.hlt_loop = function() CPU.prototype.hlt_loop = function()
{ {
dbg_assert(this.flags[0] & flag_interrupt); if(this.flags[0] & flag_interrupt)
{
//dbg_log("In HLT loop", LOG_CPU); //dbg_log("In HLT loop", LOG_CPU);
this.run_hardware_timers(v86.microtick()); this.run_hardware_timers(v86.microtick());
this.handle_irqs(); this.handle_irqs();
return 0; return 0;
}
else
{
return 100;
}
}; };
CPU.prototype.run_hardware_timers = function(now) CPU.prototype.run_hardware_timers = function(now)
@ -3161,13 +3172,10 @@ CPU.prototype.hlt_op = function()
if((this.flags[0] & flag_interrupt) === 0) if((this.flags[0] & flag_interrupt) === 0)
{ {
this.debug.show("cpu halted"); // execution can never resume (until NMIs are supported)
this.bus.send("cpu-event-halt"); this.bus.send("cpu-event-halt");
if(DEBUG) this.debug.dump_regs();
throw "HALT";
} }
else
{
// get out of here and into hlt_loop // get out of here and into hlt_loop
this.in_hlt = true; this.in_hlt = true;
@ -3184,7 +3192,6 @@ CPU.prototype.hlt_op = function()
{ {
throw MAGIC_CPU_EXCEPTION; throw MAGIC_CPU_EXCEPTION;
} }
}
}; };
// assumes ip to point to the byte before the next instruction // assumes ip to point to the byte before the next instruction

View file

@ -26,6 +26,8 @@ function v86(bus, wm)
v86.prototype.run = function() v86.prototype.run = function()
{ {
this.stopped = false;
if(!this.running) if(!this.running)
{ {
this.bus.send("emulator-started"); this.bus.send("emulator-started");

View file

@ -21,6 +21,7 @@ const cluster = require('cluster');
const MAX_PARALLEL_TESTS = +process.env.MAX_PARALLEL_TESTS || 99; const MAX_PARALLEL_TESTS = +process.env.MAX_PARALLEL_TESTS || 99;
const TEST_DIR = __dirname + "/build/"; const TEST_DIR = __dirname + "/build/";
const DONE_MSG = 'DONE'; const DONE_MSG = 'DONE';
const TERMINATE_MSG = 'DONE';
const MASK_ARITH = 1 | 1 << 2 | 1 << 4 | 1 << 6 | 1 << 7 | 1 << 11; const MASK_ARITH = 1 | 1 << 2 | 1 << 4 | 1 << 6 | 1 << 7 | 1 << 11;
@ -101,8 +102,15 @@ if (cluster.isMaster) {
current_test++; current_test++;
} }
else { else {
worker.send(TERMINATE_MSG);
worker.disconnect(); worker.disconnect();
setTimeout(() => {
// The emulator currently doesn't cleanly exit, so this is necessary
console.log("Worker killed");
worker.kill();
}, 100);
finished_workers++; finished_workers++;
if(finished_workers === nr_of_cpus) if(finished_workers === nr_of_cpus)
{ {
@ -155,7 +163,7 @@ if (cluster.isMaster) {
worker.on('online', send_work_to_worker.bind(null, worker)); worker.on('online', send_work_to_worker.bind(null, worker));
worker.on('exit', function(code, signal) { worker.on('exit', function(code, signal) {
if(code !== 0) { if(code !== 0 && code !== null) {
console.log('Worker error code:', code); console.log('Worker error code:', code);
process.exit(code); process.exit(code);
} }
@ -191,42 +199,70 @@ if (cluster.isMaster) {
} }
} }
else { else {
function run_test(test, done) { function run_test(test)
{
if(!loaded)
{
first_test = test;
return;
}
current_test = test;
console.info('Testing', test.img_name); console.info('Testing', test.img_name);
let emulator = new V86({
multiboot: {
url: TEST_DIR + test.img_name
},
autostart: false
});
//emulator.v86.cpu.debug.show = () => {};
emulator.bus.register('cpu-event-halt', function() {
var cpu = emulator.v86.cpu; var cpu = emulator.v86.cpu;
const filename = TEST_DIR + test.img_name; cpu.reset();
cpu.reset_memory();
cpu.load_multiboot(new Uint8Array(fs.readFileSync(TEST_DIR + current_test.img_name)).buffer);
emulator.run();
}
let loaded = false;
let current_test = undefined;
let first_test = undefined;
let emulator = new V86({
autostart: false,
memory_size: 2 * 1024 * 1024,
});
emulator.add_listener("emulator-loaded", function()
{
loaded = true;
if(first_test)
{
run_test(first_test);
}
});
emulator.bus.register('cpu-event-halt', function() {
emulator.stop();
var cpu = emulator.v86.cpu;
const filename = TEST_DIR + current_test.img_name;
const evaluated_mmxs = cpu.reg_mmxs; const evaluated_mmxs = cpu.reg_mmxs;
const evaluated_xmms = cpu.reg_xmm32s; const evaluated_xmms = cpu.reg_xmm32s;
const esp = cpu.reg32s[4]; const esp = cpu.reg32s[4];
const evaluated_memory = new Int32Array(cpu.mem8.slice(0x120000 - 16 * 4, 0x120000).buffer); const evaluated_memory = new Int32Array(cpu.mem8.slice(0x120000 - 16 * 4, 0x120000).buffer);
let individual_failures = []; let individual_failures = [];
if(test.exception) if(current_test.exception)
{ {
throw "TODO: Handle exceptions"; throw "TODO: Handle exceptions";
} }
console.assert(test.fixture.array); console.assert(current_test.fixture.array);
if(test.fixture.array) if(current_test.fixture.array)
{ {
let offset = 0; let offset = 0;
const expected_reg32s = test.fixture.array.slice(offset, offset += 8); const expected_reg32s = current_test.fixture.array.slice(offset, offset += 8);
const expected_mmx_registers = test.fixture.array.slice(offset, offset += 16); const expected_mmx_registers = current_test.fixture.array.slice(offset, offset += 16);
const expected_xmm_registers = test.fixture.array.slice(offset, offset += 32); const expected_xmm_registers = current_test.fixture.array.slice(offset, offset += 32);
const expected_memory = test.fixture.array.slice(offset, offset += 16); const expected_memory = current_test.fixture.array.slice(offset, offset += 16);
const expected_eflags = test.fixture.array[offset] & MASK_ARITH; const expected_eflags = current_test.fixture.array[offset] & MASK_ARITH;
for (let i = 0; i < cpu.reg32s.length; i++) { for (let i = 0; i < cpu.reg32s.length; i++) {
let reg = cpu.reg32s[i]; let reg = cpu.reg32s[i];
@ -281,45 +317,25 @@ else {
} }
if (individual_failures.length > 0) { if (individual_failures.length > 0) {
done({ process.send({
failures: individual_failures, failures: individual_failures,
img_name: test.img_name img_name: current_test.img_name
}); });
} }
else {
done();
}
});
emulator.bus.register('emulator-ready', function() {
try {
emulator.run();
}
catch(e) {
console.log(e);
}
});
}
// To silence logs from emulator in the worker
console.log = () => {};
process.on('uncaughtException', (err) => {
if (err !== 'HALT') {
console.error(err);
throw err;
}
});
cluster.worker.on('message', function(test) {
run_test(test, function(test_failure) {
if (test_failure) {
process.send(test_failure);
}
else { else {
process.send(DONE_MSG); process.send(DONE_MSG);
} }
}); });
cluster.worker.on('message', function(message) {
if(message === TERMINATE_MSG)
{
emulator.stop();
emulator = null;
}
else
{
run_test(message);
}
}); });
} }