Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
migration: Move rate_limit_max and rate_limit_used to migration_stats
These way we can make them atomic and use this functions from any
place.  I also moved all functions that use rate_limit to
migration-stats.

Functions got renamed, they are not qemu_file anymore.

qemu_file_rate_limit -> migration_rate_exceeded
qemu_file_set_rate_limit -> migration_rate_set
qemu_file_get_rate_limit -> migration_rate_get
qemu_file_reset_rate_limit -> migration_rate_reset
qemu_file_acct_rate_limit -> migration_rate_account.

Reviewed-by: Harsh Prateek Bora <harshpb@linux.ibm.com>
Signed-off-by: Juan Quintela <quintela@redhat.com>
Message-Id: <20230515195709.63843-6-quintela@redhat.com>
Signed-off-by: Juan Quintela <quintela@redhat.com>
  • Loading branch information
Juan Quintela committed May 18, 2023
1 parent de37f8b commit e1fde0e
Show file tree
Hide file tree
Showing 16 changed files with 124 additions and 90 deletions.
4 changes: 2 additions & 2 deletions hw/ppc/spapr.c
Expand Up @@ -2166,7 +2166,7 @@ static void htab_save_first_pass(QEMUFile *f, SpaprMachineState *spapr,
break;
}
}
} while ((index < htabslots) && !qemu_file_rate_limit(f));
} while ((index < htabslots) && !migration_rate_exceeded(f));

if (index >= htabslots) {
assert(index == htabslots);
Expand Down Expand Up @@ -2237,7 +2237,7 @@ static int htab_save_later_pass(QEMUFile *f, SpaprMachineState *spapr,
assert(index == htabslots);
index = 0;
}
} while ((examined < htabslots) && (!qemu_file_rate_limit(f) || final));
} while ((examined < htabslots) && (!migration_rate_exceeded(f) || final));

if (index >= htabslots) {
assert(index == htabslots);
Expand Down
2 changes: 1 addition & 1 deletion hw/s390x/s390-stattrib.c
Expand Up @@ -209,7 +209,7 @@ static int cmma_save(QEMUFile *f, void *opaque, int final)
return -ENOMEM;
}

