1cc2b33eaSHyman Huang(黄勇) /* 2cc2b33eaSHyman Huang(黄勇) * Dirty page rate limit implementation code 3cc2b33eaSHyman Huang(黄勇) * 4cc2b33eaSHyman Huang(黄勇) * Copyright (c) 2022 CHINA TELECOM CO.,LTD. 5cc2b33eaSHyman Huang(黄勇) * 6cc2b33eaSHyman Huang(黄勇) * Authors: 7cc2b33eaSHyman Huang(黄勇) * Hyman Huang(黄勇) <huangy81@chinatelecom.cn> 8cc2b33eaSHyman Huang(黄勇) * 9cc2b33eaSHyman Huang(黄勇) * This work is licensed under the terms of the GNU GPL, version 2 or later. 10cc2b33eaSHyman Huang(黄勇) * See the COPYING file in the top-level directory. 11cc2b33eaSHyman Huang(黄勇) */ 12cc2b33eaSHyman Huang(黄勇) 13cc2b33eaSHyman Huang(黄勇) #include "qemu/osdep.h" 14cc2b33eaSHyman Huang(黄勇) #include "qemu/main-loop.h" 15cc2b33eaSHyman Huang(黄勇) #include "qapi/qapi-commands-migration.h" 16f3b2e38cSHyman Huang(黄勇) #include "qapi/qmp/qdict.h" 17f3b2e38cSHyman Huang(黄勇) #include "qapi/error.h" 18cc2b33eaSHyman Huang(黄勇) #include "sysemu/dirtyrate.h" 19cc2b33eaSHyman Huang(黄勇) #include "sysemu/dirtylimit.h" 20f3b2e38cSHyman Huang(黄勇) #include "monitor/hmp.h" 21f3b2e38cSHyman Huang(黄勇) #include "monitor/monitor.h" 22cc2b33eaSHyman Huang(黄勇) #include "exec/memory.h" 2330ee29fdSThomas Huth #include "exec/target_page.h" 24cc2b33eaSHyman Huang(黄勇) #include "hw/boards.h" 25baa60983SHyman Huang(黄勇) #include "sysemu/kvm.h" 26baa60983SHyman Huang(黄勇) #include "trace.h" 27dc623955SHyman Huang(黄勇) #include "migration/misc.h" 28dc623955SHyman Huang(黄勇) #include "migration/migration.h" 29baa60983SHyman Huang(黄勇) 30baa60983SHyman Huang(黄勇) /* 31baa60983SHyman Huang(黄勇) * Dirtylimit stop working if dirty page rate error 32baa60983SHyman Huang(黄勇) * value less than DIRTYLIMIT_TOLERANCE_RANGE 33baa60983SHyman Huang(黄勇) */ 34baa60983SHyman Huang(黄勇) #define DIRTYLIMIT_TOLERANCE_RANGE 25 /* MB/s */ 35baa60983SHyman Huang(黄勇) /* 36baa60983SHyman Huang(黄勇) * Plus or minus vcpu sleep time linearly if dirty 37baa60983SHyman Huang(黄勇) * page rate error value percentage over 38baa60983SHyman Huang(黄勇) * DIRTYLIMIT_LINEAR_ADJUSTMENT_PCT. 39baa60983SHyman Huang(黄勇) * Otherwise, plus or minus a fixed vcpu sleep time. 40baa60983SHyman Huang(黄勇) */ 41baa60983SHyman Huang(黄勇) #define DIRTYLIMIT_LINEAR_ADJUSTMENT_PCT 50 42baa60983SHyman Huang(黄勇) /* 43baa60983SHyman Huang(黄勇) * Max vcpu sleep time percentage during a cycle 44baa60983SHyman Huang(黄勇) * composed of dirty ring full and sleep time. 45baa60983SHyman Huang(黄勇) */ 46baa60983SHyman Huang(黄勇) #define DIRTYLIMIT_THROTTLE_PCT_MAX 99 47cc2b33eaSHyman Huang(黄勇) 48cc2b33eaSHyman Huang(黄勇) struct { 49cc2b33eaSHyman Huang(黄勇) VcpuStat stat; 50cc2b33eaSHyman Huang(黄勇) bool running; 51cc2b33eaSHyman Huang(黄勇) QemuThread thread; 52cc2b33eaSHyman Huang(黄勇) } *vcpu_dirty_rate_stat; 53cc2b33eaSHyman Huang(黄勇) 54baa60983SHyman Huang(黄勇) typedef struct VcpuDirtyLimitState { 55baa60983SHyman Huang(黄勇) int cpu_index; 56baa60983SHyman Huang(黄勇) bool enabled; 57baa60983SHyman Huang(黄勇) /* 58baa60983SHyman Huang(黄勇) * Quota dirty page rate, unit is MB/s 59baa60983SHyman Huang(黄勇) * zero if not enabled. 60baa60983SHyman Huang(黄勇) */ 61baa60983SHyman Huang(黄勇) uint64_t quota; 62baa60983SHyman Huang(黄勇) } VcpuDirtyLimitState; 63baa60983SHyman Huang(黄勇) 64baa60983SHyman Huang(黄勇) struct { 65baa60983SHyman Huang(黄勇) VcpuDirtyLimitState *states; 66baa60983SHyman Huang(黄勇) /* Max cpus number configured by user */ 67baa60983SHyman Huang(黄勇) int max_cpus; 68baa60983SHyman Huang(黄勇) /* Number of vcpu under dirtylimit */ 69baa60983SHyman Huang(黄勇) int limited_nvcpu; 70baa60983SHyman Huang(黄勇) } *dirtylimit_state; 71baa60983SHyman Huang(黄勇) 72baa60983SHyman Huang(黄勇) /* protect dirtylimit_state */ 73baa60983SHyman Huang(黄勇) static QemuMutex dirtylimit_mutex; 74baa60983SHyman Huang(黄勇) 75baa60983SHyman Huang(黄勇) /* dirtylimit thread quit if dirtylimit_quit is true */ 76baa60983SHyman Huang(黄勇) static bool dirtylimit_quit; 77baa60983SHyman Huang(黄勇) 78cc2b33eaSHyman Huang(黄勇) static void vcpu_dirty_rate_stat_collect(void) 79cc2b33eaSHyman Huang(黄勇) { 80dc623955SHyman Huang(黄勇) MigrationState *s = migrate_get_current(); 81cc2b33eaSHyman Huang(黄勇) VcpuStat stat; 82cc2b33eaSHyman Huang(黄勇) int i = 0; 83dc623955SHyman Huang(黄勇) int64_t period = DIRTYLIMIT_CALC_TIME_MS; 84dc623955SHyman Huang(黄勇) 85dc623955SHyman Huang(黄勇) if (migrate_dirty_limit() && 863a6813b6SSteve Sistare migration_is_active()) { 87dc623955SHyman Huang(黄勇) period = s->parameters.x_vcpu_dirty_limit_period; 88dc623955SHyman Huang(黄勇) } 89cc2b33eaSHyman Huang(黄勇) 90cc2b33eaSHyman Huang(黄勇) /* calculate vcpu dirtyrate */ 91dc623955SHyman Huang(黄勇) vcpu_calculate_dirtyrate(period, 92cc2b33eaSHyman Huang(黄勇) &stat, 93cc2b33eaSHyman Huang(黄勇) GLOBAL_DIRTY_LIMIT, 94cc2b33eaSHyman Huang(黄勇) false); 95cc2b33eaSHyman Huang(黄勇) 96cc2b33eaSHyman Huang(黄勇) for (i = 0; i < stat.nvcpu; i++) { 97cc2b33eaSHyman Huang(黄勇) vcpu_dirty_rate_stat->stat.rates[i].id = i; 98cc2b33eaSHyman Huang(黄勇) vcpu_dirty_rate_stat->stat.rates[i].dirty_rate = 99cc2b33eaSHyman Huang(黄勇) stat.rates[i].dirty_rate; 100cc2b33eaSHyman Huang(黄勇) } 101cc2b33eaSHyman Huang(黄勇) 10219b14ceaSalloc.young g_free(stat.rates); 103cc2b33eaSHyman Huang(黄勇) } 104cc2b33eaSHyman Huang(黄勇) 105cc2b33eaSHyman Huang(黄勇) static void *vcpu_dirty_rate_stat_thread(void *opaque) 106cc2b33eaSHyman Huang(黄勇) { 107cc2b33eaSHyman Huang(黄勇) rcu_register_thread(); 108cc2b33eaSHyman Huang(黄勇) 109cc2b33eaSHyman Huang(黄勇) /* start log sync */ 110cc2b33eaSHyman Huang(黄勇) global_dirty_log_change(GLOBAL_DIRTY_LIMIT, true); 111cc2b33eaSHyman Huang(黄勇) 112cc2b33eaSHyman Huang(黄勇) while (qatomic_read(&vcpu_dirty_rate_stat->running)) { 113cc2b33eaSHyman Huang(黄勇) vcpu_dirty_rate_stat_collect(); 114baa60983SHyman Huang(黄勇) if (dirtylimit_in_service()) { 115baa60983SHyman Huang(黄勇) dirtylimit_process(); 116baa60983SHyman Huang(黄勇) } 117cc2b33eaSHyman Huang(黄勇) } 118cc2b33eaSHyman Huang(黄勇) 119cc2b33eaSHyman Huang(黄勇) /* stop log sync */ 120cc2b33eaSHyman Huang(黄勇) global_dirty_log_change(GLOBAL_DIRTY_LIMIT, false); 121cc2b33eaSHyman Huang(黄勇) 122cc2b33eaSHyman Huang(黄勇) rcu_unregister_thread(); 123cc2b33eaSHyman Huang(黄勇) return NULL; 124cc2b33eaSHyman Huang(黄勇) } 125cc2b33eaSHyman Huang(黄勇) 126cc2b33eaSHyman Huang(黄勇) int64_t vcpu_dirty_rate_get(int cpu_index) 127cc2b33eaSHyman Huang(黄勇) { 128cc2b33eaSHyman Huang(黄勇) DirtyRateVcpu *rates = vcpu_dirty_rate_stat->stat.rates; 129cc2b33eaSHyman Huang(黄勇) return qatomic_read_i64(&rates[cpu_index].dirty_rate); 130cc2b33eaSHyman Huang(黄勇) } 131cc2b33eaSHyman Huang(黄勇) 132cc2b33eaSHyman Huang(黄勇) void vcpu_dirty_rate_stat_start(void) 133cc2b33eaSHyman Huang(黄勇) { 134cc2b33eaSHyman Huang(黄勇) if (qatomic_read(&vcpu_dirty_rate_stat->running)) { 135cc2b33eaSHyman Huang(黄勇) return; 136cc2b33eaSHyman Huang(黄勇) } 137cc2b33eaSHyman Huang(黄勇) 138cc2b33eaSHyman Huang(黄勇) qatomic_set(&vcpu_dirty_rate_stat->running, 1); 139cc2b33eaSHyman Huang(黄勇) qemu_thread_create(&vcpu_dirty_rate_stat->thread, 140cc2b33eaSHyman Huang(黄勇) "dirtyrate-stat", 141cc2b33eaSHyman Huang(黄勇) vcpu_dirty_rate_stat_thread, 142cc2b33eaSHyman Huang(黄勇) NULL, 143cc2b33eaSHyman Huang(黄勇) QEMU_THREAD_JOINABLE); 144cc2b33eaSHyman Huang(黄勇) } 145cc2b33eaSHyman Huang(黄勇) 146cc2b33eaSHyman Huang(黄勇) void vcpu_dirty_rate_stat_stop(void) 147cc2b33eaSHyman Huang(黄勇) { 148cc2b33eaSHyman Huang(黄勇) qatomic_set(&vcpu_dirty_rate_stat->running, 0); 149baa60983SHyman Huang(黄勇) dirtylimit_state_unlock(); 150195801d7SStefan Hajnoczi bql_unlock(); 151cc2b33eaSHyman Huang(黄勇) qemu_thread_join(&vcpu_dirty_rate_stat->thread); 152195801d7SStefan Hajnoczi bql_lock(); 153baa60983SHyman Huang(黄勇) dirtylimit_state_lock(); 154cc2b33eaSHyman Huang(黄勇) } 155cc2b33eaSHyman Huang(黄勇) 156cc2b33eaSHyman Huang(黄勇) void vcpu_dirty_rate_stat_initialize(void) 157cc2b33eaSHyman Huang(黄勇) { 158cc2b33eaSHyman Huang(黄勇) MachineState *ms = MACHINE(qdev_get_machine()); 159cc2b33eaSHyman Huang(黄勇) int max_cpus = ms->smp.max_cpus; 160cc2b33eaSHyman Huang(黄勇) 161cc2b33eaSHyman Huang(黄勇) vcpu_dirty_rate_stat = 162cc2b33eaSHyman Huang(黄勇) g_malloc0(sizeof(*vcpu_dirty_rate_stat)); 163cc2b33eaSHyman Huang(黄勇) 164cc2b33eaSHyman Huang(黄勇) vcpu_dirty_rate_stat->stat.nvcpu = max_cpus; 165cc2b33eaSHyman Huang(黄勇) vcpu_dirty_rate_stat->stat.rates = 166c5e8d518SMarkus Armbruster g_new0(DirtyRateVcpu, max_cpus); 167cc2b33eaSHyman Huang(黄勇) 168cc2b33eaSHyman Huang(黄勇) vcpu_dirty_rate_stat->running = false; 169cc2b33eaSHyman Huang(黄勇) } 170cc2b33eaSHyman Huang(黄勇) 171cc2b33eaSHyman Huang(黄勇) void vcpu_dirty_rate_stat_finalize(void) 172cc2b33eaSHyman Huang(黄勇) { 17319b14ceaSalloc.young g_free(vcpu_dirty_rate_stat->stat.rates); 174cc2b33eaSHyman Huang(黄勇) vcpu_dirty_rate_stat->stat.rates = NULL; 175cc2b33eaSHyman Huang(黄勇) 17619b14ceaSalloc.young g_free(vcpu_dirty_rate_stat); 177cc2b33eaSHyman Huang(黄勇) vcpu_dirty_rate_stat = NULL; 178cc2b33eaSHyman Huang(黄勇) } 179baa60983SHyman Huang(黄勇) 180baa60983SHyman Huang(黄勇) void dirtylimit_state_lock(void) 181baa60983SHyman Huang(黄勇) { 182baa60983SHyman Huang(黄勇) qemu_mutex_lock(&dirtylimit_mutex); 183baa60983SHyman Huang(黄勇) } 184baa60983SHyman Huang(黄勇) 185baa60983SHyman Huang(黄勇) void dirtylimit_state_unlock(void) 186baa60983SHyman Huang(黄勇) { 187baa60983SHyman Huang(黄勇) qemu_mutex_unlock(&dirtylimit_mutex); 188baa60983SHyman Huang(黄勇) } 189baa60983SHyman Huang(黄勇) 190baa60983SHyman Huang(黄勇) static void 191baa60983SHyman Huang(黄勇) __attribute__((__constructor__)) dirtylimit_mutex_init(void) 192baa60983SHyman Huang(黄勇) { 193baa60983SHyman Huang(黄勇) qemu_mutex_init(&dirtylimit_mutex); 194baa60983SHyman Huang(黄勇) } 195baa60983SHyman Huang(黄勇) 196baa60983SHyman Huang(黄勇) static inline VcpuDirtyLimitState *dirtylimit_vcpu_get_state(int cpu_index) 197baa60983SHyman Huang(黄勇) { 198baa60983SHyman Huang(黄勇) return &dirtylimit_state->states[cpu_index]; 199baa60983SHyman Huang(黄勇) } 200baa60983SHyman Huang(黄勇) 201baa60983SHyman Huang(黄勇) void dirtylimit_state_initialize(void) 202baa60983SHyman Huang(黄勇) { 203baa60983SHyman Huang(黄勇) MachineState *ms = MACHINE(qdev_get_machine()); 204baa60983SHyman Huang(黄勇) int max_cpus = ms->smp.max_cpus; 205baa60983SHyman Huang(黄勇) int i; 206baa60983SHyman Huang(黄勇) 207baa60983SHyman Huang(黄勇) dirtylimit_state = g_malloc0(sizeof(*dirtylimit_state)); 208baa60983SHyman Huang(黄勇) 209baa60983SHyman Huang(黄勇) dirtylimit_state->states = 210c5e8d518SMarkus Armbruster g_new0(VcpuDirtyLimitState, max_cpus); 211baa60983SHyman Huang(黄勇) 212baa60983SHyman Huang(黄勇) for (i = 0; i < max_cpus; i++) { 213baa60983SHyman Huang(黄勇) dirtylimit_state->states[i].cpu_index = i; 214baa60983SHyman Huang(黄勇) } 215baa60983SHyman Huang(黄勇) 216baa60983SHyman Huang(黄勇) dirtylimit_state->max_cpus = max_cpus; 217baa60983SHyman Huang(黄勇) trace_dirtylimit_state_initialize(max_cpus); 218baa60983SHyman Huang(黄勇) } 219baa60983SHyman Huang(黄勇) 220baa60983SHyman Huang(黄勇) void dirtylimit_state_finalize(void) 221baa60983SHyman Huang(黄勇) { 22219b14ceaSalloc.young g_free(dirtylimit_state->states); 223baa60983SHyman Huang(黄勇) dirtylimit_state->states = NULL; 224baa60983SHyman Huang(黄勇) 22519b14ceaSalloc.young g_free(dirtylimit_state); 226baa60983SHyman Huang(黄勇) dirtylimit_state = NULL; 227baa60983SHyman Huang(黄勇) 228baa60983SHyman Huang(黄勇) trace_dirtylimit_state_finalize(); 229baa60983SHyman Huang(黄勇) } 230baa60983SHyman Huang(黄勇) 231baa60983SHyman Huang(黄勇) bool dirtylimit_in_service(void) 232baa60983SHyman Huang(黄勇) { 233baa60983SHyman Huang(黄勇) return !!dirtylimit_state; 234baa60983SHyman Huang(黄勇) } 235baa60983SHyman Huang(黄勇) 236baa60983SHyman Huang(黄勇) bool dirtylimit_vcpu_index_valid(int cpu_index) 237baa60983SHyman Huang(黄勇) { 238baa60983SHyman Huang(黄勇) MachineState *ms = MACHINE(qdev_get_machine()); 239baa60983SHyman Huang(黄勇) 240baa60983SHyman Huang(黄勇) return !(cpu_index < 0 || 241baa60983SHyman Huang(黄勇) cpu_index >= ms->smp.max_cpus); 242baa60983SHyman Huang(黄勇) } 243baa60983SHyman Huang(黄勇) 2446a6447feSRichard Henderson static uint64_t dirtylimit_dirty_ring_full_time(uint64_t dirtyrate) 245baa60983SHyman Huang(黄勇) { 246baa60983SHyman Huang(黄勇) static uint64_t max_dirtyrate; 247beeda9b7SJuan Quintela uint64_t dirty_ring_size_MiB; 2486a6447feSRichard Henderson 249beeda9b7SJuan Quintela dirty_ring_size_MiB = qemu_target_pages_to_MiB(kvm_dirty_ring_size()); 250baa60983SHyman Huang(黄勇) 251baa60983SHyman Huang(黄勇) if (max_dirtyrate < dirtyrate) { 252baa60983SHyman Huang(黄勇) max_dirtyrate = dirtyrate; 253baa60983SHyman Huang(黄勇) } 254baa60983SHyman Huang(黄勇) 255beeda9b7SJuan Quintela return dirty_ring_size_MiB * 1000000 / max_dirtyrate; 256baa60983SHyman Huang(黄勇) } 257baa60983SHyman Huang(黄勇) 258baa60983SHyman Huang(黄勇) static inline bool dirtylimit_done(uint64_t quota, 259baa60983SHyman Huang(黄勇) uint64_t current) 260baa60983SHyman Huang(黄勇) { 261baa60983SHyman Huang(黄勇) uint64_t min, max; 262baa60983SHyman Huang(黄勇) 263baa60983SHyman Huang(黄勇) min = MIN(quota, current); 264baa60983SHyman Huang(黄勇) max = MAX(quota, current); 265baa60983SHyman Huang(黄勇) 266baa60983SHyman Huang(黄勇) return ((max - min) <= DIRTYLIMIT_TOLERANCE_RANGE) ? true : false; 267baa60983SHyman Huang(黄勇) } 268baa60983SHyman Huang(黄勇) 269baa60983SHyman Huang(黄勇) static inline bool 270baa60983SHyman Huang(黄勇) dirtylimit_need_linear_adjustment(uint64_t quota, 271baa60983SHyman Huang(黄勇) uint64_t current) 272baa60983SHyman Huang(黄勇) { 273baa60983SHyman Huang(黄勇) uint64_t min, max; 274baa60983SHyman Huang(黄勇) 275baa60983SHyman Huang(黄勇) min = MIN(quota, current); 276baa60983SHyman Huang(黄勇) max = MAX(quota, current); 277baa60983SHyman Huang(黄勇) 278baa60983SHyman Huang(黄勇) return ((max - min) * 100 / max) > DIRTYLIMIT_LINEAR_ADJUSTMENT_PCT; 279baa60983SHyman Huang(黄勇) } 280baa60983SHyman Huang(黄勇) 281baa60983SHyman Huang(黄勇) static void dirtylimit_set_throttle(CPUState *cpu, 282baa60983SHyman Huang(黄勇) uint64_t quota, 283baa60983SHyman Huang(黄勇) uint64_t current) 284baa60983SHyman Huang(黄勇) { 285baa60983SHyman Huang(黄勇) int64_t ring_full_time_us = 0; 286baa60983SHyman Huang(黄勇) uint64_t sleep_pct = 0; 287baa60983SHyman Huang(黄勇) uint64_t throttle_us = 0; 288baa60983SHyman Huang(黄勇) 289baa60983SHyman Huang(黄勇) if (current == 0) { 290baa60983SHyman Huang(黄勇) cpu->throttle_us_per_full = 0; 291baa60983SHyman Huang(黄勇) return; 292baa60983SHyman Huang(黄勇) } 293baa60983SHyman Huang(黄勇) 294baa60983SHyman Huang(黄勇) ring_full_time_us = dirtylimit_dirty_ring_full_time(current); 295baa60983SHyman Huang(黄勇) 296baa60983SHyman Huang(黄勇) if (dirtylimit_need_linear_adjustment(quota, current)) { 297baa60983SHyman Huang(黄勇) if (quota < current) { 298baa60983SHyman Huang(黄勇) sleep_pct = (current - quota) * 100 / current; 299baa60983SHyman Huang(黄勇) throttle_us = 300baa60983SHyman Huang(黄勇) ring_full_time_us * sleep_pct / (double)(100 - sleep_pct); 301baa60983SHyman Huang(黄勇) cpu->throttle_us_per_full += throttle_us; 302baa60983SHyman Huang(黄勇) } else { 303baa60983SHyman Huang(黄勇) sleep_pct = (quota - current) * 100 / quota; 304baa60983SHyman Huang(黄勇) throttle_us = 305baa60983SHyman Huang(黄勇) ring_full_time_us * sleep_pct / (double)(100 - sleep_pct); 306baa60983SHyman Huang(黄勇) cpu->throttle_us_per_full -= throttle_us; 307baa60983SHyman Huang(黄勇) } 308baa60983SHyman Huang(黄勇) 309baa60983SHyman Huang(黄勇) trace_dirtylimit_throttle_pct(cpu->cpu_index, 310baa60983SHyman Huang(黄勇) sleep_pct, 311baa60983SHyman Huang(黄勇) throttle_us); 312baa60983SHyman Huang(黄勇) } else { 313baa60983SHyman Huang(黄勇) if (quota < current) { 314baa60983SHyman Huang(黄勇) cpu->throttle_us_per_full += ring_full_time_us / 10; 315baa60983SHyman Huang(黄勇) } else { 316baa60983SHyman Huang(黄勇) cpu->throttle_us_per_full -= ring_full_time_us / 10; 317baa60983SHyman Huang(黄勇) } 318baa60983SHyman Huang(黄勇) } 319baa60983SHyman Huang(黄勇) 320baa60983SHyman Huang(黄勇) /* 321baa60983SHyman Huang(黄勇) * TODO: in the big kvm_dirty_ring_size case (eg: 65536, or other scenario), 322baa60983SHyman Huang(黄勇) * current dirty page rate may never reach the quota, we should stop 323baa60983SHyman Huang(黄勇) * increasing sleep time? 324baa60983SHyman Huang(黄勇) */ 325baa60983SHyman Huang(黄勇) cpu->throttle_us_per_full = MIN(cpu->throttle_us_per_full, 326baa60983SHyman Huang(黄勇) ring_full_time_us * DIRTYLIMIT_THROTTLE_PCT_MAX); 327baa60983SHyman Huang(黄勇) 328baa60983SHyman Huang(黄勇) cpu->throttle_us_per_full = MAX(cpu->throttle_us_per_full, 0); 329baa60983SHyman Huang(黄勇) } 330baa60983SHyman Huang(黄勇) 331baa60983SHyman Huang(黄勇) static void dirtylimit_adjust_throttle(CPUState *cpu) 332baa60983SHyman Huang(黄勇) { 333baa60983SHyman Huang(黄勇) uint64_t quota = 0; 334baa60983SHyman Huang(黄勇) uint64_t current = 0; 335baa60983SHyman Huang(黄勇) int cpu_index = cpu->cpu_index; 336baa60983SHyman Huang(黄勇) 337baa60983SHyman Huang(黄勇) quota = dirtylimit_vcpu_get_state(cpu_index)->quota; 338baa60983SHyman Huang(黄勇) current = vcpu_dirty_rate_get(cpu_index); 339baa60983SHyman Huang(黄勇) 340baa60983SHyman Huang(黄勇) if (!dirtylimit_done(quota, current)) { 341baa60983SHyman Huang(黄勇) dirtylimit_set_throttle(cpu, quota, current); 342baa60983SHyman Huang(黄勇) } 343baa60983SHyman Huang(黄勇) 344baa60983SHyman Huang(黄勇) return; 345baa60983SHyman Huang(黄勇) } 346baa60983SHyman Huang(黄勇) 347baa60983SHyman Huang(黄勇) void dirtylimit_process(void) 348baa60983SHyman Huang(黄勇) { 349baa60983SHyman Huang(黄勇) CPUState *cpu; 350baa60983SHyman Huang(黄勇) 351baa60983SHyman Huang(黄勇) if (!qatomic_read(&dirtylimit_quit)) { 352baa60983SHyman Huang(黄勇) dirtylimit_state_lock(); 353baa60983SHyman Huang(黄勇) 354baa60983SHyman Huang(黄勇) if (!dirtylimit_in_service()) { 355baa60983SHyman Huang(黄勇) dirtylimit_state_unlock(); 356baa60983SHyman Huang(黄勇) return; 357baa60983SHyman Huang(黄勇) } 358baa60983SHyman Huang(黄勇) 359baa60983SHyman Huang(黄勇) CPU_FOREACH(cpu) { 360baa60983SHyman Huang(黄勇) if (!dirtylimit_vcpu_get_state(cpu->cpu_index)->enabled) { 361baa60983SHyman Huang(黄勇) continue; 362baa60983SHyman Huang(黄勇) } 363baa60983SHyman Huang(黄勇) dirtylimit_adjust_throttle(cpu); 364baa60983SHyman Huang(黄勇) } 365baa60983SHyman Huang(黄勇) dirtylimit_state_unlock(); 366baa60983SHyman Huang(黄勇) } 367baa60983SHyman Huang(黄勇) } 368baa60983SHyman Huang(黄勇) 369baa60983SHyman Huang(黄勇) void dirtylimit_change(bool start) 370baa60983SHyman Huang(黄勇) { 371baa60983SHyman Huang(黄勇) if (start) { 372baa60983SHyman Huang(黄勇) qatomic_set(&dirtylimit_quit, 0); 373baa60983SHyman Huang(黄勇) } else { 374baa60983SHyman Huang(黄勇) qatomic_set(&dirtylimit_quit, 1); 375baa60983SHyman Huang(黄勇) } 376baa60983SHyman Huang(黄勇) } 377baa60983SHyman Huang(黄勇) 378baa60983SHyman Huang(黄勇) void dirtylimit_set_vcpu(int cpu_index, 379baa60983SHyman Huang(黄勇) uint64_t quota, 380baa60983SHyman Huang(黄勇) bool enable) 381baa60983SHyman Huang(黄勇) { 382baa60983SHyman Huang(黄勇) trace_dirtylimit_set_vcpu(cpu_index, quota); 383baa60983SHyman Huang(黄勇) 384baa60983SHyman Huang(黄勇) if (enable) { 385baa60983SHyman Huang(黄勇) dirtylimit_state->states[cpu_index].quota = quota; 386baa60983SHyman Huang(黄勇) if (!dirtylimit_vcpu_get_state(cpu_index)->enabled) { 387baa60983SHyman Huang(黄勇) dirtylimit_state->limited_nvcpu++; 388baa60983SHyman Huang(黄勇) } 389baa60983SHyman Huang(黄勇) } else { 390baa60983SHyman Huang(黄勇) dirtylimit_state->states[cpu_index].quota = 0; 391baa60983SHyman Huang(黄勇) if (dirtylimit_state->states[cpu_index].enabled) { 392baa60983SHyman Huang(黄勇) dirtylimit_state->limited_nvcpu--; 393baa60983SHyman Huang(黄勇) } 394baa60983SHyman Huang(黄勇) } 395baa60983SHyman Huang(黄勇) 396baa60983SHyman Huang(黄勇) dirtylimit_state->states[cpu_index].enabled = enable; 397baa60983SHyman Huang(黄勇) } 398baa60983SHyman Huang(黄勇) 399baa60983SHyman Huang(黄勇) void dirtylimit_set_all(uint64_t quota, 400baa60983SHyman Huang(黄勇) bool enable) 401baa60983SHyman Huang(黄勇) { 402baa60983SHyman Huang(黄勇) MachineState *ms = MACHINE(qdev_get_machine()); 403baa60983SHyman Huang(黄勇) int max_cpus = ms->smp.max_cpus; 404baa60983SHyman Huang(黄勇) int i; 405baa60983SHyman Huang(黄勇) 406baa60983SHyman Huang(黄勇) for (i = 0; i < max_cpus; i++) { 407baa60983SHyman Huang(黄勇) dirtylimit_set_vcpu(i, quota, enable); 408baa60983SHyman Huang(黄勇) } 409baa60983SHyman Huang(黄勇) } 410baa60983SHyman Huang(黄勇) 411baa60983SHyman Huang(黄勇) void dirtylimit_vcpu_execute(CPUState *cpu) 412baa60983SHyman Huang(黄勇) { 413cce10a1fSHyman Huang if (cpu->throttle_us_per_full) { 414cce10a1fSHyman Huang dirtylimit_state_lock(); 415cce10a1fSHyman Huang 416baa60983SHyman Huang(黄勇) if (dirtylimit_in_service() && 417cce10a1fSHyman Huang dirtylimit_vcpu_get_state(cpu->cpu_index)->enabled) { 418cce10a1fSHyman Huang dirtylimit_state_unlock(); 419baa60983SHyman Huang(黄勇) trace_dirtylimit_vcpu_execute(cpu->cpu_index, 420baa60983SHyman Huang(黄勇) cpu->throttle_us_per_full); 421cce10a1fSHyman Huang 422cce10a1fSHyman Huang g_usleep(cpu->throttle_us_per_full); 423cce10a1fSHyman Huang return; 424cce10a1fSHyman Huang } 425cce10a1fSHyman Huang 426cce10a1fSHyman Huang dirtylimit_state_unlock(); 427baa60983SHyman Huang(黄勇) } 428baa60983SHyman Huang(黄勇) } 429f3b2e38cSHyman Huang(黄勇) 430f3b2e38cSHyman Huang(黄勇) static void dirtylimit_init(void) 431f3b2e38cSHyman Huang(黄勇) { 432f3b2e38cSHyman Huang(黄勇) dirtylimit_state_initialize(); 433f3b2e38cSHyman Huang(黄勇) dirtylimit_change(true); 434f3b2e38cSHyman Huang(黄勇) vcpu_dirty_rate_stat_initialize(); 435f3b2e38cSHyman Huang(黄勇) vcpu_dirty_rate_stat_start(); 436f3b2e38cSHyman Huang(黄勇) } 437f3b2e38cSHyman Huang(黄勇) 438f3b2e38cSHyman Huang(黄勇) static void dirtylimit_cleanup(void) 439f3b2e38cSHyman Huang(黄勇) { 440f3b2e38cSHyman Huang(黄勇) vcpu_dirty_rate_stat_stop(); 441f3b2e38cSHyman Huang(黄勇) vcpu_dirty_rate_stat_finalize(); 442f3b2e38cSHyman Huang(黄勇) dirtylimit_change(false); 443f3b2e38cSHyman Huang(黄勇) dirtylimit_state_finalize(); 444f3b2e38cSHyman Huang(黄勇) } 445f3b2e38cSHyman Huang(黄勇) 446acac51baSHyman Huang(黄勇) /* 447acac51baSHyman Huang(黄勇) * dirty page rate limit is not allowed to set if migration 448acac51baSHyman Huang(黄勇) * is running with dirty-limit capability enabled. 449acac51baSHyman Huang(黄勇) */ 450acac51baSHyman Huang(黄勇) static bool dirtylimit_is_allowed(void) 451acac51baSHyman Huang(黄勇) { 452acac51baSHyman Huang(黄勇) MigrationState *ms = migrate_get_current(); 453acac51baSHyman Huang(黄勇) 454*aeaafb1eSSteve Sistare if (migration_is_running() && 455acac51baSHyman Huang(黄勇) (!qemu_thread_is_self(&ms->thread)) && 456acac51baSHyman Huang(黄勇) migrate_dirty_limit() && 457acac51baSHyman Huang(黄勇) dirtylimit_in_service()) { 458acac51baSHyman Huang(黄勇) return false; 459acac51baSHyman Huang(黄勇) } 460acac51baSHyman Huang(黄勇) return true; 461acac51baSHyman Huang(黄勇) } 462acac51baSHyman Huang(黄勇) 463f3b2e38cSHyman Huang(黄勇) void qmp_cancel_vcpu_dirty_limit(bool has_cpu_index, 464f3b2e38cSHyman Huang(黄勇) int64_t cpu_index, 465f3b2e38cSHyman Huang(黄勇) Error **errp) 466f3b2e38cSHyman Huang(黄勇) { 467f3b2e38cSHyman Huang(黄勇) if (!kvm_enabled() || !kvm_dirty_ring_enabled()) { 468f3b2e38cSHyman Huang(黄勇) return; 469f3b2e38cSHyman Huang(黄勇) } 470f3b2e38cSHyman Huang(黄勇) 471f3b2e38cSHyman Huang(黄勇) if (has_cpu_index && !dirtylimit_vcpu_index_valid(cpu_index)) { 472f3b2e38cSHyman Huang(黄勇) error_setg(errp, "incorrect cpu index specified"); 473f3b2e38cSHyman Huang(黄勇) return; 474f3b2e38cSHyman Huang(黄勇) } 475f3b2e38cSHyman Huang(黄勇) 476acac51baSHyman Huang(黄勇) if (!dirtylimit_is_allowed()) { 477acac51baSHyman Huang(黄勇) error_setg(errp, "can't cancel dirty page rate limit while" 478acac51baSHyman Huang(黄勇) " migration is running"); 479acac51baSHyman Huang(黄勇) return; 480acac51baSHyman Huang(黄勇) } 481acac51baSHyman Huang(黄勇) 482f3b2e38cSHyman Huang(黄勇) if (!dirtylimit_in_service()) { 483f3b2e38cSHyman Huang(黄勇) return; 484f3b2e38cSHyman Huang(黄勇) } 485f3b2e38cSHyman Huang(黄勇) 486f3b2e38cSHyman Huang(黄勇) dirtylimit_state_lock(); 487f3b2e38cSHyman Huang(黄勇) 488f3b2e38cSHyman Huang(黄勇) if (has_cpu_index) { 489f3b2e38cSHyman Huang(黄勇) dirtylimit_set_vcpu(cpu_index, 0, false); 490f3b2e38cSHyman Huang(黄勇) } else { 491f3b2e38cSHyman Huang(黄勇) dirtylimit_set_all(0, false); 492f3b2e38cSHyman Huang(黄勇) } 493f3b2e38cSHyman Huang(黄勇) 494f3b2e38cSHyman Huang(黄勇) if (!dirtylimit_state->limited_nvcpu) { 495f3b2e38cSHyman Huang(黄勇) dirtylimit_cleanup(); 496f3b2e38cSHyman Huang(黄勇) } 497f3b2e38cSHyman Huang(黄勇) 498f3b2e38cSHyman Huang(黄勇) dirtylimit_state_unlock(); 499f3b2e38cSHyman Huang(黄勇) } 500f3b2e38cSHyman Huang(黄勇) 501f3b2e38cSHyman Huang(黄勇) void hmp_cancel_vcpu_dirty_limit(Monitor *mon, const QDict *qdict) 502f3b2e38cSHyman Huang(黄勇) { 503f3b2e38cSHyman Huang(黄勇) int64_t cpu_index = qdict_get_try_int(qdict, "cpu_index", -1); 504f3b2e38cSHyman Huang(黄勇) Error *err = NULL; 505f3b2e38cSHyman Huang(黄勇) 506f3b2e38cSHyman Huang(黄勇) qmp_cancel_vcpu_dirty_limit(!!(cpu_index != -1), cpu_index, &err); 507f3b2e38cSHyman Huang(黄勇) if (err) { 508f3b2e38cSHyman Huang(黄勇) hmp_handle_error(mon, err); 509f3b2e38cSHyman Huang(黄勇) return; 510f3b2e38cSHyman Huang(黄勇) } 511f3b2e38cSHyman Huang(黄勇) 512f3b2e38cSHyman Huang(黄勇) monitor_printf(mon, "[Please use 'info vcpu_dirty_limit' to query " 513f3b2e38cSHyman Huang(黄勇) "dirty limit for virtual CPU]\n"); 514f3b2e38cSHyman Huang(黄勇) } 515f3b2e38cSHyman Huang(黄勇) 516f3b2e38cSHyman Huang(黄勇) void qmp_set_vcpu_dirty_limit(bool has_cpu_index, 517f3b2e38cSHyman Huang(黄勇) int64_t cpu_index, 518f3b2e38cSHyman Huang(黄勇) uint64_t dirty_rate, 519f3b2e38cSHyman Huang(黄勇) Error **errp) 520f3b2e38cSHyman Huang(黄勇) { 521f3b2e38cSHyman Huang(黄勇) if (!kvm_enabled() || !kvm_dirty_ring_enabled()) { 522f3b2e38cSHyman Huang(黄勇) error_setg(errp, "dirty page limit feature requires KVM with" 523f3b2e38cSHyman Huang(黄勇) " accelerator property 'dirty-ring-size' set'"); 524f3b2e38cSHyman Huang(黄勇) return; 525f3b2e38cSHyman Huang(黄勇) } 526f3b2e38cSHyman Huang(黄勇) 527f3b2e38cSHyman Huang(黄勇) if (has_cpu_index && !dirtylimit_vcpu_index_valid(cpu_index)) { 528f3b2e38cSHyman Huang(黄勇) error_setg(errp, "incorrect cpu index specified"); 529f3b2e38cSHyman Huang(黄勇) return; 530f3b2e38cSHyman Huang(黄勇) } 531f3b2e38cSHyman Huang(黄勇) 532acac51baSHyman Huang(黄勇) if (!dirtylimit_is_allowed()) { 533acac51baSHyman Huang(黄勇) error_setg(errp, "can't set dirty page rate limit while" 534acac51baSHyman Huang(黄勇) " migration is running"); 535acac51baSHyman Huang(黄勇) return; 536acac51baSHyman Huang(黄勇) } 537acac51baSHyman Huang(黄勇) 538f3b2e38cSHyman Huang(黄勇) if (!dirty_rate) { 539f3b2e38cSHyman Huang(黄勇) qmp_cancel_vcpu_dirty_limit(has_cpu_index, cpu_index, errp); 540f3b2e38cSHyman Huang(黄勇) return; 541f3b2e38cSHyman Huang(黄勇) } 542f3b2e38cSHyman Huang(黄勇) 543f3b2e38cSHyman Huang(黄勇) dirtylimit_state_lock(); 544f3b2e38cSHyman Huang(黄勇) 545f3b2e38cSHyman Huang(黄勇) if (!dirtylimit_in_service()) { 546f3b2e38cSHyman Huang(黄勇) dirtylimit_init(); 547f3b2e38cSHyman Huang(黄勇) } 548f3b2e38cSHyman Huang(黄勇) 549f3b2e38cSHyman Huang(黄勇) if (has_cpu_index) { 550f3b2e38cSHyman Huang(黄勇) dirtylimit_set_vcpu(cpu_index, dirty_rate, true); 551f3b2e38cSHyman Huang(黄勇) } else { 552f3b2e38cSHyman Huang(黄勇) dirtylimit_set_all(dirty_rate, true); 553f3b2e38cSHyman Huang(黄勇) } 554f3b2e38cSHyman Huang(黄勇) 555f3b2e38cSHyman Huang(黄勇) dirtylimit_state_unlock(); 556f3b2e38cSHyman Huang(黄勇) } 557f3b2e38cSHyman Huang(黄勇) 558f3b2e38cSHyman Huang(黄勇) void hmp_set_vcpu_dirty_limit(Monitor *mon, const QDict *qdict) 559f3b2e38cSHyman Huang(黄勇) { 560f3b2e38cSHyman Huang(黄勇) int64_t dirty_rate = qdict_get_int(qdict, "dirty_rate"); 561f3b2e38cSHyman Huang(黄勇) int64_t cpu_index = qdict_get_try_int(qdict, "cpu_index", -1); 562f3b2e38cSHyman Huang(黄勇) Error *err = NULL; 563f3b2e38cSHyman Huang(黄勇) 564140e5a76SHyman Huang(黄勇) if (dirty_rate < 0) { 565140e5a76SHyman Huang(黄勇) error_setg(&err, "invalid dirty page limit %" PRId64, dirty_rate); 566140e5a76SHyman Huang(黄勇) goto out; 567f3b2e38cSHyman Huang(黄勇) } 568f3b2e38cSHyman Huang(黄勇) 569140e5a76SHyman Huang(黄勇) qmp_set_vcpu_dirty_limit(!!(cpu_index != -1), cpu_index, dirty_rate, &err); 570140e5a76SHyman Huang(黄勇) 571140e5a76SHyman Huang(黄勇) out: 572140e5a76SHyman Huang(黄勇) hmp_handle_error(mon, err); 573f3b2e38cSHyman Huang(黄勇) } 574f3b2e38cSHyman Huang(黄勇) 57515699cf5SHyman Huang(黄勇) /* Return the max throttle time of each virtual CPU */ 57615699cf5SHyman Huang(黄勇) uint64_t dirtylimit_throttle_time_per_round(void) 57715699cf5SHyman Huang(黄勇) { 57815699cf5SHyman Huang(黄勇) CPUState *cpu; 57915699cf5SHyman Huang(黄勇) int64_t max = 0; 58015699cf5SHyman Huang(黄勇) 58115699cf5SHyman Huang(黄勇) CPU_FOREACH(cpu) { 58215699cf5SHyman Huang(黄勇) if (cpu->throttle_us_per_full > max) { 58315699cf5SHyman Huang(黄勇) max = cpu->throttle_us_per_full; 58415699cf5SHyman Huang(黄勇) } 58515699cf5SHyman Huang(黄勇) } 58615699cf5SHyman Huang(黄勇) 58715699cf5SHyman Huang(黄勇) return max; 58815699cf5SHyman Huang(黄勇) } 58915699cf5SHyman Huang(黄勇) 59015699cf5SHyman Huang(黄勇) /* 59115699cf5SHyman Huang(黄勇) * Estimate average dirty ring full time of each virtaul CPU. 59215699cf5SHyman Huang(黄勇) * Return 0 if guest doesn't dirty memory. 59315699cf5SHyman Huang(黄勇) */ 59415699cf5SHyman Huang(黄勇) uint64_t dirtylimit_ring_full_time(void) 59515699cf5SHyman Huang(黄勇) { 59615699cf5SHyman Huang(黄勇) CPUState *cpu; 59715699cf5SHyman Huang(黄勇) uint64_t curr_rate = 0; 59815699cf5SHyman Huang(黄勇) int nvcpus = 0; 59915699cf5SHyman Huang(黄勇) 60015699cf5SHyman Huang(黄勇) CPU_FOREACH(cpu) { 60115699cf5SHyman Huang(黄勇) if (cpu->running) { 60215699cf5SHyman Huang(黄勇) nvcpus++; 60315699cf5SHyman Huang(黄勇) curr_rate += vcpu_dirty_rate_get(cpu->cpu_index); 60415699cf5SHyman Huang(黄勇) } 60515699cf5SHyman Huang(黄勇) } 60615699cf5SHyman Huang(黄勇) 60715699cf5SHyman Huang(黄勇) if (!curr_rate || !nvcpus) { 60815699cf5SHyman Huang(黄勇) return 0; 60915699cf5SHyman Huang(黄勇) } 61015699cf5SHyman Huang(黄勇) 61115699cf5SHyman Huang(黄勇) return dirtylimit_dirty_ring_full_time(curr_rate / nvcpus); 61215699cf5SHyman Huang(黄勇) } 61315699cf5SHyman Huang(黄勇) 614f3b2e38cSHyman Huang(黄勇) static struct DirtyLimitInfo *dirtylimit_query_vcpu(int cpu_index) 615f3b2e38cSHyman Huang(黄勇) { 616f3b2e38cSHyman Huang(黄勇) DirtyLimitInfo *info = NULL; 617f3b2e38cSHyman Huang(黄勇) 618f3b2e38cSHyman Huang(黄勇) info = g_malloc0(sizeof(*info)); 619f3b2e38cSHyman Huang(黄勇) info->cpu_index = cpu_index; 620f3b2e38cSHyman Huang(黄勇) info->limit_rate = dirtylimit_vcpu_get_state(cpu_index)->quota; 621f3b2e38cSHyman Huang(黄勇) info->current_rate = vcpu_dirty_rate_get(cpu_index); 622f3b2e38cSHyman Huang(黄勇) 623f3b2e38cSHyman Huang(黄勇) return info; 624f3b2e38cSHyman Huang(黄勇) } 625f3b2e38cSHyman Huang(黄勇) 626f3b2e38cSHyman Huang(黄勇) static struct DirtyLimitInfoList *dirtylimit_query_all(void) 627f3b2e38cSHyman Huang(黄勇) { 628f3b2e38cSHyman Huang(黄勇) int i, index; 629f3b2e38cSHyman Huang(黄勇) DirtyLimitInfo *info = NULL; 630f3b2e38cSHyman Huang(黄勇) DirtyLimitInfoList *head = NULL, **tail = &head; 631f3b2e38cSHyman Huang(黄勇) 632f3b2e38cSHyman Huang(黄勇) dirtylimit_state_lock(); 633f3b2e38cSHyman Huang(黄勇) 634f3b2e38cSHyman Huang(黄勇) if (!dirtylimit_in_service()) { 635f3b2e38cSHyman Huang(黄勇) dirtylimit_state_unlock(); 636f3b2e38cSHyman Huang(黄勇) return NULL; 637f3b2e38cSHyman Huang(黄勇) } 638f3b2e38cSHyman Huang(黄勇) 639f3b2e38cSHyman Huang(黄勇) for (i = 0; i < dirtylimit_state->max_cpus; i++) { 640f3b2e38cSHyman Huang(黄勇) index = dirtylimit_state->states[i].cpu_index; 641f3b2e38cSHyman Huang(黄勇) if (dirtylimit_vcpu_get_state(index)->enabled) { 642f3b2e38cSHyman Huang(黄勇) info = dirtylimit_query_vcpu(index); 643f3b2e38cSHyman Huang(黄勇) QAPI_LIST_APPEND(tail, info); 644f3b2e38cSHyman Huang(黄勇) } 645f3b2e38cSHyman Huang(黄勇) } 646f3b2e38cSHyman Huang(黄勇) 647f3b2e38cSHyman Huang(黄勇) dirtylimit_state_unlock(); 648f3b2e38cSHyman Huang(黄勇) 649f3b2e38cSHyman Huang(黄勇) return head; 650f3b2e38cSHyman Huang(黄勇) } 651f3b2e38cSHyman Huang(黄勇) 652f3b2e38cSHyman Huang(黄勇) struct DirtyLimitInfoList *qmp_query_vcpu_dirty_limit(Error **errp) 653f3b2e38cSHyman Huang(黄勇) { 654f3b2e38cSHyman Huang(黄勇) return dirtylimit_query_all(); 655f3b2e38cSHyman Huang(黄勇) } 656f3b2e38cSHyman Huang(黄勇) 657f3b2e38cSHyman Huang(黄勇) void hmp_info_vcpu_dirty_limit(Monitor *mon, const QDict *qdict) 658f3b2e38cSHyman Huang(黄勇) { 65958b4def2Salloc.young DirtyLimitInfoList *info; 66058b4def2Salloc.young g_autoptr(DirtyLimitInfoList) head = NULL; 661f3b2e38cSHyman Huang(黄勇) Error *err = NULL; 662f3b2e38cSHyman Huang(黄勇) 663f3b2e38cSHyman Huang(黄勇) if (!dirtylimit_in_service()) { 664f3b2e38cSHyman Huang(黄勇) monitor_printf(mon, "Dirty page limit not enabled!\n"); 665f3b2e38cSHyman Huang(黄勇) return; 666f3b2e38cSHyman Huang(黄勇) } 667f3b2e38cSHyman Huang(黄勇) 66858b4def2Salloc.young head = qmp_query_vcpu_dirty_limit(&err); 669f3b2e38cSHyman Huang(黄勇) if (err) { 670f3b2e38cSHyman Huang(黄勇) hmp_handle_error(mon, err); 671f3b2e38cSHyman Huang(黄勇) return; 672f3b2e38cSHyman Huang(黄勇) } 673f3b2e38cSHyman Huang(黄勇) 67458b4def2Salloc.young for (info = head; info != NULL; info = info->next) { 675f3b2e38cSHyman Huang(黄勇) monitor_printf(mon, "vcpu[%"PRIi64"], limit rate %"PRIi64 " (MB/s)," 676f3b2e38cSHyman Huang(黄勇) " current rate %"PRIi64 " (MB/s)\n", 67758b4def2Salloc.young info->value->cpu_index, 67858b4def2Salloc.young info->value->limit_rate, 67958b4def2Salloc.young info->value->current_rate); 680f3b2e38cSHyman Huang(黄勇) } 681f3b2e38cSHyman Huang(黄勇) } 682