Skip to content

Commit

Permalink
Merge pull request #1307 from o1-labs/rb/debugging-info
Browse files Browse the repository at this point in the history
Pretty print info according to CLI frequency specification
  • Loading branch information
dannywillems authored Nov 14, 2023
2 parents b23c39e + 934770a commit 248e72a
Show file tree
Hide file tree
Showing 5 changed files with 376 additions and 33 deletions.
25 changes: 23 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions optimism/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,5 @@ libflate = "2"
base64 = "0.21.5"
strum = "0.24.0"
strum_macros = "0.24.0"
log = "0.4.20"
env_logger = "0.10.0"
216 changes: 197 additions & 19 deletions optimism/src/cannon.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
// Data structure and stuff for compatibility with Cannon

use base64::{engine::general_purpose, Engine as _};

use libflate::zlib::Decoder;
use regex::Regex;
use serde::{Deserialize, Deserializer, Serialize};
use std::io::Read;

pub const PAGE_SIZE: usize = 4096;
pub const PAGE_ADDRESS_SIZE: usize = 12;
pub const PAGE_SIZE: usize = 1 << PAGE_ADDRESS_SIZE;
pub const PAGE_ADDRESS_MASK: usize = PAGE_SIZE - 1;

#[derive(Serialize, Deserialize, Debug)]
pub struct Page {
Expand Down Expand Up @@ -83,22 +86,6 @@ pub fn step_frequency_parser(s: &str) -> std::result::Result<StepFrequency, Stri
}
}

#[cfg(test)]
mod tests {

use super::*;

#[test]
fn sp_parser() {
use StepFrequency::*;
assert_eq!(step_frequency_parser("never"), Ok(Never));
assert_eq!(step_frequency_parser("always"), Ok(Always));
assert_eq!(step_frequency_parser("=123"), Ok(Exactly(123)));
assert_eq!(step_frequency_parser("%123"), Ok(Every(123)));
assert!(step_frequency_parser("@123").is_err());
}
}

impl ToString for State {
// A very debatable and incomplete, but serviceable, `to_string` implementation.
fn to_string(&self) -> String {
Expand All @@ -116,13 +103,13 @@ impl ToString for State {
}
}

#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct HostProgram {
pub name: String,
pub arguments: Vec<String>,
}

#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct VmConfiguration {
pub input_state_file: String,
pub output_state_file: String,
Expand All @@ -135,3 +122,194 @@ pub struct VmConfiguration {
pub pprof_cpu: bool,
pub host: Option<HostProgram>,
}

#[derive(Debug, Clone)]
pub struct Start {
pub time: std::time::Instant,
pub step: usize,
}

impl Start {
pub fn create(step: usize) -> Start {
Start {
time: std::time::Instant::now(),
step,
}
}
}

#[derive(Debug, PartialEq, Clone, Deserialize)]
pub struct Symbol {
pub name: String,
pub start: u32,
pub size: usize,
}

#[derive(Debug, PartialEq, Clone, Deserialize)]
pub struct Meta {
#[serde(deserialize_with = "filtered_ordered")]
pub symbols: Vec<Symbol>, // Needs to be in ascending order w.r.t start address
}

// Make sure that deserialized data are ordered in ascending order and that we
// have removed 0-size symbols
fn filtered_ordered<'de, D>(deserializer: D) -> Result<Vec<Symbol>, D::Error>
where
D: Deserializer<'de>,
{
let v: Vec<Symbol> = Deserialize::deserialize(deserializer)?;
let mut filtered: Vec<Symbol> = v.into_iter().filter(|e| e.size != 0).collect();
filtered.sort_by(|a, b| a.start.cmp(&b.start));
Ok(filtered)
}

impl Meta {
pub fn find_address_symbol(&self, address: u32) -> Option<String> {
use std::cmp::Ordering;

self.symbols
.binary_search_by(
|Symbol {
start,
size,
name: _,
}| {
if address < *start {
Ordering::Greater
} else {
let end = *start + *size as u32;
if address >= end {
Ordering::Less
} else {
Ordering::Equal
}
}
},
)
.map_or_else(|_| None, |idx| Some(self.symbols[idx].name.to_string()))
}
}

