Skip to content

Commit 0b69e3d

Browse files
thefallentreeNobody
authored and
Nobody
committed
selftests/bpf: Add timing to tests_progs
This patch adds '--timing' to test_progs. It tracks and print timing information for each tests, it also prints top 10 slowest tests in the summary. Example output: $./test_progs --timing -j #1 align:OK (16 ms) ... #203 xdp_bonding:OK (2019 ms) #206 xdp_cpumap_attach:OK (3 ms) #207 xdp_devmap_attach:OK (4 ms) #208 xdp_info:OK (4 ms) #209 xdp_link:OK (4 ms) Top 10 Slowest tests: #48 fexit_stress: 34356 ms #160 test_lsm: 29602 ms #161 test_overhead: 29190 ms #159 test_local_storage: 28959 ms #158 test_ima: 28521 ms #185 verif_scale_pyperf600: 19524 ms #199 vmlinux: 17310 ms #154 tc_redirect: 11491 ms (serial) #147 task_local_storage: 7612 ms #183 verif_scale_pyperf180: 7186 ms Summary: 212/973 PASSED, 3 SKIPPED, 0 FAILED Signed-off-by: Yucong Sun <[email protected]>
1 parent f0a4f9f commit 0b69e3d

File tree

2 files changed

+120
-7
lines changed

2 files changed

+120
-7
lines changed

tools/testing/selftests/bpf/test_progs.c

Lines changed: 118 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -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

496497
static 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

933967
struct 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+
10951189
static 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

tools/testing/selftests/bpf/test_progs.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ struct test_env {
6464
bool verifier_stats;
6565
bool debug;
6666
enum verbosity verbosity;
67+
bool timing;
6768

6869
bool jit_enabled;
6970
bool has_testmod;
@@ -109,6 +110,7 @@ struct msg {
109110
int sub_succ_cnt;
110111
int error_cnt;
111112
int skip_cnt;
113+
__u32 duration_ms;
112114
bool have_log;
113115
} test_done;
114116
struct {

0 commit comments

Comments
 (0)