Skip to content

Commit

Permalink
Save all dirty memory pages (including executable pages) and it's fla…
Browse files Browse the repository at this point in the history
…g to snapshot (#218)

* Store and resume page flag in snapshot

* cargo fmt

* Save code in snapshot

* Keep the dirty flag caused by load_elf
  • Loading branch information
mohanson authored Nov 15, 2021
1 parent 05e6f59 commit 5f1e124
Show file tree
Hide file tree
Showing 6 changed files with 32 additions and 50 deletions.
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "ckb-vm"
description = "CKB's Virtual machine"
version = "0.20.0"
version = "0.20.1"
license = "MIT"
authors = ["Nervos Core Dev <[email protected]>"]
edition = "2018"
Expand All @@ -25,7 +25,7 @@ goblin_v023 = { package = "goblin", version = "=0.2.3" }
goblin_v040 = { package = "goblin", version = "=0.4.0" }
scroll = "0.10"
serde = { version = "1.0", features = ["derive"] }
ckb-vm-definitions = { path = "definitions", version = "0.20.0" }
ckb-vm-definitions = { path = "definitions", version = "0.20.1" }
derive_more = "0.99.2"
rand = "0.7.3"

Expand Down
2 changes: 1 addition & 1 deletion definitions/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "ckb-vm-definitions"
description = "Common definition files for CKB VM"
version = "0.20.0"
version = "0.20.1"
license = "MIT"
authors = ["Nervos Core Dev <[email protected]>"]
edition = "2018"
Expand Down
6 changes: 1 addition & 5 deletions src/machine/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,11 @@ use scroll::Pread;
use super::debugger::Debugger;
use super::decoder::{build_decoder, Decoder};
use super::instructions::{execute, Instruction, Register};
use super::memory::{round_page_down, round_page_up, Memory, FLAG_DIRTY};
use super::memory::{round_page_down, round_page_up, Memory};
use super::syscalls::Syscalls;
use super::{
registers::{A0, A7, REGISTER_ABI_NAMES, SP},
Error, DEFAULT_STACK_SIZE, ISA_MOP, RISCV_GENERAL_REGISTER_NUMBER, RISCV_MAX_MEMORY,
RISCV_PAGES,
};

// Version 0 is the initial launched CKB VM, it is used in CKB Lina mainnet
Expand Down Expand Up @@ -180,9 +179,6 @@ pub trait SupportMachine: CoreMachine {
self.update_pc(Self::REG::from_u64(e_entry));
self.commit_pc();
}
for i in 0..RISCV_PAGES {
self.memory_mut().clear_flag(i as u64, FLAG_DIRTY)?;
}
Ok(bytes)
}

Expand Down
4 changes: 4 additions & 0 deletions src/snapshot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ pub struct Snapshot {
pub registers: [u64; RISCV_GENERAL_REGISTER_NUMBER],
pub pc: u64,
pub page_indices: Vec<u64>,
pub page_flags: Vec<u8>,
pub pages: Vec<Vec<u8>>,
}

Expand Down Expand Up @@ -70,6 +71,7 @@ pub fn make_snapshot<T: CoreMachine>(machine: &mut T) -> Result<Snapshot, Error>
}

snap.page_indices.push(i as u64);
snap.page_flags.push(flag);
snap.pages.push(page);
}
}
Expand All @@ -87,9 +89,11 @@ pub fn resume<T: CoreMachine>(machine: &mut T, snapshot: &Snapshot) -> Result<()
machine.commit_pc();
for i in 0..snapshot.page_indices.len() {
let page_index = snapshot.page_indices[i];
let page_flag = snapshot.page_flags[i];
let page = &snapshot.pages[i];
let addr_from = page_index << RISCV_PAGE_SHIFTS;
machine.memory_mut().store_bytes(addr_from, &page[..])?;
machine.memory_mut().set_flag(page_index, page_flag)?;
}

