vmm: Make Transparent Huge Pages controllable (default on)

Add MemoryConfig::thp and `--memory thp=on|off` to allow control of
Transparent Huge Pages.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
This commit is contained in:
Rob Bradford 2022-11-07 16:25:36 +00:00
parent b68add2d0d
commit f603afc46e
6 changed files with 32 additions and 4 deletions

View File

@ -137,6 +137,7 @@ fn create_dummy_virtio_mem(bytes: &[u8; VIRTIO_MEM_DATA_SIZE]) -> (Mem, Arc<Gues
None, None,
numa_id, numa_id,
None, None,
false,
) )
.unwrap(); .unwrap();

View File

@ -166,7 +166,7 @@ fn create_app(default_vcpus: String, default_memory: String, default_rng: String
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\"", prefault=on|off,thp=on|off\"",
) )
.default_value(default_memory) .default_value(default_memory)
.group("vm-config"), .group("vm-config"),
@ -676,6 +676,7 @@ mod unit_tests {
hugepage_size: None, hugepage_size: None,
prefault: false, prefault: false,
zones: None, zones: None,
thp: true,
}, },
payload: Some(PayloadConfig { payload: Some(PayloadConfig {
kernel: Some(PathBuf::from("/path/to/kernel")), kernel: Some(PathBuf::from("/path/to/kernel")),

View File

@ -658,7 +658,8 @@ impl MemoryConfig {
.add("shared") .add("shared")
.add("hugepages") .add("hugepages")
.add("hugepage_size") .add("hugepage_size")
.add("prefault"); .add("prefault")
.add("thp");
parser.parse(memory).map_err(Error::ParseMemory)?; parser.parse(memory).map_err(Error::ParseMemory)?;
let size = parser let size = parser
@ -702,6 +703,11 @@ impl MemoryConfig {
.map_err(Error::ParseMemory)? .map_err(Error::ParseMemory)?
.unwrap_or(Toggle(false)) .unwrap_or(Toggle(false))
.0; .0;
let thp = parser
.convert::<Toggle>("thp")
.map_err(Error::ParseMemory)?
.unwrap_or(Toggle(true))
.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();
@ -788,6 +794,7 @@ impl MemoryConfig {
hugepage_size, hugepage_size,
prefault, prefault,
zones, zones,
thp,
}) })
} }
@ -2727,6 +2734,7 @@ mod tests {
hugepage_size: None, hugepage_size: None,
prefault: false, prefault: false,
zones: None, zones: None,
thp: true,
}, },
payload: Some(PayloadConfig { payload: Some(PayloadConfig {
kernel: Some(PathBuf::from("/path/to/kernel")), kernel: Some(PathBuf::from("/path/to/kernel")),

View File

@ -2062,6 +2062,7 @@ mod unit_tests {
hugepage_size: None, hugepage_size: None,
prefault: false, prefault: false,
zones: None, zones: None,
thp: true,
}, },
payload: Some(PayloadConfig { payload: Some(PayloadConfig {
kernel: Some(PathBuf::from("/path/to/kernel")), kernel: Some(PathBuf::from("/path/to/kernel")),

View File

@ -175,6 +175,7 @@ pub struct MemoryManager {
hugepages: bool, hugepages: bool,
hugepage_size: Option<u64>, hugepage_size: Option<u64>,
prefault: bool, prefault: bool,
thp: 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,
@ -442,6 +443,7 @@ impl MemoryManager {
ram_regions: &[(GuestAddress, usize)], ram_regions: &[(GuestAddress, usize)],
zones: &[MemoryZoneConfig], zones: &[MemoryZoneConfig],
prefault: Option<bool>, prefault: Option<bool>,
thp: 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();
@ -498,6 +500,7 @@ impl MemoryManager {
zone.hugepage_size, zone.hugepage_size,
zone.host_numa_node, zone.host_numa_node,
None, None,
thp,
)?; )?;
// Add region to the list of regions associated with the // Add region to the list of regions associated with the
@ -550,6 +553,7 @@ impl MemoryManager {
zones_config: &[MemoryZoneConfig], zones_config: &[MemoryZoneConfig],
prefault: Option<bool>, prefault: Option<bool>,
mut existing_memory_files: HashMap<u32, File>, mut existing_memory_files: HashMap<u32, File>,
thp: bool,
) -> Result<(Vec<Arc<GuestRegionMmap>>, MemoryZones), Error> { ) -> Result<(Vec<Arc<GuestRegionMmap>>, MemoryZones), Error> {
let mut memory_regions = Vec::new(); let mut memory_regions = Vec::new();
let mut memory_zones = HashMap::new(); let mut memory_zones = HashMap::new();
@ -575,6 +579,7 @@ impl MemoryManager {
zone_config.hugepage_size, zone_config.hugepage_size,
zone_config.host_numa_node, zone_config.host_numa_node,
existing_memory_files.remove(&guest_ram_mapping.slot), existing_memory_files.remove(&guest_ram_mapping.slot),
thp,
)?; )?;
memory_regions.push(Arc::clone(&region)); memory_regions.push(Arc::clone(&region));
if let Some(memory_zone) = memory_zones.get_mut(&guest_ram_mapping.zone_id) { if let Some(memory_zone) = memory_zones.get_mut(&guest_ram_mapping.zone_id) {
@ -911,6 +916,7 @@ impl MemoryManager {
&zones, &zones,
prefault, prefault,
existing_memory_files.unwrap_or_default(), existing_memory_files.unwrap_or_default(),
config.thp,
)?; )?;
let guest_memory = let guest_memory =
GuestMemoryMmap::from_arc_regions(regions).map_err(Error::GuestMemory)?; GuestMemoryMmap::from_arc_regions(regions).map_err(Error::GuestMemory)?;
@ -948,7 +954,7 @@ impl MemoryManager {
.collect(); .collect();
let (mem_regions, mut memory_zones) = let (mem_regions, mut memory_zones) =
Self::create_memory_regions_from_zones(&ram_regions, &zones, prefault)?; Self::create_memory_regions_from_zones(&ram_regions, &zones, prefault, config.thp)?;
let mut guest_memory = let mut guest_memory =
GuestMemoryMmap::from_arc_regions(mem_regions).map_err(Error::GuestMemory)?; GuestMemoryMmap::from_arc_regions(mem_regions).map_err(Error::GuestMemory)?;
@ -997,6 +1003,7 @@ impl MemoryManager {
zone.hugepage_size, zone.hugepage_size,
zone.host_numa_node, zone.host_numa_node,
None, None,
config.thp,
)?; )?;
guest_memory = guest_memory guest_memory = guest_memory
@ -1125,6 +1132,7 @@ impl MemoryManager {
dynamic, dynamic,
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
uefi_flash: None, uefi_flash: None,
thp: config.thp,
}; };
memory_manager.allocate_address_space()?; memory_manager.allocate_address_space()?;
@ -1298,6 +1306,7 @@ impl MemoryManager {
hugepage_size: Option<u64>, hugepage_size: Option<u64>,
host_numa_node: Option<u32>, host_numa_node: Option<u32>,
existing_memory_file: Option<File>, existing_memory_file: Option<File>,
thp: bool,
) -> Result<Arc<GuestRegionMmap>, Error> { ) -> Result<Arc<GuestRegionMmap>, Error> {
let mut mmap_flags = libc::MAP_NORESERVE; let mut mmap_flags = libc::MAP_NORESERVE;
@ -1336,7 +1345,7 @@ impl MemoryManager {
) )
.map_err(Error::GuestMemory)?; .map_err(Error::GuestMemory)?;
if region.file_offset().is_none() { if region.file_offset().is_none() && thp {
info!( info!(
"Anonymous mapping at 0x{:x} (size = 0x{:x})", "Anonymous mapping at 0x{:x} (size = 0x{:x})",
region.as_ptr() as u64, region.as_ptr() as u64,
@ -1438,6 +1447,7 @@ impl MemoryManager {
self.hugepage_size, self.hugepage_size,
None, None,
None, None,
self.thp,
)?; )?;
// Map it into the guest // Map it into the guest

View File

@ -139,6 +139,10 @@ impl Default for HotplugMethod {
} }
} }
fn default_memoryconfig_thp() -> bool {
true
}
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
pub struct MemoryConfig { pub struct MemoryConfig {
pub size: u64, pub size: u64,
@ -160,6 +164,8 @@ pub struct MemoryConfig {
pub prefault: bool, pub prefault: bool,
#[serde(default)] #[serde(default)]
pub zones: Option<Vec<MemoryZoneConfig>>, pub zones: Option<Vec<MemoryZoneConfig>>,
#[serde(default = "default_memoryconfig_thp")]
pub thp: bool,
} }
pub const DEFAULT_MEMORY_MB: u64 = 512; pub const DEFAULT_MEMORY_MB: u64 = 512;
@ -177,6 +183,7 @@ impl Default for MemoryConfig {
hugepage_size: None, hugepage_size: None,
prefault: false, prefault: false,
zones: None, zones: None,
thp: true,
} }
} }
} }