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