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