From f590f8ed3cfe8d1d4e6686de1a3377fe58db39e6 Mon Sep 17 00:00:00 2001 From: nick Date: Fri, 26 Jul 2013 11:50:01 +0100 Subject: [PATCH] status: Add migration_speed ( bytes per second ) and migration_duration( seconds ) to the migration output --- src/mirror.c | 10 +++++++++ src/mirror.h | 12 ++++++++++ src/status.c | 17 +++++++++++++++ src/status.h | 10 +++++++++ tests/unit/check_status.c | 46 +++++++++++++++++++++++++++++++-------- 5 files changed, 86 insertions(+), 9 deletions(-) diff --git a/src/mirror.c b/src/mirror.c index 71a4948..9bee6e2 100644 --- a/src/mirror.c +++ b/src/mirror.c @@ -106,6 +106,12 @@ void mirror_reset( struct mirror * mirror ) NULLCHECK( mirror->dirty_map ); mirror_set_state( mirror, MS_INIT ); bitset_set(mirror->dirty_map); + mirror->all_dirty = 0; + mirror->all_clean = 0; + mirror->pass = 0; + mirror->this_pass_dirty = 0; + mirror->this_pass_clean = 0; + mirror->migration_started = 0; } @@ -216,9 +222,11 @@ int mirror_pass(struct server * serve, int is_last_pass, uint64_t *written) if (!is_last_pass) { server_unlock_io( serve ); } m->this_pass_dirty += run; + m->all_dirty += run; *written += run; } else { m->this_pass_clean += run; + m->all_clean += run; } current += run; @@ -365,6 +373,8 @@ void mirror_run( struct server *serve ) uint64_t written; info("Starting mirror" ); + + m->migration_started = monotonic_time_ms(); for (m->pass=0; m->pass < mirror_maximum_passes-1; m->pass++) { m->this_pass_clean = 0; m->this_pass_dirty = 0; diff --git a/src/mirror.h b/src/mirror.h index 3300a4b..ec246f9 100644 --- a/src/mirror.h +++ b/src/mirror.h @@ -67,7 +67,11 @@ struct mirror { union mysockaddr * connect_from; int client; const char * filename; + + /* Not used yet. Will be a limiter, used to restrict migration speed. + * only dirty bytes (those going over the network) will be considered */ off64_t max_bytes_per_second; + enum mirror_finish_action action_at_finish; char *mapped; @@ -83,6 +87,14 @@ struct mirror { /* The current mirror pass. We put this here so status can query it */ int pass; + /* Number of dirty and clean bytes for the entire migration */ + uint64_t all_dirty; + uint64_t all_clean; + + /* The time (from monotonic_time_ms()) the migration was started. Can be + * used to calculate bps, etc. */ + uint64_t migration_started; + /* The number of dirty (had to send to dest) and clean (could skip) bytes * for this pass. Add them together and subtract from size to get remaining * bytes. */ diff --git a/src/status.c b/src/status.c index 841d47f..06e6620 100644 --- a/src/status.c +++ b/src/status.c @@ -19,8 +19,23 @@ struct status * status_create( struct server * serve ) status->migration_pass = serve->mirror->pass; status->pass_dirty_bytes = serve->mirror->this_pass_dirty; status->pass_clean_bytes = serve->mirror->this_pass_clean; + + status->migration_duration = monotonic_time_ms(); + + if ( ( serve->mirror->migration_started ) < status->migration_duration ) { + status->migration_duration -= serve->mirror->migration_started; + } else { + status->migration_duration = 0; + } + status->migration_duration /= 1000; + + status->migration_speed = serve->mirror->all_dirty / ( status->migration_duration + 1 ); + + } + + server_unlock_start_mirror( serve ); return status; @@ -46,6 +61,8 @@ int status_write( struct status * status, int fd ) PRINT_INT( migration_pass ); PRINT_UINT64( pass_dirty_bytes ); PRINT_UINT64( pass_clean_bytes ); + PRINT_UINT64( migration_speed ); + PRINT_UINT64( migration_duration ); } dprintf(fd, "\n"); diff --git a/src/status.h b/src/status.h index d2cc67e..761635f 100644 --- a/src/status.h +++ b/src/status.h @@ -41,6 +41,13 @@ * If is_migrating is true, then a number of other attributes may appear, * relating to the progress of the migration. * + * migration_duration: + * How long the migration has been running for, in ms. + * + * migration_speed: + * Network transfer speed, in bytes/second. This only takes dirty bytes + * into account. + * * migration_pass: * When migrating, we perform a number of passes over the file. This indicates * the current pass. @@ -53,6 +60,7 @@ * For the current pass, how many clean bytes? These are bytes we don't need * to send to the destination. Once all the bytes are clean, the migration is * done. + * */ @@ -70,6 +78,8 @@ struct status { uint64_t pass_dirty_bytes; uint64_t pass_clean_bytes; + uint64_t migration_duration; + uint64_t migration_speed; }; /** Create a status object for the given server. */ diff --git a/tests/unit/check_status.c b/tests/unit/check_status.c index ebbb198..fc8bb9b 100644 --- a/tests/unit/check_status.c +++ b/tests/unit/check_status.c @@ -119,17 +119,34 @@ START_TEST( test_gets_size ) } END_TEST -START_TEST( test_gets_pass_statistics ) +START_TEST( test_gets_migration_statistics ) { struct server * server = mock_mirroring_server(); server->mirror->this_pass_clean = 2048; server->mirror->this_pass_dirty = 4096; + server->mirror->all_dirty = 16384; + + /* we have a bit of a time dependency here */ + server->mirror->migration_started = monotonic_time_ms(); struct status * status = status_create( server ); fail_unless( 2048 == status->pass_clean_bytes, "pass_clean_bytes wasn't gathered" ); fail_unless( 4096 == status->pass_dirty_bytes, "pass_dirty_bytes wasn't gathered" ); + fail_unless ( + 0 == status->migration_duration || + 1 == status->migration_duration || + 2 == status->migration_duration, + "migration_duration is unreasonable!" + ); + + fail_unless( + 16384 / ( status->migration_duration + 1 ) == status->migration_speed, + "migration_speed not calculated correctly" + ); + + status_destroy( status ); destroy_mock_server( server ); } @@ -255,7 +272,7 @@ START_TEST( test_renders_migration_pass ) } END_TEST -START_TEST( test_renders_pass_statistics ) +START_TEST( test_renders_migration_statistics ) { struct status status; int fds[2]; @@ -266,15 +283,23 @@ START_TEST( test_renders_pass_statistics ) status.is_mirroring = 0; status.pass_dirty_bytes = 2048; status.pass_clean_bytes = 4096; + status.migration_duration = 8; + status.migration_speed = 40000000; + status_write( &status, fds[1] ); fail_unless( read_until_newline( fds[0], buf, 1024 ) > 0, "Couldn't read the result" ); found = strstr( buf, "pass_dirty_bytes" ); - fail_if( NULL != found, "migration pass output when not migrating" ); + fail_if( NULL != found, "pass_dirty_bytes output when not migrating" ); found = strstr( buf, "pass_clean_bytes" ); - fail_if( NULL != found, "migration pass output when not migrating" ); + fail_if( NULL != found, "pass_clean_bytes output when not migrating" ); + + found = strstr( buf, "migration_duration" ); + fail_if( NULL != found, "migration_duration output when not migrating" ); + found = strstr( buf, "migration_speed" ); + fail_if( NULL != found, "migration_speed output when not migrating" ); status.is_mirroring = 1; status_write( &status, fds[1] ); @@ -282,10 +307,13 @@ START_TEST( test_renders_pass_statistics ) fail_unless( read_until_newline( fds[0], buf, 1024 ) > 0, "Couldn't read the result" ); found = strstr( buf, "pass_dirty_bytes=2048" ); - fail_if( NULL == found, "migration pass not output when not migrating" ); + fail_if( NULL == found, "pass_dirty_bytes not output when migrating" ); found = strstr( buf, "pass_clean_bytes=4096" ); - fail_if( NULL == found, "migration pass not output when not migrating" ); - + fail_if( NULL == found, "pass_clean_bytes not output when migrating" ); + found = strstr( buf, "migration_duration=8" ); + fail_if( NULL == found, "migration_duration not output when migrating" ); + found = strstr( buf, "migration_speed=40000000" ); + fail_if( NULL == found, "migration_speed not output when migrating" ); } END_TEST @@ -302,7 +330,7 @@ Suite *status_suite(void) tcase_add_test(tc_create, test_gets_pid); tcase_add_test(tc_create, test_gets_size); tcase_add_test(tc_create, test_gets_migration_pass); - tcase_add_test(tc_create, test_gets_pass_statistics); + tcase_add_test(tc_create, test_gets_migration_statistics); tcase_add_test(tc_render, test_renders_has_control); @@ -310,7 +338,7 @@ Suite *status_suite(void) tcase_add_test(tc_render, test_renders_pid); tcase_add_test(tc_render, test_renders_size); tcase_add_test(tc_render, test_renders_migration_pass); - tcase_add_test(tc_render, test_renders_pass_statistics); + tcase_add_test(tc_render, test_renders_migration_statistics); suite_add_tcase(s, tc_create); suite_add_tcase(s, tc_render);