Ok(())
Expand Down
60 changes: 21 additions & 39 deletions tests/test_resume.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use ckb_vm::{
trace::TraceMachine,
DefaultCoreMachine, DefaultMachine, SupportMachine, VERSION0, VERSION1,
},
memory::sparse::SparseMemory,
memory::{sparse::SparseMemory, wxorx::WXorXMemory},
snapshot::{make_snapshot, resume, Snapshot},
DefaultMachineBuilder, Error, Instruction, ISA_IMC,
};
Expand Down Expand Up @@ -76,9 +76,6 @@ pub fn resume_asm_2_asm(version: u32, except_cycles: u64) {
let snapshot = machine1.snapshot().unwrap();

let mut machine2 = MachineTy::Asm.build(version, 40, None);
machine2
.load_program(&buffer, &vec!["alloc_many".into()])
.unwrap();
machine2.resume(&snapshot).unwrap();
let result2 = machine2.run();
let cycles2 = machine2.cycles();
Expand All @@ -101,9 +98,6 @@ pub fn resume_asm_2_asm_2_asm(version: u32, except_cycles: u64) {
let snapshot1 = machine1.snapshot().unwrap();

let mut machine2 = MachineTy::Asm.build(version, 4000000, None);
machine2
.load_program(&buffer, &vec!["alloc_many".into()])
.unwrap();
machine2.resume(&snapshot1).unwrap();
let result2 = machine2.run();
let cycles2 = machine2.cycles();
Expand All @@ -112,9 +106,6 @@ pub fn resume_asm_2_asm_2_asm(version: u32, except_cycles: u64) {
let snapshot2 = machine2.snapshot().unwrap();

let mut machine3 = MachineTy::Asm.build(version, 4000000, None);
machine3
.load_program(&buffer, &vec!["alloc_many".into()])
.unwrap();
machine3.resume(&snapshot2).unwrap();
let result3 = machine3.run();
let cycles3 = machine3.cycles();
Expand All @@ -137,9 +128,6 @@ pub fn resume_asm_2_interpreter(version: u32, except_cycles: u64) {
let snapshot = machine1.snapshot().unwrap();

let mut machine2 = MachineTy::Interpreter.build(version, 40, None);
machine2
.load_program(&buffer, &vec!["alloc_many".into()])
.unwrap();
machine2.resume(&snapshot).unwrap();

let result2 = machine2.run();
Expand All @@ -163,9 +151,6 @@ pub fn resume_interpreter_2_interpreter(version: u32, except_cycles: u64) {
let snapshot = machine1.snapshot().unwrap();

let mut machine2 = MachineTy::Interpreter.build(version, 30, None);
machine2
.load_program(&buffer, &vec!["alloc_many".into()])
.unwrap();
machine2.resume(&snapshot).unwrap();
let result2 = machine2.run();
let cycles2 = machine2.cycles();
Expand All @@ -188,9 +173,6 @@ pub fn resume_interpreter_2_asm(version: u32, except_cycles: u64) {
let snapshot = machine1.snapshot().unwrap();

let mut machine2 = MachineTy::Asm.build(version, 30, None);
machine2
.load_program(&buffer, &vec!["alloc_many".into()])
.unwrap();
machine2.resume(&snapshot).unwrap();
let result2 = machine2.run();
let cycles2 = machine2.cycles();
Expand All @@ -217,9 +199,6 @@ pub fn resume_aot_2_asm(version: u32, except_cycles: u64) {
let snapshot = machine1.snapshot().unwrap();

let mut machine2 = MachineTy::Asm.build(version, 40, None);
machine2
.load_program(&buffer, &vec!["alloc_many".into()])
.unwrap();
machine2.resume(&snapshot).unwrap();
let result2 = machine2.run();
let cycles2 = machine2.cycles();
Expand All @@ -242,9 +221,6 @@ pub fn resume_interpreter_with_trace_2_asm_inner(version: u32, except_cycles: u6
let snapshot = machine1.snapshot().unwrap();

let mut machine2 = MachineTy::Asm.build(version, 30, None);
machine2
.load_program(&buffer, &vec!["alloc_many".into()])
.unwrap();
machine2.resume(&snapshot).unwrap();
let result2 = machine2.run();
let cycles2 = machine2.cycles();
Expand Down Expand Up @@ -285,26 +261,30 @@ impl MachineTy {
Machine::Aot(AsmMachine::new(core1, program))
}
MachineTy::Interpreter => {
let core_machine1 =
DefaultCoreMachine::<u64, SparseMemory<u64>>::new(ISA_IMC, version, max_cycles);
let core_machine1 = DefaultCoreMachine::<u64, WXorXMemory<SparseMemory<u64>>>::new(
ISA_IMC, version, max_cycles,
);
Machine::Interpreter(
DefaultMachineBuilder::<DefaultCoreMachine<u64, SparseMemory<u64>>>::new(
DefaultMachineBuilder::<DefaultCoreMachine<u64, WXorXMemory<SparseMemory<u64>>>>::new(
core_machine1,
)
.instruction_cycle_func(Box::new(dummy_cycle_func))
.build(),
)
}
MachineTy::InterpreterWithTrace => {
let core_machine1 =
DefaultCoreMachine::<u64, SparseMemory<u64>>::new(ISA_IMC, version, max_cycles);
Machine::InterpreterWithTrace(TraceMachine::new(
DefaultMachineBuilder::<DefaultCoreMachine<u64, SparseMemory<u64>>>::new(
core_machine1,
)
.instruction_cycle_func(Box::new(dummy_cycle_func))
.build(),
))
let core_machine1 = DefaultCoreMachine::<u64, WXorXMemory<SparseMemory<u64>>>::new(
ISA_IMC, version, max_cycles,
);
Machine::InterpreterWithTrace(
TraceMachine::new(
DefaultMachineBuilder::<
DefaultCoreMachine<u64, WXorXMemory<SparseMemory<u64>>>,
>::new(core_machine1)
.instruction_cycle_func(Box::new(dummy_cycle_func))
.build(),
),
)
}
}
}
Expand All @@ -313,8 +293,10 @@ impl MachineTy {
enum Machine<'a> {
Asm(AsmMachine<'static>),
Aot(AsmMachine<'a>),
Interpreter(DefaultMachine<'static, DefaultCoreMachine<u64, SparseMemory<u64>>>),
InterpreterWithTrace(TraceMachine<'static, DefaultCoreMachine<u64, SparseMemory<u64>>>),
Interpreter(DefaultMachine<'static, DefaultCoreMachine<u64, WXorXMemory<SparseMemory<u64>>>>),
InterpreterWithTrace(
TraceMachine<'static, DefaultCoreMachine<u64, WXorXMemory<SparseMemory<u64>>>>,
),
}

impl<'a> Machine<'a> {
Expand Down
6 changes: 3 additions & 3 deletions tests/test_versions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use ckb_vm::{
asm::{AsmCoreMachine, AsmMachine},
VERSION0, VERSION1,
},
memory::FLAG_FREEZED,
memory::{FLAG_DIRTY, FLAG_FREEZED},
CoreMachine, DefaultCoreMachine, DefaultMachine, DefaultMachineBuilder, Error, Memory,
SparseMemory, WXorXMemory, ISA_IMC, RISCV_PAGESIZE,
};
Expand Down Expand Up @@ -434,7 +434,7 @@ pub fn test_asm_version0_writable_page() {
// 0x12000 is the address of the variable "buffer", which can be found from the dump file.
let page_index = 0x12000 / RISCV_PAGESIZE as u64;
let flag = machine.machine.memory_mut().fetch_flag(page_index).unwrap();
assert_eq!(flag, FLAG_FREEZED);
assert_eq!(flag, FLAG_DIRTY | FLAG_FREEZED);
let result = machine.run();
assert!(result.is_ok());
assert_eq!(result.unwrap(), 0);
Expand All @@ -445,7 +445,7 @@ pub fn test_asm_version1_writable_page() {
let mut machine = create_asm_machine("writable_page".to_string(), VERSION1);
let page_index = 0x12000 / RISCV_PAGESIZE as u64;
let flag = machine.machine.memory_mut().fetch_flag(page_index).unwrap();
assert_eq!(flag, 0);
assert_eq!(flag, FLAG_DIRTY);
let result = machine.run();
assert!(result.is_ok());
assert_eq!(result.unwrap(), 0);
Expand Down

0 comments on commit 5f1e124

Please sign in to comment.