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<bool>`, when
its value is None, config from memory will be used, otherwise
argument in Option will be used.

Signed-off-by: Yu Li <liyu.yukiteru@bytedance.com>
This commit is contained in:
Yu Li 2021-09-29 12:54:22 +08:00 committed by Sebastien Boeuf
parent 90d79fa76b
commit 08021087ec
5 changed files with 54 additions and 13 deletions

View File

@ -163,7 +163,8 @@ fn create_app<'a, 'b>(
hugepages=on|off,hugepage_size=<hugepage_size>,\ hugepages=on|off,hugepage_size=<hugepage_size>,\
hotplug_method=acpi|virtio-mem,\ hotplug_method=acpi|virtio-mem,\
hotplug_size=<hotpluggable_memory_size>,\ hotplug_size=<hotpluggable_memory_size>,\
hotplugged_size=<hotplugged_memory_size>\"", hotplugged_size=<hotplugged_memory_size>,\
prefault=on|off\"",
) )
.default_value(default_memory) .default_value(default_memory)
.group("vm-config"), .group("vm-config"),
@ -178,7 +179,8 @@ fn create_app<'a, 'b>(
hugepages=on|off,hugepage_size=<hugepage_size>,\ hugepages=on|off,hugepage_size=<hugepage_size>,\
host_numa_node=<node_id>,\ host_numa_node=<node_id>,\
id=<zone_identifier>,hotplug_size=<hotpluggable_memory_size>,\ id=<zone_identifier>,hotplug_size=<hotpluggable_memory_size>,\
hotplugged_size=<hotplugged_memory_size>\"", hotplugged_size=<hotplugged_memory_size>,\
prefault=on|off\"",
) )
.takes_value(true) .takes_value(true)
.min_values(1) .min_values(1)
@ -644,8 +646,9 @@ mod unit_tests {
hotplugged_size: None, hotplugged_size: None,
shared: false, shared: false,
hugepages: false, hugepages: false,
zones: None,
hugepage_size: None, hugepage_size: None,
prefault: false,
zones: None,
}, },
kernel: Some(KernelConfig { kernel: Some(KernelConfig {
path: PathBuf::from("/path/to/kernel"), path: PathBuf::from("/path/to/kernel"),

View File

@ -546,6 +546,9 @@ components:
hotplugged_size: hotplugged_size:
type: integer type: integer
format: int64 format: int64
prefault:
type: boolean
default: false
MemoryConfig: MemoryConfig:
required: required:
@ -577,6 +580,9 @@ components:
hugepage_size: hugepage_size:
type: integer type: integer
format: int64 format: int64
prefault:
type: boolean
default: false
zones: zones:
type: array type: array
items: items:

View File

@ -491,6 +491,8 @@ pub struct MemoryZoneConfig {
pub hotplug_size: Option<u64>, pub hotplug_size: Option<u64>,
#[serde(default)] #[serde(default)]
pub hotplugged_size: Option<u64>, pub hotplugged_size: Option<u64>,
#[serde(default)]
pub prefault: bool,
} }
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
@ -511,6 +513,8 @@ pub struct MemoryConfig {
#[serde(default)] #[serde(default)]
pub hugepage_size: Option<u64>, pub hugepage_size: Option<u64>,
#[serde(default)] #[serde(default)]
pub prefault: bool,
#[serde(default)]
pub zones: Option<Vec<MemoryZoneConfig>>, pub zones: Option<Vec<MemoryZoneConfig>>,
} }
@ -526,7 +530,8 @@ impl MemoryConfig {
.add("hotplugged_size") .add("hotplugged_size")
.add("shared") .add("shared")
.add("hugepages") .add("hugepages")
.add("hugepage_size"); .add("hugepage_size")
.add("prefault");
parser.parse(memory).map_err(Error::ParseMemory)?; parser.parse(memory).map_err(Error::ParseMemory)?;
let size = parser let size = parser
@ -565,6 +570,11 @@ impl MemoryConfig {
.convert::<ByteSized>("hugepage_size") .convert::<ByteSized>("hugepage_size")
.map_err(Error::ParseMemory)? .map_err(Error::ParseMemory)?
.map(|v| v.0); .map(|v| v.0);
let prefault = parser
.convert::<Toggle>("prefault")
.map_err(Error::ParseMemory)?
.unwrap_or(Toggle(false))
.0;
let zones: Option<Vec<MemoryZoneConfig>> = if let Some(memory_zones) = &memory_zones { let zones: Option<Vec<MemoryZoneConfig>> = if let Some(memory_zones) = &memory_zones {
let mut zones = Vec::new(); let mut zones = Vec::new();
@ -579,7 +589,8 @@ impl MemoryConfig {
.add("hugepage_size") .add("hugepage_size")
.add("host_numa_node") .add("host_numa_node")
.add("hotplug_size") .add("hotplug_size")
.add("hotplugged_size"); .add("hotplugged_size")
.add("prefault");
parser.parse(memory_zone).map_err(Error::ParseMemoryZone)?; parser.parse(memory_zone).map_err(Error::ParseMemoryZone)?;
let id = parser.get("id").ok_or(Error::ParseMemoryZoneIdMissing)?; let id = parser.get("id").ok_or(Error::ParseMemoryZoneIdMissing)?;
@ -615,6 +626,11 @@ impl MemoryConfig {
.convert::<ByteSized>("hotplugged_size") .convert::<ByteSized>("hotplugged_size")
.map_err(Error::ParseMemoryZone)? .map_err(Error::ParseMemoryZone)?
.map(|v| v.0); .map(|v| v.0);
let prefault = parser
.convert::<Toggle>("prefault")
.map_err(Error::ParseMemoryZone)?
.unwrap_or(Toggle(false))
.0;
zones.push(MemoryZoneConfig { zones.push(MemoryZoneConfig {
id, id,
@ -626,6 +642,7 @@ impl MemoryConfig {
host_numa_node, host_numa_node,
hotplug_size, hotplug_size,
hotplugged_size, hotplugged_size,
prefault,
}); });
} }
Some(zones) Some(zones)
@ -642,6 +659,7 @@ impl MemoryConfig {
shared, shared,
hugepages, hugepages,
hugepage_size, hugepage_size,
prefault,
zones, zones,
}) })
} }
@ -676,6 +694,7 @@ impl Default for MemoryConfig {
shared: false, shared: false,
hugepages: false, hugepages: false,
hugepage_size: None, hugepage_size: None,
prefault: false,
zones: None, zones: None,
} }
} }
@ -2678,6 +2697,7 @@ mod tests {
shared: false, shared: false,
hugepages: false, hugepages: false,
hugepage_size: None, hugepage_size: None,
prefault: false,
zones: None, zones: None,
}, },
kernel: Some(KernelConfig { kernel: Some(KernelConfig {

View File

@ -144,6 +144,7 @@ pub struct MemoryManager {
shared: bool, shared: bool,
hugepages: bool, hugepages: bool,
hugepage_size: Option<u64>, hugepage_size: Option<u64>,
prefault: bool,
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
sgx_epc_region: Option<SgxEpcRegion>, sgx_epc_region: Option<SgxEpcRegion>,
user_provided_zones: bool, user_provided_zones: bool,
@ -399,7 +400,7 @@ impl MemoryManager {
fn create_memory_regions_from_zones( fn create_memory_regions_from_zones(
ram_regions: &[(GuestAddress, usize)], ram_regions: &[(GuestAddress, usize)],
zones: &[MemoryZoneConfig], zones: &[MemoryZoneConfig],
prefault: bool, prefault: Option<bool>,
) -> Result<(Vec<Arc<GuestRegionMmap>>, MemoryZones), Error> { ) -> Result<(Vec<Arc<GuestRegionMmap>>, MemoryZones), Error> {
let mut zones = zones.to_owned(); let mut zones = zones.to_owned();
let mut mem_regions = Vec::new(); let mut mem_regions = Vec::new();
@ -447,7 +448,10 @@ impl MemoryManager {
file_offset, file_offset,
region_start, region_start,
region_size, region_size,
prefault, match prefault {
Some(pf) => pf,
None => zone.prefault,
},
zone.shared, zone.shared,
zone.hugepages, zone.hugepages,
zone.hugepage_size, zone.hugepage_size,
@ -543,7 +547,7 @@ impl MemoryManager {
pub fn new( pub fn new(
vm: Arc<dyn hypervisor::Vm>, vm: Arc<dyn hypervisor::Vm>,
config: &MemoryConfig, config: &MemoryConfig,
prefault: bool, prefault: Option<bool>,
phys_bits: u8, phys_bits: u8,
#[cfg(feature = "tdx")] tdx_enabled: bool, #[cfg(feature = "tdx")] tdx_enabled: bool,
) -> Result<Arc<Mutex<MemoryManager>>, Error> { ) -> Result<Arc<Mutex<MemoryManager>>, Error> {
@ -601,6 +605,7 @@ impl MemoryManager {
host_numa_node: None, host_numa_node: None,
hotplug_size: config.hotplug_size, hotplug_size: config.hotplug_size,
hotplugged_size: config.hotplugged_size, hotplugged_size: config.hotplugged_size,
prefault: config.prefault,
}]; }];
(config.size, zones) (config.size, zones)
@ -716,12 +721,18 @@ impl MemoryManager {
* virtio_devices::VIRTIO_MEM_ALIGN_SIZE, * 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( let region = MemoryManager::create_ram_region(
&None, &None,
0, 0,
start_addr, start_addr,
hotplug_size as usize, hotplug_size as usize,
false, match prefault {
Some(pf) => pf,
None => zone.prefault,
},
zone.shared, zone.shared,
zone.hugepages, zone.hugepages,
zone.hugepage_size, zone.hugepage_size,
@ -810,6 +821,7 @@ impl MemoryManager {
shared: config.shared, shared: config.shared,
hugepages: config.hugepages, hugepages: config.hugepages,
hugepage_size: config.hugepage_size, hugepage_size: config.hugepage_size,
prefault: config.prefault,
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
sgx_epc_region: None, sgx_epc_region: None,
user_provided_zones, user_provided_zones,
@ -883,7 +895,7 @@ impl MemoryManager {
let mm = MemoryManager::new( let mm = MemoryManager::new(
vm, vm,
config, config,
prefault, Some(prefault),
phys_bits, phys_bits,
#[cfg(feature = "tdx")] #[cfg(feature = "tdx")]
false, false,
@ -1123,7 +1135,7 @@ impl MemoryManager {
0, 0,
start_addr, start_addr,
size, size,
false, self.prefault,
self.shared, self.shared,
self.hugepages, self.hugepages,
self.hugepage_size, self.hugepage_size,

View File

@ -762,7 +762,7 @@ impl Vm {
let memory_manager = MemoryManager::new( let memory_manager = MemoryManager::new(
vm.clone(), vm.clone(),
&config.lock().unwrap().memory.clone(), &config.lock().unwrap().memory.clone(),
false, None,
phys_bits, phys_bits,
#[cfg(feature = "tdx")] #[cfg(feature = "tdx")]
tdx_enabled, tdx_enabled,
@ -886,7 +886,7 @@ impl Vm {
let memory_manager = MemoryManager::new( let memory_manager = MemoryManager::new(
vm.clone(), vm.clone(),
&config.lock().unwrap().memory.clone(), &config.lock().unwrap().memory.clone(),
false, None,
phys_bits, phys_bits,
#[cfg(feature = "tdx")] #[cfg(feature = "tdx")]
false, false,