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