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 <yusukes@chromium.org>
Owners-Override: Yusuke Sato <yusukes@chromium.org>
Tested-by: kokoro <noreply+kokoro@google.com>
Reviewed-by: Daniel Verkamp <dverkamp@chromium.org>
Reviewed-by: Joel Hockey <joelhockey@chromium.org>
Reviewed-by: Jorge Lucangeli Obes <jorgelo@chromium.org>
This commit is contained in:
Yusuke Sato 2021-08-18 11:51:38 -07:00 committed by Commit Bot
parent cce4054aa8
commit 31e136aeda
3 changed files with 28 additions and 2 deletions

View file

@ -302,6 +302,7 @@ pub struct Config {
pub vcpu_affinity: Option<VcpuAffinity>,
pub cpu_clusters: Vec<Vec<usize>>,
pub cpu_capacity: BTreeMap<usize, u32>, // CPU index -> capacity
pub per_vm_core_scheduling: bool,
#[cfg(feature = "audio_cras")]
pub cras_snd: Option<CrasSndParameters>,
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,

View file

@ -1826,6 +1826,7 @@ fn runnable_vcpu<V>(
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<V>(
#[cfg(all(target_arch = "x86_64", feature = "gdb"))] to_gdb_tube: Option<
mpsc::Sender<VcpuDebugStatusMessage>,
>,
enable_per_vm_core_scheduling: bool,
) -> Result<JoinHandle<()>>
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<V: VmArch + 'static, Vcpu: VcpuArch + 'static>(
sandbox: bool,
map_request: Arc<Mutex<Option<ExternalMapping>>>,
mut gralloc: RutabagaGralloc,
enable_per_vm_core_scheduling: bool,
) -> Result<()> {
#[derive(PollToken)]
enum Token {
@ -2816,6 +2824,15 @@ fn run_control<V: VmArch + 'static, Vcpu: VcpuArch + 'static>(
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<V: VmArch + 'static, Vcpu: VcpuArch + 'static>(
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));
}

View file

@ -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]",