Skip to content

Commit 063028f

Browse files
committed
vmm: actually populate migration progress
The first version has the limitation that we populate the latest snapshot once per memory iteration, although this is the most interesting part by far. In a follow-up, we can make this more fine-grained. Signed-off-by: Philipp Schuster <[email protected]> On-behalf-of: SAP [email protected]
1 parent 7e033f7 commit 063028f

File tree

1 file changed

+94
-3
lines changed

1 file changed

+94
-3
lines changed

vmm/src/lib.rs

Lines changed: 94 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,9 @@ use vm_memory::{
5454
GuestAddress, GuestAddressSpace, GuestMemory, GuestMemoryAtomic, ReadVolatile,
5555
VolatileMemoryError, VolatileSlice, WriteVolatile,
5656
};
57-
use vm_migration::progress::MigrationProgressAndStatus;
57+
use vm_migration::progress::{
58+
MemoryTransmissionInfo, MigrationPhase, MigrationProgressAndStatus, TransportationMode,
59+
};
5860
use vm_migration::protocol::*;
5961
use vm_migration::tls::{TlsConnectionWrapper, TlsStream, TlsStreamWrapper};
6062
use vm_migration::{
@@ -278,6 +280,9 @@ impl From<u64> for EpollDispatch {
278280
}
279281
}
280282

