From 08021087eca19ce143d0b29618fec1e2edaae3d3 Mon Sep 17 00:00:00 2001 From: Yu Li Date: Wed, 29 Sep 2021 12:54:22 +0800 Subject: [PATCH] vmm: add prefault option in memory and memory-zone The argument `prefault` is provided in MemoryManager, but it can only be used by SGX and restore. With prefault (MAP_POPULATE) been set, subsequent page faults will decrease during running, although it will make boot slower. This commit adds `prefault` in MemoryConfig and MemoryZoneConfig. To resolve conflict between memory and restore, argument `prefault` has been changed from `bool` to `Option`, when its value is None, config from memory will be used, otherwise argument in Option will be used. Signed-off-by: Yu Li --- src/main.rs | 9 ++++++--- vmm/src/api/openapi/cloud-hypervisor.yaml | 6 ++++++ vmm/src/config.rs | 24 +++++++++++++++++++++-- vmm/src/memory_manager.rs | 24 +++++++++++++++++------ vmm/src/vm.rs | 4 ++-- 5 files changed, 54 insertions(+), 13 deletions(-) diff --git a/src/main.rs b/src/main.rs index 72c598afd..8726eddd7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -163,7 +163,8 @@ fn create_app<'a, 'b>( hugepages=on|off,hugepage_size=,\ hotplug_method=acpi|virtio-mem,\ hotplug_size=,\ - hotplugged_size=\"", + hotplugged_size=,\ + prefault=on|off\"", ) .default_value(default_memory) .group("vm-config"), @@ -178,7 +179,8 @@ fn create_app<'a, 'b>( hugepages=on|off,hugepage_size=,\ host_numa_node=,\ id=,hotplug_size=,\ - hotplugged_size=\"", + hotplugged_size=,\ + prefault=on|off\"", ) .takes_value(true) .min_values(1) @@ -644,8 +646,9 @@ mod unit_tests { hotplugged_size: None, shared: false, hugepages: false, - zones: None, hugepage_size: None, + prefault: false, + zones: None, }, kernel: Some(KernelConfig { path: PathBuf::from("/path/to/kernel"), diff --git a/vmm/src/api/openapi/cloud-hypervisor.yaml b/vmm/src/api/openapi/cloud-hypervisor.yaml index 56f63a3be..684f3cfaa 100644 --- a/vmm/src/api/openapi/cloud-hypervisor.yaml +++ b/vmm/src/api/openapi/cloud-hypervisor.yaml @@ -546,6 +546,9 @@ components: hotplugged_size: type: integer format: int64 + prefault: + type: boolean + default: false MemoryConfig: required: @@ -577,6 +580,9 @@ components: hugepage_size: type: integer format: int64 + prefault: + type: boolean + default: false zones: type: array items: diff --git a/vmm/src/config.rs b/vmm/src/config.rs index 97c7dd6c4..95e2e5fb5 100644 --- a/vmm/src/config.rs +++ b/vmm/src/config.rs @@ -491,6 +491,8 @@ pub struct MemoryZoneConfig { pub hotplug_size: Option, #[serde(default)] pub hotplugged_size: Option, + #[serde(default)] + pub prefault: bool, } #[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] @@ -511,6 +513,8 @@ pub struct MemoryConfig { #[serde(default)] pub hugepage_size: Option, #[serde(default)] + pub prefault: bool, + #[serde(default)] pub zones: Option>, } @@ -526,7 +530,8 @@ impl MemoryConfig { .add("hotplugged_size") .add("shared") .add("hugepages") - .add("hugepage_size"); + .add("hugepage_size") + .add("prefault"); parser.parse(memory).map_err(Error::ParseMemory)?; let size = parser @@ -565,6 +570,11 @@ impl MemoryConfig { .convert::("hugepage_size") .map_err(Error::ParseMemory)? .map(|v| v.0); + let prefault = parser + .convert::("prefault") + .map_err(Error::ParseMemory)? + .unwrap_or(Toggle(false)) + .0; let zones: Option> = if let Some(memory_zones) = &memory_zones { let mut zones = Vec::new(); @@ -579,7 +589,8 @@ impl MemoryConfig { .add("hugepage_size") .add("host_numa_node") .add("hotplug_size") - .add("hotplugged_size"); + .add("hotplugged_size") + .add("prefault"); parser.parse(memory_zone).map_err(Error::ParseMemoryZone)?; let id = parser.get("id").ok_or(Error::ParseMemoryZoneIdMissing)?; @@ -615,6 +626,11 @@ impl MemoryConfig { .convert::("hotplugged_size") .map_err(Error::ParseMemoryZone)? .map(|v| v.0); + let prefault = parser + .convert::("prefault") + .map_err(Error::ParseMemoryZone)? + .unwrap_or(Toggle(false)) + .0; zones.push(MemoryZoneConfig { id, @@ -626,6 +642,7 @@ impl MemoryConfig { host_numa_node, hotplug_size, hotplugged_size, + prefault, }); } Some(zones) @@ -642,6 +659,7 @@ impl MemoryConfig { shared, hugepages, hugepage_size, + prefault, zones, }) } @@ -676,6 +694,7 @@ impl Default for MemoryConfig { shared: false, hugepages: false, hugepage_size: None, + prefault: false, zones: None, } } @@ -2678,6 +2697,7 @@ mod tests { shared: false, hugepages: false, hugepage_size: None, + prefault: false, zones: None, }, kernel: Some(KernelConfig { diff --git a/vmm/src/memory_manager.rs b/vmm/src/memory_manager.rs index 54ecf3d94..69369803e 100644 --- a/vmm/src/memory_manager.rs +++ b/vmm/src/memory_manager.rs @@ -144,6 +144,7 @@ pub struct MemoryManager { shared: bool, hugepages: bool, hugepage_size: Option, + prefault: bool, #[cfg(target_arch = "x86_64")] sgx_epc_region: Option, user_provided_zones: bool, @@ -399,7 +400,7 @@ impl MemoryManager { fn create_memory_regions_from_zones( ram_regions: &[(GuestAddress, usize)], zones: &[MemoryZoneConfig], - prefault: bool, + prefault: Option, ) -> Result<(Vec>, MemoryZones), Error> { let mut zones = zones.to_owned(); let mut mem_regions = Vec::new(); @@ -447,7 +448,10 @@ impl MemoryManager { file_offset, region_start, region_size, - prefault, + match prefault { + Some(pf) => pf, + None => zone.prefault, + }, zone.shared, zone.hugepages, zone.hugepage_size, @@ -543,7 +547,7 @@ impl MemoryManager { pub fn new( vm: Arc, config: &MemoryConfig, - prefault: bool, + prefault: Option, phys_bits: u8, #[cfg(feature = "tdx")] tdx_enabled: bool, ) -> Result>, Error> { @@ -601,6 +605,7 @@ impl MemoryManager { host_numa_node: None, hotplug_size: config.hotplug_size, hotplugged_size: config.hotplugged_size, + prefault: config.prefault, }]; (config.size, zones) @@ -716,12 +721,18 @@ impl MemoryManager { * virtio_devices::VIRTIO_MEM_ALIGN_SIZE, ); + // When `prefault` is set by vm_restore, memory manager + // will create ram region with `prefault` option in + // restore config rather than same option in zone let region = MemoryManager::create_ram_region( &None, 0, start_addr, hotplug_size as usize, - false, + match prefault { + Some(pf) => pf, + None => zone.prefault, + }, zone.shared, zone.hugepages, zone.hugepage_size, @@ -810,6 +821,7 @@ impl MemoryManager { shared: config.shared, hugepages: config.hugepages, hugepage_size: config.hugepage_size, + prefault: config.prefault, #[cfg(target_arch = "x86_64")] sgx_epc_region: None, user_provided_zones, @@ -883,7 +895,7 @@ impl MemoryManager { let mm = MemoryManager::new( vm, config, - prefault, + Some(prefault), phys_bits, #[cfg(feature = "tdx")] false, @@ -1123,7 +1135,7 @@ impl MemoryManager { 0, start_addr, size, - false, + self.prefault, self.shared, self.hugepages, self.hugepage_size, diff --git a/vmm/src/vm.rs b/vmm/src/vm.rs index 9036c53ea..871a356e6 100644 --- a/vmm/src/vm.rs +++ b/vmm/src/vm.rs @@ -762,7 +762,7 @@ impl Vm { let memory_manager = MemoryManager::new( vm.clone(), &config.lock().unwrap().memory.clone(), - false, + None, phys_bits, #[cfg(feature = "tdx")] tdx_enabled, @@ -886,7 +886,7 @@ impl Vm { let memory_manager = MemoryManager::new( vm.clone(), &config.lock().unwrap().memory.clone(), - false, + None, phys_bits, #[cfg(feature = "tdx")] false,