mirror of https://github.com/xemu-project/xemu.git
tests: Add migration dirty-limit capability test
Add migration dirty-limit capability test if kernel support dirty ring. Migration dirty-limit capability introduce dirty limit capability, two parameters: x-vcpu-dirty-limit-period and vcpu-dirty-limit are introduced to implement the live migration with dirty limit. The test case does the following things: 1. start src, dst vm and enable dirty-limit capability 2. start migrate and set cancel it to check if dirty limit stop working. 3. restart dst vm 4. start migrate and enable dirty-limit capability 5. check if migration satisfy the convergence condition during pre-switchover phase. Note that this test case involves many passes, so it runs in slow mode only. Signed-off-by: Hyman Huang <yong.huang@smartx.com> Acked-by: Peter Xu <peterx@redhat.com> Reviewed-by: Fabiano Rosas <farosas@suse.de> Reviewed-by: Juan Quintela <quintela@redhat.com> Signed-off-by: Juan Quintela <quintela@redhat.com> Message-ID: <e55a302df9da7dbc00ad825f47f57c1a756d303e.1698847223.git.yong.huang@smartx.com>
This commit is contained in:
parent
78a7ef1580
commit
17257b90be
|
@ -3091,6 +3091,166 @@ static void test_vcpu_dirty_limit(void)
|
||||||
dirtylimit_stop_vm(vm);
|
dirtylimit_stop_vm(vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void migrate_dirty_limit_wait_showup(QTestState *from,
|
||||||
|
const int64_t period,
|
||||||
|
const int64_t value)
|
||||||
|
{
|
||||||
|
/* Enable dirty limit capability */
|
||||||
|
migrate_set_capability(from, "dirty-limit", true);
|
||||||
|
|
||||||
|
/* Set dirty limit parameters */
|
||||||
|
migrate_set_parameter_int(from, "x-vcpu-dirty-limit-period", period);
|
||||||
|
migrate_set_parameter_int(from, "vcpu-dirty-limit", value);
|
||||||
|
|
||||||
|
/* Make sure migrate can't converge */
|
||||||
|
migrate_ensure_non_converge(from);
|
||||||
|
|
||||||
|
/* To check limit rate after precopy */
|
||||||
|
migrate_set_capability(from, "pause-before-switchover", true);
|
||||||
|
|
||||||
|
/* Wait for the serial output from the source */
|
||||||
|
wait_for_serial("src_serial");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This test does:
|
||||||
|
* source destination
|
||||||
|
* start vm
|
||||||
|
* start incoming vm
|
||||||
|
* migrate
|
||||||
|
* wait dirty limit to begin
|
||||||
|
* cancel migrate
|
||||||
|
* cancellation check
|
||||||
|
* restart incoming vm
|
||||||
|
* migrate
|
||||||
|
* wait dirty limit to begin
|
||||||
|
* wait pre-switchover event
|
||||||
|
* convergence condition check
|
||||||
|
*
|
||||||
|
* And see if dirty limit migration works correctly.
|
||||||
|
* This test case involves many passes, so it runs in slow mode only.
|
||||||
|
*/
|
||||||
|
static void test_migrate_dirty_limit(void)
|
||||||
|
{
|
||||||
|
g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
|
||||||
|
QTestState *from, *to;
|
||||||
|
int64_t remaining;
|
||||||
|
uint64_t throttle_us_per_full;
|
||||||
|
/*
|
||||||
|
* We want the test to be stable and as fast as possible.
|
||||||
|
* E.g., with 1Gb/s bandwith migration may pass without dirty limit,
|
||||||
|
* so we need to decrease a bandwidth.
|
||||||
|
*/
|
||||||
|
const int64_t dirtylimit_period = 1000, dirtylimit_value = 50;
|
||||||
|
const int64_t max_bandwidth = 400000000; /* ~400Mb/s */
|
||||||
|
const int64_t downtime_limit = 250; /* 250ms */
|
||||||
|
/*
|
||||||
|
* We migrate through unix-socket (> 500Mb/s).
|
||||||
|
* Thus, expected migration speed ~= bandwidth limit (< 500Mb/s).
|
||||||
|
* So, we can predict expected_threshold
|
||||||
|
*/
|
||||||
|
const int64_t expected_threshold = max_bandwidth * downtime_limit / 1000;
|
||||||
|
int max_try_count = 10;
|
||||||
|
MigrateCommon args = {
|
||||||
|
.start = {
|
||||||
|
.hide_stderr = true,
|
||||||
|
.use_dirty_ring = true,
|
||||||
|
},
|
||||||
|
.listen_uri = uri,
|
||||||
|
.connect_uri = uri,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Start src, dst vm */
|
||||||
|
if (test_migrate_start(&from, &to, args.listen_uri, &args.start)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Prepare for dirty limit migration and wait src vm show up */
|
||||||
|
migrate_dirty_limit_wait_showup(from, dirtylimit_period, dirtylimit_value);
|
||||||
|
|
||||||
|
/* Start migrate */
|
||||||
|
migrate_qmp(from, uri, "{}");
|
||||||
|
|
||||||
|
/* Wait for dirty limit throttle begin */
|
||||||
|
throttle_us_per_full = 0;
|
||||||
|
while (throttle_us_per_full == 0) {
|
||||||
|
throttle_us_per_full =
|
||||||
|
read_migrate_property_int(from, "dirty-limit-throttle-time-per-round");
|
||||||
|
usleep(100);
|
||||||
|
g_assert_false(got_src_stop);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now cancel migrate and wait for dirty limit throttle switch off */
|
||||||
|
migrate_cancel(from);
|
||||||
|
wait_for_migration_status(from, "cancelled", NULL);
|
||||||
|
|
||||||
|
/* Check if dirty limit throttle switched off, set timeout 1ms */
|
||||||
|
do {
|
||||||
|
throttle_us_per_full =
|
||||||
|
read_migrate_property_int(from, "dirty-limit-throttle-time-per-round");
|
||||||
|
usleep(100);
|
||||||
|
g_assert_false(got_src_stop);
|
||||||
|
} while (throttle_us_per_full != 0 && --max_try_count);
|
||||||
|
|
||||||
|
/* Assert dirty limit is not in service */
|
||||||
|
g_assert_cmpint(throttle_us_per_full, ==, 0);
|
||||||
|
|
||||||
|
args = (MigrateCommon) {
|
||||||
|
.start = {
|
||||||
|
.only_target = true,
|
||||||
|
.use_dirty_ring = true,
|
||||||
|
},
|
||||||
|
.listen_uri = uri,
|
||||||
|
.connect_uri = uri,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Restart dst vm, src vm already show up so we needn't wait anymore */
|
||||||
|
if (test_migrate_start(&from, &to, args.listen_uri, &args.start)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Start migrate */
|
||||||
|
migrate_qmp(from, uri, "{}");
|
||||||
|
|
||||||
|
/* Wait for dirty limit throttle begin */
|
||||||
|
throttle_us_per_full = 0;
|
||||||
|
while (throttle_us_per_full == 0) {
|
||||||
|
throttle_us_per_full =
|
||||||
|
read_migrate_property_int(from, "dirty-limit-throttle-time-per-round");
|
||||||
|
usleep(100);
|
||||||
|
g_assert_false(got_src_stop);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The dirty limit rate should equals the return value of
|
||||||
|
* query-vcpu-dirty-limit if dirty limit cap set
|
||||||
|
*/
|
||||||
|
g_assert_cmpint(dirtylimit_value, ==, get_limit_rate(from));
|
||||||
|
|
||||||
|
/* Now, we have tested if dirty limit works, let it converge */
|
||||||
|
migrate_set_parameter_int(from, "downtime-limit", downtime_limit);
|
||||||
|
migrate_set_parameter_int(from, "max-bandwidth", max_bandwidth);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Wait for pre-switchover status to check if migration
|
||||||
|
* satisfy the convergence condition
|
||||||
|
*/
|
||||||
|
wait_for_migration_status(from, "pre-switchover", NULL);
|
||||||
|
|
||||||
|
remaining = read_ram_property_int(from, "remaining");
|
||||||
|
g_assert_cmpint(remaining, <,
|
||||||
|
(expected_threshold + expected_threshold / 100));
|
||||||
|
|
||||||
|
migrate_continue(from, "pre-switchover");
|
||||||
|
|
||||||
|
qtest_qmp_eventwait(to, "RESUME");
|
||||||
|
|
||||||
|
wait_for_serial("dest_serial");
|
||||||
|
wait_for_migration_complete(from);
|
||||||
|
|
||||||
|
test_migrate_end(from, to, true);
|
||||||
|
}
|
||||||
|
|
||||||
static bool kvm_dirty_ring_supported(void)
|
static bool kvm_dirty_ring_supported(void)
|
||||||
{
|
{
|
||||||
#if defined(__linux__) && defined(HOST_X86_64)
|
#if defined(__linux__) && defined(HOST_X86_64)
|
||||||
|
@ -3301,6 +3461,10 @@ int main(int argc, char **argv)
|
||||||
*/
|
*/
|
||||||
if (g_test_slow()) {
|
if (g_test_slow()) {
|
||||||
qtest_add_func("/migration/auto_converge", test_migrate_auto_converge);
|
qtest_add_func("/migration/auto_converge", test_migrate_auto_converge);
|
||||||
|
if (g_str_equal(arch, "x86_64") &&
|
||||||
|
has_kvm && kvm_dirty_ring_supported()) {
|
||||||
|
qtest_add_func("/migration/dirty_limit", test_migrate_dirty_limit);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
qtest_add_func("/migration/multifd/tcp/plain/none",
|
qtest_add_func("/migration/multifd/tcp/plain/none",
|
||||||
test_multifd_tcp_none);
|
test_multifd_tcp_none);
|
||||||
|
|
Loading…
Reference in New Issue