7 changes: 6 additions & 1 deletion migration/meson.build
Expand Up @@ -19,9 +19,12 @@ softmmu_ss.add(files(
'fd.c',
'global_state.c',
'migration-hmp-cmds.c',
'migration-stats.c',
'migration.c',
'multifd.c',
'multifd-zlib.c',
'multifd-zlib.c',
'ram-compress.c',
'options.c',
'postcopy-ram.c',
'savevm.c',
Expand All @@ -37,4 +40,6 @@ endif
softmmu_ss.add(when: zstd, if_true: files('multifd-zstd.c'))

specific_ss.add(when: 'CONFIG_SOFTMMU',
if_true: files('dirtyrate.c', 'ram.c', 'target.c'))
if_true: files('dirtyrate.c',
'ram.c',
'target.c'))
17 changes: 17 additions & 0 deletions migration/migration-stats.c
@@ -0,0 +1,17 @@
/*
* Migration stats
*
* Copyright (c) 2012-2023 Red Hat Inc
*
* Authors:
* Juan Quintela <quintela@redhat.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/

#include "qemu/osdep.h"
#include "qemu/stats64.h"
#include "migration-stats.h"

MigrationAtomicStats mig_stats;
41 changes: 41 additions & 0 deletions migration/migration-stats.h
@@ -0,0 +1,41 @@
/*
* Migration stats
*
* Copyright (c) 2012-2023 Red Hat Inc
*
* Authors:
* Juan Quintela <quintela@redhat.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/

#ifndef QEMU_MIGRATION_STATS_H
#define QEMU_MIGRATION_STATS_H

#include "qemu/stats64.h"

/*
* These are the ram migration statistic counters. It is loosely
* based on MigrationStats. We change to Stat64 any counter that
* needs to be updated using atomic ops (can be accessed by more than
* one thread).
*/
typedef struct {
Stat64 dirty_bytes_last_sync;
Stat64 dirty_pages_rate;
Stat64 dirty_sync_count;
Stat64 dirty_sync_missed_zero_copy;
Stat64 downtime_bytes;
Stat64 zero_pages;
Stat64 multifd_bytes;
Stat64 normal_pages;
Stat64 postcopy_bytes;
Stat64 postcopy_requests;
Stat64 precopy_bytes;
Stat64 transferred;
} MigrationAtomicStats;

extern MigrationAtomicStats mig_stats;

#endif
42 changes: 26 additions & 16 deletions migration/migration.c
Expand Up @@ -26,9 +26,11 @@
#include "sysemu/cpu-throttle.h"
#include "rdma.h"
#include "ram.h"
#include "ram-compress.h"
#include "migration/global_state.h"
#include "migration/misc.h"
#include "migration.h"
#include "migration-stats.h"
#include "savevm.h"
#include "qemu-file.h"
#include "channel.h"
Expand Down Expand Up @@ -227,6 +229,7 @@ void migration_incoming_state_destroy(void)
struct MigrationIncomingState *mis = migration_incoming_get_current();

multifd_load_cleanup();
compress_threads_load_cleanup();

if (mis->to_src_file) {
/* Tell source that we are done */
Expand Down Expand Up @@ -499,6 +502,12 @@ process_incoming_migration_co(void *opaque)
Error *local_err = NULL;

assert(mis->from_src_file);

if (compress_threads_load_setup(mis->from_src_file)) {
error_report("Failed to setup decompress threads");
goto fail;
}

mis->migration_incoming_co = qemu_coroutine_self();
mis->largest_page_size = qemu_ram_pagesize_largest();
postcopy_state_set(POSTCOPY_INCOMING_NONE);
Expand Down Expand Up @@ -564,6 +573,7 @@ process_incoming_migration_co(void *opaque)
qemu_fclose(mis->from_src_file);

multifd_load_cleanup();
compress_threads_load_cleanup();

exit(EXIT_FAILURE);
}
Expand Down Expand Up @@ -908,26 +918,26 @@ static void populate_ram_info(MigrationInfo *info, MigrationState *s)
size_t page_size = qemu_target_page_size();

info->ram = g_malloc0(sizeof(*info->ram));
info->ram->transferred = stat64_get(&ram_counters.transferred);
info->ram->transferred = stat64_get(&mig_stats.transferred);
info->ram->total = ram_bytes_total();
info->ram->duplicate = stat64_get(&ram_counters.zero_pages);
info->ram->duplicate = stat64_get(&mig_stats.zero_pages);
/* legacy value. It is not used anymore */
info->ram->skipped = 0;
info->ram->normal = stat64_get(&ram_counters.normal_pages);
info->ram->normal = stat64_get(&mig_stats.normal_pages);
info->ram->normal_bytes = info->ram->normal * page_size;
info->ram->mbps = s->mbps;
info->ram->dirty_sync_count =
stat64_get(&ram_counters.dirty_sync_count);
stat64_get(&mig_stats.dirty_sync_count);
info->ram->dirty_sync_missed_zero_copy =
stat64_get(&ram_counters.dirty_sync_missed_zero_copy);
stat64_get(&mig_stats.dirty_sync_missed_zero_copy);
info->ram->postcopy_requests =
stat64_get(&ram_counters.postcopy_requests);
stat64_get(&mig_stats.postcopy_requests);
info->ram->page_size = page_size;
info->ram->multifd_bytes = stat64_get(&ram_counters.multifd_bytes);
info->ram->multifd_bytes = stat64_get(&mig_stats.multifd_bytes);
info->ram->pages_per_second = s->pages_per_second;
info->ram->precopy_bytes = stat64_get(&ram_counters.precopy_bytes);
info->ram->downtime_bytes = stat64_get(&ram_counters.downtime_bytes);
info->ram->postcopy_bytes = stat64_get(&ram_counters.postcopy_bytes);
info->ram->precopy_bytes = stat64_get(&mig_stats.precopy_bytes);
info->ram->downtime_bytes = stat64_get(&mig_stats.downtime_bytes);
info->ram->postcopy_bytes = stat64_get(&mig_stats.postcopy_bytes);

if (migrate_xbzrle()) {
info->xbzrle_cache = g_malloc0(sizeof(*info->xbzrle_cache));
Expand Down Expand Up @@ -959,7 +969,7 @@ static void populate_ram_info(MigrationInfo *info, MigrationState *s)
if (s->state != MIGRATION_STATUS_COMPLETED) {
info->ram->remaining = ram_bytes_remaining();
info->ram->dirty_pages_rate =
stat64_get(&ram_counters.dirty_pages_rate);
stat64_get(&mig_stats.dirty_pages_rate);
}
}

Expand Down Expand Up @@ -1612,10 +1622,10 @@ static bool migrate_prepare(MigrationState *s, bool blk, bool blk_inc,

migrate_init(s);
/*
* set ram_counters compression_counters memory to zero for a
* set mig_stats compression_counters memory to zero for a
* new migration
*/
memset(&ram_counters, 0, sizeof(ram_counters));
memset(&mig_stats, 0, sizeof(mig_stats));
memset(&compression_counters, 0, sizeof(compression_counters));

return true;
Expand Down Expand Up @@ -2626,7 +2636,7 @@ static MigThrError migration_detect_error(MigrationState *s)
static uint64_t migration_total_bytes(MigrationState *s)
{
return qemu_file_total_transferred(s->to_dst_file) +
stat64_get(&ram_counters.multifd_bytes);
stat64_get(&mig_stats.multifd_bytes);
}

static void migration_calculate_complete(MigrationState *s)
Expand Down Expand Up @@ -2690,10 +2700,10 @@ static void migration_update_counters(MigrationState *s,
* if we haven't sent anything, we don't want to
* recalculate. 10000 is a small enough number for our purposes
*/
if (stat64_get(&ram_counters.dirty_pages_rate) &&
if (stat64_get(&mig_stats.dirty_pages_rate) &&
transferred > 10000) {
s->expected_downtime =
stat64_get(&ram_counters.dirty_bytes_last_sync) / bandwidth;
stat64_get(&mig_stats.dirty_bytes_last_sync) / bandwidth;
}

qemu_file_reset_rate_limit(s->to_dst_file);
Expand Down
12 changes: 5 additions & 7 deletions migration/multifd.c
Expand Up @@ -19,6 +19,7 @@
#include "qapi/error.h"
#include "ram.h"
#include "migration.h"
#include "migration-stats.h"
#include "socket.h"
#include "tls.h"
#include "qemu-file.h"
Expand Down Expand Up @@ -433,8 +434,8 @@ static int multifd_send_pages(QEMUFile *f)
transferred = ((uint64_t) pages->num) * p->page_size + p->packet_len;
qemu_file_acct_rate_limit(f, transferred);
qemu_mutex_unlock(&p->mutex);
stat64_add(&ram_counters.transferred, transferred);
stat64_add(&ram_counters.multifd_bytes, transferred);
stat64_add(&mig_stats.transferred, transferred);
stat64_add(&mig_stats.multifd_bytes, transferred);
qemu_sem_post(&p->sem);

return 1;
Expand Down Expand Up @@ -576,7 +577,7 @@ static int multifd_zero_copy_flush(QIOChannel *c)
return -1;
}
if (ret == 1) {
stat64_add(&ram_counters.dirty_sync_missed_zero_copy, 1);
stat64_add(&mig_stats.dirty_sync_missed_zero_copy, 1);
}

return ret;
Expand Down Expand Up @@ -626,10 +627,7 @@ int multifd_send_sync_main(QEMUFile *f)
p->packet_num = multifd_send_state->packet_num++;
p->flags |= MULTIFD_FLAG_SYNC;
p->pending_job++;
qemu_file_acct_rate_limit(f, p->packet_len);
qemu_mutex_unlock(&p->mutex);
stat64_add(&ram_counters.transferred, p->packet_len);
stat64_add(&ram_counters.multifd_bytes, p->packet_len);
qemu_sem_post(&p->sem);
}
for (i = 0; i < migrate_multifd_channels(); i++) {
Expand Down Expand Up @@ -823,7 +821,7 @@ static void multifd_tls_channel_connect(MultiFDSendParams *p,
const char *hostname = s->hostname;
QIOChannelTLS *tioc;

tioc = migration_tls_client_create(s, ioc, hostname, errp);
tioc = migration_tls_client_create(ioc, hostname, errp);
if (!tioc) {
return;
}
Expand Down
2 changes: 1 addition & 1 deletion migration/postcopy-ram.c
Expand Up @@ -1632,7 +1632,7 @@ postcopy_preempt_send_channel_new(QIOTask *task, gpointer opaque)
}

if (migrate_channel_requires_tls_upgrade(ioc)) {
tioc = migration_tls_client_create(s, ioc, s->hostname, &local_err);
tioc = migration_tls_client_create(ioc, s->hostname, &local_err);
if (!tioc) {
goto out;
}
Expand Down
11 changes: 11 additions & 0 deletions migration/qemu-file.c
Expand Up @@ -887,6 +887,17 @@ int qemu_put_qemu_file(QEMUFile *f_des, QEMUFile *f_src)
return len;
}

/*
* Check if the writable buffer is empty
*/

bool qemu_file_buffer_empty(QEMUFile *file)
{
assert(qemu_file_is_writable(file));

return !file->iovcnt;
}

/*
* Get a string whose length is determined by a single preceding byte
* A preallocated 256 byte buffer must be passed in.
Expand Down
1 change: 1 addition & 0 deletions migration/qemu-file.h
Expand Up @@ -113,6 +113,7 @@ size_t coroutine_mixed_fn qemu_get_buffer_in_place(QEMUFile *f, uint8_t **buf, s
ssize_t qemu_put_compression_data(QEMUFile *f, z_stream *stream,
const uint8_t *p, size_t size);
int qemu_put_qemu_file(QEMUFile *f_des, QEMUFile *f_src);
bool qemu_file_buffer_empty(QEMUFile *file);

/*
* Note that you can only peek continuous bytes from where the current pointer
Expand Down