Skip to content

Commit

Permalink
Optimize pack_memory by moving zero check to rust.
Browse files Browse the repository at this point in the history
As suggested by copy in #1219 move the check if a memory
page is all zeros to rust.  Executes on 64bit chunks, which
is likely not as good simd could do, but is still a 5x speedup
in the included snapshot benchmark on my machine.

Co-authored-by: Adam M. Smith <[email protected]>
  • Loading branch information
2 people authored and copy committed Feb 2, 2025
1 parent 85ec802 commit d2fc7dc
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 15 deletions.
17 changes: 2 additions & 15 deletions src/cpu.js
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,7 @@ CPU.prototype.wasm_patch = function()

this.allocate_memory = get_import("allocate_memory");
this.zero_memory = get_import("zero_memory");
this.is_memory_zeroed = get_import("is_memory_zeroed");

this.svga_allocate_memory = get_import("svga_allocate_memory");
this.svga_allocate_dest_buffer = get_import("svga_allocate_dest_buffer");
Expand Down Expand Up @@ -625,23 +626,9 @@ CPU.prototype.pack_memory = function()

const page_count = this.mem8.length >> 12;
const nonzero_pages = [];

for(let page = 0; page < page_count; page++)
{
const offset = page << 12;
const view = this.mem32s.subarray(offset >> 2, offset + 0x1000 >> 2);
let is_zero = true;

for(let i = 0; i < view.length; i++)
{
if(view[i] !== 0)
{
is_zero = false;
break;
}
}

if(!is_zero)
if(!this.is_memory_zeroed(page << 12, 0x1000))
{
nonzero_pages.push(page);
}
Expand Down
12 changes: 12 additions & 0 deletions src/rust/cpu/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -310,3 +310,15 @@ pub unsafe fn mmap_write128(addr: u32, v0: u64, v1: u64) {
)
}
}

#[no_mangle]
pub unsafe fn is_memory_zeroed(addr: u32, length: u32) -> bool {
dbg_assert!(addr % 8 == 0);
dbg_assert!(length % 8 == 0);
for i in (addr..addr + length).step_by(8) {
if *(mem8.offset(i as isize) as *const i64) != 0 {
return false;
}
}
return true;
}
63 changes: 63 additions & 0 deletions tests/benchmark/snapshot.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#!/usr/bin/env node
"use strict";

const BENCH_COLLECT_STATS = +process.env.BENCH_COLLECT_STATS;

const V86 = require(`../../build/${BENCH_COLLECT_STATS ? "libv86-debug" : "libv86"}.js`).V86;
const print_stats = require("../../build/libv86.js").print_stats;
const fs = require("fs");
const path = require("path");
const V86_ROOT = path.join(__dirname, "../..");

const LOG_SERIAL = true;


var emulator = new V86({
bios: { url: __dirname + "/../../bios/seabios.bin" },
vga_bios: { url: __dirname + "/../../bios/vgabios.bin" },
cdrom: { url: __dirname + "/../../images/linux3.iso" },
autostart: true,
memory_size: 1024 * 1024 * 1024,
disable_jit: +process.env.DISABLE_JIT,
log_level: 0,
});


emulator.bus.register("emulator-started", function()
{
console.log("Booting now, please stand by");
start_time = Date.now();
});

var serial_text = "";
var start_time;

emulator.add_listener("serial0-output-byte", function(byte)
{
var chr = String.fromCharCode(byte);
if(chr < " " && chr !== "\n" && chr !== "\t" || chr > "~")
{
return;
}

if(LOG_SERIAL) process.stdout.write(chr);

serial_text += chr;

if(serial_text.endsWith("~% ") || serial_text.endsWith("root@localhost:~# "))
{
console.log("Creating snapshots");
const start_time = Date.now();
for(var i = 0; i < 10; ++i) emulator.save_state();
const end_time = Date.now();
const elapsed = end_time - start_time;
console.log("Done in %dms", elapsed);
emulator.destroy();

if(BENCH_COLLECT_STATS)
{
const cpu = emulator.v86.cpu;
console.log(print_stats.stats_to_string(cpu));
}
}
});

0 comments on commit d2fc7dc

Please sign in to comment.