xref: /qemu/migration/dirtyrate.c (revision 4998a37e4bf2bc47f76775e6e6a0cd50bacfb16a)
14240dceeSChuan Zheng /*
24240dceeSChuan Zheng  * Dirtyrate implement code
34240dceeSChuan Zheng  *
44240dceeSChuan Zheng  * Copyright (c) 2020 HUAWEI TECHNOLOGIES CO.,LTD.
54240dceeSChuan Zheng  *
64240dceeSChuan Zheng  * Authors:
74240dceeSChuan Zheng  *  Chuan Zheng <zhengchuan@huawei.com>
84240dceeSChuan Zheng  *
94240dceeSChuan Zheng  * This work is licensed under the terms of the GNU GPL, version 2 or later.
104240dceeSChuan Zheng  * See the COPYING file in the top-level directory.
114240dceeSChuan Zheng  */
124240dceeSChuan Zheng 
134240dceeSChuan Zheng #include "qemu/osdep.h"
14662770afSMarc-André Lureau #include <zlib.h>
154240dceeSChuan Zheng #include "qapi/error.h"
164240dceeSChuan Zheng #include "cpu.h"
174240dceeSChuan Zheng #include "exec/ramblock.h"
184240dceeSChuan Zheng #include "qemu/rcu_queue.h"
190e21bf24SHyman Huang(黄勇) #include "qemu/main-loop.h"
204240dceeSChuan Zheng #include "qapi/qapi-commands-migration.h"
213ded54b1SChuan Zheng #include "ram.h"
223c0b5dffSChuan Zheng #include "trace.h"
234240dceeSChuan Zheng #include "dirtyrate.h"
24a4a571d9SPeter Xu #include "monitor/hmp.h"
25a4a571d9SPeter Xu #include "monitor/monitor.h"
26a4a571d9SPeter Xu #include "qapi/qmp/qdict.h"
270e21bf24SHyman Huang(黄勇) #include "sysemu/kvm.h"
280e21bf24SHyman Huang(黄勇) #include "sysemu/runstate.h"
290e21bf24SHyman Huang(黄勇) #include "exec/memory.h"
300e21bf24SHyman Huang(黄勇) 
31*4998a37eSHyman Huang(黄勇) /*
32*4998a37eSHyman Huang(黄勇)  * total_dirty_pages is procted by BQL and is used
33*4998a37eSHyman Huang(黄勇)  * to stat dirty pages during the period of two
34*4998a37eSHyman Huang(黄勇)  * memory_global_dirty_log_sync
35*4998a37eSHyman Huang(黄勇)  */
36*4998a37eSHyman Huang(黄勇) uint64_t total_dirty_pages;
37*4998a37eSHyman Huang(黄勇) 
380e21bf24SHyman Huang(黄勇) typedef struct DirtyPageRecord {
390e21bf24SHyman Huang(黄勇)     uint64_t start_pages;
400e21bf24SHyman Huang(黄勇)     uint64_t end_pages;
410e21bf24SHyman Huang(黄勇) } DirtyPageRecord;
424240dceeSChuan Zheng 
437df3aa30SChuan Zheng static int CalculatingState = DIRTY_RATE_STATUS_UNSTARTED;
44c9a58d71SChuan Zheng static struct DirtyRateStat DirtyStat;
450e21bf24SHyman Huang(黄勇) static DirtyRateMeasureMode dirtyrate_mode =
460e21bf24SHyman Huang(黄勇)                 DIRTY_RATE_MEASURE_MODE_PAGE_SAMPLING;
477df3aa30SChuan Zheng 
48eca58224SChuan Zheng static int64_t set_sample_page_period(int64_t msec, int64_t initial_time)
49eca58224SChuan Zheng {
50eca58224SChuan Zheng     int64_t current_time;
51eca58224SChuan Zheng 
52eca58224SChuan Zheng     current_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
53eca58224SChuan Zheng     if ((current_time - initial_time) >= msec) {
54eca58224SChuan Zheng         msec = current_time - initial_time;
55eca58224SChuan Zheng     } else {
56eca58224SChuan Zheng         g_usleep((msec + initial_time - current_time) * 1000);
57eca58224SChuan Zheng     }
58eca58224SChuan Zheng 
59eca58224SChuan Zheng     return msec;
60eca58224SChuan Zheng }
61eca58224SChuan Zheng 
62eca58224SChuan Zheng static bool is_sample_period_valid(int64_t sec)
63eca58224SChuan Zheng {
64eca58224SChuan Zheng     if (sec < MIN_FETCH_DIRTYRATE_TIME_SEC ||
65eca58224SChuan Zheng         sec > MAX_FETCH_DIRTYRATE_TIME_SEC) {
66eca58224SChuan Zheng         return false;
67eca58224SChuan Zheng     }
68eca58224SChuan Zheng 
69eca58224SChuan Zheng     return true;
70eca58224SChuan Zheng }
71eca58224SChuan Zheng 
727afa08cdSHyman Huang(黄勇) static bool is_sample_pages_valid(int64_t pages)
737afa08cdSHyman Huang(黄勇) {
747afa08cdSHyman Huang(黄勇)     return pages >= MIN_SAMPLE_PAGE_COUNT &&
757afa08cdSHyman Huang(黄勇)            pages <= MAX_SAMPLE_PAGE_COUNT;
767afa08cdSHyman Huang(黄勇) }
777afa08cdSHyman Huang(黄勇) 
787df3aa30SChuan Zheng static int dirtyrate_set_state(int *state, int old_state, int new_state)
797df3aa30SChuan Zheng {
807df3aa30SChuan Zheng     assert(new_state < DIRTY_RATE_STATUS__MAX);
813c0b5dffSChuan Zheng     trace_dirtyrate_set_state(DirtyRateStatus_str(new_state));
827df3aa30SChuan Zheng     if (qatomic_cmpxchg(state, old_state, new_state) == old_state) {
837df3aa30SChuan Zheng         return 0;
847df3aa30SChuan Zheng     } else {
857df3aa30SChuan Zheng         return -1;
867df3aa30SChuan Zheng     }
877df3aa30SChuan Zheng }
887df3aa30SChuan Zheng 
894c437254SChuan Zheng static struct DirtyRateInfo *query_dirty_rate_info(void)
904c437254SChuan Zheng {
910e21bf24SHyman Huang(黄勇)     int i;
924c437254SChuan Zheng     int64_t dirty_rate = DirtyStat.dirty_rate;
934c437254SChuan Zheng     struct DirtyRateInfo *info = g_malloc0(sizeof(DirtyRateInfo));
940e21bf24SHyman Huang(黄勇)     DirtyRateVcpuList *head = NULL, **tail = &head;
954c437254SChuan Zheng 
964c437254SChuan Zheng     info->status = CalculatingState;
974c437254SChuan Zheng     info->start_time = DirtyStat.start_time;
984c437254SChuan Zheng     info->calc_time = DirtyStat.calc_time;
997afa08cdSHyman Huang(黄勇)     info->sample_pages = DirtyStat.sample_pages;
1000e21bf24SHyman Huang(黄勇)     info->mode = dirtyrate_mode;
1010e21bf24SHyman Huang(黄勇) 
1020e21bf24SHyman Huang(黄勇)     if (qatomic_read(&CalculatingState) == DIRTY_RATE_STATUS_MEASURED) {
1030e21bf24SHyman Huang(黄勇)         info->has_dirty_rate = true;
1040e21bf24SHyman Huang(黄勇)         info->dirty_rate = dirty_rate;
1050e21bf24SHyman Huang(黄勇) 
1060e21bf24SHyman Huang(黄勇)         if (dirtyrate_mode == DIRTY_RATE_MEASURE_MODE_DIRTY_RING) {
1070e21bf24SHyman Huang(黄勇)             /*
1080e21bf24SHyman Huang(黄勇)              * set sample_pages with 0 to indicate page sampling
1090e21bf24SHyman Huang(黄勇)              * isn't enabled
1100e21bf24SHyman Huang(黄勇)              **/
1110e21bf24SHyman Huang(黄勇)             info->sample_pages = 0;
1120e21bf24SHyman Huang(黄勇)             info->has_vcpu_dirty_rate = true;
1130e21bf24SHyman Huang(黄勇)             for (i = 0; i < DirtyStat.dirty_ring.nvcpu; i++) {
1140e21bf24SHyman Huang(黄勇)                 DirtyRateVcpu *rate = g_malloc0(sizeof(DirtyRateVcpu));
1150e21bf24SHyman Huang(黄勇)                 rate->id = DirtyStat.dirty_ring.rates[i].id;
1160e21bf24SHyman Huang(黄勇)                 rate->dirty_rate = DirtyStat.dirty_ring.rates[i].dirty_rate;
1170e21bf24SHyman Huang(黄勇)                 QAPI_LIST_APPEND(tail, rate);
1180e21bf24SHyman Huang(黄勇)             }
1190e21bf24SHyman Huang(黄勇)             info->vcpu_dirty_rate = head;
1200e21bf24SHyman Huang(黄勇)         }
1210e21bf24SHyman Huang(黄勇)     }
1224c437254SChuan Zheng 
1233c0b5dffSChuan Zheng     trace_query_dirty_rate_info(DirtyRateStatus_str(CalculatingState));
1243c0b5dffSChuan Zheng 
1254c437254SChuan Zheng     return info;
1264c437254SChuan Zheng }
1274c437254SChuan Zheng 
12871864eadSHyman Huang(黄勇) static void init_dirtyrate_stat(int64_t start_time,
12971864eadSHyman Huang(黄勇)                                 struct DirtyRateConfig config)
130c9a58d71SChuan Zheng {
131c9a58d71SChuan Zheng     DirtyStat.dirty_rate = -1;
132aa84b506SChuan Zheng     DirtyStat.start_time = start_time;
13371864eadSHyman Huang(黄勇)     DirtyStat.calc_time = config.sample_period_seconds;
13471864eadSHyman Huang(黄勇)     DirtyStat.sample_pages = config.sample_pages_per_gigabytes;
13571864eadSHyman Huang(黄勇) 
13671864eadSHyman Huang(黄勇)     switch (config.mode) {
13771864eadSHyman Huang(黄勇)     case DIRTY_RATE_MEASURE_MODE_PAGE_SAMPLING:
13871864eadSHyman Huang(黄勇)         DirtyStat.page_sampling.total_dirty_samples = 0;
13971864eadSHyman Huang(黄勇)         DirtyStat.page_sampling.total_sample_count = 0;
14071864eadSHyman Huang(黄勇)         DirtyStat.page_sampling.total_block_mem_MB = 0;
14171864eadSHyman Huang(黄勇)         break;
14271864eadSHyman Huang(黄勇)     case DIRTY_RATE_MEASURE_MODE_DIRTY_RING:
14371864eadSHyman Huang(黄勇)         DirtyStat.dirty_ring.nvcpu = -1;
14471864eadSHyman Huang(黄勇)         DirtyStat.dirty_ring.rates = NULL;
14571864eadSHyman Huang(黄勇)         break;
14671864eadSHyman Huang(黄勇)     default:
14771864eadSHyman Huang(黄勇)         break;
14871864eadSHyman Huang(黄勇)     }
149c9a58d71SChuan Zheng }
150c9a58d71SChuan Zheng 
1510e21bf24SHyman Huang(黄勇) static void cleanup_dirtyrate_stat(struct DirtyRateConfig config)
1520e21bf24SHyman Huang(黄勇) {
1530e21bf24SHyman Huang(黄勇)     /* last calc-dirty-rate qmp use dirty ring mode */
1540e21bf24SHyman Huang(黄勇)     if (dirtyrate_mode == DIRTY_RATE_MEASURE_MODE_DIRTY_RING) {
1550e21bf24SHyman Huang(黄勇)         free(DirtyStat.dirty_ring.rates);
1560e21bf24SHyman Huang(黄勇)         DirtyStat.dirty_ring.rates = NULL;
1570e21bf24SHyman Huang(黄勇)     }
1580e21bf24SHyman Huang(黄勇) }
1590e21bf24SHyman Huang(黄勇) 
160c9a58d71SChuan Zheng static void update_dirtyrate_stat(struct RamblockDirtyInfo *info)
161c9a58d71SChuan Zheng {
16271864eadSHyman Huang(黄勇)     DirtyStat.page_sampling.total_dirty_samples += info->sample_dirty_count;
16371864eadSHyman Huang(黄勇)     DirtyStat.page_sampling.total_sample_count += info->sample_pages_count;
164c9a58d71SChuan Zheng     /* size of total pages in MB */
16571864eadSHyman Huang(黄勇)     DirtyStat.page_sampling.total_block_mem_MB += (info->ramblock_pages *
166c9a58d71SChuan Zheng                                                    TARGET_PAGE_SIZE) >> 20;
167c9a58d71SChuan Zheng }
168c9a58d71SChuan Zheng 
169c9a58d71SChuan Zheng static void update_dirtyrate(uint64_t msec)
170c9a58d71SChuan Zheng {
171c9a58d71SChuan Zheng     uint64_t dirtyrate;
17271864eadSHyman Huang(黄勇)     uint64_t total_dirty_samples = DirtyStat.page_sampling.total_dirty_samples;
17371864eadSHyman Huang(黄勇)     uint64_t total_sample_count = DirtyStat.page_sampling.total_sample_count;
17471864eadSHyman Huang(黄勇)     uint64_t total_block_mem_MB = DirtyStat.page_sampling.total_block_mem_MB;
175c9a58d71SChuan Zheng 
176c9a58d71SChuan Zheng     dirtyrate = total_dirty_samples * total_block_mem_MB *
177c9a58d71SChuan Zheng                 1000 / (total_sample_count * msec);
178c9a58d71SChuan Zheng 
179c9a58d71SChuan Zheng     DirtyStat.dirty_rate = dirtyrate;
180c9a58d71SChuan Zheng }
1817df3aa30SChuan Zheng 
182ba0e519fSChuan Zheng /*
183ba0e519fSChuan Zheng  * get hash result for the sampled memory with length of TARGET_PAGE_SIZE
184ba0e519fSChuan Zheng  * in ramblock, which starts from ramblock base address.
185ba0e519fSChuan Zheng  */
186ba0e519fSChuan Zheng static uint32_t get_ramblock_vfn_hash(struct RamblockDirtyInfo *info,
187ba0e519fSChuan Zheng                                       uint64_t vfn)
188ba0e519fSChuan Zheng {
189ba0e519fSChuan Zheng     uint32_t crc;
190ba0e519fSChuan Zheng 
191ba0e519fSChuan Zheng     crc = crc32(0, (info->ramblock_addr +
192ba0e519fSChuan Zheng                 vfn * TARGET_PAGE_SIZE), TARGET_PAGE_SIZE);
193ba0e519fSChuan Zheng 
1943c0b5dffSChuan Zheng     trace_get_ramblock_vfn_hash(info->idstr, vfn, crc);
195ba0e519fSChuan Zheng     return crc;
196ba0e519fSChuan Zheng }
197ba0e519fSChuan Zheng 
198ba0e519fSChuan Zheng static bool save_ramblock_hash(struct RamblockDirtyInfo *info)
199ba0e519fSChuan Zheng {
200ba0e519fSChuan Zheng     unsigned int sample_pages_count;
201ba0e519fSChuan Zheng     int i;
202ba0e519fSChuan Zheng     GRand *rand;
203ba0e519fSChuan Zheng 
204ba0e519fSChuan Zheng     sample_pages_count = info->sample_pages_count;
205ba0e519fSChuan Zheng 
206ba0e519fSChuan Zheng     /* ramblock size less than one page, return success to skip this ramblock */
207ba0e519fSChuan Zheng     if (unlikely(info->ramblock_pages == 0 || sample_pages_count == 0)) {
208ba0e519fSChuan Zheng         return true;
209ba0e519fSChuan Zheng     }
210ba0e519fSChuan Zheng 
211ba0e519fSChuan Zheng     info->hash_result = g_try_malloc0_n(sample_pages_count,
212ba0e519fSChuan Zheng                                         sizeof(uint32_t));
213ba0e519fSChuan Zheng     if (!info->hash_result) {
214ba0e519fSChuan Zheng         return false;
215ba0e519fSChuan Zheng     }
216ba0e519fSChuan Zheng 
217ba0e519fSChuan Zheng     info->sample_page_vfn = g_try_malloc0_n(sample_pages_count,
218ba0e519fSChuan Zheng                                             sizeof(uint64_t));
219ba0e519fSChuan Zheng     if (!info->sample_page_vfn) {
220ba0e519fSChuan Zheng         g_free(info->hash_result);
221ba0e519fSChuan Zheng         return false;
222ba0e519fSChuan Zheng     }
223ba0e519fSChuan Zheng 
224ba0e519fSChuan Zheng     rand  = g_rand_new();
225ba0e519fSChuan Zheng     for (i = 0; i < sample_pages_count; i++) {
226ba0e519fSChuan Zheng         info->sample_page_vfn[i] = g_rand_int_range(rand, 0,
227ba0e519fSChuan Zheng                                                     info->ramblock_pages - 1);
228ba0e519fSChuan Zheng         info->hash_result[i] = get_ramblock_vfn_hash(info,
229ba0e519fSChuan Zheng                                                      info->sample_page_vfn[i]);
230ba0e519fSChuan Zheng     }
231ba0e519fSChuan Zheng     g_rand_free(rand);
232ba0e519fSChuan Zheng 
233ba0e519fSChuan Zheng     return true;
234ba0e519fSChuan Zheng }
235ba0e519fSChuan Zheng 
236ba0e519fSChuan Zheng static void get_ramblock_dirty_info(RAMBlock *block,
237ba0e519fSChuan Zheng                                     struct RamblockDirtyInfo *info,
238ba0e519fSChuan Zheng                                     struct DirtyRateConfig *config)
239ba0e519fSChuan Zheng {
240ba0e519fSChuan Zheng     uint64_t sample_pages_per_gigabytes = config->sample_pages_per_gigabytes;
241ba0e519fSChuan Zheng 
242ba0e519fSChuan Zheng     /* Right shift 30 bits to calc ramblock size in GB */
243ba0e519fSChuan Zheng     info->sample_pages_count = (qemu_ram_get_used_length(block) *
244ba0e519fSChuan Zheng                                 sample_pages_per_gigabytes) >> 30;
245ba0e519fSChuan Zheng     /* Right shift TARGET_PAGE_BITS to calc page count */
246ba0e519fSChuan Zheng     info->ramblock_pages = qemu_ram_get_used_length(block) >>
247ba0e519fSChuan Zheng                            TARGET_PAGE_BITS;
248ba0e519fSChuan Zheng     info->ramblock_addr = qemu_ram_get_host_addr(block);
249ba0e519fSChuan Zheng     strcpy(info->idstr, qemu_ram_get_idstr(block));
250ba0e519fSChuan Zheng }
251ba0e519fSChuan Zheng 
252cf0bbb49SChuan Zheng static void free_ramblock_dirty_info(struct RamblockDirtyInfo *infos, int count)
253cf0bbb49SChuan Zheng {
254cf0bbb49SChuan Zheng     int i;
255cf0bbb49SChuan Zheng 
256cf0bbb49SChuan Zheng     if (!infos) {
257cf0bbb49SChuan Zheng         return;
258cf0bbb49SChuan Zheng     }
259cf0bbb49SChuan Zheng 
260cf0bbb49SChuan Zheng     for (i = 0; i < count; i++) {
261cf0bbb49SChuan Zheng         g_free(infos[i].sample_page_vfn);
262cf0bbb49SChuan Zheng         g_free(infos[i].hash_result);
263cf0bbb49SChuan Zheng     }
264cf0bbb49SChuan Zheng     g_free(infos);
265cf0bbb49SChuan Zheng }
266cf0bbb49SChuan Zheng 
267f82583cdSChuan Zheng static bool skip_sample_ramblock(RAMBlock *block)
268f82583cdSChuan Zheng {
269f82583cdSChuan Zheng     /*
270f82583cdSChuan Zheng      * Sample only blocks larger than MIN_RAMBLOCK_SIZE.
271f82583cdSChuan Zheng      */
272f82583cdSChuan Zheng     if (qemu_ram_get_used_length(block) < (MIN_RAMBLOCK_SIZE << 10)) {
2733c0b5dffSChuan Zheng         trace_skip_sample_ramblock(block->idstr,
2743c0b5dffSChuan Zheng                                    qemu_ram_get_used_length(block));
275f82583cdSChuan Zheng         return true;
276f82583cdSChuan Zheng     }
277f82583cdSChuan Zheng 
278f82583cdSChuan Zheng     return false;
279f82583cdSChuan Zheng }
280f82583cdSChuan Zheng 
281ba0e519fSChuan Zheng static bool record_ramblock_hash_info(struct RamblockDirtyInfo **block_dinfo,
282ba0e519fSChuan Zheng                                       struct DirtyRateConfig config,
283ba0e519fSChuan Zheng                                       int *block_count)
284ba0e519fSChuan Zheng {
285ba0e519fSChuan Zheng     struct RamblockDirtyInfo *info = NULL;
286ba0e519fSChuan Zheng     struct RamblockDirtyInfo *dinfo = NULL;
287ba0e519fSChuan Zheng     RAMBlock *block = NULL;
288ba0e519fSChuan Zheng     int total_count = 0;
289ba0e519fSChuan Zheng     int index = 0;
290ba0e519fSChuan Zheng     bool ret = false;
291ba0e519fSChuan Zheng 
292ba0e519fSChuan Zheng     RAMBLOCK_FOREACH_MIGRATABLE(block) {
293f82583cdSChuan Zheng         if (skip_sample_ramblock(block)) {
294f82583cdSChuan Zheng             continue;
295f82583cdSChuan Zheng         }
296ba0e519fSChuan Zheng         total_count++;
297ba0e519fSChuan Zheng     }
298ba0e519fSChuan Zheng 
299ba0e519fSChuan Zheng     dinfo = g_try_malloc0_n(total_count, sizeof(struct RamblockDirtyInfo));
300ba0e519fSChuan Zheng     if (dinfo == NULL) {
301ba0e519fSChuan Zheng         goto out;
302ba0e519fSChuan Zheng     }
303ba0e519fSChuan Zheng 
304ba0e519fSChuan Zheng     RAMBLOCK_FOREACH_MIGRATABLE(block) {
305f82583cdSChuan Zheng         if (skip_sample_ramblock(block)) {
306f82583cdSChuan Zheng             continue;
307f82583cdSChuan Zheng         }
308ba0e519fSChuan Zheng         if (index >= total_count) {
309ba0e519fSChuan Zheng             break;
310ba0e519fSChuan Zheng         }
311ba0e519fSChuan Zheng         info = &dinfo[index];
312ba0e519fSChuan Zheng         get_ramblock_dirty_info(block, info, &config);
313ba0e519fSChuan Zheng         if (!save_ramblock_hash(info)) {
314ba0e519fSChuan Zheng             goto out;
315ba0e519fSChuan Zheng         }
316ba0e519fSChuan Zheng         index++;
317ba0e519fSChuan Zheng     }
318ba0e519fSChuan Zheng     ret = true;
319ba0e519fSChuan Zheng 
320ba0e519fSChuan Zheng out:
321ba0e519fSChuan Zheng     *block_count = index;
322ba0e519fSChuan Zheng     *block_dinfo = dinfo;
323ba0e519fSChuan Zheng     return ret;
324ba0e519fSChuan Zheng }
325ba0e519fSChuan Zheng 
3269c04387bSChuan Zheng static void calc_page_dirty_rate(struct RamblockDirtyInfo *info)
3279c04387bSChuan Zheng {
3289c04387bSChuan Zheng     uint32_t crc;
3299c04387bSChuan Zheng     int i;
3309c04387bSChuan Zheng 
3319c04387bSChuan Zheng     for (i = 0; i < info->sample_pages_count; i++) {
3329c04387bSChuan Zheng         crc = get_ramblock_vfn_hash(info, info->sample_page_vfn[i]);
3339c04387bSChuan Zheng         if (crc != info->hash_result[i]) {
3343c0b5dffSChuan Zheng             trace_calc_page_dirty_rate(info->idstr, crc, info->hash_result[i]);
3359c04387bSChuan Zheng             info->sample_dirty_count++;
3369c04387bSChuan Zheng         }
3379c04387bSChuan Zheng     }
3389c04387bSChuan Zheng }
3399c04387bSChuan Zheng 
3409c04387bSChuan Zheng static struct RamblockDirtyInfo *
3419c04387bSChuan Zheng find_block_matched(RAMBlock *block, int count,
3429c04387bSChuan Zheng                   struct RamblockDirtyInfo *infos)
3439c04387bSChuan Zheng {
3449c04387bSChuan Zheng     int i;
3459c04387bSChuan Zheng     struct RamblockDirtyInfo *matched;
3469c04387bSChuan Zheng 
3479c04387bSChuan Zheng     for (i = 0; i < count; i++) {
3489c04387bSChuan Zheng         if (!strcmp(infos[i].idstr, qemu_ram_get_idstr(block))) {
3499c04387bSChuan Zheng             break;
3509c04387bSChuan Zheng         }
3519c04387bSChuan Zheng     }
3529c04387bSChuan Zheng 
3539c04387bSChuan Zheng     if (i == count) {
3549c04387bSChuan Zheng         return NULL;
3559c04387bSChuan Zheng     }
3569c04387bSChuan Zheng 
3579c04387bSChuan Zheng     if (infos[i].ramblock_addr != qemu_ram_get_host_addr(block) ||
3589c04387bSChuan Zheng         infos[i].ramblock_pages !=
3599c04387bSChuan Zheng             (qemu_ram_get_used_length(block) >> TARGET_PAGE_BITS)) {
3603c0b5dffSChuan Zheng         trace_find_page_matched(block->idstr);
3619c04387bSChuan Zheng         return NULL;
3629c04387bSChuan Zheng     }
3639c04387bSChuan Zheng 
3649c04387bSChuan Zheng     matched = &infos[i];
3659c04387bSChuan Zheng 
3669c04387bSChuan Zheng     return matched;
3679c04387bSChuan Zheng }
3689c04387bSChuan Zheng 
3699c04387bSChuan Zheng static bool compare_page_hash_info(struct RamblockDirtyInfo *info,
3709c04387bSChuan Zheng                                   int block_count)
3719c04387bSChuan Zheng {
3729c04387bSChuan Zheng     struct RamblockDirtyInfo *block_dinfo = NULL;
3739c04387bSChuan Zheng     RAMBlock *block = NULL;
3749c04387bSChuan Zheng 
3759c04387bSChuan Zheng     RAMBLOCK_FOREACH_MIGRATABLE(block) {
376f82583cdSChuan Zheng         if (skip_sample_ramblock(block)) {
377f82583cdSChuan Zheng             continue;
378f82583cdSChuan Zheng         }
3799c04387bSChuan Zheng         block_dinfo = find_block_matched(block, block_count, info);
3809c04387bSChuan Zheng         if (block_dinfo == NULL) {
3819c04387bSChuan Zheng             continue;
3829c04387bSChuan Zheng         }
3839c04387bSChuan Zheng         calc_page_dirty_rate(block_dinfo);
3849c04387bSChuan Zheng         update_dirtyrate_stat(block_dinfo);
3859c04387bSChuan Zheng     }
3869c04387bSChuan Zheng 
38771864eadSHyman Huang(黄勇)     if (DirtyStat.page_sampling.total_sample_count == 0) {
3889c04387bSChuan Zheng         return false;
3899c04387bSChuan Zheng     }
3909c04387bSChuan Zheng 
3919c04387bSChuan Zheng     return true;
3929c04387bSChuan Zheng }
3939c04387bSChuan Zheng 
3940e21bf24SHyman Huang(黄勇) static inline void record_dirtypages(DirtyPageRecord *dirty_pages,
3950e21bf24SHyman Huang(黄勇)                                      CPUState *cpu, bool start)
3960e21bf24SHyman Huang(黄勇) {
3970e21bf24SHyman Huang(黄勇)     if (start) {
3980e21bf24SHyman Huang(黄勇)         dirty_pages[cpu->cpu_index].start_pages = cpu->dirty_pages;
3990e21bf24SHyman Huang(黄勇)     } else {
4000e21bf24SHyman Huang(黄勇)         dirty_pages[cpu->cpu_index].end_pages = cpu->dirty_pages;
4010e21bf24SHyman Huang(黄勇)     }
4020e21bf24SHyman Huang(黄勇) }
4030e21bf24SHyman Huang(黄勇) 
4040e21bf24SHyman Huang(黄勇) static void dirtyrate_global_dirty_log_start(void)
4050e21bf24SHyman Huang(黄勇) {
4060e21bf24SHyman Huang(黄勇)     qemu_mutex_lock_iothread();
4070e21bf24SHyman Huang(黄勇)     memory_global_dirty_log_start(GLOBAL_DIRTY_DIRTY_RATE);
4080e21bf24SHyman Huang(黄勇)     qemu_mutex_unlock_iothread();
4090e21bf24SHyman Huang(黄勇) }
4100e21bf24SHyman Huang(黄勇) 
4110e21bf24SHyman Huang(黄勇) static void dirtyrate_global_dirty_log_stop(void)
4120e21bf24SHyman Huang(黄勇) {
4130e21bf24SHyman Huang(黄勇)     qemu_mutex_lock_iothread();
4140e21bf24SHyman Huang(黄勇)     memory_global_dirty_log_sync();
4150e21bf24SHyman Huang(黄勇)     memory_global_dirty_log_stop(GLOBAL_DIRTY_DIRTY_RATE);
4160e21bf24SHyman Huang(黄勇)     qemu_mutex_unlock_iothread();
4170e21bf24SHyman Huang(黄勇) }
4180e21bf24SHyman Huang(黄勇) 
4190e21bf24SHyman Huang(黄勇) static int64_t do_calculate_dirtyrate_vcpu(DirtyPageRecord dirty_pages)
4200e21bf24SHyman Huang(黄勇) {
4210e21bf24SHyman Huang(黄勇)     uint64_t memory_size_MB;
4220e21bf24SHyman Huang(黄勇)     int64_t time_s;
4230e21bf24SHyman Huang(黄勇)     uint64_t increased_dirty_pages =
4240e21bf24SHyman Huang(黄勇)         dirty_pages.end_pages - dirty_pages.start_pages;
4250e21bf24SHyman Huang(黄勇) 
4260e21bf24SHyman Huang(黄勇)     memory_size_MB = (increased_dirty_pages * TARGET_PAGE_SIZE) >> 20;
4270e21bf24SHyman Huang(黄勇)     time_s = DirtyStat.calc_time;
4280e21bf24SHyman Huang(黄勇) 
4290e21bf24SHyman Huang(黄勇)     return memory_size_MB / time_s;
4300e21bf24SHyman Huang(黄勇) }
4310e21bf24SHyman Huang(黄勇) 
4320e21bf24SHyman Huang(黄勇) static void calculate_dirtyrate_dirty_ring(struct DirtyRateConfig config)
4330e21bf24SHyman Huang(黄勇) {
4340e21bf24SHyman Huang(黄勇)     CPUState *cpu;
4350e21bf24SHyman Huang(黄勇)     int64_t msec = 0;
4360e21bf24SHyman Huang(黄勇)     int64_t start_time;
4370e21bf24SHyman Huang(黄勇)     uint64_t dirtyrate = 0;
4380e21bf24SHyman Huang(黄勇)     uint64_t dirtyrate_sum = 0;
4390e21bf24SHyman Huang(黄勇)     DirtyPageRecord *dirty_pages;
4400e21bf24SHyman Huang(黄勇)     int nvcpu = 0;
4410e21bf24SHyman Huang(黄勇)     int i = 0;
4420e21bf24SHyman Huang(黄勇) 
4430e21bf24SHyman Huang(黄勇)     CPU_FOREACH(cpu) {
4440e21bf24SHyman Huang(黄勇)         nvcpu++;
4450e21bf24SHyman Huang(黄勇)     }
4460e21bf24SHyman Huang(黄勇) 
4470e21bf24SHyman Huang(黄勇)     dirty_pages = malloc(sizeof(*dirty_pages) * nvcpu);
4480e21bf24SHyman Huang(黄勇) 
4490e21bf24SHyman Huang(黄勇)     DirtyStat.dirty_ring.nvcpu = nvcpu;
4500e21bf24SHyman Huang(黄勇)     DirtyStat.dirty_ring.rates = malloc(sizeof(DirtyRateVcpu) * nvcpu);
4510e21bf24SHyman Huang(黄勇) 
4520e21bf24SHyman Huang(黄勇)     dirtyrate_global_dirty_log_start();
4530e21bf24SHyman Huang(黄勇) 
4540e21bf24SHyman Huang(黄勇)     CPU_FOREACH(cpu) {
4550e21bf24SHyman Huang(黄勇)         record_dirtypages(dirty_pages, cpu, true);
4560e21bf24SHyman Huang(黄勇)     }
4570e21bf24SHyman Huang(黄勇) 
4580e21bf24SHyman Huang(黄勇)     start_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
4590e21bf24SHyman Huang(黄勇)     DirtyStat.start_time = start_time / 1000;
4600e21bf24SHyman Huang(黄勇) 
4610e21bf24SHyman Huang(黄勇)     msec = config.sample_period_seconds * 1000;
4620e21bf24SHyman Huang(黄勇)     msec = set_sample_page_period(msec, start_time);
4630e21bf24SHyman Huang(黄勇)     DirtyStat.calc_time = msec / 1000;
4640e21bf24SHyman Huang(黄勇) 
4650e21bf24SHyman Huang(黄勇)     dirtyrate_global_dirty_log_stop();
4660e21bf24SHyman Huang(黄勇) 
4670e21bf24SHyman Huang(黄勇)     CPU_FOREACH(cpu) {
4680e21bf24SHyman Huang(黄勇)         record_dirtypages(dirty_pages, cpu, false);
4690e21bf24SHyman Huang(黄勇)     }
4700e21bf24SHyman Huang(黄勇) 
4710e21bf24SHyman Huang(黄勇)     for (i = 0; i < DirtyStat.dirty_ring.nvcpu; i++) {
4720e21bf24SHyman Huang(黄勇)         dirtyrate = do_calculate_dirtyrate_vcpu(dirty_pages[i]);
4730e21bf24SHyman Huang(黄勇)         trace_dirtyrate_do_calculate_vcpu(i, dirtyrate);
4740e21bf24SHyman Huang(黄勇) 
4750e21bf24SHyman Huang(黄勇)         DirtyStat.dirty_ring.rates[i].id = i;
4760e21bf24SHyman Huang(黄勇)         DirtyStat.dirty_ring.rates[i].dirty_rate = dirtyrate;
4770e21bf24SHyman Huang(黄勇)         dirtyrate_sum += dirtyrate;
4780e21bf24SHyman Huang(黄勇)     }
4790e21bf24SHyman Huang(黄勇) 
4800e21bf24SHyman Huang(黄勇)     DirtyStat.dirty_rate = dirtyrate_sum;
4810e21bf24SHyman Huang(黄勇)     free(dirty_pages);
4820e21bf24SHyman Huang(黄勇) }
4830e21bf24SHyman Huang(黄勇) 
4840e21bf24SHyman Huang(黄勇) static void calculate_dirtyrate_sample_vm(struct DirtyRateConfig config)
4854240dceeSChuan Zheng {
486cf0bbb49SChuan Zheng     struct RamblockDirtyInfo *block_dinfo = NULL;
487cf0bbb49SChuan Zheng     int block_count = 0;
488cf0bbb49SChuan Zheng     int64_t msec = 0;
489cf0bbb49SChuan Zheng     int64_t initial_time;
490cf0bbb49SChuan Zheng 
491cf0bbb49SChuan Zheng     rcu_read_lock();
492cf0bbb49SChuan Zheng     initial_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
493cf0bbb49SChuan Zheng     if (!record_ramblock_hash_info(&block_dinfo, config, &block_count)) {
494cf0bbb49SChuan Zheng         goto out;
495cf0bbb49SChuan Zheng     }
496cf0bbb49SChuan Zheng     rcu_read_unlock();
497cf0bbb49SChuan Zheng 
498cf0bbb49SChuan Zheng     msec = config.sample_period_seconds * 1000;
499cf0bbb49SChuan Zheng     msec = set_sample_page_period(msec, initial_time);
5004c437254SChuan Zheng     DirtyStat.start_time = initial_time / 1000;
5014c437254SChuan Zheng     DirtyStat.calc_time = msec / 1000;
502cf0bbb49SChuan Zheng 
503cf0bbb49SChuan Zheng     rcu_read_lock();
504cf0bbb49SChuan Zheng     if (!compare_page_hash_info(block_dinfo, block_count)) {
505cf0bbb49SChuan Zheng         goto out;
506cf0bbb49SChuan Zheng     }
507cf0bbb49SChuan Zheng 
508cf0bbb49SChuan Zheng     update_dirtyrate(msec);
509cf0bbb49SChuan Zheng 
510cf0bbb49SChuan Zheng out:
511cf0bbb49SChuan Zheng     rcu_read_unlock();
512cf0bbb49SChuan Zheng     free_ramblock_dirty_info(block_dinfo, block_count);
5134240dceeSChuan Zheng }
5144240dceeSChuan Zheng 
5150e21bf24SHyman Huang(黄勇) static void calculate_dirtyrate(struct DirtyRateConfig config)
5160e21bf24SHyman Huang(黄勇) {
5170e21bf24SHyman Huang(黄勇)     if (config.mode == DIRTY_RATE_MEASURE_MODE_DIRTY_RING) {
5180e21bf24SHyman Huang(黄勇)         calculate_dirtyrate_dirty_ring(config);
5190e21bf24SHyman Huang(黄勇)     } else {
5200e21bf24SHyman Huang(黄勇)         calculate_dirtyrate_sample_vm(config);
5210e21bf24SHyman Huang(黄勇)     }
5220e21bf24SHyman Huang(黄勇) 
5230e21bf24SHyman Huang(黄勇)     trace_dirtyrate_calculate(DirtyStat.dirty_rate);
5240e21bf24SHyman Huang(黄勇) }
5250e21bf24SHyman Huang(黄勇) 
5264240dceeSChuan Zheng void *get_dirtyrate_thread(void *arg)
5274240dceeSChuan Zheng {
5284240dceeSChuan Zheng     struct DirtyRateConfig config = *(struct DirtyRateConfig *)arg;
5297df3aa30SChuan Zheng     int ret;
53015eb2d64SHyman Huang(黄勇)     rcu_register_thread();
5317df3aa30SChuan Zheng 
5327df3aa30SChuan Zheng     ret = dirtyrate_set_state(&CalculatingState, DIRTY_RATE_STATUS_UNSTARTED,
5337df3aa30SChuan Zheng                               DIRTY_RATE_STATUS_MEASURING);
5347df3aa30SChuan Zheng     if (ret == -1) {
5357df3aa30SChuan Zheng         error_report("change dirtyrate state failed.");
5367df3aa30SChuan Zheng         return NULL;
5377df3aa30SChuan Zheng     }
5384240dceeSChuan Zheng 
5394240dceeSChuan Zheng     calculate_dirtyrate(config);
5404240dceeSChuan Zheng 
5417df3aa30SChuan Zheng     ret = dirtyrate_set_state(&CalculatingState, DIRTY_RATE_STATUS_MEASURING,
5427df3aa30SChuan Zheng                               DIRTY_RATE_STATUS_MEASURED);
5437df3aa30SChuan Zheng     if (ret == -1) {
5447df3aa30SChuan Zheng         error_report("change dirtyrate state failed.");
5457df3aa30SChuan Zheng     }
54615eb2d64SHyman Huang(黄勇) 
54715eb2d64SHyman Huang(黄勇)     rcu_unregister_thread();
5484240dceeSChuan Zheng     return NULL;
5494240dceeSChuan Zheng }
5504c437254SChuan Zheng 
5510e21bf24SHyman Huang(黄勇) void qmp_calc_dirty_rate(int64_t calc_time,
5520e21bf24SHyman Huang(黄勇)                          bool has_sample_pages,
5530e21bf24SHyman Huang(黄勇)                          int64_t sample_pages,
5540e21bf24SHyman Huang(黄勇)                          bool has_mode,
5550e21bf24SHyman Huang(黄勇)                          DirtyRateMeasureMode mode,
5560e21bf24SHyman Huang(黄勇)                          Error **errp)
5574c437254SChuan Zheng {
5584c437254SChuan Zheng     static struct DirtyRateConfig config;
5594c437254SChuan Zheng     QemuThread thread;
5604c437254SChuan Zheng     int ret;
5619865d0f6SHyman Huang(黄勇)     int64_t start_time;
5624c437254SChuan Zheng 
5634c437254SChuan Zheng     /*
5644c437254SChuan Zheng      * If the dirty rate is already being measured, don't attempt to start.
5654c437254SChuan Zheng      */
5664c437254SChuan Zheng     if (qatomic_read(&CalculatingState) == DIRTY_RATE_STATUS_MEASURING) {
5674c437254SChuan Zheng         error_setg(errp, "the dirty rate is already being measured.");
5684c437254SChuan Zheng         return;
5694c437254SChuan Zheng     }
5704c437254SChuan Zheng 
5714c437254SChuan Zheng     if (!is_sample_period_valid(calc_time)) {
5724c437254SChuan Zheng         error_setg(errp, "calc-time is out of range[%d, %d].",
5734c437254SChuan Zheng                          MIN_FETCH_DIRTYRATE_TIME_SEC,
5744c437254SChuan Zheng                          MAX_FETCH_DIRTYRATE_TIME_SEC);
5754c437254SChuan Zheng         return;
5764c437254SChuan Zheng     }
5774c437254SChuan Zheng 
5780e21bf24SHyman Huang(黄勇)     if (!has_mode) {
5790e21bf24SHyman Huang(黄勇)         mode =  DIRTY_RATE_MEASURE_MODE_PAGE_SAMPLING;
5800e21bf24SHyman Huang(黄勇)     }
5810e21bf24SHyman Huang(黄勇) 
5820e21bf24SHyman Huang(黄勇)     if (has_sample_pages && mode == DIRTY_RATE_MEASURE_MODE_DIRTY_RING) {
5830e21bf24SHyman Huang(黄勇)         error_setg(errp, "either sample-pages or dirty-ring can be specified.");
5840e21bf24SHyman Huang(黄勇)         return;
5850e21bf24SHyman Huang(黄勇)     }
5860e21bf24SHyman Huang(黄勇) 
5877afa08cdSHyman Huang(黄勇)     if (has_sample_pages) {
5887afa08cdSHyman Huang(黄勇)         if (!is_sample_pages_valid(sample_pages)) {
5897afa08cdSHyman Huang(黄勇)             error_setg(errp, "sample-pages is out of range[%d, %d].",
5907afa08cdSHyman Huang(黄勇)                             MIN_SAMPLE_PAGE_COUNT,
5917afa08cdSHyman Huang(黄勇)                             MAX_SAMPLE_PAGE_COUNT);
5927afa08cdSHyman Huang(黄勇)             return;
5937afa08cdSHyman Huang(黄勇)         }
5947afa08cdSHyman Huang(黄勇)     } else {
5957afa08cdSHyman Huang(黄勇)         sample_pages = DIRTYRATE_DEFAULT_SAMPLE_PAGES;
5967afa08cdSHyman Huang(黄勇)     }
5977afa08cdSHyman Huang(黄勇) 
5984c437254SChuan Zheng     /*
5990e21bf24SHyman Huang(黄勇)      * dirty ring mode only works when kvm dirty ring is enabled.
6000e21bf24SHyman Huang(黄勇)      */
6010e21bf24SHyman Huang(黄勇)     if ((mode == DIRTY_RATE_MEASURE_MODE_DIRTY_RING) &&
6020e21bf24SHyman Huang(黄勇)         !kvm_dirty_ring_enabled()) {
6030e21bf24SHyman Huang(黄勇)         error_setg(errp, "dirty ring is disabled, use sample-pages method "
6040e21bf24SHyman Huang(黄勇)                          "or remeasure later.");
6050e21bf24SHyman Huang(黄勇)         return;
6060e21bf24SHyman Huang(黄勇)     }
6070e21bf24SHyman Huang(黄勇) 
6080e21bf24SHyman Huang(黄勇)     /*
6094c437254SChuan Zheng      * Init calculation state as unstarted.
6104c437254SChuan Zheng      */
6114c437254SChuan Zheng     ret = dirtyrate_set_state(&CalculatingState, CalculatingState,
6124c437254SChuan Zheng                               DIRTY_RATE_STATUS_UNSTARTED);
6134c437254SChuan Zheng     if (ret == -1) {
6144c437254SChuan Zheng         error_setg(errp, "init dirty rate calculation state failed.");
6154c437254SChuan Zheng         return;
6164c437254SChuan Zheng     }
6174c437254SChuan Zheng 
6184c437254SChuan Zheng     config.sample_period_seconds = calc_time;
6197afa08cdSHyman Huang(黄勇)     config.sample_pages_per_gigabytes = sample_pages;
6200e21bf24SHyman Huang(黄勇)     config.mode = mode;
6210e21bf24SHyman Huang(黄勇) 
6220e21bf24SHyman Huang(黄勇)     cleanup_dirtyrate_stat(config);
6230e21bf24SHyman Huang(黄勇) 
6240e21bf24SHyman Huang(黄勇)     /*
6250e21bf24SHyman Huang(黄勇)      * update dirty rate mode so that we can figure out what mode has
6260e21bf24SHyman Huang(黄勇)      * been used in last calculation
6270e21bf24SHyman Huang(黄勇)      **/
6280e21bf24SHyman Huang(黄勇)     dirtyrate_mode = mode;
6299865d0f6SHyman Huang(黄勇) 
6309865d0f6SHyman Huang(黄勇)     start_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME) / 1000;
6319865d0f6SHyman Huang(黄勇)     init_dirtyrate_stat(start_time, config);
6329865d0f6SHyman Huang(黄勇) 
6334c437254SChuan Zheng     qemu_thread_create(&thread, "get_dirtyrate", get_dirtyrate_thread,
6344c437254SChuan Zheng                        (void *)&config, QEMU_THREAD_DETACHED);
6354c437254SChuan Zheng }
6364c437254SChuan Zheng 
6374c437254SChuan Zheng struct DirtyRateInfo *qmp_query_dirty_rate(Error **errp)
6384c437254SChuan Zheng {
6394c437254SChuan Zheng     return query_dirty_rate_info();
6404c437254SChuan Zheng }
641a4a571d9SPeter Xu 
642a4a571d9SPeter Xu void hmp_info_dirty_rate(Monitor *mon, const QDict *qdict)
643a4a571d9SPeter Xu {
644a4a571d9SPeter Xu     DirtyRateInfo *info = query_dirty_rate_info();
645a4a571d9SPeter Xu 
646a4a571d9SPeter Xu     monitor_printf(mon, "Status: %s\n",
647a4a571d9SPeter Xu                    DirtyRateStatus_str(info->status));
648a4a571d9SPeter Xu     monitor_printf(mon, "Start Time: %"PRIi64" (ms)\n",
649a4a571d9SPeter Xu                    info->start_time);
650a4a571d9SPeter Xu     monitor_printf(mon, "Sample Pages: %"PRIu64" (per GB)\n",
651a4a571d9SPeter Xu                    info->sample_pages);
652a4a571d9SPeter Xu     monitor_printf(mon, "Period: %"PRIi64" (sec)\n",
653a4a571d9SPeter Xu                    info->calc_time);
6540e21bf24SHyman Huang(黄勇)     monitor_printf(mon, "Mode: %s\n",
6550e21bf24SHyman Huang(黄勇)                    DirtyRateMeasureMode_str(info->mode));
656a4a571d9SPeter Xu     monitor_printf(mon, "Dirty rate: ");
657a4a571d9SPeter Xu     if (info->has_dirty_rate) {
658a4a571d9SPeter Xu         monitor_printf(mon, "%"PRIi64" (MB/s)\n", info->dirty_rate);
6590e21bf24SHyman Huang(黄勇)         if (info->has_vcpu_dirty_rate) {
6600e21bf24SHyman Huang(黄勇)             DirtyRateVcpuList *rate, *head = info->vcpu_dirty_rate;
6610e21bf24SHyman Huang(黄勇)             for (rate = head; rate != NULL; rate = rate->next) {
6620e21bf24SHyman Huang(黄勇)                 monitor_printf(mon, "vcpu[%"PRIi64"], Dirty rate: %"PRIi64
6630e21bf24SHyman Huang(黄勇)                                " (MB/s)\n", rate->value->id,
6640e21bf24SHyman Huang(黄勇)                                rate->value->dirty_rate);
6650e21bf24SHyman Huang(黄勇)             }
6660e21bf24SHyman Huang(黄勇)         }
667a4a571d9SPeter Xu     } else {
668a4a571d9SPeter Xu         monitor_printf(mon, "(not ready)\n");
669a4a571d9SPeter Xu     }
6700e21bf24SHyman Huang(黄勇) 
6710e21bf24SHyman Huang(黄勇)     qapi_free_DirtyRateVcpuList(info->vcpu_dirty_rate);
672a4a571d9SPeter Xu     g_free(info);
673a4a571d9SPeter Xu }
674a4a571d9SPeter Xu 
675a4a571d9SPeter Xu void hmp_calc_dirty_rate(Monitor *mon, const QDict *qdict)
676a4a571d9SPeter Xu {
677a4a571d9SPeter Xu     int64_t sec = qdict_get_try_int(qdict, "second", 0);
678a4a571d9SPeter Xu     int64_t sample_pages = qdict_get_try_int(qdict, "sample_pages_per_GB", -1);
679a4a571d9SPeter Xu     bool has_sample_pages = (sample_pages != -1);
6800e21bf24SHyman Huang(黄勇)     bool dirty_ring = qdict_get_try_bool(qdict, "dirty_ring", false);
6810e21bf24SHyman Huang(黄勇)     DirtyRateMeasureMode mode =
6820e21bf24SHyman Huang(黄勇)         (dirty_ring ? DIRTY_RATE_MEASURE_MODE_DIRTY_RING :
6830e21bf24SHyman Huang(黄勇)          DIRTY_RATE_MEASURE_MODE_PAGE_SAMPLING);
684a4a571d9SPeter Xu     Error *err = NULL;
685a4a571d9SPeter Xu 
686a4a571d9SPeter Xu     if (!sec) {
687a4a571d9SPeter Xu         monitor_printf(mon, "Incorrect period length specified!\n");
688a4a571d9SPeter Xu         return;
689a4a571d9SPeter Xu     }
690a4a571d9SPeter Xu 
6910e21bf24SHyman Huang(黄勇)     qmp_calc_dirty_rate(sec, has_sample_pages, sample_pages, true,
6920e21bf24SHyman Huang(黄勇)                         mode, &err);
693a4a571d9SPeter Xu     if (err) {
694a4a571d9SPeter Xu         hmp_handle_error(mon, err);
695a4a571d9SPeter Xu         return;
696a4a571d9SPeter Xu     }
697a4a571d9SPeter Xu 
698a4a571d9SPeter Xu     monitor_printf(mon, "Starting dirty rate measurement with period %"PRIi64
699a4a571d9SPeter Xu                    " seconds\n", sec);
700a4a571d9SPeter Xu     monitor_printf(mon, "[Please use 'info dirty_rate' to check results]\n");
701a4a571d9SPeter Xu }
702