#[cfg(test)]
mod tests {

use super::*;
use std::fs::File;
use std::io::{BufReader, Write};

#[test]
fn sp_parser() {
use StepFrequency::*;
assert_eq!(step_frequency_parser("never"), Ok(Never));
assert_eq!(step_frequency_parser("always"), Ok(Always));
assert_eq!(step_frequency_parser("=123"), Ok(Exactly(123)));
assert_eq!(step_frequency_parser("%123"), Ok(Every(123)));
assert!(step_frequency_parser("@123").is_err());
}

// This sample is a subset taken from a Cannon-generated "meta.json" file
// Interestingly, it contains 0-size symbols - there are removed by
// deserialization.
const META_SAMPLE: &str = r#"{
"symbols": [
{
"name": "go.go",
"start": 0,
"size": 0
},
{
"name": "internal/cpu.processOptions",
"start": 69632,
"size": 1872
},
{
"name": "runtime.text",
"start": 69632,
"size": 0
},
{
"name": "runtime/internal/atomic.(*Uint8).Load",
"start": 71504,
"size": 28
},
{
"name": "runtime/internal/atomic.(*Uint8).Store",
"start": 71532,
"size": 28
},
{
"name": "runtime/internal/atomic.(*Uint8).And",
"start": 71560,
"size": 88
},
{
"name": "runtime/internal/atomic.(*Uint8).Or",
"start": 71648,
"size": 72
}]}"#;

fn deserialize_meta_sample() -> Meta {
serde_json::from_str::<Meta>(META_SAMPLE).unwrap()
}

#[test]
fn test_meta_deserialize_from_file() {
let path = "meta_test.json";
let mut output =
File::create(path).unwrap_or_else(|_| panic!("Could not create file {path}"));
write!(output, "{}", META_SAMPLE)
.unwrap_or_else(|_| panic!("Could not write to file {path}"));

let input = File::open(path).unwrap_or_else(|_| panic!("Could not open file {path}"));
let buffered = BufReader::new(input);
let read: Meta = serde_json::from_reader(buffered)
.unwrap_or_else(|_| panic!("Failed to deserialize metadata from file {path}"));

let expected = Meta {
symbols: vec![
Symbol {
name: "internal/cpu.processOptions".to_string(),
start: 69632,
size: 1872,
},
Symbol {
name: "runtime/internal/atomic.(*Uint8).Load".to_string(),
start: 71504,
size: 28,
},
Symbol {
name: "runtime/internal/atomic.(*Uint8).Store".to_string(),
start: 71532,
size: 28,
},
Symbol {
name: "runtime/internal/atomic.(*Uint8).And".to_string(),
start: 71560,
size: 88,
},
Symbol {
name: "runtime/internal/atomic.(*Uint8).Or".to_string(),
start: 71648,
size: 72,
},
],
};

assert_eq!(read, expected);
}

#[test]
fn test_find_address_symbol() {
let meta = deserialize_meta_sample();

assert_eq!(
meta.find_address_symbol(69633),
Some("internal/cpu.processOptions".to_string())
);
assert_eq!(
meta.find_address_symbol(69632),
Some("internal/cpu.processOptions".to_string())
);
assert_eq!(meta.find_address_symbol(42), None);
}
}
36 changes: 26 additions & 10 deletions optimism/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use clap::{arg, value_parser, Arg, ArgAction, Command};
use kimchi_optimism::{
cannon::{State, VmConfiguration},
cannon::{self, Meta, Start, State, VmConfiguration},
mips::witness,
};
use std::{fs::File, io::BufReader, process::ExitCode};
Expand Down Expand Up @@ -113,29 +113,45 @@ fn cli() -> VmConfiguration {
pub fn main() -> ExitCode {
let configuration = cli();

println!("configuration\n{:#?}", configuration);

let file = File::open(configuration.input_state_file).expect("Error opening input state file ");
let file =
File::open(&configuration.input_state_file).expect("Error opening input state file ");

let reader = BufReader::new(file);
// Read the JSON contents of the file as an instance of `State`.
let state: State = serde_json::from_reader(reader).expect("Error reading input state file");

if let Some(host_program) = configuration.host {
let meta_file = File::open(&configuration.metadata_file).unwrap_or_else(|_| {
panic!(
"Could not open metadata file {}",
&configuration.metadata_file
)
});

let meta: Meta = serde_json::from_reader(BufReader::new(meta_file)).unwrap_or_else(|_| {
panic!(
"Error deserializing metadata file {}",
&configuration.metadata_file
)
});

if let Some(host_program) = &configuration.host {
println!("Launching host program {}", host_program.name);

let _child = std::process::Command::new(host_program.name)
.args(host_program.arguments)
let _child = std::process::Command::new(&host_program.name)
.args(&host_program.arguments)
.spawn()
.expect("Could not spawn host process");
};

let page_size = 1 << 12;
// Initialize some data used for statistical computations
let start = Start::create(state.step as usize);

env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init();

let mut env = witness::Env::<ark_bn254::Fq>::create(page_size, state);
let mut env = witness::Env::<ark_bn254::Fq>::create(cannon::PAGE_SIZE, state);

while !env.halt {
env.step();
env.step(configuration.clone(), &meta, &start);
}

// TODO: Logic
Expand Down
Loading

0 comments on commit 248e72a

Please sign in to comment.