18d7f2e76SPhilippe Mathieu-Daudé /* 28d7f2e76SPhilippe Mathieu-Daudé * Dirty page rate limit implementation code 38d7f2e76SPhilippe Mathieu-Daudé * 48d7f2e76SPhilippe Mathieu-Daudé * Copyright (c) 2022 CHINA TELECOM CO.,LTD. 58d7f2e76SPhilippe Mathieu-Daudé * 68d7f2e76SPhilippe Mathieu-Daudé * Authors: 78d7f2e76SPhilippe Mathieu-Daudé * Hyman Huang(黄勇) <huangy81@chinatelecom.cn> 88d7f2e76SPhilippe Mathieu-Daudé * 98d7f2e76SPhilippe Mathieu-Daudé * This work is licensed under the terms of the GNU GPL, version 2 or later. 108d7f2e76SPhilippe Mathieu-Daudé * See the COPYING file in the top-level directory. 118d7f2e76SPhilippe Mathieu-Daudé */ 128d7f2e76SPhilippe Mathieu-Daudé 138d7f2e76SPhilippe Mathieu-Daudé #include "qemu/osdep.h" 148d7f2e76SPhilippe Mathieu-Daudé #include "qemu/main-loop.h" 158d7f2e76SPhilippe Mathieu-Daudé #include "qapi/qapi-commands-migration.h" 168d7f2e76SPhilippe Mathieu-Daudé #include "qapi/qmp/qdict.h" 178d7f2e76SPhilippe Mathieu-Daudé #include "qapi/error.h" 188d7f2e76SPhilippe Mathieu-Daudé #include "sysemu/dirtyrate.h" 198d7f2e76SPhilippe Mathieu-Daudé #include "sysemu/dirtylimit.h" 208d7f2e76SPhilippe Mathieu-Daudé #include "monitor/hmp.h" 218d7f2e76SPhilippe Mathieu-Daudé #include "monitor/monitor.h" 228d7f2e76SPhilippe Mathieu-Daudé #include "exec/memory.h" 238d7f2e76SPhilippe Mathieu-Daudé #include "exec/target_page.h" 248d7f2e76SPhilippe Mathieu-Daudé #include "hw/boards.h" 258d7f2e76SPhilippe Mathieu-Daudé #include "sysemu/kvm.h" 268d7f2e76SPhilippe Mathieu-Daudé #include "trace.h" 278d7f2e76SPhilippe Mathieu-Daudé #include "migration/misc.h" 288d7f2e76SPhilippe Mathieu-Daudé #include "migration/migration.h" 298d7f2e76SPhilippe Mathieu-Daudé #include "migration/options.h" 308d7f2e76SPhilippe Mathieu-Daudé 318d7f2e76SPhilippe Mathieu-Daudé /* 328d7f2e76SPhilippe Mathieu-Daudé * Dirtylimit stop working if dirty page rate error 338d7f2e76SPhilippe Mathieu-Daudé * value less than DIRTYLIMIT_TOLERANCE_RANGE 348d7f2e76SPhilippe Mathieu-Daudé */ 358d7f2e76SPhilippe Mathieu-Daudé #define DIRTYLIMIT_TOLERANCE_RANGE 25 /* MB/s */ 368d7f2e76SPhilippe Mathieu-Daudé /* 378d7f2e76SPhilippe Mathieu-Daudé * Plus or minus vcpu sleep time linearly if dirty 388d7f2e76SPhilippe Mathieu-Daudé * page rate error value percentage over 398d7f2e76SPhilippe Mathieu-Daudé * DIRTYLIMIT_LINEAR_ADJUSTMENT_PCT. 408d7f2e76SPhilippe Mathieu-Daudé * Otherwise, plus or minus a fixed vcpu sleep time. 418d7f2e76SPhilippe Mathieu-Daudé */ 428d7f2e76SPhilippe Mathieu-Daudé #define DIRTYLIMIT_LINEAR_ADJUSTMENT_PCT 50 438d7f2e76SPhilippe Mathieu-Daudé /* 448d7f2e76SPhilippe Mathieu-Daudé * Max vcpu sleep time percentage during a cycle 458d7f2e76SPhilippe Mathieu-Daudé * composed of dirty ring full and sleep time. 468d7f2e76SPhilippe Mathieu-Daudé */ 478d7f2e76SPhilippe Mathieu-Daudé #define DIRTYLIMIT_THROTTLE_PCT_MAX 99 488d7f2e76SPhilippe Mathieu-Daudé 498d7f2e76SPhilippe Mathieu-Daudé struct { 508d7f2e76SPhilippe Mathieu-Daudé VcpuStat stat; 518d7f2e76SPhilippe Mathieu-Daudé bool running; 528d7f2e76SPhilippe Mathieu-Daudé QemuThread thread; 538d7f2e76SPhilippe Mathieu-Daudé } *vcpu_dirty_rate_stat; 548d7f2e76SPhilippe Mathieu-Daudé 558d7f2e76SPhilippe Mathieu-Daudé typedef struct VcpuDirtyLimitState { 568d7f2e76SPhilippe Mathieu-Daudé int cpu_index; 578d7f2e76SPhilippe Mathieu-Daudé bool enabled; 588d7f2e76SPhilippe Mathieu-Daudé /* 598d7f2e76SPhilippe Mathieu-Daudé * Quota dirty page rate, unit is MB/s 608d7f2e76SPhilippe Mathieu-Daudé * zero if not enabled. 618d7f2e76SPhilippe Mathieu-Daudé */ 628d7f2e76SPhilippe Mathieu-Daudé uint64_t quota; 638d7f2e76SPhilippe Mathieu-Daudé } VcpuDirtyLimitState; 648d7f2e76SPhilippe Mathieu-Daudé 658d7f2e76SPhilippe Mathieu-Daudé struct { 668d7f2e76SPhilippe Mathieu-Daudé VcpuDirtyLimitState *states; 678d7f2e76SPhilippe Mathieu-Daudé /* Max cpus number configured by user */ 688d7f2e76SPhilippe Mathieu-Daudé int max_cpus; 698d7f2e76SPhilippe Mathieu-Daudé /* Number of vcpu under dirtylimit */ 708d7f2e76SPhilippe Mathieu-Daudé int limited_nvcpu; 718d7f2e76SPhilippe Mathieu-Daudé } *dirtylimit_state; 728d7f2e76SPhilippe Mathieu-Daudé 738d7f2e76SPhilippe Mathieu-Daudé /* protect dirtylimit_state */ 748d7f2e76SPhilippe Mathieu-Daudé static QemuMutex dirtylimit_mutex; 758d7f2e76SPhilippe Mathieu-Daudé 768d7f2e76SPhilippe Mathieu-Daudé /* dirtylimit thread quit if dirtylimit_quit is true */ 778d7f2e76SPhilippe Mathieu-Daudé static bool dirtylimit_quit; 788d7f2e76SPhilippe Mathieu-Daudé 798d7f2e76SPhilippe Mathieu-Daudé static void vcpu_dirty_rate_stat_collect(void) 808d7f2e76SPhilippe Mathieu-Daudé { 818d7f2e76SPhilippe Mathieu-Daudé MigrationState *s = migrate_get_current(); 828d7f2e76SPhilippe Mathieu-Daudé VcpuStat stat; 838d7f2e76SPhilippe Mathieu-Daudé int i = 0; 848d7f2e76SPhilippe Mathieu-Daudé int64_t period = DIRTYLIMIT_CALC_TIME_MS; 858d7f2e76SPhilippe Mathieu-Daudé 868d7f2e76SPhilippe Mathieu-Daudé if (migrate_dirty_limit() && 878d7f2e76SPhilippe Mathieu-Daudé migration_is_active(s)) { 888d7f2e76SPhilippe Mathieu-Daudé period = s->parameters.x_vcpu_dirty_limit_period; 898d7f2e76SPhilippe Mathieu-Daudé } 908d7f2e76SPhilippe Mathieu-Daudé 918d7f2e76SPhilippe Mathieu-Daudé /* calculate vcpu dirtyrate */ 928d7f2e76SPhilippe Mathieu-Daudé vcpu_calculate_dirtyrate(period, 938d7f2e76SPhilippe Mathieu-Daudé &stat, 948d7f2e76SPhilippe Mathieu-Daudé GLOBAL_DIRTY_LIMIT, 958d7f2e76SPhilippe Mathieu-Daudé false); 968d7f2e76SPhilippe Mathieu-Daudé 978d7f2e76SPhilippe Mathieu-Daudé for (i = 0; i < stat.nvcpu; i++) { 988d7f2e76SPhilippe Mathieu-Daudé vcpu_dirty_rate_stat->stat.rates[i].id = i; 998d7f2e76SPhilippe Mathieu-Daudé vcpu_dirty_rate_stat->stat.rates[i].dirty_rate = 1008d7f2e76SPhilippe Mathieu-Daudé stat.rates[i].dirty_rate; 1018d7f2e76SPhilippe Mathieu-Daudé } 1028d7f2e76SPhilippe Mathieu-Daudé 1038d7f2e76SPhilippe Mathieu-Daudé g_free(stat.rates); 1048d7f2e76SPhilippe Mathieu-Daudé } 1058d7f2e76SPhilippe Mathieu-Daudé 1068d7f2e76SPhilippe Mathieu-Daudé static void *vcpu_dirty_rate_stat_thread(void *opaque) 1078d7f2e76SPhilippe Mathieu-Daudé { 1088d7f2e76SPhilippe Mathieu-Daudé rcu_register_thread(); 1098d7f2e76SPhilippe Mathieu-Daudé 1108d7f2e76SPhilippe Mathieu-Daudé /* start log sync */ 1118d7f2e76SPhilippe Mathieu-Daudé global_dirty_log_change(GLOBAL_DIRTY_LIMIT, true); 1128d7f2e76SPhilippe Mathieu-Daudé 1138d7f2e76SPhilippe Mathieu-Daudé while (qatomic_read(&vcpu_dirty_rate_stat->running)) { 1148d7f2e76SPhilippe Mathieu-Daudé vcpu_dirty_rate_stat_collect(); 1158d7f2e76SPhilippe Mathieu-Daudé if (dirtylimit_in_service()) { 1168d7f2e76SPhilippe Mathieu-Daudé dirtylimit_process(); 1178d7f2e76SPhilippe Mathieu-Daudé } 1188d7f2e76SPhilippe Mathieu-Daudé } 1198d7f2e76SPhilippe Mathieu-Daudé 1208d7f2e76SPhilippe Mathieu-Daudé /* stop log sync */ 1218d7f2e76SPhilippe Mathieu-Daudé global_dirty_log_change(GLOBAL_DIRTY_LIMIT, false); 1228d7f2e76SPhilippe Mathieu-Daudé 1238d7f2e76SPhilippe Mathieu-Daudé rcu_unregister_thread(); 1248d7f2e76SPhilippe Mathieu-Daudé return NULL; 1258d7f2e76SPhilippe Mathieu-Daudé } 1268d7f2e76SPhilippe Mathieu-Daudé 1278d7f2e76SPhilippe Mathieu-Daudé int64_t vcpu_dirty_rate_get(int cpu_index) 1288d7f2e76SPhilippe Mathieu-Daudé { 1298d7f2e76SPhilippe Mathieu-Daudé DirtyRateVcpu *rates = vcpu_dirty_rate_stat->stat.rates; 1308d7f2e76SPhilippe Mathieu-Daudé return qatomic_read_i64(&rates[cpu_index].dirty_rate); 1318d7f2e76SPhilippe Mathieu-Daudé } 1328d7f2e76SPhilippe Mathieu-Daudé 1338d7f2e76SPhilippe Mathieu-Daudé void vcpu_dirty_rate_stat_start(void) 1348d7f2e76SPhilippe Mathieu-Daudé { 1358d7f2e76SPhilippe Mathieu-Daudé if (qatomic_read(&vcpu_dirty_rate_stat->running)) { 1368d7f2e76SPhilippe Mathieu-Daudé return; 1378d7f2e76SPhilippe Mathieu-Daudé } 1388d7f2e76SPhilippe Mathieu-Daudé 1398d7f2e76SPhilippe Mathieu-Daudé qatomic_set(&vcpu_dirty_rate_stat->running, 1); 1408d7f2e76SPhilippe Mathieu-Daudé qemu_thread_create(&vcpu_dirty_rate_stat->thread, 1418d7f2e76SPhilippe Mathieu-Daudé "dirtyrate-stat", 1428d7f2e76SPhilippe Mathieu-Daudé vcpu_dirty_rate_stat_thread, 1438d7f2e76SPhilippe Mathieu-Daudé NULL, 1448d7f2e76SPhilippe Mathieu-Daudé QEMU_THREAD_JOINABLE); 1458d7f2e76SPhilippe Mathieu-Daudé } 1468d7f2e76SPhilippe Mathieu-Daudé 1478d7f2e76SPhilippe Mathieu-Daudé void vcpu_dirty_rate_stat_stop(void) 1488d7f2e76SPhilippe Mathieu-Daudé { 1498d7f2e76SPhilippe Mathieu-Daudé qatomic_set(&vcpu_dirty_rate_stat->running, 0); 1508d7f2e76SPhilippe Mathieu-Daudé dirtylimit_state_unlock(); 151*195801d7SStefan Hajnoczi bql_unlock(); 1528d7f2e76SPhilippe Mathieu-Daudé qemu_thread_join(&vcpu_dirty_rate_stat->thread); 153*195801d7SStefan Hajnoczi bql_lock(); 1548d7f2e76SPhilippe Mathieu-Daudé dirtylimit_state_lock(); 1558d7f2e76SPhilippe Mathieu-Daudé } 1568d7f2e76SPhilippe Mathieu-Daudé 1578d7f2e76SPhilippe Mathieu-Daudé void vcpu_dirty_rate_stat_initialize(void) 1588d7f2e76SPhilippe Mathieu-Daudé { 1598d7f2e76SPhilippe Mathieu-Daudé MachineState *ms = MACHINE(qdev_get_machine()); 1608d7f2e76SPhilippe Mathieu-Daudé int max_cpus = ms->smp.max_cpus; 1618d7f2e76SPhilippe Mathieu-Daudé 1628d7f2e76SPhilippe Mathieu-Daudé vcpu_dirty_rate_stat = 1638d7f2e76SPhilippe Mathieu-Daudé g_malloc0(sizeof(*vcpu_dirty_rate_stat)); 1648d7f2e76SPhilippe Mathieu-Daudé 1658d7f2e76SPhilippe Mathieu-Daudé vcpu_dirty_rate_stat->stat.nvcpu = max_cpus; 1668d7f2e76SPhilippe Mathieu-Daudé vcpu_dirty_rate_stat->stat.rates = 1678d7f2e76SPhilippe Mathieu-Daudé g_new0(DirtyRateVcpu, max_cpus); 1688d7f2e76SPhilippe Mathieu-Daudé 1698d7f2e76SPhilippe Mathieu-Daudé vcpu_dirty_rate_stat->running = false; 1708d7f2e76SPhilippe Mathieu-Daudé } 1718d7f2e76SPhilippe Mathieu-Daudé 1728d7f2e76SPhilippe Mathieu-Daudé void vcpu_dirty_rate_stat_finalize(void) 1738d7f2e76SPhilippe Mathieu-Daudé { 1748d7f2e76SPhilippe Mathieu-Daudé g_free(vcpu_dirty_rate_stat->stat.rates); 1758d7f2e76SPhilippe Mathieu-Daudé vcpu_dirty_rate_stat->stat.rates = NULL; 1768d7f2e76SPhilippe Mathieu-Daudé 1778d7f2e76SPhilippe Mathieu-Daudé g_free(vcpu_dirty_rate_stat); 1788d7f2e76SPhilippe Mathieu-Daudé vcpu_dirty_rate_stat = NULL; 1798d7f2e76SPhilippe Mathieu-Daudé } 1808d7f2e76SPhilippe Mathieu-Daudé 1818d7f2e76SPhilippe Mathieu-Daudé void dirtylimit_state_lock(void) 1828d7f2e76SPhilippe Mathieu-Daudé { 1838d7f2e76SPhilippe Mathieu-Daudé qemu_mutex_lock(&dirtylimit_mutex); 1848d7f2e76SPhilippe Mathieu-Daudé } 1858d7f2e76SPhilippe Mathieu-Daudé 1868d7f2e76SPhilippe Mathieu-Daudé void dirtylimit_state_unlock(void) 1878d7f2e76SPhilippe Mathieu-Daudé { 1888d7f2e76SPhilippe Mathieu-Daudé qemu_mutex_unlock(&dirtylimit_mutex); 1898d7f2e76SPhilippe Mathieu-Daudé } 1908d7f2e76SPhilippe Mathieu-Daudé 1918d7f2e76SPhilippe Mathieu-Daudé static void 1928d7f2e76SPhilippe Mathieu-Daudé __attribute__((__constructor__)) dirtylimit_mutex_init(void) 1938d7f2e76SPhilippe Mathieu-Daudé { 1948d7f2e76SPhilippe Mathieu-Daudé qemu_mutex_init(&dirtylimit_mutex); 1958d7f2e76SPhilippe Mathieu-Daudé } 1968d7f2e76SPhilippe Mathieu-Daudé 1978d7f2e76SPhilippe Mathieu-Daudé static inline VcpuDirtyLimitState *dirtylimit_vcpu_get_state(int cpu_index) 1988d7f2e76SPhilippe Mathieu-Daudé { 1998d7f2e76SPhilippe Mathieu-Daudé return &dirtylimit_state->states[cpu_index]; 2008d7f2e76SPhilippe Mathieu-Daudé } 2018d7f2e76SPhilippe Mathieu-Daudé 2028d7f2e76SPhilippe Mathieu-Daudé void dirtylimit_state_initialize(void) 2038d7f2e76SPhilippe Mathieu-Daudé { 2048d7f2e76SPhilippe Mathieu-Daudé MachineState *ms = MACHINE(qdev_get_machine()); 2058d7f2e76SPhilippe Mathieu-Daudé int max_cpus = ms->smp.max_cpus; 2068d7f2e76SPhilippe Mathieu-Daudé int i; 2078d7f2e76SPhilippe Mathieu-Daudé 2088d7f2e76SPhilippe Mathieu-Daudé dirtylimit_state = g_malloc0(sizeof(*dirtylimit_state)); 2098d7f2e76SPhilippe Mathieu-Daudé 2108d7f2e76SPhilippe Mathieu-Daudé dirtylimit_state->states = 2118d7f2e76SPhilippe Mathieu-Daudé g_new0(VcpuDirtyLimitState, max_cpus); 2128d7f2e76SPhilippe Mathieu-Daudé 2138d7f2e76SPhilippe Mathieu-Daudé for (i = 0; i < max_cpus; i++) { 2148d7f2e76SPhilippe Mathieu-Daudé dirtylimit_state->states[i].cpu_index = i; 2158d7f2e76SPhilippe Mathieu-Daudé } 2168d7f2e76SPhilippe Mathieu-Daudé 2178d7f2e76SPhilippe Mathieu-Daudé dirtylimit_state->max_cpus = max_cpus; 2188d7f2e76SPhilippe Mathieu-Daudé trace_dirtylimit_state_initialize(max_cpus); 2198d7f2e76SPhilippe Mathieu-Daudé } 2208d7f2e76SPhilippe Mathieu-Daudé 2218d7f2e76SPhilippe Mathieu-Daudé void dirtylimit_state_finalize(void) 2228d7f2e76SPhilippe Mathieu-Daudé { 2238d7f2e76SPhilippe Mathieu-Daudé g_free(dirtylimit_state->states); 2248d7f2e76SPhilippe Mathieu-Daudé dirtylimit_state->states = NULL; 2258d7f2e76SPhilippe Mathieu-Daudé 2268d7f2e76SPhilippe Mathieu-Daudé g_free(dirtylimit_state); 2278d7f2e76SPhilippe Mathieu-Daudé dirtylimit_state = NULL; 2288d7f2e76SPhilippe Mathieu-Daudé 2298d7f2e76SPhilippe Mathieu-Daudé trace_dirtylimit_state_finalize(); 2308d7f2e76SPhilippe Mathieu-Daudé } 2318d7f2e76SPhilippe Mathieu-Daudé 2328d7f2e76SPhilippe Mathieu-Daudé bool dirtylimit_in_service(void) 2338d7f2e76SPhilippe Mathieu-Daudé { 2348d7f2e76SPhilippe Mathieu-Daudé return !!dirtylimit_state; 2358d7f2e76SPhilippe Mathieu-Daudé } 2368d7f2e76SPhilippe Mathieu-Daudé 2378d7f2e76SPhilippe Mathieu-Daudé bool dirtylimit_vcpu_index_valid(int cpu_index) 2388d7f2e76SPhilippe Mathieu-Daudé { 2398d7f2e76SPhilippe Mathieu-Daudé MachineState *ms = MACHINE(qdev_get_machine()); 2408d7f2e76SPhilippe Mathieu-Daudé 2418d7f2e76SPhilippe Mathieu-Daudé return !(cpu_index < 0 || 2428d7f2e76SPhilippe Mathieu-Daudé cpu_index >= ms->smp.max_cpus); 2438d7f2e76SPhilippe Mathieu-Daudé } 2448d7f2e76SPhilippe Mathieu-Daudé 2458d7f2e76SPhilippe Mathieu-Daudé static uint64_t dirtylimit_dirty_ring_full_time(uint64_t dirtyrate) 2468d7f2e76SPhilippe Mathieu-Daudé { 2478d7f2e76SPhilippe Mathieu-Daudé static uint64_t max_dirtyrate; 2488d7f2e76SPhilippe Mathieu-Daudé uint64_t dirty_ring_size_MiB; 2498d7f2e76SPhilippe Mathieu-Daudé 2508d7f2e76SPhilippe Mathieu-Daudé dirty_ring_size_MiB = qemu_target_pages_to_MiB(kvm_dirty_ring_size()); 2518d7f2e76SPhilippe Mathieu-Daudé 2528d7f2e76SPhilippe Mathieu-Daudé if (max_dirtyrate < dirtyrate) { 2538d7f2e76SPhilippe Mathieu-Daudé max_dirtyrate = dirtyrate; 2548d7f2e76SPhilippe Mathieu-Daudé } 2558d7f2e76SPhilippe Mathieu-Daudé 2568d7f2e76SPhilippe Mathieu-Daudé return dirty_ring_size_MiB * 1000000 / max_dirtyrate; 2578d7f2e76SPhilippe Mathieu-Daudé } 2588d7f2e76SPhilippe Mathieu-Daudé 2598d7f2e76SPhilippe Mathieu-Daudé static inline bool dirtylimit_done(uint64_t quota, 2608d7f2e76SPhilippe Mathieu-Daudé uint64_t current) 2618d7f2e76SPhilippe Mathieu-Daudé { 2628d7f2e76SPhilippe Mathieu-Daudé uint64_t min, max; 2638d7f2e76SPhilippe Mathieu-Daudé 2648d7f2e76SPhilippe Mathieu-Daudé min = MIN(quota, current); 2658d7f2e76SPhilippe Mathieu-Daudé max = MAX(quota, current); 2668d7f2e76SPhilippe Mathieu-Daudé 2678d7f2e76SPhilippe Mathieu-Daudé return ((max - min) <= DIRTYLIMIT_TOLERANCE_RANGE) ? true : false; 2688d7f2e76SPhilippe Mathieu-Daudé } 2698d7f2e76SPhilippe Mathieu-Daudé 2708d7f2e76SPhilippe Mathieu-Daudé static inline bool 2718d7f2e76SPhilippe Mathieu-Daudé dirtylimit_need_linear_adjustment(uint64_t quota, 2728d7f2e76SPhilippe Mathieu-Daudé uint64_t current) 2738d7f2e76SPhilippe Mathieu-Daudé { 2748d7f2e76SPhilippe Mathieu-Daudé uint64_t min, max; 2758d7f2e76SPhilippe Mathieu-Daudé 2768d7f2e76SPhilippe Mathieu-Daudé min = MIN(quota, current); 2778d7f2e76SPhilippe Mathieu-Daudé max = MAX(quota, current); 2788d7f2e76SPhilippe Mathieu-Daudé 2798d7f2e76SPhilippe Mathieu-Daudé return ((max - min) * 100 / max) > DIRTYLIMIT_LINEAR_ADJUSTMENT_PCT; 2808d7f2e76SPhilippe Mathieu-Daudé } 2818d7f2e76SPhilippe Mathieu-Daudé 2828d7f2e76SPhilippe Mathieu-Daudé static void dirtylimit_set_throttle(CPUState *cpu, 2838d7f2e76SPhilippe Mathieu-Daudé uint64_t quota, 2848d7f2e76SPhilippe Mathieu-Daudé uint64_t current) 2858d7f2e76SPhilippe Mathieu-Daudé { 2868d7f2e76SPhilippe Mathieu-Daudé int64_t ring_full_time_us = 0; 2878d7f2e76SPhilippe Mathieu-Daudé uint64_t sleep_pct = 0; 2888d7f2e76SPhilippe Mathieu-Daudé uint64_t throttle_us = 0; 2898d7f2e76SPhilippe Mathieu-Daudé 2908d7f2e76SPhilippe Mathieu-Daudé if (current == 0) { 2918d7f2e76SPhilippe Mathieu-Daudé cpu->throttle_us_per_full = 0; 2928d7f2e76SPhilippe Mathieu-Daudé return; 2938d7f2e76SPhilippe Mathieu-Daudé } 2948d7f2e76SPhilippe Mathieu-Daudé 2958d7f2e76SPhilippe Mathieu-Daudé ring_full_time_us = dirtylimit_dirty_ring_full_time(current); 2968d7f2e76SPhilippe Mathieu-Daudé 2978d7f2e76SPhilippe Mathieu-Daudé if (dirtylimit_need_linear_adjustment(quota, current)) { 2988d7f2e76SPhilippe Mathieu-Daudé if (quota < current) { 2998d7f2e76SPhilippe Mathieu-Daudé sleep_pct = (current - quota) * 100 / current; 3008d7f2e76SPhilippe Mathieu-Daudé throttle_us = 3018d7f2e76SPhilippe Mathieu-Daudé ring_full_time_us * sleep_pct / (double)(100 - sleep_pct); 3028d7f2e76SPhilippe Mathieu-Daudé cpu->throttle_us_per_full += throttle_us; 3038d7f2e76SPhilippe Mathieu-Daudé } else { 3048d7f2e76SPhilippe Mathieu-Daudé sleep_pct = (quota - current) * 100 / quota; 3058d7f2e76SPhilippe Mathieu-Daudé throttle_us = 3068d7f2e76SPhilippe Mathieu-Daudé ring_full_time_us * sleep_pct / (double)(100 - sleep_pct); 3078d7f2e76SPhilippe Mathieu-Daudé cpu->throttle_us_per_full -= throttle_us; 3088d7f2e76SPhilippe Mathieu-Daudé } 3098d7f2e76SPhilippe Mathieu-Daudé 3108d7f2e76SPhilippe Mathieu-Daudé trace_dirtylimit_throttle_pct(cpu->cpu_index, 3118d7f2e76SPhilippe Mathieu-Daudé sleep_pct, 3128d7f2e76SPhilippe Mathieu-Daudé throttle_us); 3138d7f2e76SPhilippe Mathieu-Daudé } else { 3148d7f2e76SPhilippe Mathieu-Daudé if (quota < current) { 3158d7f2e76SPhilippe Mathieu-Daudé cpu->throttle_us_per_full += ring_full_time_us / 10; 3168d7f2e76SPhilippe Mathieu-Daudé } else { 3178d7f2e76SPhilippe Mathieu-Daudé cpu->throttle_us_per_full -= ring_full_time_us / 10; 3188d7f2e76SPhilippe Mathieu-Daudé } 3198d7f2e76SPhilippe Mathieu-Daudé } 3208d7f2e76SPhilippe Mathieu-Daudé 3218d7f2e76SPhilippe Mathieu-Daudé /* 3228d7f2e76SPhilippe Mathieu-Daudé * TODO: in the big kvm_dirty_ring_size case (eg: 65536, or other scenario), 3238d7f2e76SPhilippe Mathieu-Daudé * current dirty page rate may never reach the quota, we should stop 3248d7f2e76SPhilippe Mathieu-Daudé * increasing sleep time? 3258d7f2e76SPhilippe Mathieu-Daudé */ 3268d7f2e76SPhilippe Mathieu-Daudé cpu->throttle_us_per_full = MIN(cpu->throttle_us_per_full, 3278d7f2e76SPhilippe Mathieu-Daudé ring_full_time_us * DIRTYLIMIT_THROTTLE_PCT_MAX); 3288d7f2e76SPhilippe Mathieu-Daudé 3298d7f2e76SPhilippe Mathieu-Daudé cpu->throttle_us_per_full = MAX(cpu->throttle_us_per_full, 0); 3308d7f2e76SPhilippe Mathieu-Daudé } 3318d7f2e76SPhilippe Mathieu-Daudé 3328d7f2e76SPhilippe Mathieu-Daudé static void dirtylimit_adjust_throttle(CPUState *cpu) 3338d7f2e76SPhilippe Mathieu-Daudé { 3348d7f2e76SPhilippe Mathieu-Daudé uint64_t quota = 0; 3358d7f2e76SPhilippe Mathieu-Daudé uint64_t current = 0; 3368d7f2e76SPhilippe Mathieu-Daudé int cpu_index = cpu->cpu_index; 3378d7f2e76SPhilippe Mathieu-Daudé 3388d7f2e76SPhilippe Mathieu-Daudé quota = dirtylimit_vcpu_get_state(cpu_index)->quota; 3398d7f2e76SPhilippe Mathieu-Daudé current = vcpu_dirty_rate_get(cpu_index); 3408d7f2e76SPhilippe Mathieu-Daudé 3418d7f2e76SPhilippe Mathieu-Daudé if (!dirtylimit_done(quota, current)) { 3428d7f2e76SPhilippe Mathieu-Daudé dirtylimit_set_throttle(cpu, quota, current); 3438d7f2e76SPhilippe Mathieu-Daudé } 3448d7f2e76SPhilippe Mathieu-Daudé 3458d7f2e76SPhilippe Mathieu-Daudé return; 3468d7f2e76SPhilippe Mathieu-Daudé } 3478d7f2e76SPhilippe Mathieu-Daudé 3488d7f2e76SPhilippe Mathieu-Daudé void dirtylimit_process(void) 3498d7f2e76SPhilippe Mathieu-Daudé { 3508d7f2e76SPhilippe Mathieu-Daudé CPUState *cpu; 3518d7f2e76SPhilippe Mathieu-Daudé 3528d7f2e76SPhilippe Mathieu-Daudé if (!qatomic_read(&dirtylimit_quit)) { 3538d7f2e76SPhilippe Mathieu-Daudé dirtylimit_state_lock(); 3548d7f2e76SPhilippe Mathieu-Daudé 3558d7f2e76SPhilippe Mathieu-Daudé if (!dirtylimit_in_service()) { 3568d7f2e76SPhilippe Mathieu-Daudé dirtylimit_state_unlock(); 3578d7f2e76SPhilippe Mathieu-Daudé return; 3588d7f2e76SPhilippe Mathieu-Daudé } 3598d7f2e76SPhilippe Mathieu-Daudé 3608d7f2e76SPhilippe Mathieu-Daudé CPU_FOREACH(cpu) { 3618d7f2e76SPhilippe Mathieu-Daudé if (!dirtylimit_vcpu_get_state(cpu->cpu_index)->enabled) { 3628d7f2e76SPhilippe Mathieu-Daudé continue; 3638d7f2e76SPhilippe Mathieu-Daudé } 3648d7f2e76SPhilippe Mathieu-Daudé dirtylimit_adjust_throttle(cpu); 3658d7f2e76SPhilippe Mathieu-Daudé } 3668d7f2e76SPhilippe Mathieu-Daudé dirtylimit_state_unlock(); 3678d7f2e76SPhilippe Mathieu-Daudé } 3688d7f2e76SPhilippe Mathieu-Daudé } 3698d7f2e76SPhilippe Mathieu-Daudé 3708d7f2e76SPhilippe Mathieu-Daudé void dirtylimit_change(bool start) 3718d7f2e76SPhilippe Mathieu-Daudé { 3728d7f2e76SPhilippe Mathieu-Daudé if (start) { 3738d7f2e76SPhilippe Mathieu-Daudé qatomic_set(&dirtylimit_quit, 0); 3748d7f2e76SPhilippe Mathieu-Daudé } else { 3758d7f2e76SPhilippe Mathieu-Daudé qatomic_set(&dirtylimit_quit, 1); 3768d7f2e76SPhilippe Mathieu-Daudé } 3778d7f2e76SPhilippe Mathieu-Daudé } 3788d7f2e76SPhilippe Mathieu-Daudé 3798d7f2e76SPhilippe Mathieu-Daudé void dirtylimit_set_vcpu(int cpu_index, 3808d7f2e76SPhilippe Mathieu-Daudé uint64_t quota, 3818d7f2e76SPhilippe Mathieu-Daudé bool enable) 3828d7f2e76SPhilippe Mathieu-Daudé { 3838d7f2e76SPhilippe Mathieu-Daudé trace_dirtylimit_set_vcpu(cpu_index, quota); 3848d7f2e76SPhilippe Mathieu-Daudé 3858d7f2e76SPhilippe Mathieu-Daudé if (enable) { 3868d7f2e76SPhilippe Mathieu-Daudé dirtylimit_state->states[cpu_index].quota = quota; 3878d7f2e76SPhilippe Mathieu-Daudé if (!dirtylimit_vcpu_get_state(cpu_index)->enabled) { 3888d7f2e76SPhilippe Mathieu-Daudé dirtylimit_state->limited_nvcpu++; 3898d7f2e76SPhilippe Mathieu-Daudé } 3908d7f2e76SPhilippe Mathieu-Daudé } else { 3918d7f2e76SPhilippe Mathieu-Daudé dirtylimit_state->states[cpu_index].quota = 0; 3928d7f2e76SPhilippe Mathieu-Daudé if (dirtylimit_state->states[cpu_index].enabled) { 3938d7f2e76SPhilippe Mathieu-Daudé dirtylimit_state->limited_nvcpu--; 3948d7f2e76SPhilippe Mathieu-Daudé } 3958d7f2e76SPhilippe Mathieu-Daudé } 3968d7f2e76SPhilippe Mathieu-Daudé 3978d7f2e76SPhilippe Mathieu-Daudé dirtylimit_state->states[cpu_index].enabled = enable; 3988d7f2e76SPhilippe Mathieu-Daudé } 3998d7f2e76SPhilippe Mathieu-Daudé 4008d7f2e76SPhilippe Mathieu-Daudé void dirtylimit_set_all(uint64_t quota, 4018d7f2e76SPhilippe Mathieu-Daudé bool enable) 4028d7f2e76SPhilippe Mathieu-Daudé { 4038d7f2e76SPhilippe Mathieu-Daudé MachineState *ms = MACHINE(qdev_get_machine()); 4048d7f2e76SPhilippe Mathieu-Daudé int max_cpus = ms->smp.max_cpus; 4058d7f2e76SPhilippe Mathieu-Daudé int i; 4068d7f2e76SPhilippe Mathieu-Daudé 4078d7f2e76SPhilippe Mathieu-Daudé for (i = 0; i < max_cpus; i++) { 4088d7f2e76SPhilippe Mathieu-Daudé dirtylimit_set_vcpu(i, quota, enable); 4098d7f2e76SPhilippe Mathieu-Daudé } 4108d7f2e76SPhilippe Mathieu-Daudé } 4118d7f2e76SPhilippe Mathieu-Daudé 4128d7f2e76SPhilippe Mathieu-Daudé void dirtylimit_vcpu_execute(CPUState *cpu) 4138d7f2e76SPhilippe Mathieu-Daudé { 414cce10a1fSHyman Huang if (cpu->throttle_us_per_full) { 415cce10a1fSHyman Huang dirtylimit_state_lock(); 416cce10a1fSHyman Huang 4178d7f2e76SPhilippe Mathieu-Daudé if (dirtylimit_in_service() && 418cce10a1fSHyman Huang dirtylimit_vcpu_get_state(cpu->cpu_index)->enabled) { 419cce10a1fSHyman Huang dirtylimit_state_unlock(); 4208d7f2e76SPhilippe Mathieu-Daudé trace_dirtylimit_vcpu_execute(cpu->cpu_index, 4218d7f2e76SPhilippe Mathieu-Daudé cpu->throttle_us_per_full); 422cce10a1fSHyman Huang 423cce10a1fSHyman Huang g_usleep(cpu->throttle_us_per_full); 424cce10a1fSHyman Huang return; 425cce10a1fSHyman Huang } 426cce10a1fSHyman Huang 427cce10a1fSHyman Huang dirtylimit_state_unlock(); 4288d7f2e76SPhilippe Mathieu-Daudé } 4298d7f2e76SPhilippe Mathieu-Daudé } 4308d7f2e76SPhilippe Mathieu-Daudé 4318d7f2e76SPhilippe Mathieu-Daudé static void dirtylimit_init(void) 4328d7f2e76SPhilippe Mathieu-Daudé { 4338d7f2e76SPhilippe Mathieu-Daudé dirtylimit_state_initialize(); 4348d7f2e76SPhilippe Mathieu-Daudé dirtylimit_change(true); 4358d7f2e76SPhilippe Mathieu-Daudé vcpu_dirty_rate_stat_initialize(); 4368d7f2e76SPhilippe Mathieu-Daudé vcpu_dirty_rate_stat_start(); 4378d7f2e76SPhilippe Mathieu-Daudé } 4388d7f2e76SPhilippe Mathieu-Daudé 4398d7f2e76SPhilippe Mathieu-Daudé static void dirtylimit_cleanup(void) 4408d7f2e76SPhilippe Mathieu-Daudé { 4418d7f2e76SPhilippe Mathieu-Daudé vcpu_dirty_rate_stat_stop(); 4428d7f2e76SPhilippe Mathieu-Daudé vcpu_dirty_rate_stat_finalize(); 4438d7f2e76SPhilippe Mathieu-Daudé dirtylimit_change(false); 4448d7f2e76SPhilippe Mathieu-Daudé dirtylimit_state_finalize(); 4458d7f2e76SPhilippe Mathieu-Daudé } 4468d7f2e76SPhilippe Mathieu-Daudé 4478d7f2e76SPhilippe Mathieu-Daudé /* 4488d7f2e76SPhilippe Mathieu-Daudé * dirty page rate limit is not allowed to set if migration 4498d7f2e76SPhilippe Mathieu-Daudé * is running with dirty-limit capability enabled. 4508d7f2e76SPhilippe Mathieu-Daudé */ 4518d7f2e76SPhilippe Mathieu-Daudé static bool dirtylimit_is_allowed(void) 4528d7f2e76SPhilippe Mathieu-Daudé { 4538d7f2e76SPhilippe Mathieu-Daudé MigrationState *ms = migrate_get_current(); 4548d7f2e76SPhilippe Mathieu-Daudé 4558d7f2e76SPhilippe Mathieu-Daudé if (migration_is_running(ms->state) && 4568d7f2e76SPhilippe Mathieu-Daudé (!qemu_thread_is_self(&ms->thread)) && 4578d7f2e76SPhilippe Mathieu-Daudé migrate_dirty_limit() && 4588d7f2e76SPhilippe Mathieu-Daudé dirtylimit_in_service()) { 4598d7f2e76SPhilippe Mathieu-Daudé return false; 4608d7f2e76SPhilippe Mathieu-Daudé } 4618d7f2e76SPhilippe Mathieu-Daudé return true; 4628d7f2e76SPhilippe Mathieu-Daudé } 4638d7f2e76SPhilippe Mathieu-Daudé 4648d7f2e76SPhilippe Mathieu-Daudé void qmp_cancel_vcpu_dirty_limit(bool has_cpu_index, 4658d7f2e76SPhilippe Mathieu-Daudé int64_t cpu_index, 4668d7f2e76SPhilippe Mathieu-Daudé Error **errp) 4678d7f2e76SPhilippe Mathieu-Daudé { 4688d7f2e76SPhilippe Mathieu-Daudé if (!kvm_enabled() || !kvm_dirty_ring_enabled()) { 4698d7f2e76SPhilippe Mathieu-Daudé return; 4708d7f2e76SPhilippe Mathieu-Daudé } 4718d7f2e76SPhilippe Mathieu-Daudé 4728d7f2e76SPhilippe Mathieu-Daudé if (has_cpu_index && !dirtylimit_vcpu_index_valid(cpu_index)) { 4738d7f2e76SPhilippe Mathieu-Daudé error_setg(errp, "incorrect cpu index specified"); 4748d7f2e76SPhilippe Mathieu-Daudé return; 4758d7f2e76SPhilippe Mathieu-Daudé } 4768d7f2e76SPhilippe Mathieu-Daudé 4778d7f2e76SPhilippe Mathieu-Daudé if (!dirtylimit_is_allowed()) { 4788d7f2e76SPhilippe Mathieu-Daudé error_setg(errp, "can't cancel dirty page rate limit while" 4798d7f2e76SPhilippe Mathieu-Daudé " migration is running"); 4808d7f2e76SPhilippe Mathieu-Daudé return; 4818d7f2e76SPhilippe Mathieu-Daudé } 4828d7f2e76SPhilippe Mathieu-Daudé 4838d7f2e76SPhilippe Mathieu-Daudé if (!dirtylimit_in_service()) { 4848d7f2e76SPhilippe Mathieu-Daudé return; 4858d7f2e76SPhilippe Mathieu-Daudé } 4868d7f2e76SPhilippe Mathieu-Daudé 4878d7f2e76SPhilippe Mathieu-Daudé dirtylimit_state_lock(); 4888d7f2e76SPhilippe Mathieu-Daudé 4898d7f2e76SPhilippe Mathieu-Daudé if (has_cpu_index) { 4908d7f2e76SPhilippe Mathieu-Daudé dirtylimit_set_vcpu(cpu_index, 0, false); 4918d7f2e76SPhilippe Mathieu-Daudé } else { 4928d7f2e76SPhilippe Mathieu-Daudé dirtylimit_set_all(0, false); 4938d7f2e76SPhilippe Mathieu-Daudé } 4948d7f2e76SPhilippe Mathieu-Daudé 4958d7f2e76SPhilippe Mathieu-Daudé if (!dirtylimit_state->limited_nvcpu) { 4968d7f2e76SPhilippe Mathieu-Daudé dirtylimit_cleanup(); 4978d7f2e76SPhilippe Mathieu-Daudé } 4988d7f2e76SPhilippe Mathieu-Daudé 4998d7f2e76SPhilippe Mathieu-Daudé dirtylimit_state_unlock(); 5008d7f2e76SPhilippe Mathieu-Daudé } 5018d7f2e76SPhilippe Mathieu-Daudé 5028d7f2e76SPhilippe Mathieu-Daudé void hmp_cancel_vcpu_dirty_limit(Monitor *mon, const QDict *qdict) 5038d7f2e76SPhilippe Mathieu-Daudé { 5048d7f2e76SPhilippe Mathieu-Daudé int64_t cpu_index = qdict_get_try_int(qdict, "cpu_index", -1); 5058d7f2e76SPhilippe Mathieu-Daudé Error *err = NULL; 5068d7f2e76SPhilippe Mathieu-Daudé 5078d7f2e76SPhilippe Mathieu-Daudé qmp_cancel_vcpu_dirty_limit(!!(cpu_index != -1), cpu_index, &err); 5088d7f2e76SPhilippe Mathieu-Daudé if (err) { 5098d7f2e76SPhilippe Mathieu-Daudé hmp_handle_error(mon, err); 5108d7f2e76SPhilippe Mathieu-Daudé return; 5118d7f2e76SPhilippe Mathieu-Daudé } 5128d7f2e76SPhilippe Mathieu-Daudé 5138d7f2e76SPhilippe Mathieu-Daudé monitor_printf(mon, "[Please use 'info vcpu_dirty_limit' to query " 5148d7f2e76SPhilippe Mathieu-Daudé "dirty limit for virtual CPU]\n"); 5158d7f2e76SPhilippe Mathieu-Daudé } 5168d7f2e76SPhilippe Mathieu-Daudé 5178d7f2e76SPhilippe Mathieu-Daudé void qmp_set_vcpu_dirty_limit(bool has_cpu_index, 5188d7f2e76SPhilippe Mathieu-Daudé int64_t cpu_index, 5198d7f2e76SPhilippe Mathieu-Daudé uint64_t dirty_rate, 5208d7f2e76SPhilippe Mathieu-Daudé Error **errp) 5218d7f2e76SPhilippe Mathieu-Daudé { 5228d7f2e76SPhilippe Mathieu-Daudé if (!kvm_enabled() || !kvm_dirty_ring_enabled()) { 5238d7f2e76SPhilippe Mathieu-Daudé error_setg(errp, "dirty page limit feature requires KVM with" 5248d7f2e76SPhilippe Mathieu-Daudé " accelerator property 'dirty-ring-size' set'"); 5258d7f2e76SPhilippe Mathieu-Daudé return; 5268d7f2e76SPhilippe Mathieu-Daudé } 5278d7f2e76SPhilippe Mathieu-Daudé 5288d7f2e76SPhilippe Mathieu-Daudé if (has_cpu_index && !dirtylimit_vcpu_index_valid(cpu_index)) { 5298d7f2e76SPhilippe Mathieu-Daudé error_setg(errp, "incorrect cpu index specified"); 5308d7f2e76SPhilippe Mathieu-Daudé return; 5318d7f2e76SPhilippe Mathieu-Daudé } 5328d7f2e76SPhilippe Mathieu-Daudé 5338d7f2e76SPhilippe Mathieu-Daudé if (!dirtylimit_is_allowed()) { 5348d7f2e76SPhilippe Mathieu-Daudé error_setg(errp, "can't set dirty page rate limit while" 5358d7f2e76SPhilippe Mathieu-Daudé " migration is running"); 5368d7f2e76SPhilippe Mathieu-Daudé return; 5378d7f2e76SPhilippe Mathieu-Daudé } 5388d7f2e76SPhilippe Mathieu-Daudé 5398d7f2e76SPhilippe Mathieu-Daudé if (!dirty_rate) { 5408d7f2e76SPhilippe Mathieu-Daudé qmp_cancel_vcpu_dirty_limit(has_cpu_index, cpu_index, errp); 5418d7f2e76SPhilippe Mathieu-Daudé return; 5428d7f2e76SPhilippe Mathieu-Daudé } 5438d7f2e76SPhilippe Mathieu-Daudé 5448d7f2e76SPhilippe Mathieu-Daudé dirtylimit_state_lock(); 5458d7f2e76SPhilippe Mathieu-Daudé 5468d7f2e76SPhilippe Mathieu-Daudé if (!dirtylimit_in_service()) { 5478d7f2e76SPhilippe Mathieu-Daudé dirtylimit_init(); 5488d7f2e76SPhilippe Mathieu-Daudé } 5498d7f2e76SPhilippe Mathieu-Daudé 5508d7f2e76SPhilippe Mathieu-Daudé if (has_cpu_index) { 5518d7f2e76SPhilippe Mathieu-Daudé dirtylimit_set_vcpu(cpu_index, dirty_rate, true); 5528d7f2e76SPhilippe Mathieu-Daudé } else { 5538d7f2e76SPhilippe Mathieu-Daudé dirtylimit_set_all(dirty_rate, true); 5548d7f2e76SPhilippe Mathieu-Daudé } 5558d7f2e76SPhilippe Mathieu-Daudé 5568d7f2e76SPhilippe Mathieu-Daudé dirtylimit_state_unlock(); 5578d7f2e76SPhilippe Mathieu-Daudé } 5588d7f2e76SPhilippe Mathieu-Daudé 5598d7f2e76SPhilippe Mathieu-Daudé void hmp_set_vcpu_dirty_limit(Monitor *mon, const QDict *qdict) 5608d7f2e76SPhilippe Mathieu-Daudé { 5618d7f2e76SPhilippe Mathieu-Daudé int64_t dirty_rate = qdict_get_int(qdict, "dirty_rate"); 5628d7f2e76SPhilippe Mathieu-Daudé int64_t cpu_index = qdict_get_try_int(qdict, "cpu_index", -1); 5638d7f2e76SPhilippe Mathieu-Daudé Error *err = NULL; 5648d7f2e76SPhilippe Mathieu-Daudé 5658d7f2e76SPhilippe Mathieu-Daudé if (dirty_rate < 0) { 5668d7f2e76SPhilippe Mathieu-Daudé error_setg(&err, "invalid dirty page limit %" PRId64, dirty_rate); 5678d7f2e76SPhilippe Mathieu-Daudé goto out; 5688d7f2e76SPhilippe Mathieu-Daudé } 5698d7f2e76SPhilippe Mathieu-Daudé 5708d7f2e76SPhilippe Mathieu-Daudé qmp_set_vcpu_dirty_limit(!!(cpu_index != -1), cpu_index, dirty_rate, &err); 5718d7f2e76SPhilippe Mathieu-Daudé 5728d7f2e76SPhilippe Mathieu-Daudé out: 5738d7f2e76SPhilippe Mathieu-Daudé hmp_handle_error(mon, err); 5748d7f2e76SPhilippe Mathieu-Daudé } 5758d7f2e76SPhilippe Mathieu-Daudé 5768d7f2e76SPhilippe Mathieu-Daudé /* Return the max throttle time of each virtual CPU */ 5778d7f2e76SPhilippe Mathieu-Daudé uint64_t dirtylimit_throttle_time_per_round(void) 5788d7f2e76SPhilippe Mathieu-Daudé { 5798d7f2e76SPhilippe Mathieu-Daudé CPUState *cpu; 5808d7f2e76SPhilippe Mathieu-Daudé int64_t max = 0; 5818d7f2e76SPhilippe Mathieu-Daudé 5828d7f2e76SPhilippe Mathieu-Daudé CPU_FOREACH(cpu) { 5838d7f2e76SPhilippe Mathieu-Daudé if (cpu->throttle_us_per_full > max) { 5848d7f2e76SPhilippe Mathieu-Daudé max = cpu->throttle_us_per_full; 5858d7f2e76SPhilippe Mathieu-Daudé } 5868d7f2e76SPhilippe Mathieu-Daudé } 5878d7f2e76SPhilippe Mathieu-Daudé 5888d7f2e76SPhilippe Mathieu-Daudé return max; 5898d7f2e76SPhilippe Mathieu-Daudé } 5908d7f2e76SPhilippe Mathieu-Daudé 5918d7f2e76SPhilippe Mathieu-Daudé /* 5928d7f2e76SPhilippe Mathieu-Daudé * Estimate average dirty ring full time of each virtaul CPU. 5938d7f2e76SPhilippe Mathieu-Daudé * Return 0 if guest doesn't dirty memory. 5948d7f2e76SPhilippe Mathieu-Daudé */ 5958d7f2e76SPhilippe Mathieu-Daudé uint64_t dirtylimit_ring_full_time(void) 5968d7f2e76SPhilippe Mathieu-Daudé { 5978d7f2e76SPhilippe Mathieu-Daudé CPUState *cpu; 5988d7f2e76SPhilippe Mathieu-Daudé uint64_t curr_rate = 0; 5998d7f2e76SPhilippe Mathieu-Daudé int nvcpus = 0; 6008d7f2e76SPhilippe Mathieu-Daudé 6018d7f2e76SPhilippe Mathieu-Daudé CPU_FOREACH(cpu) { 6028d7f2e76SPhilippe Mathieu-Daudé if (cpu->running) { 6038d7f2e76SPhilippe Mathieu-Daudé nvcpus++; 6048d7f2e76SPhilippe Mathieu-Daudé curr_rate += vcpu_dirty_rate_get(cpu->cpu_index); 6058d7f2e76SPhilippe Mathieu-Daudé } 6068d7f2e76SPhilippe Mathieu-Daudé } 6078d7f2e76SPhilippe Mathieu-Daudé 6088d7f2e76SPhilippe Mathieu-Daudé if (!curr_rate || !nvcpus) { 6098d7f2e76SPhilippe Mathieu-Daudé return 0; 6108d7f2e76SPhilippe Mathieu-Daudé } 6118d7f2e76SPhilippe Mathieu-Daudé 6128d7f2e76SPhilippe Mathieu-Daudé return dirtylimit_dirty_ring_full_time(curr_rate / nvcpus); 6138d7f2e76SPhilippe Mathieu-Daudé } 6148d7f2e76SPhilippe Mathieu-Daudé 6158d7f2e76SPhilippe Mathieu-Daudé static struct DirtyLimitInfo *dirtylimit_query_vcpu(int cpu_index) 6168d7f2e76SPhilippe Mathieu-Daudé { 6178d7f2e76SPhilippe Mathieu-Daudé DirtyLimitInfo *info = NULL; 6188d7f2e76SPhilippe Mathieu-Daudé 6198d7f2e76SPhilippe Mathieu-Daudé info = g_malloc0(sizeof(*info)); 6208d7f2e76SPhilippe Mathieu-Daudé info->cpu_index = cpu_index; 6218d7f2e76SPhilippe Mathieu-Daudé info->limit_rate = dirtylimit_vcpu_get_state(cpu_index)->quota; 6228d7f2e76SPhilippe Mathieu-Daudé info->current_rate = vcpu_dirty_rate_get(cpu_index); 6238d7f2e76SPhilippe Mathieu-Daudé 6248d7f2e76SPhilippe Mathieu-Daudé return info; 6258d7f2e76SPhilippe Mathieu-Daudé } 6268d7f2e76SPhilippe Mathieu-Daudé 6278d7f2e76SPhilippe Mathieu-Daudé static struct DirtyLimitInfoList *dirtylimit_query_all(void) 6288d7f2e76SPhilippe Mathieu-Daudé { 6298d7f2e76SPhilippe Mathieu-Daudé int i, index; 6308d7f2e76SPhilippe Mathieu-Daudé DirtyLimitInfo *info = NULL; 6318d7f2e76SPhilippe Mathieu-Daudé DirtyLimitInfoList *head = NULL, **tail = &head; 6328d7f2e76SPhilippe Mathieu-Daudé 6338d7f2e76SPhilippe Mathieu-Daudé dirtylimit_state_lock(); 6348d7f2e76SPhilippe Mathieu-Daudé 6358d7f2e76SPhilippe Mathieu-Daudé if (!dirtylimit_in_service()) { 6368d7f2e76SPhilippe Mathieu-Daudé dirtylimit_state_unlock(); 6378d7f2e76SPhilippe Mathieu-Daudé return NULL; 6388d7f2e76SPhilippe Mathieu-Daudé } 6398d7f2e76SPhilippe Mathieu-Daudé 6408d7f2e76SPhilippe Mathieu-Daudé for (i = 0; i < dirtylimit_state->max_cpus; i++) { 6418d7f2e76SPhilippe Mathieu-Daudé index = dirtylimit_state->states[i].cpu_index; 6428d7f2e76SPhilippe Mathieu-Daudé if (dirtylimit_vcpu_get_state(index)->enabled) { 6438d7f2e76SPhilippe Mathieu-Daudé info = dirtylimit_query_vcpu(index); 6448d7f2e76SPhilippe Mathieu-Daudé QAPI_LIST_APPEND(tail, info); 6458d7f2e76SPhilippe Mathieu-Daudé } 6468d7f2e76SPhilippe Mathieu-Daudé } 6478d7f2e76SPhilippe Mathieu-Daudé 6488d7f2e76SPhilippe Mathieu-Daudé dirtylimit_state_unlock(); 6498d7f2e76SPhilippe Mathieu-Daudé 6508d7f2e76SPhilippe Mathieu-Daudé return head; 6518d7f2e76SPhilippe Mathieu-Daudé } 6528d7f2e76SPhilippe Mathieu-Daudé 6538d7f2e76SPhilippe Mathieu-Daudé struct DirtyLimitInfoList *qmp_query_vcpu_dirty_limit(Error **errp) 6548d7f2e76SPhilippe Mathieu-Daudé { 6558d7f2e76SPhilippe Mathieu-Daudé return dirtylimit_query_all(); 6568d7f2e76SPhilippe Mathieu-Daudé } 6578d7f2e76SPhilippe Mathieu-Daudé 6588d7f2e76SPhilippe Mathieu-Daudé void hmp_info_vcpu_dirty_limit(Monitor *mon, const QDict *qdict) 6598d7f2e76SPhilippe Mathieu-Daudé { 6608d7f2e76SPhilippe Mathieu-Daudé DirtyLimitInfoList *info; 6618d7f2e76SPhilippe Mathieu-Daudé g_autoptr(DirtyLimitInfoList) head = NULL; 6628d7f2e76SPhilippe Mathieu-Daudé Error *err = NULL; 6638d7f2e76SPhilippe Mathieu-Daudé 6648d7f2e76SPhilippe Mathieu-Daudé if (!dirtylimit_in_service()) { 6658d7f2e76SPhilippe Mathieu-Daudé monitor_printf(mon, "Dirty page limit not enabled!\n"); 6668d7f2e76SPhilippe Mathieu-Daudé return; 6678d7f2e76SPhilippe Mathieu-Daudé } 6688d7f2e76SPhilippe Mathieu-Daudé 6698d7f2e76SPhilippe Mathieu-Daudé head = qmp_query_vcpu_dirty_limit(&err); 6708d7f2e76SPhilippe Mathieu-Daudé if (err) { 6718d7f2e76SPhilippe Mathieu-Daudé hmp_handle_error(mon, err); 6728d7f2e76SPhilippe Mathieu-Daudé return; 6738d7f2e76SPhilippe Mathieu-Daudé } 6748d7f2e76SPhilippe Mathieu-Daudé 6758d7f2e76SPhilippe Mathieu-Daudé for (info = head; info != NULL; info = info->next) { 6768d7f2e76SPhilippe Mathieu-Daudé monitor_printf(mon, "vcpu[%"PRIi64"], limit rate %"PRIi64 " (MB/s)," 6778d7f2e76SPhilippe Mathieu-Daudé " current rate %"PRIi64 " (MB/s)\n", 6788d7f2e76SPhilippe Mathieu-Daudé info->value->cpu_index, 6798d7f2e76SPhilippe Mathieu-Daudé info->value->limit_rate, 6808d7f2e76SPhilippe Mathieu-Daudé info->value->current_rate); 6818d7f2e76SPhilippe Mathieu-Daudé } 6828d7f2e76SPhilippe Mathieu-Daudé } 683