vmm: memory: Add prefault option when creating region

When CoW can be used, the VM restoration time is reduced, but the pages
are not populated. This can lead to some slowness from the guest when
accessing these pages.

Depending on the use case, we might prefer a slower boot time for better
performances from guest runtime. The way to achieve this is to prefault
the pages in this case, using the MAP_POPULATE flag along with CoW.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
This commit is contained in:
Sebastien Boeuf 2020-04-07 13:33:18 +02:00
parent b2cdee80b6
commit 6712958f23
2 changed files with 20 additions and 7 deletions

View File

@ -229,6 +229,7 @@ impl MemoryManager {
fd: Arc<VmFd>, fd: Arc<VmFd>,
config: &MemoryConfig, config: &MemoryConfig,
ext_regions: Option<Vec<MemoryRegion>>, ext_regions: Option<Vec<MemoryRegion>>,
prefault: bool,
) -> Result<Arc<Mutex<MemoryManager>>, Error> { ) -> Result<Arc<Mutex<MemoryManager>>, Error> {
// Init guest memory // Init guest memory
let arch_mem_regions = arch::arch_memory_regions(config.size); let arch_mem_regions = arch::arch_memory_regions(config.size);
@ -251,6 +252,7 @@ impl MemoryManager {
region.start_addr, region.start_addr,
region.size as usize, region.size as usize,
true, true,
prefault,
)?); )?);
} }
} else { } else {
@ -260,6 +262,7 @@ impl MemoryManager {
region.0, region.0,
region.1, region.1,
false, false,
prefault,
)?); )?);
} }
} }
@ -288,6 +291,7 @@ impl MemoryManager {
start_addr, start_addr,
size as usize, size as usize,
false, false,
false,
)?); )?);
virtiomem_resize = Some(vm_virtio::Resize::new().map_err(Error::EventFdFail)?); virtiomem_resize = Some(vm_virtio::Resize::new().map_err(Error::EventFdFail)?);
@ -415,10 +419,10 @@ impl MemoryManager {
// allows for a faster VM restoration and does not require us to // allows for a faster VM restoration and does not require us to
// fill the memory content, hence we can return right away. // fill the memory content, hence we can return right away.
if config.file.is_none() { if config.file.is_none() {
return MemoryManager::new(fd, config, Some(ext_regions)); return MemoryManager::new(fd, config, Some(ext_regions), false);
}; };
let memory_manager = MemoryManager::new(fd, config, None)?; let memory_manager = MemoryManager::new(fd, config, None, false)?;
let guest_memory = memory_manager.lock().unwrap().guest_memory(); let guest_memory = memory_manager.lock().unwrap().guest_memory();
// In case the previous config was using a backing file, this means // In case the previous config was using a backing file, this means
@ -458,6 +462,7 @@ impl MemoryManager {
start_addr: GuestAddress, start_addr: GuestAddress,
size: usize, size: usize,
copy_on_write: bool, copy_on_write: bool,
prefault: bool,
) -> Result<Arc<GuestRegionMmap>, Error> { ) -> Result<Arc<GuestRegionMmap>, Error> {
Ok(Arc::new(match backing_file { Ok(Arc::new(match backing_file {
Some(ref file) => { Some(ref file) => {
@ -479,11 +484,14 @@ impl MemoryManager {
f.set_len(size as u64).map_err(Error::SharedFileSetLen)?; f.set_len(size as u64).map_err(Error::SharedFileSetLen)?;
let mmap_flags = if copy_on_write { let mut mmap_flags = if copy_on_write {
libc::MAP_NORESERVE | libc::MAP_PRIVATE libc::MAP_NORESERVE | libc::MAP_PRIVATE
} else { } else {
libc::MAP_NORESERVE | libc::MAP_SHARED libc::MAP_NORESERVE | libc::MAP_SHARED
}; };
if prefault {
mmap_flags |= libc::MAP_POPULATE;
}
GuestRegionMmap::new( GuestRegionMmap::new(
MmapRegion::build( MmapRegion::build(
Some(FileOffset::new(f, 0)), Some(FileOffset::new(f, 0)),
@ -544,7 +552,8 @@ impl MemoryManager {
} }
// Allocate memory for the region // Allocate memory for the region
let region = MemoryManager::create_ram_region(&self.backing_file, start_addr, size, false)?; let region =
MemoryManager::create_ram_region(&self.backing_file, start_addr, size, false, false)?;
// Map it into the guest // Map it into the guest
self.create_userspace_mapping( self.create_userspace_mapping(

View File

@ -360,8 +360,12 @@ impl Vm {
vmm_path: PathBuf, vmm_path: PathBuf,
) -> Result<Self> { ) -> Result<Self> {
let (kvm, fd) = Vm::kvm_new()?; let (kvm, fd) = Vm::kvm_new()?;
let memory_manager = let memory_manager = MemoryManager::new(
MemoryManager::new(fd.clone(), &config.lock().unwrap().memory.clone(), None) fd.clone(),
&config.lock().unwrap().memory.clone(),
None,
false,
)
.map_err(Error::MemoryManager)?; .map_err(Error::MemoryManager)?;
Vm::new_from_memory_manager( Vm::new_from_memory_manager(