@@ -491,6 +491,7 @@ enum ARG_KEYS {
491491 ARG_TEST_NAME_GLOB_DENYLIST = 'd' ,
492492 ARG_NUM_WORKERS = 'j' ,
493493 ARG_DEBUG = -1 ,
494+ ARG_TIMING = -2 ,
494495};
495496
496497static const struct argp_option opts [] = {
@@ -516,6 +517,8 @@ static const struct argp_option opts[] = {
516517 "Number of workers to run in parallel, default to number of cpus." },
517518 { "debug" , ARG_DEBUG , NULL , 0 ,
518519 "print extra debug information for test_progs." },
520+ { "timing" , ARG_TIMING , NULL , 0 ,
521+ "track and print timing information for each test." },
519522 {},
520523};
521524
@@ -696,6 +699,9 @@ static error_t parse_arg(int key, char *arg, struct argp_state *state)
696699 case ARG_DEBUG :
697700 env -> debug = true;
698701 break ;
702+ case ARG_TIMING :
703+ env -> timing = true;
704+ break ;
699705 case ARGP_KEY_ARG :
700706 argp_usage (state );
701707 break ;
@@ -848,6 +854,7 @@ struct test_result {
848854 int error_cnt ;
849855 int skip_cnt ;
850856 int sub_succ_cnt ;
857+ __u32 duration_ms ;
851858
852859 size_t log_cnt ;
853860 char * log_buf ;
@@ -905,9 +912,29 @@ static int recv_message(int sock, struct msg *msg)
905912 return ret ;
906913}
907914
908- static void run_one_test (int test_num )
915+ static __u32 timespec_diff_ms (struct timespec start , struct timespec end )
916+ {
917+ struct timespec temp ;
918+
919+ if ((end .tv_nsec - start .tv_nsec ) < 0 ) {
920+ temp .tv_sec = end .tv_sec - start .tv_sec - 1 ;
921+ temp .tv_nsec = 1000000000 + end .tv_nsec - start .tv_nsec ;
922+ } else {
923+ temp .tv_sec = end .tv_sec - start .tv_sec ;
924+ temp .tv_nsec = end .tv_nsec - start .tv_nsec ;
925+ }
926+ return (temp .tv_sec * 1000 ) + (temp .tv_nsec / 1000000 );
927+ }
928+
929+
930+ static double run_one_test (int test_num )
909931{
910932 struct prog_test_def * test = & prog_test_defs [test_num ];
933+ struct timespec start = {}, end = {};
934+ __u32 duration_ms = 0 ;
935+
936+ if (env .timing )
937+ clock_gettime (CLOCK_MONOTONIC , & start );
911938
912939 env .test = test ;
913940
@@ -928,6 +955,13 @@ static void run_one_test(int test_num)
928955 restore_netns ();
929956 if (test -> need_cgroup_cleanup )
930957 cleanup_cgroup_environment ();
958+
959+ if (env .timing ) {
960+ clock_gettime (CLOCK_MONOTONIC , & end );
961+ duration_ms = timespec_diff_ms (start , end );
962+ }
963+
964+ return duration_ms ;
931965}
932966
933967struct dispatch_data {
@@ -999,6 +1033,7 @@ static void *dispatch_thread(void *ctx)
9991033 result -> error_cnt = msg_test_done .test_done .error_cnt ;
10001034 result -> skip_cnt = msg_test_done .test_done .skip_cnt ;
10011035 result -> sub_succ_cnt = msg_test_done .test_done .sub_succ_cnt ;
1036+ result -> duration_ms = msg_test_done .test_done .duration_ms ;
10021037
10031038 /* collect all logs */
10041039 if (msg_test_done .test_done .have_log ) {
@@ -1023,6 +1058,8 @@ static void *dispatch_thread(void *ctx)
10231058 }
10241059 /* output log */
10251060 {
1061+ char buf [255 ] = {};
1062+
10261063 pthread_mutex_lock (& stdout_output_lock );
10271064
10281065 if (result -> log_cnt ) {
@@ -1032,9 +1069,15 @@ static void *dispatch_thread(void *ctx)
10321069 fprintf (stdout , "\n" );
10331070 }
10341071
1035- fprintf (stdout , "#%d %s:%s\n" ,
1072+ if (env .timing ) {
1073+ snprintf (buf , sizeof (buf ), " (%u ms)" , result -> duration_ms );
1074+ buf [sizeof (buf ) - 1 ] = '\0' ;
1075+ }
1076+
1077+ fprintf (stdout , "#%d %s:%s%s\n" ,
10361078 test -> test_num , test -> test_name ,
1037- result -> error_cnt ? "FAIL" : (result -> skip_cnt ? "SKIP" : "OK" ));
1079+ result -> error_cnt ? "FAIL" : (result -> skip_cnt ? "SKIP" : "OK" ),
1080+ buf );
10381081
10391082 pthread_mutex_unlock (& stdout_output_lock );
10401083 }
@@ -1092,6 +1135,57 @@ static void print_all_error_logs(void)
10921135 }
10931136}
10941137
1138+ struct item {
1139+ int id ;
1140+ __u32 duration_ms ;
1141+ };
1142+
1143+ static int rcompitem (const void * a , const void * b )
1144+ {
1145+ __u32 val_a = ((struct item * )a )-> duration_ms ;
1146+ __u32 val_b = ((struct item * )b )-> duration_ms ;
1147+
1148+ if (val_a > val_b )
1149+ return -1 ;
1150+ if (val_a < val_b )
1151+ return 1 ;
1152+ return 0 ;
1153+ }
1154+
1155+ static void print_slow_tests (void )
1156+ {
1157+ int i ;
1158+ struct item items [ARRAY_SIZE (prog_test_defs )] = {};
1159+
1160+ for (i = 0 ; i < prog_test_cnt ; i ++ ) {
1161+ struct prog_test_def * test = & prog_test_defs [i ];
1162+ struct test_result * result = & test_results [i ];
1163+
1164+ if (!test -> tested || !result -> duration_ms )
1165+ continue ;
1166+
1167+ items [i ].id = i ;
1168+ items [i ].duration_ms = result -> duration_ms ;
1169+ }
1170+ qsort (& items [0 ], ARRAY_SIZE (items ), sizeof (items [0 ]), rcompitem );
1171+
1172+ fprintf (stdout , "\nTop 10 Slowest tests:\n" );
1173+
1174+ for (i = 0 ; i < 10 ; i ++ ) {
1175+ struct item * v = & items [i ];
1176+ struct prog_test_def * test ;
1177+
1178+ if (!v -> duration_ms )
1179+ break ;
1180+
1181+ test = & prog_test_defs [v -> id ];
1182+ fprintf (stdout , "#%d %s: %u ms%s\n" ,
1183+ test -> test_num , test -> test_name , v -> duration_ms ,
1184+ test -> run_serial_test != NULL ? " (serial)" : "" );
1185+ }
1186+ }
1187+
1188+
10951189static int server_main (void )
10961190{
10971191 pthread_t * dispatcher_threads ;
@@ -1149,13 +1243,15 @@ static int server_main(void)
11491243 for (int i = 0 ; i < prog_test_cnt ; i ++ ) {
11501244 struct prog_test_def * test = & prog_test_defs [i ];
11511245 struct test_result * result = & test_results [i ];
1246+ char buf [255 ] = {};
1247+ __u32 duration_ms = 0 ;
11521248
11531249 if (!test -> should_run || !test -> run_serial_test )
11541250 continue ;
11551251
11561252 stdio_hijack ();
11571253
1158- run_one_test (i );
1254+ duration_ms = run_one_test (i );
11591255
11601256 stdio_restore ();
11611257 if (env .log_buf ) {
@@ -1168,13 +1264,20 @@ static int server_main(void)
11681264 }
11691265 restore_netns ();
11701266
1171- fprintf (stdout , "#%d %s:%s\n" ,
1267+ if (env .timing ) {
1268+ snprintf (buf , sizeof (buf ), " (%u ms)" , duration_ms );
1269+ buf [sizeof (buf ) - 1 ] = '\0' ;
1270+ }
1271+
1272+ fprintf (stdout , "#%d %s:%s%s\n" ,
11721273 test -> test_num , test -> test_name ,
1173- test -> error_cnt ? "FAIL" : (test -> skip_cnt ? "SKIP" : "OK" ));
1274+ test -> error_cnt ? "FAIL" : (test -> skip_cnt ? "SKIP" : "OK" ),
1275+ buf );
11741276
11751277 result -> error_cnt = test -> error_cnt ;
11761278 result -> skip_cnt = test -> skip_cnt ;
11771279 result -> sub_succ_cnt = test -> sub_succ_cnt ;
1280+ result -> duration_ms = duration_ms ;
11781281 }
11791282
11801283 /* generate summary */
@@ -1200,6 +1303,9 @@ static int server_main(void)
12001303
12011304 print_all_error_logs ();
12021305
1306+ if (env .timing )
1307+ print_slow_tests ();
1308+
12031309 fprintf (stdout , "Summary: %d/%d PASSED, %d SKIPPED, %d FAILED\n" ,
12041310 env .succ_cnt , env .sub_succ_cnt , env .skip_cnt , env .fail_cnt );
12051311
@@ -1236,6 +1342,7 @@ static int worker_main(int sock)
12361342 int test_to_run ;
12371343 struct prog_test_def * test ;
12381344 struct msg msg_done ;
1345+ __u32 duration_ms = 0 ;
12391346
12401347 test_to_run = msg .do_test .test_num ;
12411348 test = & prog_test_defs [test_to_run ];
@@ -1248,7 +1355,7 @@ static int worker_main(int sock)
12481355
12491356 stdio_hijack ();
12501357
1251- run_one_test (test_to_run );
1358+ duration_ms = run_one_test (test_to_run );
12521359
12531360 stdio_restore ();
12541361
@@ -1258,6 +1365,7 @@ static int worker_main(int sock)
12581365 msg_done .test_done .error_cnt = test -> error_cnt ;
12591366 msg_done .test_done .skip_cnt = test -> skip_cnt ;
12601367 msg_done .test_done .sub_succ_cnt = test -> sub_succ_cnt ;
1368+ msg_done .test_done .duration_ms = duration_ms ;
12611369 msg_done .test_done .have_log = false;
12621370
12631371 if (env .verbosity > VERBOSE_NONE || test -> force_log || test -> error_cnt ) {
@@ -1486,6 +1594,9 @@ int main(int argc, char **argv)
14861594
14871595 print_all_error_logs ();
14881596
1597+ if (env .timing )
1598+ print_slow_tests ();
1599+
14891600 fprintf (stdout , "Summary: %d/%d PASSED, %d SKIPPED, %d FAILED\n" ,
14901601 env .succ_cnt , env .sub_succ_cnt , env .skip_cnt , env .fail_cnt );
14911602
0 commit comments