while (final ? 1 : qemu_file_rate_limit(f) == 0) {
while (final ? 1 : migration_rate_exceeded(f) == 0) {
reallen = sac->get_stattr(sas, &start_gfn, buflen, buf);
if (reallen < 0) {
g_free(buf);
Expand Down
12 changes: 11 additions & 1 deletion include/migration/qemu-file-types.h
Expand Up @@ -165,6 +165,16 @@ size_t coroutine_mixed_fn qemu_get_counted_string(QEMUFile *f, char buf[256]);

void qemu_put_counted_string(QEMUFile *f, const char *name);

int qemu_file_rate_limit(QEMUFile *f);
/**
* migration_rate_exceeded: Check if we have exceeded rate for this interval
*
* Checks if we have already transferred more data that we are allowed
* in the current interval.
*
* @f: QEMUFile used for main migration channel
*
* Returns if we should stop sending data for this interval.
*/
bool migration_rate_exceeded(QEMUFile *f);

#endif
2 changes: 1 addition & 1 deletion migration/block-dirty-bitmap.c
Expand Up @@ -706,7 +706,7 @@ static void bulk_phase(QEMUFile *f, DBMSaveState *s, bool limit)
QSIMPLEQ_FOREACH(dbms, &s->dbms_list, entry) {
while (!dbms->bulk_completed) {
bulk_phase_send_chunk(f, s, dbms);
if (limit && qemu_file_rate_limit(f)) {
if (limit && migration_rate_exceeded(f)) {
return;
}
}
Expand Down
5 changes: 3 additions & 2 deletions migration/block.c
Expand Up @@ -23,6 +23,7 @@
#include "block/dirty-bitmap.h"
#include "migration/misc.h"
#include "migration.h"
#include "migration-stats.h"
#include "migration/register.h"
#include "qemu-file.h"
#include "migration/vmstate.h"
Expand Down Expand Up @@ -625,7 +626,7 @@ static int flush_blks(QEMUFile *f)

blk_mig_lock();
while ((blk = QSIMPLEQ_FIRST(&block_mig_state.blk_list)) != NULL) {
if (qemu_file_rate_limit(f)) {
if (migration_rate_exceeded(f)) {
break;
}
if (blk->ret < 0) {
Expand Down Expand Up @@ -762,7 +763,7 @@ static int block_save_iterate(QEMUFile *f, void *opaque)
/* control the rate of transfer */
blk_mig_lock();
while (block_mig_state.read_done * BLK_MIG_BLOCK_SIZE <
qemu_file_get_rate_limit(f) &&
migration_rate_get() &&
block_mig_state.submitted < MAX_PARALLEL_IO &&
(block_mig_state.submitted + block_mig_state.read_done) <
MAX_IO_BUFFERS) {
Expand Down
2 changes: 1 addition & 1 deletion migration/meson.build
@@ -1,5 +1,6 @@
# Files needed by unit tests
migration_files = files(
'migration-stats.c',
'page_cache.c',
'xbzrle.c',
'vmstate-types.c',
Expand All @@ -18,7 +19,6 @@ softmmu_ss.add(files(
'fd.c',
'global_state.c',
'migration-hmp-cmds.c',
'migration-stats.c',
'migration.c',
'multifd.c',
'multifd-zlib.c',
Expand Down
44 changes: 44 additions & 0 deletions migration/migration-stats.c
Expand Up @@ -12,6 +12,50 @@

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

MigrationAtomicStats mig_stats;

bool migration_rate_exceeded(QEMUFile *f)
{
if (qemu_file_get_error(f)) {
return true;
}

uint64_t rate_limit_used = stat64_get(&mig_stats.rate_limit_used);
uint64_t rate_limit_max = stat64_get(&mig_stats.rate_limit_max);

if (rate_limit_max == RATE_LIMIT_DISABLED) {
return false;
}
if (rate_limit_max > 0 && rate_limit_used > rate_limit_max) {
return true;
}
return false;
}

uint64_t migration_rate_get(void)
{
return stat64_get(&mig_stats.rate_limit_max);
}

#define XFER_LIMIT_RATIO (1000 / BUFFER_DELAY)

void migration_rate_set(uint64_t limit)
{
/*
* 'limit' is per second. But we check it each BUFER_DELAY miliseconds.
*/
stat64_set(&mig_stats.rate_limit_max, limit / XFER_LIMIT_RATIO);
}

void migration_rate_reset(void)
{
stat64_set(&mig_stats.rate_limit_used, 0);
}

void migration_rate_account(uint64_t len)
{
stat64_add(&mig_stats.rate_limit_used, len);
}
46 changes: 46 additions & 0 deletions migration/migration-stats.h
Expand Up @@ -15,6 +15,12 @@

#include "qemu/stats64.h"

/*
* Amount of time to allocate to each "chunk" of bandwidth-throttled
* data.
*/
#define BUFFER_DELAY 100

/*
* If rate_limit_max is 0, there is special code to remove the rate
* limit.
Expand Down Expand Up @@ -75,6 +81,14 @@ typedef struct {
* Number of bytes sent during precopy stage.
*/
Stat64 precopy_bytes;
/*
* Maximum amount of data we can send in a cycle.
*/
Stat64 rate_limit_max;
/*
* Amount of data we have sent in the current cycle.
*/
Stat64 rate_limit_used;
/*
* Total number of bytes transferred.
*/
Expand All @@ -87,4 +101,36 @@ typedef struct {

extern MigrationAtomicStats mig_stats;

/**
* migration_rate_account: Increase the number of bytes transferred.
*
* Report on a number of bytes the have been transferred that need to
* be applied to the rate limiting calcuations.
*
* @len: amount of bytes transferred
*/
void migration_rate_account(uint64_t len);

/**
* migration_rate_get: Get the maximum amount that can be transferred.
*
* Returns the maximum number of bytes that can be transferred in a cycle.
*/
uint64_t migration_rate_get(void);

/**
* migration_rate_reset: Reset the rate limit counter.
*
* This is called when we know we start a new transfer cycle.
*/
void migration_rate_reset(void);

/**
* migration_rate_set: Set the maximum amount that can be transferred.
*
* Sets the maximum amount of bytes that can be transferred in one cycle.
*
* @new_rate: new maximum amount
*/
void migration_rate_set(uint64_t new_rate);
#endif
14 changes: 7 additions & 7 deletions migration/migration.c
Expand Up @@ -2120,7 +2120,7 @@ static int postcopy_start(MigrationState *ms)
* will notice we're in POSTCOPY_ACTIVE and not actually
* wrap their state up here
*/
qemu_file_set_rate_limit(ms->to_dst_file, bandwidth);
migration_rate_set(bandwidth);
if (migrate_postcopy_ram()) {
/* Ping just for debugging, helps line traces up */
qemu_savevm_send_ping(ms->to_dst_file, 2);
Expand Down Expand Up @@ -2304,7 +2304,7 @@ static void migration_completion(MigrationState *s)
* them if migration fails or is cancelled.
*/
s->block_inactive = !migrate_colo();
qemu_file_set_rate_limit(s->to_dst_file, RATE_LIMIT_DISABLED);
migration_rate_set(RATE_LIMIT_DISABLED);
ret = qemu_savevm_state_complete_precopy(s->to_dst_file, false,
s->block_inactive);
}
Expand Down Expand Up @@ -2699,7 +2699,7 @@ static void migration_update_counters(MigrationState *s,
stat64_get(&mig_stats.dirty_bytes_last_sync) / bandwidth;
}

qemu_file_reset_rate_limit(s->to_dst_file);
migration_rate_reset();

update_iteration_initial_status(s);

Expand Down Expand Up @@ -2852,7 +2852,7 @@ bool migration_rate_limit(void)

bool urgent = false;
migration_update_counters(s, now);
if (qemu_file_rate_limit(s->to_dst_file)) {
if (migration_rate_exceeded(s->to_dst_file)) {

if (qemu_file_get_error(s->to_dst_file)) {
return false;
Expand Down Expand Up @@ -2974,7 +2974,7 @@ static void *migration_thread(void *opaque)
trace_migration_thread_setup_complete();

while (migration_is_active(s)) {
if (urgent || !qemu_file_rate_limit(s->to_dst_file)) {
if (urgent || !migration_rate_exceeded(s->to_dst_file)) {
MigIterateState iter_state = migration_iteration_run(s);
if (iter_state == MIG_ITERATE_SKIP) {
continue;
Expand Down Expand Up @@ -3048,7 +3048,7 @@ static void *bg_migration_thread(void *opaque)
rcu_register_thread();
object_ref(OBJECT(s));

qemu_file_set_rate_limit(s->to_dst_file, RATE_LIMIT_DISABLED);
migration_rate_set(RATE_LIMIT_DISABLED);

setup_start = qemu_clock_get_ms(QEMU_CLOCK_HOST);
/*
Expand Down Expand Up @@ -3220,7 +3220,7 @@ void migrate_fd_connect(MigrationState *s, Error *error_in)
notifier_list_notify(&migration_state_notifiers, s);
}

qemu_file_set_rate_limit(s->to_dst_file, rate_limit);
migration_rate_set(rate_limit);
qemu_file_set_blocking(s->to_dst_file, true);

/*
Expand Down
2 changes: 1 addition & 1 deletion migration/multifd.c
Expand Up @@ -431,7 +431,7 @@ static int multifd_send_pages(QEMUFile *f)
multifd_send_state->pages = p->pages;
p->pages = pages;
transferred = ((uint64_t) pages->num) * p->page_size + p->packet_len;
qemu_file_acct_rate_limit(f, transferred);
migration_rate_account(transferred);
qemu_mutex_unlock(&p->mutex);
stat64_add(&mig_stats.transferred, transferred);
stat64_add(&mig_stats.multifd_bytes, transferred);
Expand Down
7 changes: 3 additions & 4 deletions migration/options.c
Expand Up @@ -23,6 +23,7 @@
#include "migration/colo.h"
#include "migration/misc.h"
#include "migration.h"
#include "migration-stats.h"
#include "qemu-file.h"
#include "ram.h"
#include "options.h"
Expand Down Expand Up @@ -1242,8 +1243,7 @@ static void migrate_params_apply(MigrateSetParameters *params, Error **errp)
if (params->has_max_bandwidth) {
s->parameters.max_bandwidth = params->max_bandwidth;
if (s->to_dst_file && !migration_in_postcopy()) {
qemu_file_set_rate_limit(s->to_dst_file,
s->parameters.max_bandwidth);
migration_rate_set(s->parameters.max_bandwidth);
}
}

Expand Down Expand Up @@ -1272,8 +1272,7 @@ static void migrate_params_apply(MigrateSetParameters *params, Error **errp)
if (params->has_max_postcopy_bandwidth) {
s->parameters.max_postcopy_bandwidth = params->max_postcopy_bandwidth;
if (s->to_dst_file && migration_in_postcopy()) {
qemu_file_set_rate_limit(s->to_dst_file,
s->parameters.max_postcopy_bandwidth);
migration_rate_set(s->parameters.max_postcopy_bandwidth);
}
}
if (params->has_max_cpu_throttle) {
Expand Down
7 changes: 0 additions & 7 deletions migration/options.h
Expand Up @@ -17,13 +17,6 @@
#include "hw/qdev-properties.h"
#include "hw/qdev-properties-system.h"

/* constants */

/* Amount of time to allocate to each "chunk" of bandwidth-throttled
* data. */
#define BUFFER_DELAY 100
#define XFER_LIMIT_RATIO (1000 / BUFFER_DELAY)

/* migration properties */

extern Property migration_properties[];
Expand Down

0 comments on commit e1fde0e

Please sign in to comment.