Skip to content

Commit 7fc0741

Browse files
committed
pyhl: default surrogate process pool to 1 for library callers
Move the HYPERLIGHT_INITIAL_SURROGATES=1 default from the CLI binary into the pyhl library so Rust callers of pyhl::install / Runtime::new also avoid the ~3.5s startup cost of pre-spawning 512 surrogate processes on Windows. Callers can still override via the env var. Signed-off-by: danbugs <danilochiarlone@gmail.com>
1 parent d23fdee commit 7fc0741

2 files changed

Lines changed: 20 additions & 14 deletions

File tree

host/src/bin/pyhl.rs

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -581,20 +581,6 @@ fn fresh_seed() -> u128 {
581581
// -- main ---------------------------------------------------------------------
582582

583583
fn main() -> Result<()> {
584-
// On Windows, hyperlight's surrogate-process manager pre-spawns
585-
// HYPERLIGHT_INITIAL_SURROGATES Windows processes (default 512)
586-
// the first time any sandbox is created. At ~7ms per CreateProcessA
587-
// that's ~3.5s of amortised cost we pay on every `pyhl run`. Since
588-
// pyhl is a short-lived single-sandbox CLI, pinning the initial
589-
// count at 1 drops that to ~7ms. Caller can override by setting
590-
// the env var explicitly before invoking pyhl.
591-
if std::env::var_os("HYPERLIGHT_INITIAL_SURROGATES").is_none() {
592-
// Safety: main() runs single-threaded on entry; set_var is safe here.
593-
unsafe {
594-
std::env::set_var("HYPERLIGHT_INITIAL_SURROGATES", "1");
595-
}
596-
}
597-
598584
let cli = Cli::parse();
599585
match cli.cmd {
600586
Command::Setup(args) => cmd_setup(args),

host/src/pyhl.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,24 @@ use std::time::Instant;
4646

4747
use crate::{Preopen, Sandbox};
4848

49+
/// Default Hyperlight's surrogate-process pool to 1 on Windows.
50+
///
51+
/// The surrogate-process manager pre-spawns `HYPERLIGHT_INITIAL_SURROGATES`
52+
/// Windows processes (default 512) the first time any sandbox is created.
53+
/// At ~7 ms per `CreateProcessA` that is ~3.5 s of latency that library
54+
/// callers would pay on the very first sandbox. Pinning the default to 1
55+
/// drops that to ~7 ms. Callers (or the embedding binary) can still
56+
/// override by setting the env var before calling into `pyhl`.
57+
fn default_surrogate_count() {
58+
if std::env::var_os("HYPERLIGHT_INITIAL_SURROGATES").is_none() {
59+
// Safety: must be called before any sandbox is created and
60+
// before additional threads are spawned.
61+
unsafe {
62+
std::env::set_var("HYPERLIGHT_INITIAL_SURROGATES", "1");
63+
}
64+
}
65+
}
66+
4967
/// Standard file names inside an image home.
5068
pub const KERNEL_FILE: &str = "kernel";
5169
/// Standard file names inside an image home.
@@ -104,6 +122,7 @@ pub struct InstallReport {
104122
/// are local file copies. See [`InstallSource`] for each variant's
105123
/// semantics.
106124
pub fn install(opts: &InstallOptions<'_>) -> Result<InstallReport> {
125+
default_surrogate_count();
107126
let home = opts.home.to_path_buf();
108127
let dst_kernel = home.join(KERNEL_FILE);
109128
let dst_initrd = home.join(INITRD_FILE);
@@ -216,6 +235,7 @@ impl Runtime {
216235
/// directories to expose under the guest paths that were baked in
217236
/// at `install` time.
218237
pub fn new(home: &Path, mounts: &[Preopen]) -> Result<Self> {
238+
default_surrogate_count();
219239
let snap = home.join(SNAPSHOT_FILE);
220240
if !snap.is_file() {
221241
bail!(

0 commit comments

Comments
 (0)