From 31e136aeda4b40915811acc5e55a83e6a4ed3f0c Mon Sep 17 00:00:00 2001 From: Yusuke Sato Date: Wed, 18 Aug 2021 11:51:38 -0700 Subject: [PATCH] crosvm: Allow all vCPU threads to share same cookie for core scheduling This CL adds --per-vm-core-scheduling command line option to crosvm to allow ARCVM to use per-VM core scheduling for better performance. Note that per-VM core scheduling makes all vCPU threads to share the same core scheduling cookie. The feature is disabled by default, and does not change Linux VMs behavior unless the new command line flag is explicitly passed in. Also, this CL never affect Parallels since it uses the plugin infrastructure (src/plugin/). For ARCVM, the feature will be enabled by default via Chromium's base::Feature (see crrev.com/c/3207747) as an interim solution until the optimized two-level core scheduling is ready. This is based on the latest recommendation from the security team (newfel@, resch@, and others) at go/arcvm-core-scheduling-recommendations. Credit: This CL is based on an idea from joelhockey@ and bgeffon@ at go/exawj BUG=b:194022819 TEST=boot ARCVM with the new flag and verify all vCPU threads have same cookie. Change-Id: Ib97ab9942b2516df9fbffe35517919f29b309a83 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/3101607 Commit-Queue: Yusuke Sato Owners-Override: Yusuke Sato Tested-by: kokoro Reviewed-by: Daniel Verkamp Reviewed-by: Joel Hockey Reviewed-by: Jorge Lucangeli Obes --- src/crosvm.rs | 2 ++ src/linux.rs | 22 ++++++++++++++++++++-- src/main.rs | 6 ++++++ 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/src/crosvm.rs b/src/crosvm.rs index 78dbdc6b0d..dc6e78de3a 100644 --- a/src/crosvm.rs +++ b/src/crosvm.rs @@ -302,6 +302,7 @@ pub struct Config { pub vcpu_affinity: Option, pub cpu_clusters: Vec>, pub cpu_capacity: BTreeMap, // CPU index -> capacity + pub per_vm_core_scheduling: bool, #[cfg(feature = "audio_cras")] pub cras_snd: Option, pub delay_rt: bool, @@ -390,6 +391,7 @@ impl Default for Config { vcpu_affinity: None, cpu_clusters: Vec::new(), cpu_capacity: BTreeMap::new(), + per_vm_core_scheduling: false, #[cfg(feature = "audio_cras")] cras_snd: None, delay_rt: false, diff --git a/src/linux.rs b/src/linux.rs index c5554827f4..adedad5e60 100644 --- a/src/linux.rs +++ b/src/linux.rs @@ -1826,6 +1826,7 @@ fn runnable_vcpu( no_smt: bool, has_bios: bool, use_hypervisor_signals: bool, + enable_per_vm_core_scheduling: bool, ) -> Result<(V, VcpuRunHandle)> where V: VcpuArch, @@ -1868,8 +1869,11 @@ where ) .map_err(Error::ConfigureVcpu)?; - if let Err(e) = enable_core_scheduling() { - error!("Failed to enable core scheduling: {}", e); + if !enable_per_vm_core_scheduling { + // Do per-vCPU core scheduling by setting a unique cookie to each vCPU. + if let Err(e) = enable_core_scheduling() { + error!("Failed to enable core scheduling: {}", e); + } } if run_rt { @@ -1991,6 +1995,7 @@ fn run_vcpu( #[cfg(all(target_arch = "x86_64", feature = "gdb"))] to_gdb_tube: Option< mpsc::Sender, >, + enable_per_vm_core_scheduling: bool, ) -> Result> where V: VcpuArch + 'static, @@ -2015,6 +2020,7 @@ where no_smt, has_bios, use_hypervisor_signals, + enable_per_vm_core_scheduling, ); start_barrier.wait(); @@ -2654,6 +2660,7 @@ where cfg.sandbox, Arc::clone(&map_request), gralloc, + cfg.per_vm_core_scheduling, ) } @@ -2746,6 +2753,7 @@ fn run_control( sandbox: bool, map_request: Arc>>, mut gralloc: RutabagaGralloc, + enable_per_vm_core_scheduling: bool, ) -> Result<()> { #[derive(PollToken)] enum Token { @@ -2816,6 +2824,15 @@ fn run_control( Some(vec) => vec.into_iter().map(Some).collect(), None => iter::repeat_with(|| None).take(linux.vcpu_count).collect(), }; + // Enable core scheduling before creating vCPUs so that the cookie will be + // shared by all vCPU threads. + // TODO(b/199312402): Avoid enabling core scheduling for the crosvm process + // itself for even better performance. Only vCPUs need the feature. + if enable_per_vm_core_scheduling { + if let Err(e) = enable_core_scheduling() { + error!("Failed to enable core scheduling: {}", e); + } + } for (cpu_id, vcpu) in vcpus.into_iter().enumerate() { let (to_vcpu_channel, from_main_channel) = mpsc::channel(); let vcpu_affinity = match linux.vcpu_affinity.clone() { @@ -2843,6 +2860,7 @@ fn run_control( use_hypervisor_signals, #[cfg(all(target_arch = "x86_64", feature = "gdb"))] to_gdb_channel.clone(), + enable_per_vm_core_scheduling, )?; vcpu_handles.push((handle, to_vcpu_channel)); } diff --git a/src/main.rs b/src/main.rs index 24ec73bdad..38b081ed6c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -978,6 +978,9 @@ fn set_argument(cfg: &mut Config, name: &str, value: Option<&str>) -> argument:: "cpu-capacity" => { parse_cpu_capacity(value.unwrap(), &mut cfg.cpu_capacity)?; } + "per-vm-core-scheduling" => { + cfg.per_vm_core_scheduling = true; + } #[cfg(feature = "audio_cras")] "cras-snd" => { cfg.cras_snd = Some( @@ -2041,6 +2044,9 @@ fn run_vm(args: std::env::Args) -> std::result::Result<(), ()> { or colon-separated list of assignments of guest to host CPU assignments (e.g. 0=0:1=1:2=2) (default: no mask)"), Argument::value("cpu-cluster", "CPUSET", "Group the given CPUs into a cluster (default: no clusters)"), Argument::value("cpu-capacity", "CPU=CAP[,CPU=CAP[,...]]", "Set the relative capacity of the given CPU (default: no capacity)"), + Argument::flag("per-vm-core-scheduling", "Enable per-VM core scheduling intead of the default one (per-vCPU core scheduing) by + making all vCPU threads share same cookie for core scheduling. + This option is no-op on devices that have neither MDS nor L1TF vulnerability."), #[cfg(feature = "audio_cras")] Argument::value("cras-snd", "[capture=true,client=crosvm,socket=unified]",