Skip to content

Commit

Permalink
chore: add screenshot, grammar/spelling
Browse files Browse the repository at this point in the history
  • Loading branch information
nhtyy committed Nov 22, 2024
1 parent 64417f6 commit a8f9188
Show file tree
Hide file tree
Showing 4 changed files with 20 additions and 15 deletions.
Binary file added book/profiling.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
19 changes: 12 additions & 7 deletions book/writing-programs/cycle-tracking.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,20 +58,24 @@ This will log the cycle count for `block name` and include it in the `ExecutionR

### Profiling a ZKVM program

Profiling a zkvm program is a good way to get an understanding of what is bottlenecking your program, note only one program may be profiled at a time.
Profiling a zkvm program is a good way to get an understanding of what is bottlenecking your program. Note only one program may be profiled at a time.

To profile a program, you have to setup a script to execute the program,
many examples can be found in the repo, such as this ['fibonacci'](https://github.com/succinctlabs/sp1/blob/12f212e386ae4c2da30cf6a61a7d87615d56bdac/examples/fibonacci/script/src/main.rs#L22) script.
To profile a program, you have to setup a script to execute the program.

Once you have your script it should contain the following code:
Many examples can be found in the repo, such as this ['fibonacci'](https://github.com/succinctlabs/sp1/blob/12f212e386ae4c2da30cf6a61a7d87615d56bdac/examples/fibonacci/script/src/main.rs#L22) script.

Once you have your script it should look like the following:
```rs
// Execute the program using the `ProverClient.execute` method, without generating a proof.
let (_, report) = client.execute(ELF, stdin.clone()).run().unwrap();
```

The data captured by the profiler can be quite large, you can set the sample rate using the `TRACE_SAMPLE_RATE` env var.
To enable profiling, set the `TRACE_FILE` env var to the path where you want the profile to be saved.
As well you must enable the profiling feature on the SDK:
```toml
sp1-sdk = { version = "3.0.0", features = ["profiling"] }
```

The `TRACE_FILE` env var tells the executor where to save the profile, and the `TRACE_SAMPLE_RATE` env var tells the executor how often to sample the program.
A larger sample rate will give you a smaller profile, it is the number of instructions in between each sample.

The full command to profile should look something like this
Expand All @@ -85,4 +89,5 @@ To view these profiles, we recommend [Samply](https://github.com/mstange/samply)
samply load output.json
```

Samply uses the firefox profiler to create a nice visualization for your programs execution.
Samply uses the Firefox profiler to create a nice visualization of your programs execution.
![An example screenshot of the Firefox Profiler](../profiling.png)
6 changes: 4 additions & 2 deletions crates/core/executor/src/executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,9 @@ pub struct Executor<'a> {
/// A buffer for stdout and stderr IO.
pub io_buf: HashMap<u32, String>,

/// The ZKVM profiler.
/// The ZKVM program profiler.
///
/// Keeps track of the number of cycles spent in each function.
#[cfg(feature = "profiling")]
pub profiler: Option<(Profiler, BufWriter<File>)>,

Expand Down Expand Up @@ -192,7 +194,7 @@ impl<'a> Executor<'a> {
Self::with_context(program, opts, SP1Context::default())
}

/// Crete a new runtime for the program, and setup the profiler if `TRACE_FILE` env var is set
/// Create a new runtime for the program, and setup the profiler if `TRACE_FILE` env var is set
/// and the feature flag `profiling` is enabled.
#[must_use]
pub fn with_context_and_elf(
Expand Down
10 changes: 4 additions & 6 deletions crates/core/executor/src/profiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ pub enum ProfilerError {
Serde(#[from] serde_json::Error),
}

/// The ZKVM Profiler.
///
/// During execution, the profiler always keeps track of the callstack
/// and will occasionally save the stack according to the sample rate.
pub struct Profiler {
Expand Down Expand Up @@ -51,8 +49,8 @@ impl Profiler {
let mut function_ranges = Vec::new();
let mut builder = ThreadBuilder::new(1, 0, std::time::Instant::now(), false, false);

// We need to extract all the functions from the elf file
// and thier corresponding PC ranges.
// We need to extract all the functions from the ELF file
// and their corresponding PC ranges.
let mut main_idx = None;
for sym in &elf.syms {
// check if its a function
Expand All @@ -63,7 +61,7 @@ impl Profiler {
let start_address = sym.st_value;
let end_address = start_address + size - 4;

// Now that we have the name lets immediately intern it so we only need to copy
// Now that we have the name let's immediately intern it so we only need to copy
// around a usize
let demangled_name = demangled_name.to_string();
let string_idx = builder.intern_string(&demangled_name);
Expand Down Expand Up @@ -180,7 +178,7 @@ impl Profiler {
last_known_time,
sample.stack.into_iter(),
// We don't have a way to know the duration of each sample, so we just use 1us for
// all instructions
// all instructions.
std::time::Duration::from_micros(self.sample_rate),
);

Expand Down

0 comments on commit a8f9188

Please sign in to comment.