283+
// TODO make this a member of Vmm
284+
static MIGRATION_PROGRESS_SNAPSHOT: Mutex<Option<MigrationProgressAndStatus>> = Mutex::new(None);
285+
281286
enum SocketStream {
282287
Unix(UnixStream),
283288
Tcp(TcpStream),
@@ -2039,6 +2044,12 @@ impl Vmm {
20392044
) -> result::Result<MemoryRangeTable, MigratableError> {
20402045
let mut bandwidth = 0.0;
20412046
let mut iteration_table;
2047+
let total_memory_size_bytes = vm
2048+
.memory_range_table()?
2049+
.regions()
2050+
.iter()
2051+
.map(|range| range.length)
2052+
.sum::<u64>();
20422053

20432054
loop {
20442055
// todo: check if auto-converge is enabled at all?
@@ -2095,6 +2106,30 @@ impl Vmm {
20952106
s.current_dirty_pages = s.pending_size.div_ceil(PAGE_SIZE as u64);
20962107
s.total_transferred_dirty_pages += s.current_dirty_pages;
20972108

2109+
// Update migration progress snapshot
2110+
// TODO the first version alters this at the beginning of each iteration.
2111+
// We should do this continuously instead.
2112+
{
2113+
let mut lock = MIGRATION_PROGRESS_SNAPSHOT.lock().unwrap();
2114+
lock.as_mut()
2115+
.expect("live migration should be ongoing")
2116+
.update_ongoing_migration_state(
2117+
MigrationPhase::MemoryPrecopy,
2118+
Some(MemoryTransmissionInfo {
2119+
memory_iteration: s.iteration,
2120+
memory_transmission_bps: s.mb_per_sec as u64 * 1024 * 1024,
2121+
memory_bytes_total: total_memory_size_bytes,
2122+
memory_bytes_transmitted: s.total_transferred_bytes,
2123+
memory_pages_4k_transmitted: s.total_transferred_dirty_pages,
2124+
memory_pages_4k_remaining_iteration: s.current_dirty_pages,
2125+
memory_bytes_remaining_iteration: s.pending_size,
2126+
memory_dirty_rate_pps: 0, /* TODO */
2127+
memory_pages_constant_count: 0,
2128+
}),
2129+
Some(vm.throttle_percent()),
2130+
);
2131+
}
2132+
20982133
// Send the current dirty pages
20992134
let transfer_start = Instant::now();
21002135
mem_send.send_memory(&iteration_table, socket)?;
@@ -2207,6 +2242,25 @@ impl Vmm {
22072242
hypervisor: &dyn hypervisor::Hypervisor,
22082243
send_data_migration: &VmSendMigrationData,
22092244
) -> result::Result<(), MigratableError> {
2245+
// Update migration progress snapshot
2246+
{
2247+
let mut lock = MIGRATION_PROGRESS_SNAPSHOT.lock().unwrap();
2248+
// if this fails, we made a programming error in our state handling
2249+
assert!(lock.is_none());
2250+
let transportation_mode = if send_data_migration.local {
2251+
TransportationMode::Local
2252+
} else {
2253+
TransportationMode::Tcp {
2254+
connections: send_data_migration.connections,
2255+
tls: send_data_migration.tls_dir.is_some(),
2256+
}
2257+
};
2258+
lock.replace(MigrationProgressAndStatus::new(
2259+
transportation_mode,
2260+
Duration::from_millis(send_data_migration.downtime),
2261+
));
2262+
}
2263+
22102264
let mut s = MigrationState::new();
22112265

22122266
// Set up the socket connection
@@ -2251,6 +2305,11 @@ impl Vmm {
22512305
if send_data_migration.local {
22522306
match &mut socket {
22532307
SocketStream::Unix(unix_socket) => {
2308+
let mut lock = MIGRATION_PROGRESS_SNAPSHOT.lock().unwrap();
2309+
lock.as_mut()
2310+
.expect("live migration should be ongoing")
2311+
.update_ongoing_migration_state(MigrationPhase::MemoryFds, None, None);
2312+
22542313
// Proceed with sending memory file descriptors over UNIX socket
22552314
vm.send_memory_fds(unix_socket)?;
22562315
}
@@ -2291,6 +2350,14 @@ impl Vmm {
22912350
vm.pause()?;
22922351
} else {
22932352
Self::do_memory_migration(vm, &mut socket, &mut s, send_data_migration)?;
2353+
2354+
// Update migration progress snapshot
2355+
{
2356+
let mut lock = MIGRATION_PROGRESS_SNAPSHOT.lock().unwrap();
2357+
lock.as_mut()
2358+
.expect("live migration should be ongoing")
2359+
.update_ongoing_migration_state(MigrationPhase::Completing, None, None);
2360+
}
22942361
}
22952362

22962363
// We release the locks early to enable locking them on the destination host.
@@ -2336,10 +2403,26 @@ impl Vmm {
23362403
// Record total migration time
23372404
s.total_time = s.start_time.elapsed();
23382405

2339-
info!("Migration complete");
2406+
info!("Migration complete: {}s", s.total_time.as_secs_f32());
2407+
2408+
// Update migration progress snapshot
2409+
{
2410+
let mut lock = MIGRATION_PROGRESS_SNAPSHOT.lock().unwrap();
2411+
lock.as_mut()
2412+
.expect("live migration should be ongoing")
2413+
.mark_as_finished();
2414+
}
23402415

23412416
// Let every Migratable object know about the migration being complete
2342-
vm.complete_migration()
2417+
vm.complete_migration()?;
2418+
2419+
// Give management software a chance to fetch the migration state.
2420+
info!("Sleeping five seconds before shutting off.");
2421+
// TODO right now, the http-server is single-threaded and the blocking
2422+
// start-migration API call will block other requests here.
2423+
thread::sleep(Duration::from_secs(5));
2424+
2425+
Ok(())
23432426
}
23442427

23452428
#[cfg(all(feature = "kvm", target_arch = "x86_64"))]
@@ -2488,6 +2571,14 @@ impl Vmm {
24882571
}
24892572
}
24902573
Err(e) => {
2574+
// Update migration progress snapshot
2575+
{
2576+
let mut lock = MIGRATION_PROGRESS_SNAPSHOT.lock().unwrap();
2577+
lock.as_mut()
2578+
.expect("live migration should be ongoing")
2579+
.mark_as_failed(&e);
2580+
}
2581+
24912582
error!("Migration failed: {e}");
24922583
{
24932584
info!("Sending Receiver in HTTP thread that migration failed");

0 commit comments

Comments
 (0)