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