1
//! Bare bones upper bound estimator that uses the rv32im
2
//! emulation utils for fast lookups in the opcode list
3
//! to extract the cycle count from an elf.
4

            
5
use anyhow::Result;
6
use risc0_binfmt::{MemoryImage, Program};
7
use risc0_zkvm::{ExecutorEnv, ExecutorImpl, Session, GUEST_MAX_MEM};
8
use risc0_zkvm_platform::PAGE_SIZE;
9

            
10
pub fn estimate<E: MkImage>(elf: E, env: ExecutorEnv) -> Result<()> {
11
    let session = get_session(elf, env)?;
12
    println!(
13
        "User cycles: {}\nTotal cycles: {}\nSegments: {}",
14
        session.user_cycles,
15
        session.total_cycles,
16
        session.segments.len()
17
    );
18

            
19
    Ok(())
20
}
21

            
22
/// Get the total number of cycles by stepping through the ELF using emulation
23
/// tools from the risc0_circuit_rv32im module.
24
1
pub fn get_session<E: MkImage>(elf: E, env: ExecutorEnv) -> Result<Session> {
25
1
    ExecutorImpl::new(env, elf.mk_image()?)?.run()
26
1
}
27

            
28
/// Helper trait for loading an image from an elf.
29
pub trait MkImage {
30
    fn mk_image(self) -> Result<MemoryImage>;
31
}
32
impl<'a> MkImage for &'a [u8] {
33
    fn mk_image(self) -> Result<MemoryImage> {
34
        let program = Program::load_elf(self, GUEST_MAX_MEM as u32)?;
35
        MemoryImage::new(&program, PAGE_SIZE as u32)
36
    }
37
}
38

            
39
#[cfg(test)]
40
mod estimate_tests {
41
    use anyhow::Result;
42
    use risc0_binfmt::MemoryImage;
43
    use risc0_circuit_rv32im::prove::emu::{
44
        exec::DEFAULT_SEGMENT_LIMIT_PO2,
45
        testutil::{basic as basic_test_program, DEFAULT_SESSION_LIMIT},
46
    };
47
    use risc0_zkvm::{ExecutorEnv, PAGE_SIZE};
48

            
49
    use super::MkImage;
50
    use crate::estimate;
51

            
52
    impl MkImage for MemoryImage {
53
1
        fn mk_image(self) -> Result<MemoryImage> {
54
1
            Ok(self)
55
1
        }
56
    }
57

            
58
    #[test]
59
1
    fn estimate_basic() {
60
1
        let program = basic_test_program();
61
1
        let mut env = &mut ExecutorEnv::builder();
62
1
        env = env
63
1
            .segment_limit_po2(DEFAULT_SEGMENT_LIMIT_PO2 as u32)
64
1
            .session_limit(DEFAULT_SESSION_LIMIT);
65
1
        let image = MemoryImage::new(&program, PAGE_SIZE as u32)
66
1
            .expect("failed to create image from basic program");
67
1
        let res = estimate::get_session(image, env.build().unwrap());
68
1

            
69
1
        assert_eq!(res.ok().map(|session| session.total_cycles), Some(16384));
70
1
    }
71
}