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(-)
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);
--
2.40.0
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;
> }
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.
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.
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. > >
© 2016 - 2026 Red Hat, Inc.