aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hw/ppc/spapr.c4
-rw-r--r--hw/s390x/s390-stattrib.c2
-rw-r--r--include/migration/qemu-file-types.h12
-rw-r--r--migration/block-dirty-bitmap.c2
-rw-r--r--migration/block.c5
-rw-r--r--migration/meson.build2
-rw-r--r--migration/migration-stats.c44
-rw-r--r--migration/migration-stats.h46
-rw-r--r--migration/migration.c14
-rw-r--r--migration/multifd.c2
-rw-r--r--migration/options.c7
-rw-r--r--migration/options.h7
-rw-r--r--migration/qemu-file.c52
-rw-r--r--migration/qemu-file.h11
-rw-r--r--migration/ram.c2
-rw-r--r--migration/savevm.c2
16 files changed, 124 insertions, 90 deletions
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index ddc9c7b..1baea16 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_exceeded(f));
if (index >= htabslots) {
assert(index == htabslots);
@@ -2237,7 +2237,7 @@ static int htab_save_later_pass(QEMUFile *f, SpaprMachineState *spapr,
assert(index == htabslots);
index = 0;
}
- } while ((examined < htabslots) && (!qemu_file_rate_limit(f) || final));
+ } while ((examined < htabslots) && (!migration_rate_exceeded(f) || final));
if (index >= htabslots) {
assert(index == htabslots);
diff --git a/hw/s390x/s390-stattrib.c b/hw/s390x/s390-stattrib.c
index aed919a..220e845 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_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 1436f9c..9ba163f 100644
--- a/include/migration/qemu-file-types.h
+++ b/include/migration/qemu-file-types.h
@@ -165,6 +165,16 @@ size_t coroutine_mixed_fn qemu_get_counted_string(QEMUFile *f, char buf[256]);
void qemu_put_counted_string(QEMUFile *f, const char *name);
-int qemu_file_rate_limit(QEMUFile *f);
+/**
+ * migration_rate_exceeded: Check if we have exceeded rate for this interval
+ *
+ * Checks if we have already transferred more data that we are allowed
+ * in the current interval.
+ *
+ * @f: QEMUFile used for main migration channel
+ *
+ * Returns if we should stop sending data for this interval.
+ */
+bool migration_rate_exceeded(QEMUFile *f);
#endif
diff --git a/migration/block-dirty-bitmap.c b/migration/block-dirty-bitmap.c
index 20f36e6..032fc5f 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_exceeded(f)) {
return;
}
}
diff --git a/migration/block.c b/migration/block.c
index 12617b4..b9580a6 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_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_get() &&
block_mig_state.submitted < MAX_PARALLEL_IO &&
(block_mig_state.submitted + block_mig_state.read_done) <
MAX_IO_BUFFERS) {
diff --git a/migration/meson.build b/migration/meson.build
index dc8b1da..b3d0c53 100644
--- a/migration/meson.build
+++ b/migration/meson.build
@@ -1,5 +1,6 @@
# Files needed by unit tests
migration_files = files(
+ 'migration-stats.c',
'page_cache.c',
'xbzrle.c',
'vmstate-types.c',
@@ -18,7 +19,6 @@ softmmu_ss.add(files(
'fd.c',
'global_state.c',
'migration-hmp-cmds.c',
- 'migration-stats.c',
'migration.c',
'multifd.c',
'multifd-zlib.c',
diff --git a/migration/migration-stats.c b/migration/migration-stats.c
index 2f2cea9..0890220 100644
--- a/migration/migration-stats.c
+++ b/migration/migration-stats.c
@@ -12,6 +12,50 @@
#include "qemu/osdep.h"
#include "qemu/stats64.h"
+#include "qemu-file.h"
#include "migration-stats.h"
MigrationAtomicStats mig_stats;
+
+bool migration_rate_exceeded(QEMUFile *f)
+{
+ if (qemu_file_get_error(f)) {
+ return true;
+ }
+
+ uint64_t rate_limit_used = stat64_get(&mig_stats.rate_limit_used);
+ uint64_t rate_limit_max = stat64_get(&mig_stats.rate_limit_max);
+
+ if (rate_limit_max == RATE_LIMIT_DISABLED) {
+ return false;
+ }
+ if (rate_limit_max > 0 && rate_limit_used > rate_limit_max) {
+ return true;
+ }
+ return false;
+}
+
+uint64_t migration_rate_get(void)
+{
+ return stat64_get(&mig_stats.rate_limit_max);
+}
+
+#define XFER_LIMIT_RATIO (1000 / BUFFER_DELAY)
+
+void migration_rate_set(uint64_t limit)
+{
+ /*
+ * 'limit' is per second. But we check it each BUFER_DELAY miliseconds.
+ */
+ stat64_set(&mig_stats.rate_limit_max, limit / XFER_LIMIT_RATIO);
+}
+
+void migration_rate_reset(void)
+{
+ stat64_set(&mig_stats.rate_limit_used, 0);
+}
+
+void migration_rate_account(uint64_t len)
+{
+ stat64_add(&mig_stats.rate_limit_used, len);
+}
diff --git a/migration/migration-stats.h b/migration/migration-stats.h
index e7f1269..7b64dc7 100644
--- a/migration/migration-stats.h
+++ b/migration/migration-stats.h
@@ -16,6 +16,12 @@
#include "qemu/stats64.h"
/*
+ * Amount of time to allocate to each "chunk" of bandwidth-throttled
+ * data.
+ */
+#define BUFFER_DELAY 100
+
+/*
* If rate_limit_max is 0, there is special code to remove the rate
* limit.
*/
@@ -76,6 +82,14 @@ typedef struct {
*/
Stat64 precopy_bytes;
/*
+ * Maximum amount of data we can send in a cycle.
+ */
+ Stat64 rate_limit_max;
+ /*
+ * Amount of data we have sent in the current cycle.
+ */
+ Stat64 rate_limit_used;
+ /*
* Total number of bytes transferred.
*/
Stat64 transferred;
@@ -87,4 +101,36 @@ typedef struct {
extern MigrationAtomicStats mig_stats;
+/**
+ * migration_rate_account: Increase the number of bytes transferred.
+ *
+ * Report on a number of bytes the have been transferred that need to
+ * be applied to the rate limiting calcuations.
+ *
+ * @len: amount of bytes transferred
+ */
+void migration_rate_account(uint64_t len);
+
+/**
+ * migration_rate_get: Get the maximum amount that can be transferred.
+ *
+ * Returns the maximum number of bytes that can be transferred in a cycle.
+ */
+uint64_t migration_rate_get(void);
+
+/**
+ * migration_rate_reset: Reset the rate limit counter.
+ *
+ * This is called when we know we start a new transfer cycle.
+ */
+void migration_rate_reset(void);
+
+/**
+ * migration_rate_set: Set the maximum amount that can be transferred.
+ *
+ * Sets the maximum amount of bytes that can be transferred in one cycle.
+ *
+ * @new_rate: new maximum amount
+ */
+void migration_rate_set(uint64_t new_rate);
#endif
diff --git a/migration/migration.c b/migration/migration.c
index 3ceaf29..fc8974e 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -2120,7 +2120,7 @@ static int postcopy_start(MigrationState *ms)
* will notice we're in POSTCOPY_ACTIVE and not actually
* wrap their state up here
*/
- qemu_file_set_rate_limit(ms->to_dst_file, bandwidth);
+ migration_rate_set(bandwidth);
if (migrate_postcopy_ram()) {
/* Ping just for debugging, helps line traces up */
qemu_savevm_send_ping(ms->to_dst_file, 2);
@@ -2304,7 +2304,7 @@ static void migration_completion(MigrationState *s)
* them if migration fails or is cancelled.
*/
s->block_inactive = !migrate_colo();
- qemu_file_set_rate_limit(s->to_dst_file, RATE_LIMIT_DISABLED);
+ migration_rate_set(RATE_LIMIT_DISABLED);
ret = qemu_savevm_state_complete_precopy(s->to_dst_file, false,
s->block_inactive);
}
@@ -2699,7 +2699,7 @@ static void migration_update_counters(MigrationState *s,
stat64_get(&mig_stats.dirty_bytes_last_sync) / bandwidth;
}
- qemu_file_reset_rate_limit(s->to_dst_file);
+ migration_rate_reset();
update_iteration_initial_status(s);
@@ -2852,7 +2852,7 @@ bool migration_rate_limit(void)
bool urgent = false;
migration_update_counters(s, now);
- if (qemu_file_rate_limit(s->to_dst_file)) {
+ if (migration_rate_exceeded(s->to_dst_file)) {
if (qemu_file_get_error(s->to_dst_file)) {
return false;
@@ -2974,7 +2974,7 @@ static void *migration_thread(void *opaque)
trace_migration_thread_setup_complete();
while (migration_is_active(s)) {
- if (urgent || !qemu_file_rate_limit(s->to_dst_file)) {
+ if (urgent || !migration_rate_exceeded(s->to_dst_file)) {
MigIterateState iter_state = migration_iteration_run(s);
if (iter_state == MIG_ITERATE_SKIP) {
continue;
@@ -3048,7 +3048,7 @@ static void *bg_migration_thread(void *opaque)
rcu_register_thread();
object_ref(OBJECT(s));
- qemu_file_set_rate_limit(s->to_dst_file, RATE_LIMIT_DISABLED);
+ migration_rate_set(RATE_LIMIT_DISABLED);
setup_start = qemu_clock_get_ms(QEMU_CLOCK_HOST);
/*
@@ -3220,7 +3220,7 @@ void migrate_fd_connect(MigrationState *s, Error *error_in)
notifier_list_notify(&migration_state_notifiers, s);
}
- qemu_file_set_rate_limit(s->to_dst_file, rate_limit);
+ migration_rate_set(rate_limit);
qemu_file_set_blocking(s->to_dst_file, true);
/*
diff --git a/migration/multifd.c b/migration/multifd.c
index 5c4298e..5052091 100644
--- a/migration/multifd.c
+++ b/migration/multifd.c
@@ -431,7 +431,7 @@ static int multifd_send_pages(QEMUFile *f)
multifd_send_state->pages = p->pages;
p->pages = pages;
transferred = ((uint64_t) pages->num) * p->page_size + p->packet_len;
- qemu_file_acct_rate_limit(f, transferred);
+ migration_rate_account(transferred);
qemu_mutex_unlock(&p->mutex);
stat64_add(&mig_stats.transferred, transferred);
stat64_add(&mig_stats.multifd_bytes, transferred);
diff --git a/migration/options.c b/migration/options.c
index c2a278e..b62ab30 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_set(s->parameters.max_bandwidth);
}
}
@@ -1272,8 +1272,7 @@ static void migrate_params_apply(MigrateSetParameters *params, Error **errp)
if (params->has_max_postcopy_bandwidth) {
s->parameters.max_postcopy_bandwidth = params->max_postcopy_bandwidth;
if (s->to_dst_file && migration_in_postcopy()) {
- qemu_file_set_rate_limit(s->to_dst_file,
- s->parameters.max_postcopy_bandwidth);
+ migration_rate_set(s->parameters.max_postcopy_bandwidth);
}
}
if (params->has_max_cpu_throttle) {
diff --git a/migration/options.h b/migration/options.h
index 5cca332..45991af 100644
--- a/migration/options.h
+++ b/migration/options.h
@@ -17,13 +17,6 @@
#include "hw/qdev-properties.h"
#include "hw/qdev-properties-system.h"
-/* constants */
-
-/* Amount of time to allocate to each "chunk" of bandwidth-throttled
- * data. */
-#define BUFFER_DELAY 100
-#define XFER_LIMIT_RATIO (1000 / BUFFER_DELAY)
-
/* migration properties */
extern Property migration_properties[];
diff --git a/migration/qemu-file.c b/migration/qemu-file.c
index 3d66c5c..9c67b52 100644
--- a/migration/qemu-file.c
+++ b/migration/qemu-file.c
@@ -41,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;
@@ -303,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_account(size);
f->total_transferred += size;
}
@@ -356,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_account(size);
}
if (ret != RAM_SAVE_CONTROL_DELAYED &&
@@ -727,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;
- }
- if (f->rate_limit_max == RATE_LIMIT_DISABLED) {
- return 0;
- }
- if (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 bcc3908..e649718 100644
--- a/migration/qemu-file.h
+++ b/migration/qemu-file.h
@@ -130,17 +130,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 f69d8d4..15cb15b 100644
--- a/migration/ram.c
+++ b/migration/ram.c
@@ -3116,7 +3116,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_exceeded(f)) == 0 ||
postcopy_has_request(rs)) {
int pages;
diff --git a/migration/savevm.c b/migration/savevm.c
index e337883..03795ce 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -1338,7 +1338,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_exceeded(f)) {
return 0;
}
trace_savevm_section_start(se->idstr, se->section_id);