diff --git a/host/src/bin/pyhl.rs b/host/src/bin/pyhl.rs index 2014df8..d82b930 100644 --- a/host/src/bin/pyhl.rs +++ b/host/src/bin/pyhl.rs @@ -581,20 +581,6 @@ fn fresh_seed() -> u128 { // -- main --------------------------------------------------------------------- fn main() -> Result<()> { - // On Windows, hyperlight's surrogate-process manager pre-spawns - // HYPERLIGHT_INITIAL_SURROGATES Windows processes (default 512) - // the first time any sandbox is created. At ~7ms per CreateProcessA - // that's ~3.5s of amortised cost we pay on every `pyhl run`. Since - // pyhl is a short-lived single-sandbox CLI, pinning the initial - // count at 1 drops that to ~7ms. Caller can override by setting - // the env var explicitly before invoking pyhl. - if std::env::var_os("HYPERLIGHT_INITIAL_SURROGATES").is_none() { - // Safety: main() runs single-threaded on entry; set_var is safe here. - unsafe { - std::env::set_var("HYPERLIGHT_INITIAL_SURROGATES", "1"); - } - } - let cli = Cli::parse(); match cli.cmd { Command::Setup(args) => cmd_setup(args), diff --git a/host/src/pyhl.rs b/host/src/pyhl.rs index 0d7d18b..c6f47b0 100644 --- a/host/src/pyhl.rs +++ b/host/src/pyhl.rs @@ -46,6 +46,24 @@ use std::time::Instant; use crate::{Preopen, Sandbox}; +/// Default Hyperlight's surrogate-process pool to 1 on Windows. +/// +/// The surrogate-process manager pre-spawns `HYPERLIGHT_INITIAL_SURROGATES` +/// Windows processes (default 512) the first time any sandbox is created. +/// At ~7 ms per `CreateProcessA` that is ~3.5 s of latency that library +/// callers would pay on the very first sandbox. Pinning the default to 1 +/// drops that to ~7 ms. Callers (or the embedding binary) can still +/// override by setting the env var before calling into `pyhl`. +fn default_surrogate_count() { + if std::env::var_os("HYPERLIGHT_INITIAL_SURROGATES").is_none() { + // Safety: must be called before any sandbox is created and + // before additional threads are spawned. + unsafe { + std::env::set_var("HYPERLIGHT_INITIAL_SURROGATES", "1"); + } + } +} + /// Standard file names inside an image home. pub const KERNEL_FILE: &str = "kernel"; /// Standard file names inside an image home. @@ -104,6 +122,7 @@ pub struct InstallReport { /// are local file copies. See [`InstallSource`] for each variant's /// semantics. pub fn install(opts: &InstallOptions<'_>) -> Result { + default_surrogate_count(); let home = opts.home.to_path_buf(); let dst_kernel = home.join(KERNEL_FILE); let dst_initrd = home.join(INITRD_FILE); @@ -216,6 +235,7 @@ impl Runtime { /// directories to expose under the guest paths that were baked in /// at `install` time. pub fn new(home: &Path, mounts: &[Preopen]) -> Result { + default_surrogate_count(); let snap = home.join(SNAPSHOT_FILE); if !snap.is_file() { bail!(