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:
parent
4871e5a288
commit
3014f95359
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
21
src/cpu.js
21
src/cpu.js
|
@ -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
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue