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