migration: optimize the downtime
Qemu_savevm_state_cleanup takes about 300ms in my ram migration tests with a 8U24G vm(20G is really occupied), the main cost comes from KVM_SET_USER_MEMORY_REGION ioctl when mem.memory_size = 0 in kvm_set_user_memory_region. In kmod, the main cost is kvm_zap_obsolete_pages, which traverses the active_mmu_pages list to zap the unsync sptes. It can be optimized by delaying memory_global_dirty_log_stop to the next vm_start. Changes v2->v3: - NULL VMChangeStateHandler if it is deleted and protect the scenario of nested invocations of memory_global_dirty_log_start/stop [Paolo] Changes v1->v2: - create a VMChangeStateHandler in memory.c to reduce the coupling [Paolo] Signed-off-by: Jay Zhou <jianjay.zhou@huawei.com> Message-Id: <1501237733-2736-1-git-send-email-jianjay.zhou@huawei.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
8bfce83a3b
commit
1931076077
36
memory.c
36
memory.c
@ -2357,8 +2357,15 @@ void memory_global_dirty_log_sync(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static VMChangeStateEntry *vmstate_change;
|
||||||
|
|
||||||
void memory_global_dirty_log_start(void)
|
void memory_global_dirty_log_start(void)
|
||||||
{
|
{
|
||||||
|
if (vmstate_change) {
|
||||||
|
qemu_del_vm_change_state_handler(vmstate_change);
|
||||||
|
vmstate_change = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
global_dirty_log = true;
|
global_dirty_log = true;
|
||||||
|
|
||||||
MEMORY_LISTENER_CALL_GLOBAL(log_global_start, Forward);
|
MEMORY_LISTENER_CALL_GLOBAL(log_global_start, Forward);
|
||||||
@ -2369,7 +2376,7 @@ void memory_global_dirty_log_start(void)
|
|||||||
memory_region_transaction_commit();
|
memory_region_transaction_commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
void memory_global_dirty_log_stop(void)
|
static void memory_global_dirty_log_do_stop(void)
|
||||||
{
|
{
|
||||||
global_dirty_log = false;
|
global_dirty_log = false;
|
||||||
|
|
||||||
@ -2381,6 +2388,33 @@ void memory_global_dirty_log_stop(void)
|
|||||||
MEMORY_LISTENER_CALL_GLOBAL(log_global_stop, Reverse);
|
MEMORY_LISTENER_CALL_GLOBAL(log_global_stop, Reverse);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void memory_vm_change_state_handler(void *opaque, int running,
|
||||||
|
RunState state)
|
||||||
|
{
|
||||||
|
if (running) {
|
||||||
|
memory_global_dirty_log_do_stop();
|
||||||
|
|
||||||
|
if (vmstate_change) {
|
||||||
|
qemu_del_vm_change_state_handler(vmstate_change);
|
||||||
|
vmstate_change = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void memory_global_dirty_log_stop(void)
|
||||||
|
{
|
||||||
|
if (!runstate_is_running()) {
|
||||||
|
if (vmstate_change) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
vmstate_change = qemu_add_vm_change_state_handler(
|
||||||
|
memory_vm_change_state_handler, NULL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
memory_global_dirty_log_do_stop();
|
||||||
|
}
|
||||||
|
|
||||||
static void listener_add_address_space(MemoryListener *listener,
|
static void listener_add_address_space(MemoryListener *listener,
|
||||||
AddressSpace *as)
|
AddressSpace *as)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user