diff --git a/src/cli/src/commands/pool.rs b/src/cli/src/commands/pool.rs index 5938c345..3349e0aa 100644 --- a/src/cli/src/commands/pool.rs +++ b/src/cli/src/commands/pool.rs @@ -78,6 +78,11 @@ pub struct PoolStartArgs { #[arg(long)] pub deferred: bool, + /// Mark pooled VM memory KSM-mergeable so the host dedups identical pages + /// across same-image VMs (Linux 6.4+; needs /sys/kernel/mm/ksm/run=1). + #[arg(long)] + pub ksm: bool, + /// Output as JSON #[arg(long)] pub json: bool, @@ -265,6 +270,8 @@ struct PoolRegistry { /// When true, pooled VMs boot IDLE and `pool run` spawns the command as the /// box's real MAIN (full box semantics), instead of exec-into-keepalive. deferred: bool, + /// Mark pooled VM memory KSM-mergeable (host page dedup across same-image VMs). + ksm: bool, } impl PoolRegistry { @@ -292,6 +299,7 @@ impl PoolRegistry { cmd: keepalive_cmd(), pool: pool_config.clone(), deferred_main: self.deferred, + ksm: self.ksm, ..Default::default() }; let pool = std::sync::Arc::new( @@ -360,6 +368,7 @@ async fn execute_start(args: PoolStartArgs) -> Result<(), Box, @@ -175,6 +180,7 @@ impl Default for InstanceSpec { args: Vec::new(), env: Vec::new(), }, + ksm: false, console_output: None, workdir: "/".to_string(), tee_config: None, @@ -395,6 +401,7 @@ mod tests { fn test_instance_spec_serde_roundtrip() { let spec = InstanceSpec { box_id: "test-box-123".to_string(), + ksm: false, vcpus: 4, memory_mib: 2048, rootfs_path: PathBuf::from("/tmp/rootfs"), diff --git a/src/runtime/src/vm/spec.rs b/src/runtime/src/vm/spec.rs index 8ee02316..9661a2dd 100644 --- a/src/runtime/src/vm/spec.rs +++ b/src/runtime/src/vm/spec.rs @@ -344,6 +344,11 @@ impl VmManager { network: None, // Network config is set by CLI when --network is specified resource_limits: self.config.resource_limits.clone(), log_config: self.log_config.clone(), + // KSM page-merging: config field, or the A3S_BOX_KSM env override. + ksm: self.config.ksm + || std::env::var("A3S_BOX_KSM") + .map(|v| matches!(v.as_str(), "1" | "true" | "yes" | "on")) + .unwrap_or(false), }) } diff --git a/src/runtime/src/vmm/controller.rs b/src/runtime/src/vmm/controller.rs index fefda436..09880635 100644 --- a/src/runtime/src/vmm/controller.rs +++ b/src/runtime/src/vmm/controller.rs @@ -413,6 +413,12 @@ impl VmmProvider for VmController { cmd.arg("--config").arg(&config_json).stdin(Stdio::null()); self.configure_shim_stdio(&mut cmd, spec); + // KSM page-merging: the shim opts its (guest) memory in via prctl when this + // env is set; driven by InstanceSpec.ksm (BoxConfig.ksm or A3S_BOX_KSM). + if spec.ksm { + cmd.env("A3S_BOX_KSM", "1"); + } + // On macOS, set DYLD_LIBRARY_PATH to help find libkrunfw #[cfg(target_os = "macos")] {