34a68001f1
This patch allows to measure dirty page rate for sub-second intervals of time. An optional argument is introduced -- calc-time-unit. For example: {"execute": "calc-dirty-rate", "arguments": {"calc-time": 500, "calc-time-unit": "millisecond"} } Millisecond granularity allows to make predictions whether migration will succeed or not. To do this, calculate dirty rate with calc-time set to max allowed downtime (e.g. 300ms), convert measured rate into volume of dirtied memory, and divide by network throughput. If the value is lower than max allowed downtime, then migration will converge. Measurement results for single thread randomly writing to a 1/4/24GiB memory region: +----------------+-----------------------------------------------+ | calc-time | dirty rate MiB/s | | (milliseconds) +----------------+---------------+--------------+ | | theoretical | page-sampling | dirty-bitmap | | | (at 3M wr/sec) | | | +----------------+----------------+---------------+--------------+ | 1GiB | +----------------+----------------+---------------+--------------+ | 100 | 6996 | 7100 | 3192 | | 200 | 4606 | 4660 | 2655 | | 300 | 3305 | 3280 | 2371 | | 400 | 2534 | 2525 | 2154 | | 500 | 2041 | 2044 | 1871 | | 750 | 1365 | 1341 | 1358 | | 1000 | 1024 | 1052 | 1025 | | 1500 | 683 | 678 | 684 | | 2000 | 512 | 507 | 513 | +----------------+----------------+---------------+--------------+ | 4GiB | +----------------+----------------+---------------+--------------+ | 100 | 10232 | 8880 | 4070 | | 200 | 8954 | 8049 | 3195 | | 300 | 7889 | 7193 | 2881 | | 400 | 6996 | 6530 | 2700 | | 500 | 6245 | 5772 | 2312 | | 750 | 4829 | 4586 | 2465 | | 1000 | 3865 | 3780 | 2178 | | 1500 | 2694 | 2633 | 2004 | | 2000 | 2041 | 2031 | 1789 | +----------------+----------------+---------------+--------------+ | 24GiB | +----------------+----------------+---------------+--------------+ | 100 | 11495 | 8640 | 5597 | | 200 | 11226 | 8616 | 3527 | | 300 | 10965 | 8386 | 2355 | | 400 | 10713 | 8370 | 2179 | | 500 | 10469 | 8196 | 2098 | | 750 | 9890 | 7885 | 2556 | | 1000 | 9354 | 7506 | 2084 | | 1500 | 8397 | 6944 | 2075 | | 2000 | 7574 | 6402 | 2062 | +----------------+----------------+---------------+--------------+ Theoretical values are computed according to the following formula: size * (1 - (1-(4096/size))^(time*wps)) / (time * 2^20), where size is in bytes, time is in seconds, and wps is number of writes per second. Signed-off-by: Andrei Gudkov <gudkov.andrei@huawei.com> Reviewed-by: Hyman Huang <yong.huang@smartx.com> Message-Id: <d802e6b8053eb60fbec1a784cf86f67d9528e0a8.1693895970.git.gudkov.andrei@huawei.com> Signed-off-by: Hyman Huang <yong.huang@smartx.com>
88 lines
2.6 KiB
C
88 lines
2.6 KiB
C
/*
|
|
* Dirtyrate common functions
|
|
*
|
|
* Copyright (c) 2020 HUAWEI TECHNOLOGIES CO., LTD.
|
|
*
|
|
* Authors:
|
|
* Chuan Zheng <zhengchuan@huawei.com>
|
|
*
|
|
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
|
* See the COPYING file in the top-level directory.
|
|
*/
|
|
|
|
#ifndef QEMU_MIGRATION_DIRTYRATE_H
|
|
#define QEMU_MIGRATION_DIRTYRATE_H
|
|
|
|
#include "sysemu/dirtyrate.h"
|
|
|
|
/*
|
|
* Sample 512 pages per GB as default.
|
|
*/
|
|
#define DIRTYRATE_DEFAULT_SAMPLE_PAGES 512
|
|
|
|
/*
|
|
* Record ramblock idstr
|
|
*/
|
|
#define RAMBLOCK_INFO_MAX_LEN 256
|
|
|
|
/*
|
|
* Minimum RAMBlock size to sample, in megabytes.
|
|
*/
|
|
#define MIN_RAMBLOCK_SIZE 128
|
|
|
|
/*
|
|
* Allowed range for dirty page rate calculation (in milliseconds).
|
|
* Lower limit relates to the smallest realistic downtime it
|
|
* makes sense to impose on migration.
|
|
*/
|
|
#define MIN_CALC_TIME_MS 50
|
|
#define MAX_CALC_TIME_MS 60000
|
|
|
|
/*
|
|
* Take 1/16 pages in 1G as the maxmum sample page count
|
|
*/
|
|
#define MIN_SAMPLE_PAGE_COUNT 128
|
|
#define MAX_SAMPLE_PAGE_COUNT 16384
|
|
|
|
struct DirtyRateConfig {
|
|
uint64_t sample_pages_per_gigabytes; /* sample pages per GB */
|
|
int64_t calc_time_ms; /* desired calculation time (in milliseconds) */
|
|
DirtyRateMeasureMode mode; /* mode of dirtyrate measurement */
|
|
};
|
|
|
|
/*
|
|
* Store dirtypage info for each ramblock.
|
|
*/
|
|
struct RamblockDirtyInfo {
|
|
char idstr[RAMBLOCK_INFO_MAX_LEN]; /* idstr for each ramblock */
|
|
uint8_t *ramblock_addr; /* base address of ramblock we measure */
|
|
uint64_t ramblock_pages; /* ramblock size in TARGET_PAGE_SIZE */
|
|
uint64_t *sample_page_vfn; /* relative offset address for sampled page */
|
|
uint64_t sample_pages_count; /* count of sampled pages */
|
|
uint64_t sample_dirty_count; /* count of dirty pages we measure */
|
|
uint32_t *hash_result; /* array of hash result for sampled pages */
|
|
};
|
|
|
|
typedef struct SampleVMStat {
|
|
uint64_t total_dirty_samples; /* total dirty sampled page */
|
|
uint64_t total_sample_count; /* total sampled pages */
|
|
uint64_t total_block_mem_MB; /* size of total sampled pages in MB */
|
|
} SampleVMStat;
|
|
|
|
/*
|
|
* Store calculation statistics for each measure.
|
|
*/
|
|
struct DirtyRateStat {
|
|
int64_t dirty_rate; /* dirty rate in MB/s */
|
|
int64_t start_time; /* calculation start time in units of second */
|
|
int64_t calc_time_ms; /* actual calculation time (in milliseconds) */
|
|
uint64_t sample_pages; /* sample pages per GB */
|
|
union {
|
|
SampleVMStat page_sampling;
|
|
VcpuStat dirty_ring;
|
|
};
|
|
};
|
|
|
|
void *get_dirtyrate_thread(void *arg);
|
|
#endif
|