@@ -420,6 +420,12 @@ struct RAMState {
* RAM migration.
*/
unsigned int postcopy_bmap_sync_requested;
+
+ /*
+ * Ratio of bytes_dirty_period and bytes_xfer_period in the
+ * previous sync.
+ */
+ uint64_t dirty_ratio_pct;
};
typedef struct RAMState RAMState;
@@ -1019,6 +1025,43 @@ static void migration_dirty_limit_guest(void)
trace_migration_dirty_limit_guest(quota_dirtyrate);
}
+static bool migration_dirty_ratio_high(RAMState *rs)
+{
+ static int dirty_ratio_high_cnt;
+ uint64_t threshold = migrate_throttle_trigger_threshold();
+ uint64_t bytes_xfer_period =
+ migration_transferred_bytes() - rs->bytes_xfer_prev;
+ uint64_t bytes_dirty_period = rs->num_dirty_pages_period * TARGET_PAGE_SIZE;
+ bool dirty_ratio_high = false;
+ uint64_t prev, curr;
+
+ /* Calculate the dirty ratio percentage */
+ curr = 100 * (bytes_dirty_period * 1.0 / bytes_xfer_period);
+
+ prev = rs->dirty_ratio_pct;
+ rs->dirty_ratio_pct = curr;
+
+ if (prev == 0) {
+ return false;
+ }
+
+ /*
+ * If current dirty ratio is greater than previouse, determine
+ * that the migration do not converge.
+ */
+ if (curr > threshold && curr >= prev) {
+ trace_migration_dirty_ratio_high(curr, prev);
+ dirty_ratio_high_cnt++;
+ }
+
+ if (dirty_ratio_high_cnt >= 2) {
+ dirty_ratio_high = true;
+ dirty_ratio_high_cnt = 0;
+ }
+
+ return dirty_ratio_high;
+}
+
static void migration_trigger_throttle(RAMState *rs)
{
uint64_t threshold = migrate_throttle_trigger_threshold();
@@ -1026,6 +1069,11 @@ static void migration_trigger_throttle(RAMState *rs)
migration_transferred_bytes() - rs->bytes_xfer_prev;
uint64_t bytes_dirty_period = rs->num_dirty_pages_period * TARGET_PAGE_SIZE;
uint64_t bytes_dirty_threshold = bytes_xfer_period * threshold / 100;
+ bool dirty_ratio_high = false;
+
+ if (migrate_cpu_throttle_responsive() && (bytes_xfer_period != 0)) {
+ dirty_ratio_high = migration_dirty_ratio_high(rs);
+ }
/*
* The following detection logic can be refined later. For now:
@@ -1035,8 +1083,11 @@ static void migration_trigger_throttle(RAMState *rs)
* twice, start or increase throttling.
*/
if ((bytes_dirty_period > bytes_dirty_threshold) &&
- (++rs->dirty_rate_high_cnt >= 2)) {
- rs->dirty_rate_high_cnt = 0;
+ ((++rs->dirty_rate_high_cnt >= 2) || dirty_ratio_high)) {
+
+ rs->dirty_rate_high_cnt =
+ rs->dirty_rate_high_cnt >= 2 ? 0 : rs->dirty_rate_high_cnt;
+
if (migrate_auto_converge()) {
trace_migration_throttle();
mig_throttle_guest_down(bytes_dirty_period,
@@ -96,6 +96,7 @@ get_queued_page_not_dirty(const char *block_name, uint64_t tmp_offset, unsigned
migration_bitmap_sync_start(void) ""
migration_bitmap_sync_end(uint64_t dirty_pages) "dirty_pages %" PRIu64
migration_bitmap_clear_dirty(char *str, uint64_t start, uint64_t size, unsigned long page) "rb %s start 0x%"PRIx64" size 0x%"PRIx64" page 0x%lx"
+migration_dirty_ratio_high(uint64_t cur, uint64_t prev) "current ratio: %" PRIu64 " previous ratio: %" PRIu64
migration_throttle(void) ""
migration_dirty_limit_guest(int64_t dirtyrate) "guest dirty page rate limit %" PRIi64 " MB/s"
ram_discard_range(const char *rbname, uint64_t start, size_t len) "%s: start: %" PRIx64 " %zx"
@@ -2807,6 +2807,7 @@ static void test_migrate_auto_converge(void)
migrate_set_parameter_int(from, "cpu-throttle-initial", init_pct);
migrate_set_parameter_int(from, "cpu-throttle-increment", inc_pct);
migrate_set_parameter_int(from, "max-cpu-throttle", max_pct);
+ migrate_set_parameter_bool(from, "cpu-throttle-responsive", true);
/*
* Set the initial parameters so that the migration could not converge