mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2024-10-03 20:15:45 +00:00
vmm: Refine the granularity of dirty memory tracking
Instead of tracking on a block level of 64 pages, we are now collecting dirty pages one by one. It improves the efficiency of dirty memory tracking while live migration. Signed-off-by: Bo Chen <chen.bo@intel.com>
This commit is contained in:
parent
4c299c6c00
commit
78796f96b7
@ -1493,25 +1493,13 @@ impl MemoryManager {
|
|||||||
&self.memory_zones
|
&self.memory_zones
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate a table for the pages that are dirty. The algorithm is currently
|
// Generate a table for the pages that are dirty. The dirty pages are collapsed
|
||||||
// very simple. If any page in a "block" of 64 pages is dirty then that whole
|
// together in the table if they are contiguous.
|
||||||
// "block" is added to the table. These "blocks" are also collapsed together if
|
|
||||||
// they are contiguous:
|
|
||||||
//
|
|
||||||
// For every block of 64 pages we check to see if there are any dirty pages in it
|
|
||||||
// if there are we increase the size of the current range if there is one, otherwise
|
|
||||||
// create a new range. If there are no dirty pages in the current "block" the range is
|
|
||||||
// closed if there is one and added to the table. After iterating through the dirty
|
|
||||||
// page bitmaps an open range will be closed and added to the table.
|
|
||||||
//
|
|
||||||
// This algorithm is very simple and could be refined to count the number of pages
|
|
||||||
// in the block and instead create smaller ranges covering those pages.
|
|
||||||
pub fn dirty_memory_range_table(
|
pub fn dirty_memory_range_table(
|
||||||
&self,
|
&self,
|
||||||
) -> std::result::Result<MemoryRangeTable, MigratableError> {
|
) -> std::result::Result<MemoryRangeTable, MigratableError> {
|
||||||
let page_size = 4096; // TODO: Does this need to vary?
|
let page_size = 4096; // TODO: Does this need to vary?
|
||||||
let mut table = MemoryRangeTable::default();
|
let mut table = MemoryRangeTable::default();
|
||||||
let mut total_pages = 0;
|
|
||||||
for r in &self.guest_ram_mappings {
|
for r in &self.guest_ram_mappings {
|
||||||
let dirty_bitmap = self.vm.get_dirty_log(r.slot, r.size).map_err(|e| {
|
let dirty_bitmap = self.vm.get_dirty_log(r.slot, r.size).map_err(|e| {
|
||||||
MigratableError::MigrateSend(anyhow!("Error getting VM dirty log {}", e))
|
MigratableError::MigrateSend(anyhow!("Error getting VM dirty log {}", e))
|
||||||
@ -1519,20 +1507,23 @@ impl MemoryManager {
|
|||||||
|
|
||||||
let mut entry: Option<MemoryRange> = None;
|
let mut entry: Option<MemoryRange> = None;
|
||||||
for (i, block) in dirty_bitmap.iter().enumerate() {
|
for (i, block) in dirty_bitmap.iter().enumerate() {
|
||||||
if *block > 0 {
|
for j in 0..64 {
|
||||||
|
let is_page_dirty = ((block >> j) & 1u64) != 0u64;
|
||||||
|
let page_offset = ((i * 64) + j) as u64 * page_size;
|
||||||
|
if is_page_dirty {
|
||||||
if let Some(entry) = &mut entry {
|
if let Some(entry) = &mut entry {
|
||||||
entry.length += 64 * page_size;
|
entry.length += page_size;
|
||||||
} else {
|
} else {
|
||||||
entry = Some(MemoryRange {
|
entry = Some(MemoryRange {
|
||||||
gpa: r.gpa + (64 * i as u64 * page_size),
|
gpa: r.gpa + page_offset,
|
||||||
length: 64 * page_size,
|
length: page_size,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
total_pages += block.count_ones() as u64;
|
|
||||||
} else if let Some(entry) = entry.take() {
|
} else if let Some(entry) = entry.take() {
|
||||||
table.push(entry);
|
table.push(entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if let Some(entry) = entry.take() {
|
if let Some(entry) = entry.take() {
|
||||||
table.push(entry);
|
table.push(entry);
|
||||||
}
|
}
|
||||||
@ -1541,18 +1532,9 @@ impl MemoryManager {
|
|||||||
info!("Dirty Memory Range Table is empty");
|
info!("Dirty Memory Range Table is empty");
|
||||||
} else {
|
} else {
|
||||||
info!("Dirty Memory Range Table:");
|
info!("Dirty Memory Range Table:");
|
||||||
let mut total_size = 0;
|
|
||||||
for range in table.regions() {
|
for range in table.regions() {
|
||||||
info!("GPA: {:x} size: {} (KiB)", range.gpa, range.length / 1024);
|
info!("GPA: {:x} size: {} (KiB)", range.gpa, range.length / 1024);
|
||||||
total_size += range.length;
|
|
||||||
}
|
}
|
||||||
info!(
|
|
||||||
"Total pages: {} ({} KiB). Total size: {} KiB. Efficiency: {}%",
|
|
||||||
total_pages,
|
|
||||||
total_pages * page_size / 1024,
|
|
||||||
total_size / 1024,
|
|
||||||
(total_pages * page_size * 100) / total_size
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(table)
|
Ok(table)
|
||||||
|
Loading…
Reference in New Issue
Block a user