Message ID | 20230508130909.65420-11-quintela@redhat.com |
---|---|
State | Handled Elsewhere |
Headers | show |
Series | Migration: More migration atomic counters | expand |
On 5/8/23 18:38, Juan Quintela wrote: > This way we can make them atomic and use this functions from any s/this/these > 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_limit_exceeded > qemu_file_set_rate_limit -> migration_rate_limit_set > qemu_file_get_rate_limit -> migration_rate_limit_get > qemu_file_reset_rate_limit -> migration_rate_limit_reset > qemu_file_acct_rate_limit -> migration_rate_limit_account. > > Signed-off-by: Juan Quintela <quintela@redhat.com> > > --- > > If you have any good suggestion for better names, I am all ears. > --- > hw/ppc/spapr.c | 5 +-- > hw/s390x/s390-stattrib.c | 2 +- > include/migration/qemu-file-types.h | 2 +- > migration/block-dirty-bitmap.c | 2 +- > migration/block.c | 5 +-- > migration/migration-stats.c | 41 ++++++++++++++++++++++ > migration/migration-stats.h | 42 +++++++++++++++++++++++ > migration/migration.c | 14 ++++---- > migration/multifd.c | 2 +- > migration/options.c | 7 ++-- > migration/qemu-file.c | 53 ++--------------------------- > migration/qemu-file.h | 11 ------ > migration/ram.c | 2 +- > migration/savevm.c | 2 +- > 14 files changed, 108 insertions(+), 82 deletions(-) > > diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c > index ddc9c7b1a1..dbd2753278 100644 > --- a/hw/ppc/spapr.c > +++ b/hw/ppc/spapr.c > @@ -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_limit_exceeded(f)); > > if (index >= htabslots) { > assert(index == htabslots); > @@ -2237,7 +2237,8 @@ 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_limit_exceeded(f) || final)); > > if (index >= htabslots) { > assert(index == htabslots); > diff --git a/hw/s390x/s390-stattrib.c b/hw/s390x/s390-stattrib.c > index aed919ad7d..fb0a20f2e1 100644 > --- a/hw/s390x/s390-stattrib.c > +++ b/hw/s390x/s390-stattrib.c > @@ -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_limit_exceeded(f) == 0) { while (final ? 1 : !migration_rate_limit_exceeded(f)) { > reallen = sac->get_stattr(sas, &start_gfn, buflen, buf); > if (reallen < 0) { > g_free(buf); > diff --git a/include/migration/qemu-file-types.h b/include/migration/qemu-file-types.h > index 1436f9ce92..0354f45198 100644 > --- a/include/migration/qemu-file-types.h > +++ b/include/migration/qemu-file-types.h > @@ -165,6 +165,6 @@ 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); > +bool migration_rate_limit_exceeded(QEMUFile *f); > return type is also getting changed, could be mentioned in commit log. > #endif > diff --git a/migration/block-dirty-bitmap.c b/migration/block-dirty-bitmap.c > index 20f36e6bd8..a815678926 100644 > --- a/migration/block-dirty-bitmap.c > +++ b/migration/block-dirty-bitmap.c > @@ -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_limit_exceeded(f)) { > return; > } > } > diff --git a/migration/block.c b/migration/block.c > index 12617b4152..fc1caa9ca6 100644 > --- a/migration/block.c > +++ b/migration/block.c > @@ -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" > @@ -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_limit_exceeded(f)) { > break; > } > if (blk->ret < 0) { > @@ -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_limit_get() && > block_mig_state.submitted < MAX_PARALLEL_IO && > (block_mig_state.submitted + block_mig_state.read_done) < > MAX_IO_BUFFERS) { > diff --git a/migration/migration-stats.c b/migration/migration-stats.c > index 5278c6c821..e01842cabc 100644 > --- a/migration/migration-stats.c > +++ b/migration/migration-stats.c > @@ -13,6 +13,7 @@ > #include "qemu/osdep.h" > #include "qemu/stats64.h" > #include "qemu/timer.h" > +#include "qemu-file.h" > #include "migration-stats.h" > > MigrationAtomicStats mig_stats; > @@ -22,3 +23,43 @@ void calculate_time_since(Stat64 *val, int64_t since) > int64_t now = qemu_clock_get_ms(QEMU_CLOCK_HOST); > stat64_set(val, now - since); > } > + > +bool migration_rate_limit_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); > + /* > + * rate_limit_max == 0 means no rate_limit enfoncement. > + */ > + if (rate_limit_max > 0 && rate_limit_used > rate_limit_max) { > + return true; > + } > + return false; > +} > + > +uint64_t migration_rate_limit_get(void) > +{ > + return stat64_get(&mig_stats.rate_limit_max); > +} > + > +void migration_rate_limit_set(uint64_t limit) > +{ > + /* > + * 'limit' is per second. But we check it each BUFER_DELAY miliseconds. > + */ > + stat64_set(&mig_stats.rate_limit_max, limit); > +} > + > +void migration_rate_limit_reset(void) > +{ > + stat64_set(&mig_stats.rate_limit_used, 0); > +} > + > +void migration_rate_limit_account(uint64_t len) > +{ > + stat64_add(&mig_stats.rate_limit_used, len); > +} > diff --git a/migration/migration-stats.h b/migration/migration-stats.h > index 73c73d75b9..65f11ec7d1 100644 > --- a/migration/migration-stats.h > +++ b/migration/migration-stats.h > @@ -69,6 +69,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; > /* > * How long has the setup stage took. > */ > @@ -95,4 +103,38 @@ extern MigrationAtomicStats mig_stats; > */ > > void calculate_time_since(Stat64 *val, int64_t since); > + > +/** > + * migration_rate_limit_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_limit_account(uint64_t len); > + > +/** > + * migration_rate_limit_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_limit_get(void); > + > +/** > + * migration_rate_limit_reset: Reset the rate limit counter. > + * > + * This is called when we know we start a new transfer cycle. > + */ > +void migration_rate_limit_reset(void); > + > +/** > + * migration_rate_limit_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_limit_set(uint64_t new_rate); > + > #endif > diff --git a/migration/migration.c b/migration/migration.c > index 72286de969..370998600e 100644 > --- a/migration/migration.c > +++ b/migration/migration.c > @@ -2116,7 +2116,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_limit_set(bandwidth); > if (migrate_postcopy_ram()) { > /* Ping just for debugging, helps line traces up */ > qemu_savevm_send_ping(ms->to_dst_file, 2); > @@ -2295,7 +2295,7 @@ static void migration_completion(MigrationState *s) > } > if (ret >= 0) { > s->block_inactive = !migrate_colo(); > - qemu_file_set_rate_limit(s->to_dst_file, 0); > + migration_rate_limit_set(0); > ret = qemu_savevm_state_complete_precopy(s->to_dst_file, false, > s->block_inactive); > } > @@ -2691,7 +2691,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_limit_reset(); > > update_iteration_initial_status(s); > > @@ -2847,7 +2847,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_limit_exceeded(s->to_dst_file)) { > > if (qemu_file_get_error(s->to_dst_file)) { > return false; > @@ -2969,7 +2969,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_limit_exceeded(s->to_dst_file)) { > MigIterateState iter_state = migration_iteration_run(s); > if (iter_state == MIG_ITERATE_SKIP) { > continue; > @@ -3043,7 +3043,7 @@ static void *bg_migration_thread(void *opaque) > rcu_register_thread(); > object_ref(OBJECT(s)); > > - qemu_file_set_rate_limit(s->to_dst_file, 0); > + migration_rate_limit_set(0); > > setup_start = qemu_clock_get_ms(QEMU_CLOCK_HOST); > /* > @@ -3215,7 +3215,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_limit_set(rate_limit); > qemu_file_set_blocking(s->to_dst_file, true); > > /* > diff --git a/migration/multifd.c b/migration/multifd.c > index 4e71c19292..2efb313be4 100644 > --- a/migration/multifd.c > +++ b/migration/multifd.c > @@ -432,7 +432,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_limit_account(transferred); > qemu_mutex_unlock(&p->mutex); > stat64_add(&mig_stats.transferred, transferred); > stat64_add(&mig_stats.multifd_bytes, transferred); > diff --git a/migration/options.c b/migration/options.c > index d04b5fbc3a..a024fa3ce6 100644 > --- a/migration/options.c > +++ b/migration/options.c > @@ -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" > @@ -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_limit_set(s->parameters.max_bandwidth); > } > } > > @@ -1274,8 +1274,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_limit_set(s->parameters.max_postcopy_bandwidth); > } > } > if (params->has_max_cpu_throttle) { > diff --git a/migration/qemu-file.c b/migration/qemu-file.c > index 8de1ecd082..3f993e24af 100644 > --- a/migration/qemu-file.c > +++ b/migration/qemu-file.c > @@ -27,6 +27,7 @@ > #include "qemu/error-report.h" > #include "qemu/iov.h" > #include "migration.h" > +#include "migration-stats.h" > #include "qemu-file.h" > #include "trace.h" > #include "options.h" > @@ -40,17 +41,6 @@ struct QEMUFile { > QIOChannel *ioc; > bool is_writable; > > - /* > - * Maximum amount of data in bytes to transfer during one > - * rate limiting time window > - */ > - uint64_t rate_limit_max; > - /* > - * Total amount of data in bytes queued for transfer > - * during this rate limiting time window > - */ > - uint64_t rate_limit_used; > - > /* The sum of bytes transferred on the wire */ > uint64_t total_transferred; > > @@ -302,7 +292,7 @@ void qemu_fflush(QEMUFile *f) > qemu_file_set_error_obj(f, -EIO, local_error); > } else { > uint64_t size = iov_size(f->iov, f->iovcnt); > - qemu_file_acct_rate_limit(f, size); > + migration_rate_limit_account(size); > f->total_transferred += size; > } > > @@ -355,7 +345,7 @@ size_t ram_control_save_page(QEMUFile *f, ram_addr_t block_offset, > int ret = f->hooks->save_page(f, block_offset, > offset, size, bytes_sent); > if (ret != RAM_SAVE_CONTROL_NOT_SUPP) { > - qemu_file_acct_rate_limit(f, size); > + migration_rate_limit_account(size); > } > > if (ret != RAM_SAVE_CONTROL_DELAYED && > @@ -726,43 +716,6 @@ uint64_t qemu_file_transferred(QEMUFile *f) > return f->total_transferred; > } > > -int qemu_file_rate_limit(QEMUFile *f) > -{ > - if (qemu_file_get_error(f)) { > - return 1; > - } > - /* > - * rate_limit_max == 0 means no rate_limit enfoncement. > - */ > - if (f->rate_limit_max > 0 && f->rate_limit_used > f->rate_limit_max) { > - return 1; > - } > - return 0; > -} > - > -uint64_t qemu_file_get_rate_limit(QEMUFile *f) > -{ > - return f->rate_limit_max; > -} > - > -void qemu_file_set_rate_limit(QEMUFile *f, uint64_t limit) > -{ > - /* > - * 'limit' is per second. But we check it each 100 miliseconds. > - */ > - f->rate_limit_max = limit / XFER_LIMIT_RATIO; > -} > - > -void qemu_file_reset_rate_limit(QEMUFile *f) > -{ > - f->rate_limit_used = 0; > -} > - > -void qemu_file_acct_rate_limit(QEMUFile *f, uint64_t len) > -{ > - f->rate_limit_used += len; > -} > - > void qemu_put_be16(QEMUFile *f, unsigned int v) > { > qemu_put_byte(f, v >> 8); > diff --git a/migration/qemu-file.h b/migration/qemu-file.h > index ab164a58d0..46029b951c 100644 > --- a/migration/qemu-file.h > +++ b/migration/qemu-file.h > @@ -129,17 +129,6 @@ void qemu_file_skip(QEMUFile *f, int size); > * accounting information tracks the total migration traffic. > */ > void qemu_file_credit_transfer(QEMUFile *f, size_t size); > -void qemu_file_reset_rate_limit(QEMUFile *f); > -/* > - * qemu_file_acct_rate_limit: > - * > - * Report on a number of bytes the have been transferred > - * out of band from the main file object I/O methods, and > - * need to be applied to the rate limiting calcuations > - */ > -void qemu_file_acct_rate_limit(QEMUFile *f, uint64_t len); > -void qemu_file_set_rate_limit(QEMUFile *f, uint64_t new_rate); > -uint64_t qemu_file_get_rate_limit(QEMUFile *f); > int qemu_file_get_error_obj(QEMUFile *f, Error **errp); > int qemu_file_get_error_obj_any(QEMUFile *f1, QEMUFile *f2, Error **errp); > void qemu_file_set_error_obj(QEMUFile *f, int ret, Error *err); > diff --git a/migration/ram.c b/migration/ram.c > index 5ae1fdba45..2339a99932 100644 > --- a/migration/ram.c > +++ b/migration/ram.c > @@ -3351,7 +3351,7 @@ static int ram_save_iterate(QEMUFile *f, void *opaque) > > t0 = qemu_clock_get_ns(QEMU_CLOCK_REALTIME); > i = 0; > - while ((ret = qemu_file_rate_limit(f)) == 0 || > + while ((ret = migration_rate_limit_exceeded(f)) == 0 || while (!(ret = migration_rate_limit_exceeded(f))) || Otherwise, looks fine. regards, Harsh > postcopy_has_request(rs)) { > int pages; > > diff --git a/migration/savevm.c b/migration/savevm.c > index c7af9050c2..376118bc98 100644 > --- a/migration/savevm.c > +++ b/migration/savevm.c > @@ -1345,7 +1345,7 @@ int qemu_savevm_state_iterate(QEMUFile *f, bool postcopy) > !(se->ops->has_postcopy && se->ops->has_postcopy(se->opaque))) { > continue; > } > - if (qemu_file_rate_limit(f)) { > + if (migration_rate_limit_exceeded(f)) { > return 0; > } > trace_savevm_section_start(se->idstr, se->section_id);
Harsh Prateek Bora <harshpb@linux.ibm.com> wrote: > On 5/8/23 18:38, Juan Quintela wrote: >> This way we can make them atomic and use this functions from any > > s/this/these > Fixed. Thanks.
On 5/9/23 16:40, Juan Quintela wrote: > Harsh Prateek Bora <harshpb@linux.ibm.com> wrote: >> On 5/8/23 18:38, Juan Quintela wrote: >>> This way we can make them atomic and use this functions from any >> >> s/this/these >> > > Fixed. > Sure, providing ack from ppc/spapr perspective. Reviewed-by: Harsh Prateek Bora <harshpb@linux.ibm.com> > Thanks. > >
On 5/8/23 15:08, Juan Quintela wrote: > This 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_limit_exceeded > qemu_file_set_rate_limit -> migration_rate_limit_set > qemu_file_get_rate_limit -> migration_rate_limit_get > qemu_file_reset_rate_limit -> migration_rate_limit_reset > qemu_file_acct_rate_limit -> migration_rate_limit_account. > > Signed-off-by: Juan Quintela <quintela@redhat.com> > > --- > > If you have any good suggestion for better names, I am all ears. May be : qemu_file_rate_limit -> migration_rate_limit_is_exceeded qemu_file_acct_rate_limit -> migration_rate_limit_inc Also, migration_rate_limit() would need some prefix to understand what is its purpose. Do we really need "_limit" in the names ? Thanks, C. > --- > hw/ppc/spapr.c | 5 +-- > hw/s390x/s390-stattrib.c | 2 +- > include/migration/qemu-file-types.h | 2 +- > migration/block-dirty-bitmap.c | 2 +- > migration/block.c | 5 +-- > migration/migration-stats.c | 41 ++++++++++++++++++++++ > migration/migration-stats.h | 42 +++++++++++++++++++++++ > migration/migration.c | 14 ++++---- > migration/multifd.c | 2 +- > migration/options.c | 7 ++-- > migration/qemu-file.c | 53 ++--------------------------- > migration/qemu-file.h | 11 ------ > migration/ram.c | 2 +- > migration/savevm.c | 2 +- > 14 files changed, 108 insertions(+), 82 deletions(-) > > diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c > index ddc9c7b1a1..dbd2753278 100644 > --- a/hw/ppc/spapr.c > +++ b/hw/ppc/spapr.c > @@ -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_limit_exceeded(f)); > > if (index >= htabslots) { > assert(index == htabslots); > @@ -2237,7 +2237,8 @@ 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_limit_exceeded(f) || final)); > > if (index >= htabslots) { > assert(index == htabslots); > diff --git a/hw/s390x/s390-stattrib.c b/hw/s390x/s390-stattrib.c > index aed919ad7d..fb0a20f2e1 100644 > --- a/hw/s390x/s390-stattrib.c > +++ b/hw/s390x/s390-stattrib.c > @@ -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_limit_exceeded(f) == 0) { > reallen = sac->get_stattr(sas, &start_gfn, buflen, buf); > if (reallen < 0) { > g_free(buf); > diff --git a/include/migration/qemu-file-types.h b/include/migration/qemu-file-types.h > index 1436f9ce92..0354f45198 100644 > --- a/include/migration/qemu-file-types.h > +++ b/include/migration/qemu-file-types.h > @@ -165,6 +165,6 @@ 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); > +bool migration_rate_limit_exceeded(QEMUFile *f); > > #endif > diff --git a/migration/block-dirty-bitmap.c b/migration/block-dirty-bitmap.c > index 20f36e6bd8..a815678926 100644 > --- a/migration/block-dirty-bitmap.c > +++ b/migration/block-dirty-bitmap.c > @@ -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_limit_exceeded(f)) { > return; > } > } > diff --git a/migration/block.c b/migration/block.c > index 12617b4152..fc1caa9ca6 100644 > --- a/migration/block.c > +++ b/migration/block.c > @@ -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" > @@ -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_limit_exceeded(f)) { > break; > } > if (blk->ret < 0) { > @@ -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_limit_get() && > block_mig_state.submitted < MAX_PARALLEL_IO && > (block_mig_state.submitted + block_mig_state.read_done) < > MAX_IO_BUFFERS) { > diff --git a/migration/migration-stats.c b/migration/migration-stats.c > index 5278c6c821..e01842cabc 100644 > --- a/migration/migration-stats.c > +++ b/migration/migration-stats.c > @@ -13,6 +13,7 @@ > #include "qemu/osdep.h" > #include "qemu/stats64.h" > #include "qemu/timer.h" > +#include "qemu-file.h" > #include "migration-stats.h" > > MigrationAtomicStats mig_stats; > @@ -22,3 +23,43 @@ void calculate_time_since(Stat64 *val, int64_t since) > int64_t now = qemu_clock_get_ms(QEMU_CLOCK_HOST); > stat64_set(val, now - since); > } > + > +bool migration_rate_limit_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); > + /* > + * rate_limit_max == 0 means no rate_limit enfoncement. > + */ > + if (rate_limit_max > 0 && rate_limit_used > rate_limit_max) { > + return true; > + } > + return false; > +} > + > +uint64_t migration_rate_limit_get(void) > +{ > + return stat64_get(&mig_stats.rate_limit_max); > +} > + > +void migration_rate_limit_set(uint64_t limit) > +{ > + /* > + * 'limit' is per second. But we check it each BUFER_DELAY miliseconds. > + */ > + stat64_set(&mig_stats.rate_limit_max, limit); > +} > + > +void migration_rate_limit_reset(void) > +{ > + stat64_set(&mig_stats.rate_limit_used, 0); > +} > + > +void migration_rate_limit_account(uint64_t len) > +{ > + stat64_add(&mig_stats.rate_limit_used, len); > +} > diff --git a/migration/migration-stats.h b/migration/migration-stats.h > index 73c73d75b9..65f11ec7d1 100644 > --- a/migration/migration-stats.h > +++ b/migration/migration-stats.h > @@ -69,6 +69,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; > /* > * How long has the setup stage took. > */ > @@ -95,4 +103,38 @@ extern MigrationAtomicStats mig_stats; > */ > > void calculate_time_since(Stat64 *val, int64_t since); > + > +/** > + * migration_rate_limit_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_limit_account(uint64_t len); > + > +/** > + * migration_rate_limit_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_limit_get(void); > + > +/** > + * migration_rate_limit_reset: Reset the rate limit counter. > + * > + * This is called when we know we start a new transfer cycle. > + */ > +void migration_rate_limit_reset(void); > + > +/** > + * migration_rate_limit_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_limit_set(uint64_t new_rate); > + > #endif > diff --git a/migration/migration.c b/migration/migration.c > index 72286de969..370998600e 100644 > --- a/migration/migration.c > +++ b/migration/migration.c > @@ -2116,7 +2116,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_limit_set(bandwidth); > if (migrate_postcopy_ram()) { > /* Ping just for debugging, helps line traces up */ > qemu_savevm_send_ping(ms->to_dst_file, 2); > @@ -2295,7 +2295,7 @@ static void migration_completion(MigrationState *s) > } > if (ret >= 0) { > s->block_inactive = !migrate_colo(); > - qemu_file_set_rate_limit(s->to_dst_file, 0); > + migration_rate_limit_set(0); > ret = qemu_savevm_state_complete_precopy(s->to_dst_file, false, > s->block_inactive); > } > @@ -2691,7 +2691,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_limit_reset(); > > update_iteration_initial_status(s); > > @@ -2847,7 +2847,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_limit_exceeded(s->to_dst_file)) { > > if (qemu_file_get_error(s->to_dst_file)) { > return false; > @@ -2969,7 +2969,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_limit_exceeded(s->to_dst_file)) { > MigIterateState iter_state = migration_iteration_run(s); > if (iter_state == MIG_ITERATE_SKIP) { > continue; > @@ -3043,7 +3043,7 @@ static void *bg_migration_thread(void *opaque) > rcu_register_thread(); > object_ref(OBJECT(s)); > > - qemu_file_set_rate_limit(s->to_dst_file, 0); > + migration_rate_limit_set(0); > > setup_start = qemu_clock_get_ms(QEMU_CLOCK_HOST); > /* > @@ -3215,7 +3215,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_limit_set(rate_limit); > qemu_file_set_blocking(s->to_dst_file, true); > > /* > diff --git a/migration/multifd.c b/migration/multifd.c > index 4e71c19292..2efb313be4 100644 > --- a/migration/multifd.c > +++ b/migration/multifd.c > @@ -432,7 +432,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_limit_account(transferred); > qemu_mutex_unlock(&p->mutex); > stat64_add(&mig_stats.transferred, transferred); > stat64_add(&mig_stats.multifd_bytes, transferred); > diff --git a/migration/options.c b/migration/options.c > index d04b5fbc3a..a024fa3ce6 100644 > --- a/migration/options.c > +++ b/migration/options.c > @@ -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" > @@ -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_limit_set(s->parameters.max_bandwidth); > } > } > > @@ -1274,8 +1274,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_limit_set(s->parameters.max_postcopy_bandwidth); > } > } > if (params->has_max_cpu_throttle) { > diff --git a/migration/qemu-file.c b/migration/qemu-file.c > index 8de1ecd082..3f993e24af 100644 > --- a/migration/qemu-file.c > +++ b/migration/qemu-file.c > @@ -27,6 +27,7 @@ > #include "qemu/error-report.h" > #include "qemu/iov.h" > #include "migration.h" > +#include "migration-stats.h" > #include "qemu-file.h" > #include "trace.h" > #include "options.h" > @@ -40,17 +41,6 @@ struct QEMUFile { > QIOChannel *ioc; > bool is_writable; > > - /* > - * Maximum amount of data in bytes to transfer during one > - * rate limiting time window > - */ > - uint64_t rate_limit_max; > - /* > - * Total amount of data in bytes queued for transfer > - * during this rate limiting time window > - */ > - uint64_t rate_limit_used; > - > /* The sum of bytes transferred on the wire */ > uint64_t total_transferred; > > @@ -302,7 +292,7 @@ void qemu_fflush(QEMUFile *f) > qemu_file_set_error_obj(f, -EIO, local_error); > } else { > uint64_t size = iov_size(f->iov, f->iovcnt); > - qemu_file_acct_rate_limit(f, size); > + migration_rate_limit_account(size); > f->total_transferred += size; > } > > @@ -355,7 +345,7 @@ size_t ram_control_save_page(QEMUFile *f, ram_addr_t block_offset, > int ret = f->hooks->save_page(f, block_offset, > offset, size, bytes_sent); > if (ret != RAM_SAVE_CONTROL_NOT_SUPP) { > - qemu_file_acct_rate_limit(f, size); > + migration_rate_limit_account(size); > } > > if (ret != RAM_SAVE_CONTROL_DELAYED && > @@ -726,43 +716,6 @@ uint64_t qemu_file_transferred(QEMUFile *f) > return f->total_transferred; > } > > -int qemu_file_rate_limit(QEMUFile *f) > -{ > - if (qemu_file_get_error(f)) { > - return 1; > - } > - /* > - * rate_limit_max == 0 means no rate_limit enfoncement. > - */ > - if (f->rate_limit_max > 0 && f->rate_limit_used > f->rate_limit_max) { > - return 1; > - } > - return 0; > -} > - > -uint64_t qemu_file_get_rate_limit(QEMUFile *f) > -{ > - return f->rate_limit_max; > -} > - > -void qemu_file_set_rate_limit(QEMUFile *f, uint64_t limit) > -{ > - /* > - * 'limit' is per second. But we check it each 100 miliseconds. > - */ > - f->rate_limit_max = limit / XFER_LIMIT_RATIO; > -} > - > -void qemu_file_reset_rate_limit(QEMUFile *f) > -{ > - f->rate_limit_used = 0; > -} > - > -void qemu_file_acct_rate_limit(QEMUFile *f, uint64_t len) > -{ > - f->rate_limit_used += len; > -} > - > void qemu_put_be16(QEMUFile *f, unsigned int v) > { > qemu_put_byte(f, v >> 8); > diff --git a/migration/qemu-file.h b/migration/qemu-file.h > index ab164a58d0..46029b951c 100644 > --- a/migration/qemu-file.h > +++ b/migration/qemu-file.h > @@ -129,17 +129,6 @@ void qemu_file_skip(QEMUFile *f, int size); > * accounting information tracks the total migration traffic. > */ > void qemu_file_credit_transfer(QEMUFile *f, size_t size); > -void qemu_file_reset_rate_limit(QEMUFile *f); > -/* > - * qemu_file_acct_rate_limit: > - * > - * Report on a number of bytes the have been transferred > - * out of band from the main file object I/O methods, and > - * need to be applied to the rate limiting calcuations > - */ > -void qemu_file_acct_rate_limit(QEMUFile *f, uint64_t len); > -void qemu_file_set_rate_limit(QEMUFile *f, uint64_t new_rate); > -uint64_t qemu_file_get_rate_limit(QEMUFile *f); > int qemu_file_get_error_obj(QEMUFile *f, Error **errp); > int qemu_file_get_error_obj_any(QEMUFile *f1, QEMUFile *f2, Error **errp); > void qemu_file_set_error_obj(QEMUFile *f, int ret, Error *err); > diff --git a/migration/ram.c b/migration/ram.c > index 5ae1fdba45..2339a99932 100644 > --- a/migration/ram.c > +++ b/migration/ram.c > @@ -3351,7 +3351,7 @@ static int ram_save_iterate(QEMUFile *f, void *opaque) > > t0 = qemu_clock_get_ns(QEMU_CLOCK_REALTIME); > i = 0; > - while ((ret = qemu_file_rate_limit(f)) == 0 || > + while ((ret = migration_rate_limit_exceeded(f)) == 0 || > postcopy_has_request(rs)) { > int pages; > > diff --git a/migration/savevm.c b/migration/savevm.c > index c7af9050c2..376118bc98 100644 > --- a/migration/savevm.c > +++ b/migration/savevm.c > @@ -1345,7 +1345,7 @@ int qemu_savevm_state_iterate(QEMUFile *f, bool postcopy) > !(se->ops->has_postcopy && se->ops->has_postcopy(se->opaque))) { > continue; > } > - if (qemu_file_rate_limit(f)) { > + if (migration_rate_limit_exceeded(f)) { > return 0; > } > trace_savevm_section_start(se->idstr, se->section_id);
Cédric Le Goater <clg@kaod.org> wrote: > On 5/8/23 15:08, Juan Quintela wrote: >> This 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_limit_exceeded >> qemu_file_set_rate_limit -> migration_rate_limit_set >> qemu_file_get_rate_limit -> migration_rate_limit_get >> qemu_file_reset_rate_limit -> migration_rate_limit_reset >> qemu_file_acct_rate_limit -> migration_rate_limit_account. >> Signed-off-by: Juan Quintela <quintela@redhat.com> >> --- >> If you have any good suggestion for better names, I am all ears. > > May be : > > qemu_file_rate_limit -> migration_rate_limit_is_exceeded I try not to put _is_ in function names. If it needs to be there, I think that I need to rename the functino. migration_rate_limit_exceeded() seems clear to me. > qemu_file_acct_rate_limit -> migration_rate_limit_inc My problem for this one is that we are not increasing the rate_limit, we are "decreasing" the amount of data we have for this period. That is why I thought about _account(), but who knows. > Also, migration_rate_limit() would need some prefix to understand what is > its purpose. What do you mean here? This is the only rate_limit that I can think in migration. > Do we really need "_limit" in the names ? You have a point here. If nobody complains/suggest anything else, I will drop the _limit for the next submission. Thanks very much.
On 5/15/23 15:09, Juan Quintela wrote: > Cédric Le Goater <clg@kaod.org> wrote: >> On 5/8/23 15:08, Juan Quintela wrote: >>> This 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_limit_exceeded >>> qemu_file_set_rate_limit -> migration_rate_limit_set >>> qemu_file_get_rate_limit -> migration_rate_limit_get >>> qemu_file_reset_rate_limit -> migration_rate_limit_reset >>> qemu_file_acct_rate_limit -> migration_rate_limit_account. >>> Signed-off-by: Juan Quintela <quintela@redhat.com> >>> --- >>> If you have any good suggestion for better names, I am all ears. >> >> May be : >> >> qemu_file_rate_limit -> migration_rate_limit_is_exceeded > > I try not to put _is_ in function names. If it needs to be there, I > think that I need to rename the functino. It is common practice for functions doing a simple test and returning a bool. No big deal anyway. > migration_rate_limit_exceeded() > > seems clear to me. > >> qemu_file_acct_rate_limit -> migration_rate_limit_inc > > My problem for this one is that we are not increasing the rate_limit, we > are "decreasing" the amount of data we have for this period. That is > why I thought about _account(), but who knows. > > >> Also, migration_rate_limit() would need some prefix to understand what is >> its purpose. > > What do you mean here? I am referring to : /* Returns true if the rate limiting was broken by an urgent request */ bool migration_rate_limit(void) { ... return urgent; } which existed prior to the name changes and I thought migration_rate_limit() would suffer the same fate. May be keep the '_limit' suffix for this one if you remove it for the others ? Thanks, C. > This is the only rate_limit that I can think in migration. > >> Do we really need "_limit" in the names ? > > You have a point here. > > If nobody complains/suggest anything else, I will drop the _limit for > the next submission. > > Thanks very much. >
Cédric Le Goater <clg@kaod.org> wrote: > On 5/15/23 15:09, Juan Quintela wrote: >> Cédric Le Goater <clg@kaod.org> wrote: >>> On 5/8/23 15:08, Juan Quintela wrote: >>>> This 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_limit_exceeded >>>> qemu_file_set_rate_limit -> migration_rate_limit_set >>>> qemu_file_get_rate_limit -> migration_rate_limit_get >>>> qemu_file_reset_rate_limit -> migration_rate_limit_reset >>>> qemu_file_acct_rate_limit -> migration_rate_limit_account. >>>> Signed-off-by: Juan Quintela <quintela@redhat.com> >>>> --- >>>> If you have any good suggestion for better names, I am all ears. >>> >>> May be : >>> >>> qemu_file_rate_limit -> migration_rate_limit_is_exceeded >> I try not to put _is_ in function names. If it needs to be there, I >> think that I need to rename the functino. > > It is common practice for functions doing a simple test and returning a bool. > No big deal anyway. > > migration_rate_limit_exceeded() >> seems clear to me. >> >>> qemu_file_acct_rate_limit -> migration_rate_limit_inc >> My problem for this one is that we are not increasing the >> rate_limit, we >> are "decreasing" the amount of data we have for this period. That is >> why I thought about _account(), but who knows. >> >>> Also, migration_rate_limit() would need some prefix to understand what is >>> its purpose. >> What do you mean here? > > I am referring to : > > /* Returns true if the rate limiting was broken by an urgent request */ > bool migration_rate_limit(void) > { > ... > return urgent; > } > > which existed prior to the name changes and I thought migration_rate_limit() > would suffer the same fate. May be keep the '_limit' suffix for this one if > you remove it for the others ? ok, will think about this one. Later, Juan.
Cédric Le Goater <clg@kaod.org> wrote: > On 5/15/23 15:09, Juan Quintela wrote: >> Cédric Le Goater <clg@kaod.org> wrote: >>> On 5/8/23 15:08, Juan Quintela wrote: >>>> This 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_limit_exceeded >>>> qemu_file_set_rate_limit -> migration_rate_limit_set >>>> qemu_file_get_rate_limit -> migration_rate_limit_get >>>> qemu_file_reset_rate_limit -> migration_rate_limit_reset >>>> qemu_file_acct_rate_limit -> migration_rate_limit_account. >>>> Signed-off-by: Juan Quintela <quintela@redhat.com> >>>> --- >>>> If you have any good suggestion for better names, I am all ears. >>> >>> May be : >>> >>> qemu_file_rate_limit -> migration_rate_limit_is_exceeded >> I try not to put _is_ in function names. If it needs to be there, I >> think that I need to rename the functino. > > It is common practice for functions doing a simple test and returning a bool. > No big deal anyway. > > migration_rate_limit_exceeded() >> seems clear to me. >> >>> qemu_file_acct_rate_limit -> migration_rate_limit_inc >> My problem for this one is that we are not increasing the >> rate_limit, we >> are "decreasing" the amount of data we have for this period. That is >> why I thought about _account(), but who knows. >> >>> Also, migration_rate_limit() would need some prefix to understand what is >>> its purpose. >> What do you mean here? > > I am referring to : > > /* Returns true if the rate limiting was broken by an urgent request */ > bool migration_rate_limit(void) > { > ... > return urgent; > } out of ideas: migration_rate_wait() - the good *we wait if we have to - the bad we can be interrupted if there is anything urgent we only wait if counters says that we have to migration_rate_check() * we always check * we return a value consistent with checking * but we check if we have to wait, not if there is anythying urgent I am leaving it with migration_rate_limit() name until someone cames with a better one. It is not worse than what we have in. > > which existed prior to the name changes and I thought migration_rate_limit() > would suffer the same fate. May be keep the '_limit' suffix for this one if > you remove it for the others ? I am no sure if migration_rate() is better than migration_rate_limit(). Later, Juan.
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index ddc9c7b1a1..dbd2753278 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -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_limit_exceeded(f)); if (index >= htabslots) { assert(index == htabslots); @@ -2237,7 +2237,8 @@ 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_limit_exceeded(f) || final)); if (index >= htabslots) { assert(index == htabslots); diff --git a/hw/s390x/s390-stattrib.c b/hw/s390x/s390-stattrib.c index aed919ad7d..fb0a20f2e1 100644 --- a/hw/s390x/s390-stattrib.c +++ b/hw/s390x/s390-stattrib.c @@ -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_limit_exceeded(f) == 0) { reallen = sac->get_stattr(sas, &start_gfn, buflen, buf); if (reallen < 0) { g_free(buf); diff --git a/include/migration/qemu-file-types.h b/include/migration/qemu-file-types.h index 1436f9ce92..0354f45198 100644 --- a/include/migration/qemu-file-types.h +++ b/include/migration/qemu-file-types.h @@ -165,6 +165,6 @@ 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); +bool migration_rate_limit_exceeded(QEMUFile *f); #endif diff --git a/migration/block-dirty-bitmap.c b/migration/block-dirty-bitmap.c index 20f36e6bd8..a815678926 100644 --- a/migration/block-dirty-bitmap.c +++ b/migration/block-dirty-bitmap.c @@ -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_limit_exceeded(f)) { return; } } diff --git a/migration/block.c b/migration/block.c index 12617b4152..fc1caa9ca6 100644 --- a/migration/block.c +++ b/migration/block.c @@ -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" @@ -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_limit_exceeded(f)) { break; } if (blk->ret < 0) { @@ -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_limit_get() && block_mig_state.submitted < MAX_PARALLEL_IO && (block_mig_state.submitted + block_mig_state.read_done) < MAX_IO_BUFFERS) { diff --git a/migration/migration-stats.c b/migration/migration-stats.c index 5278c6c821..e01842cabc 100644 --- a/migration/migration-stats.c +++ b/migration/migration-stats.c @@ -13,6 +13,7 @@ #include "qemu/osdep.h" #include "qemu/stats64.h" #include "qemu/timer.h" +#include "qemu-file.h" #include "migration-stats.h" MigrationAtomicStats mig_stats; @@ -22,3 +23,43 @@ void calculate_time_since(Stat64 *val, int64_t since) int64_t now = qemu_clock_get_ms(QEMU_CLOCK_HOST); stat64_set(val, now - since); } + +bool migration_rate_limit_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); + /* + * rate_limit_max == 0 means no rate_limit enfoncement. + */ + if (rate_limit_max > 0 && rate_limit_used > rate_limit_max) { + return true; + } + return false; +} + +uint64_t migration_rate_limit_get(void) +{ + return stat64_get(&mig_stats.rate_limit_max); +} + +void migration_rate_limit_set(uint64_t limit) +{ + /* + * 'limit' is per second. But we check it each BUFER_DELAY miliseconds. + */ + stat64_set(&mig_stats.rate_limit_max, limit); +} + +void migration_rate_limit_reset(void) +{ + stat64_set(&mig_stats.rate_limit_used, 0); +} + +void migration_rate_limit_account(uint64_t len) +{ + stat64_add(&mig_stats.rate_limit_used, len); +} diff --git a/migration/migration-stats.h b/migration/migration-stats.h index 73c73d75b9..65f11ec7d1 100644 --- a/migration/migration-stats.h +++ b/migration/migration-stats.h @@ -69,6 +69,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; /* * How long has the setup stage took. */ @@ -95,4 +103,38 @@ extern MigrationAtomicStats mig_stats; */ void calculate_time_since(Stat64 *val, int64_t since); + +/** + * migration_rate_limit_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_limit_account(uint64_t len); + +/** + * migration_rate_limit_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_limit_get(void); + +/** + * migration_rate_limit_reset: Reset the rate limit counter. + * + * This is called when we know we start a new transfer cycle. + */ +void migration_rate_limit_reset(void); + +/** + * migration_rate_limit_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_limit_set(uint64_t new_rate); + #endif diff --git a/migration/migration.c b/migration/migration.c index 72286de969..370998600e 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -2116,7 +2116,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_limit_set(bandwidth); if (migrate_postcopy_ram()) { /* Ping just for debugging, helps line traces up */ qemu_savevm_send_ping(ms->to_dst_file, 2); @@ -2295,7 +2295,7 @@ static void migration_completion(MigrationState *s) } if (ret >= 0) { s->block_inactive = !migrate_colo(); - qemu_file_set_rate_limit(s->to_dst_file, 0); + migration_rate_limit_set(0); ret = qemu_savevm_state_complete_precopy(s->to_dst_file, false, s->block_inactive); } @@ -2691,7 +2691,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_limit_reset(); update_iteration_initial_status(s); @@ -2847,7 +2847,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_limit_exceeded(s->to_dst_file)) { if (qemu_file_get_error(s->to_dst_file)) { return false; @@ -2969,7 +2969,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_limit_exceeded(s->to_dst_file)) { MigIterateState iter_state = migration_iteration_run(s); if (iter_state == MIG_ITERATE_SKIP) { continue; @@ -3043,7 +3043,7 @@ static void *bg_migration_thread(void *opaque) rcu_register_thread(); object_ref(OBJECT(s)); - qemu_file_set_rate_limit(s->to_dst_file, 0); + migration_rate_limit_set(0); setup_start = qemu_clock_get_ms(QEMU_CLOCK_HOST); /* @@ -3215,7 +3215,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_limit_set(rate_limit); qemu_file_set_blocking(s->to_dst_file, true); /* diff --git a/migration/multifd.c b/migration/multifd.c index 4e71c19292..2efb313be4 100644 --- a/migration/multifd.c +++ b/migration/multifd.c @@ -432,7 +432,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_limit_account(transferred); qemu_mutex_unlock(&p->mutex); stat64_add(&mig_stats.transferred, transferred); stat64_add(&mig_stats.multifd_bytes, transferred); diff --git a/migration/options.c b/migration/options.c index d04b5fbc3a..a024fa3ce6 100644 --- a/migration/options.c +++ b/migration/options.c @@ -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" @@ -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_limit_set(s->parameters.max_bandwidth); } } @@ -1274,8 +1274,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_limit_set(s->parameters.max_postcopy_bandwidth); } } if (params->has_max_cpu_throttle) { diff --git a/migration/qemu-file.c b/migration/qemu-file.c index 8de1ecd082..3f993e24af 100644 --- a/migration/qemu-file.c +++ b/migration/qemu-file.c @@ -27,6 +27,7 @@ #include "qemu/error-report.h" #include "qemu/iov.h" #include "migration.h" +#include "migration-stats.h" #include "qemu-file.h" #include "trace.h" #include "options.h" @@ -40,17 +41,6 @@ struct QEMUFile { QIOChannel *ioc; bool is_writable; - /* - * Maximum amount of data in bytes to transfer during one - * rate limiting time window - */ - uint64_t rate_limit_max; - /* - * Total amount of data in bytes queued for transfer - * during this rate limiting time window - */ - uint64_t rate_limit_used; - /* The sum of bytes transferred on the wire */ uint64_t total_transferred; @@ -302,7 +292,7 @@ void qemu_fflush(QEMUFile *f) qemu_file_set_error_obj(f, -EIO, local_error); } else { uint64_t size = iov_size(f->iov, f->iovcnt); - qemu_file_acct_rate_limit(f, size); + migration_rate_limit_account(size); f->total_transferred += size; } @@ -355,7 +345,7 @@ size_t ram_control_save_page(QEMUFile *f, ram_addr_t block_offset, int ret = f->hooks->save_page(f, block_offset, offset, size, bytes_sent); if (ret != RAM_SAVE_CONTROL_NOT_SUPP) { - qemu_file_acct_rate_limit(f, size); + migration_rate_limit_account(size); } if (ret != RAM_SAVE_CONTROL_DELAYED && @@ -726,43 +716,6 @@ uint64_t qemu_file_transferred(QEMUFile *f) return f->total_transferred; } -int qemu_file_rate_limit(QEMUFile *f) -{ - if (qemu_file_get_error(f)) { - return 1; - } - /* - * rate_limit_max == 0 means no rate_limit enfoncement. - */ - if (f->rate_limit_max > 0 && f->rate_limit_used > f->rate_limit_max) { - return 1; - } - return 0; -} - -uint64_t qemu_file_get_rate_limit(QEMUFile *f) -{ - return f->rate_limit_max; -} - -void qemu_file_set_rate_limit(QEMUFile *f, uint64_t limit) -{ - /* - * 'limit' is per second. But we check it each 100 miliseconds. - */ - f->rate_limit_max = limit / XFER_LIMIT_RATIO; -} - -void qemu_file_reset_rate_limit(QEMUFile *f) -{ - f->rate_limit_used = 0; -} - -void qemu_file_acct_rate_limit(QEMUFile *f, uint64_t len) -{ - f->rate_limit_used += len; -} - void qemu_put_be16(QEMUFile *f, unsigned int v) { qemu_put_byte(f, v >> 8); diff --git a/migration/qemu-file.h b/migration/qemu-file.h index ab164a58d0..46029b951c 100644 --- a/migration/qemu-file.h +++ b/migration/qemu-file.h @@ -129,17 +129,6 @@ void qemu_file_skip(QEMUFile *f, int size); * accounting information tracks the total migration traffic. */ void qemu_file_credit_transfer(QEMUFile *f, size_t size); -void qemu_file_reset_rate_limit(QEMUFile *f); -/* - * qemu_file_acct_rate_limit: - * - * Report on a number of bytes the have been transferred - * out of band from the main file object I/O methods, and - * need to be applied to the rate limiting calcuations - */ -void qemu_file_acct_rate_limit(QEMUFile *f, uint64_t len); -void qemu_file_set_rate_limit(QEMUFile *f, uint64_t new_rate); -uint64_t qemu_file_get_rate_limit(QEMUFile *f); int qemu_file_get_error_obj(QEMUFile *f, Error **errp); int qemu_file_get_error_obj_any(QEMUFile *f1, QEMUFile *f2, Error **errp); void qemu_file_set_error_obj(QEMUFile *f, int ret, Error *err); diff --git a/migration/ram.c b/migration/ram.c index 5ae1fdba45..2339a99932 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -3351,7 +3351,7 @@ static int ram_save_iterate(QEMUFile *f, void *opaque) t0 = qemu_clock_get_ns(QEMU_CLOCK_REALTIME); i = 0; - while ((ret = qemu_file_rate_limit(f)) == 0 || + while ((ret = migration_rate_limit_exceeded(f)) == 0 || postcopy_has_request(rs)) { int pages; diff --git a/migration/savevm.c b/migration/savevm.c index c7af9050c2..376118bc98 100644 --- a/migration/savevm.c +++ b/migration/savevm.c @@ -1345,7 +1345,7 @@ int qemu_savevm_state_iterate(QEMUFile *f, bool postcopy) !(se->ops->has_postcopy && se->ops->has_postcopy(se->opaque))) { continue; } - if (qemu_file_rate_limit(f)) { + if (migration_rate_limit_exceeded(f)) { return 0; } trace_savevm_section_start(se->idstr, se->section_id);
This 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_limit_exceeded qemu_file_set_rate_limit -> migration_rate_limit_set qemu_file_get_rate_limit -> migration_rate_limit_get qemu_file_reset_rate_limit -> migration_rate_limit_reset qemu_file_acct_rate_limit -> migration_rate_limit_account. Signed-off-by: Juan Quintela <quintela@redhat.com> --- If you have any good suggestion for better names, I am all ears. --- hw/ppc/spapr.c | 5 +-- hw/s390x/s390-stattrib.c | 2 +- include/migration/qemu-file-types.h | 2 +- migration/block-dirty-bitmap.c | 2 +- migration/block.c | 5 +-- migration/migration-stats.c | 41 ++++++++++++++++++++++ migration/migration-stats.h | 42 +++++++++++++++++++++++ migration/migration.c | 14 ++++---- migration/multifd.c | 2 +- migration/options.c | 7 ++-- migration/qemu-file.c | 53 ++--------------------------- migration/qemu-file.h | 11 ------ migration/ram.c | 2 +- migration/savevm.c | 2 +- 14 files changed, 108 insertions(+), 82 deletions(-)