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