sp1_sdk/
utils.rs

1//! # SP1 SDK Utilities
2//!
3//! A collection of utilities for the SP1 SDK.
4
5use std::{
6    sync::Once,
7    thread::{sleep, spawn},
8    time::Duration,
9};
10
11use sp1_core_machine::io::SP1Stdin;
12pub use sp1_core_machine::utils::setup_logger;
13use sysinfo::{MemoryRefreshKind, RefreshKind, System};
14
15static MEMORY_USAGE_MONITORING: Once = Once::new();
16
17/// Spawns a thread that emits warnings when the used memory is high.
18pub fn setup_memory_usage_monitoring() {
19    MEMORY_USAGE_MONITORING.call_once(|| {
20        spawn(|| {
21            let mut sys = System::new_with_specifics(
22                RefreshKind::new().with_memory(MemoryRefreshKind::new().with_ram()),
23            );
24
25            let total_memory = sys.total_memory();
26
27            loop {
28                sleep(Duration::from_secs(10));
29                sys.refresh_memory();
30
31                let used_memory = sys.used_memory();
32                #[allow(clippy::cast_precision_loss)]
33                let ratio = used_memory as f64 / total_memory as f64;
34
35                if ratio > 0.8 {
36                    tracing::warn!(
37                        "Memory usage is high: {:.2}%, we recommend using the prover network",
38                        ratio * 100.0
39                    );
40                }
41            }
42        });
43    });
44}
45
46/// Dump the program and stdin to files for debugging if `SP1_DUMP` is set.
47pub(crate) fn sp1_dump(elf: &[u8], stdin: &SP1Stdin) {
48    if std::env::var("SP1_DUMP").map(|v| v == "1" || v.to_lowercase() == "true").unwrap_or(false) {
49        std::fs::write("program.bin", elf).unwrap();
50        let stdin = bincode::serialize(&stdin).unwrap();
51        std::fs::write("stdin.bin", stdin.clone()).unwrap();
52
53        eprintln!("Dumped program.bin and stdin.bin.");
54        // Exit with the success status.
55        std::process::exit(0);
56    }
57}
58
59/// Utility method for blocking on an async function.
60///
61/// If we're already in a tokio runtime, we'll block in place. Otherwise, we'll create a new
62/// runtime.
63#[cfg(feature = "network")]
64pub(crate) fn block_on<T>(fut: impl std::future::Future<Output = T>) -> T {
65    use tokio::task::block_in_place;
66
67    // Handle case if we're already in an tokio runtime.
68    if let Ok(handle) = tokio::runtime::Handle::try_current() {
69        block_in_place(|| handle.block_on(fut))
70    } else {
71        // Otherwise create a new runtime.
72        let rt = tokio::runtime::Runtime::new().expect("Failed to create a new runtime");
73        rt.block_on(fut)
74    }
75}
76
77/// Check that SP1 SDK was built in release mode. Ensures that the prover and executor
78/// will be performant, which is important for benchmarking.
79pub(crate) fn check_release_build() {
80    #[cfg(debug_assertions)]
81    panic!("sp1-sdk must be built in release mode, please compile with the --release flag.");
82}