diff --git a/Cargo.lock b/Cargo.lock index ef8dbb072..e5fc6dd4e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -280,6 +280,9 @@ dependencies = [ [[package]] name = "ceno-examples" version = "0.1.0" +dependencies = [ + "glob", +] [[package]] name = "ceno_emul" diff --git a/ceno_host/src/lib.rs b/ceno_host/src/lib.rs index d6cd94ea1..fe6765c27 100644 --- a/ceno_host/src/lib.rs +++ b/ceno_host/src/lib.rs @@ -120,14 +120,15 @@ impl From<&CenoStdin> for Vec { } impl CenoStdin { - pub fn write_slice(&mut self, bytes: AlignedVec) { + pub fn write_slice(&mut self, bytes: AlignedVec) -> &mut Self { self.items.push(bytes); + self } pub fn write( &mut self, item: &impl for<'a> Serialize, Error>>, - ) -> Result<(), Error> { + ) -> Result<&mut Self, Error> { to_bytes::(item).map(|bytes| self.write_slice(bytes)) } } diff --git a/ceno_host/tests/test_elf.rs b/ceno_host/tests/test_elf.rs index 6831ac9eb..97fcd751b 100644 --- a/ceno_host/tests/test_elf.rs +++ b/ceno_host/tests/test_elf.rs @@ -7,6 +7,7 @@ use ceno_emul::{ }; use ceno_host::CenoStdin; use itertools::{Itertools, enumerate, izip}; +use rand::{Rng, thread_rng}; use tiny_keccak::keccakf; #[test] @@ -111,14 +112,15 @@ fn test_ceno_rt_io() -> Result<()> { #[test] fn test_hints() -> Result<()> { - let mut hints = CenoStdin::default(); - hints.write(&true)?; - hints.write(&"This is my hint string.".to_string())?; - hints.write(&1997_u32)?; - hints.write(&1999_u32)?; - - let all_messages = - messages_to_strings(&ceno_host::run(CENO_PLATFORM, ceno_examples::hints, &hints)); + let all_messages = messages_to_strings(&ceno_host::run( + CENO_PLATFORM, + ceno_examples::hints, + CenoStdin::default() + .write(&true)? + .write(&"This is my hint string.".to_string())? + .write(&1997_u32)? + .write(&1999_u32)?, + )); for (i, msg) in enumerate(&all_messages) { println!("{i}: {msg}"); } @@ -128,17 +130,12 @@ fn test_hints() -> Result<()> { #[test] fn test_bubble_sorting() -> Result<()> { - use rand::Rng; - let mut hints = CenoStdin::default(); - let mut rng = rand::thread_rng(); - - // Provide some random numbers to sort. - hints.write(&(0..1_000).map(|_| rng.gen::()).collect::>())?; - + let mut rng = thread_rng(); let all_messages = messages_to_strings(&ceno_host::run( CENO_PLATFORM, - ceno_examples::bubble_sorting, - &hints, + ceno_examples::quadratic_sorting, + // Provide some random numbers to sort. + CenoStdin::default().write(&(0..1_000).map(|_| rng.gen::()).collect::>())?, )); for msg in &all_messages { print!("{msg}"); @@ -147,17 +144,12 @@ fn test_bubble_sorting() -> Result<()> { } #[test] fn test_sorting() -> Result<()> { - use rand::Rng; - let mut hints = CenoStdin::default(); - let mut rng = rand::thread_rng(); - - // Provide some random numbers to sort. - hints.write(&(0..1000).map(|_| rng.gen::()).collect::>())?; - + let mut rng = thread_rng(); let all_messages = messages_to_strings(&ceno_host::run( CENO_PLATFORM, ceno_examples::sorting, - &hints, + // Provide some random numbers to sort. + CenoStdin::default().write(&(0..1000).map(|_| rng.gen::()).collect::>())?, )); for (i, msg) in enumerate(&all_messages) { println!("{i}: {msg}"); @@ -167,9 +159,8 @@ fn test_sorting() -> Result<()> { #[test] fn test_median() -> Result<()> { - use rand::Rng; let mut hints = CenoStdin::default(); - let mut rng = rand::thread_rng(); + let mut rng = thread_rng(); // Provide some random numbers to find the median of. let mut nums = (0..1000).map(|_| rng.gen::()).collect::>(); @@ -192,23 +183,22 @@ fn test_median() -> Result<()> { #[test] #[should_panic(expected = "Trap IllegalInstruction")] fn test_hashing_fail() { - use rand::Rng; - let mut hints = CenoStdin::default(); - let mut rng = rand::thread_rng(); + let mut rng = thread_rng(); let mut nums = (0..1_000).map(|_| rng.gen::()).collect::>(); // Add a duplicate number to make uniqueness check fail: nums[211] = nums[907]; - hints.write(&nums).unwrap(); - let _ = ceno_host::run(CENO_PLATFORM, ceno_examples::hashing, &hints); + let _ = ceno_host::run( + CENO_PLATFORM, + ceno_examples::hashing, + CenoStdin::default().write(&nums).unwrap(), + ); } #[test] fn test_hashing() -> Result<()> { - use rand::Rng; - let mut hints = CenoStdin::default(); - let mut rng = rand::thread_rng(); + let mut rng = thread_rng(); // Provide some unique random numbers to verify: let uniques: Vec = { @@ -219,11 +209,10 @@ fn test_hashing() -> Result<()> { .collect::>() }; - hints.write(&uniques)?; let all_messages = messages_to_strings(&ceno_host::run( CENO_PLATFORM, ceno_examples::hashing, - &hints, + CenoStdin::default().write(&uniques)?, )); assert!(!all_messages.is_empty()); for (i, msg) in enumerate(&all_messages) { diff --git a/ceno_zkvm/src/instructions/riscv/rv32im.rs b/ceno_zkvm/src/instructions/riscv/rv32im.rs index 5d19255d7..fefb18ba5 100644 --- a/ceno_zkvm/src/instructions/riscv/rv32im.rs +++ b/ceno_zkvm/src/instructions/riscv/rv32im.rs @@ -29,12 +29,15 @@ use ceno_emul::{ }; use ecall::EcallDummy; use ff_ext::ExtensionField; -use itertools::Itertools; +use itertools::{Itertools, izip}; use mul::{MulInstruction, MulhInstruction, MulhsuInstruction}; use shift::SraInstruction; use slt::{SltInstruction, SltuInstruction}; use slti::SltiuInstruction; -use std::collections::{BTreeMap, BTreeSet}; +use std::{ + cmp::Reverse, + collections::{BTreeMap, BTreeSet}, +}; use strum::IntoEnumIterator; use super::{ @@ -337,14 +340,10 @@ impl Rv32imConfig { } }); - for (insn_kind, (_, records)) in InsnKind::iter() - .zip(all_records.iter()) - .sorted_by(|a, b| Ord::cmp(&a.1.1.len(), &b.1.1.len())) - .rev() + for (insn_kind, (_, records)) in + izip!(InsnKind::iter(), &all_records).sorted_by_key(|(_, (_, a))| Reverse(a.len())) { - if !records.is_empty() { - tracing::info!("tracer generated {:?} {} records", insn_kind, records.len()); - } + tracing::info!("tracer generated {:?} {} records", insn_kind, records.len()); } macro_rules! assign_opcode { diff --git a/examples-builder/Cargo.toml b/examples-builder/Cargo.toml index 00104ec3c..5e0ae79d0 100644 --- a/examples-builder/Cargo.toml +++ b/examples-builder/Cargo.toml @@ -7,3 +7,6 @@ license.workspace = true name = "ceno-examples" repository.workspace = true version.workspace = true + +[build-dependencies] +glob = "0.3" diff --git a/examples-builder/build.rs b/examples-builder/build.rs index 10d79d4f3..20b49b8d1 100644 --- a/examples-builder/build.rs +++ b/examples-builder/build.rs @@ -1,3 +1,4 @@ +use glob::glob; use std::{ fs::{File, read_dir}, io::{self, Write}, @@ -5,22 +6,6 @@ use std::{ process::Command, }; -/// Add each example to this list. -/// -/// Contact Matthias, if your examples get complicated enough to need their own crates, instead of just being one file. -const EXAMPLES: &[&str] = &[ - "ceno_rt_alloc", - "ceno_rt_io", - "ceno_rt_mem", - "ceno_rt_mini", - "ceno_rt_panic", - "ceno_rt_keccak", - "hints", - "sorting", - "median", - "bubble_sorting", - "hashing", -]; const CARGO_MANIFEST_DIR: &str = env!("CARGO_MANIFEST_DIR"); fn rerun_all_but_target(dir: &Path) { @@ -51,7 +36,12 @@ fn build_elfs() { io::stderr().write_all(&output.stderr).unwrap(); panic!("cargo build of examples failed."); } - for example in EXAMPLES { + // Contact Matthias, if your examples get complicated enough to need their own crates, instead of just being one file. + for example in glob("../examples/examples/*.rs") + .unwrap() + .map(Result::unwrap) + { + let example = example.file_stem().unwrap().to_str().unwrap(); writeln!( dest, r#"#[allow(non_upper_case_globals)] diff --git a/examples/examples/bubble_sorting.rs b/examples/examples/quadratic_sorting.rs similarity index 100% rename from examples/examples/bubble_sorting.rs rename to examples/examples/quadratic_sorting.rs