Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

perf tests: Run time generate shell test suites

Rather than special shell test logic, do a single pass to create an
array of test suites. Hold the shell test file name in the test suite
priv field. This makes the special shell test logic in builtin-test.c
redundant so remove it.

Signed-off-by: Ian Rogers <irogers@google.com>
Cc: James Clark <james.clark@arm.com>
Cc: Justin Stitt <justinstitt@google.com>
Cc: Bill Wendling <morbo@google.com>
Cc: Nick Desaulniers <ndesaulniers@google.com>
Cc: Yang Jihong <yangjihong1@huawei.com>
Cc: Nathan Chancellor <nathan@kernel.org>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Athira Jajeev <atrajeev@linux.vnet.ibm.com>
Cc: llvm@lists.linux.dev
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Link: https://lore.kernel.org/r/20240221034155.1500118-8-irogers@google.com

authored by

Ian Rogers and committed by
Namhyung Kim
964461ee f3295f5b

+80 -149
+3 -87
tools/perf/tests/builtin-test.c
··· 130 130 static struct test_suite **tests[] = { 131 131 generic_tests, 132 132 arch_tests, 133 + NULL, /* shell tests created at runtime. */ 133 134 }; 134 135 135 136 static struct test_workload *workloads[] = { ··· 300 299 return err; 301 300 } 302 301 303 - struct shell_test { 304 - const char *file; 305 - }; 306 - 307 - static int shell_test__run(struct test_suite *test, int subdir __maybe_unused) 308 - { 309 - int err; 310 - struct shell_test *st = test->priv; 311 - char *cmd = NULL; 312 - 313 - if (asprintf(&cmd, "%s%s", st->file, verbose ? " -v" : "") < 0) 314 - return TEST_FAIL; 315 - err = system(cmd); 316 - free(cmd); 317 - if (!err) 318 - return TEST_OK; 319 - 320 - return WEXITSTATUS(err) == 2 ? TEST_SKIP : TEST_FAIL; 321 - } 322 - 323 - static int run_shell_tests(int argc, const char *argv[], int i, int width, 324 - struct intlist *skiplist) 325 - { 326 - struct shell_test st; 327 - const struct script_file *files, *file; 328 - 329 - files = list_script_files(); 330 - if (!files) 331 - return 0; 332 - for (file = files; file->file; file++) { 333 - int curr = i++; 334 - struct test_case test_cases[] = { 335 - { 336 - .desc = file->desc, 337 - .run_case = shell_test__run, 338 - }, 339 - { .name = NULL, } 340 - }; 341 - struct test_suite test_suite = { 342 - .desc = test_cases[0].desc, 343 - .test_cases = test_cases, 344 - .priv = &st, 345 - }; 346 - st.file = file->file; 347 - 348 - if (test_suite.desc == NULL || 349 - !perf_test__matches(test_suite.desc, curr, argc, argv)) 350 - continue; 351 - 352 - pr_info("%3d: %-*s:", i, width, test_suite.desc); 353 - 354 - if (intlist__find(skiplist, i)) { 355 - color_fprintf(stderr, PERF_COLOR_YELLOW, " Skip (user override)\n"); 356 - continue; 357 - } 358 - 359 - test_and_print(&test_suite, 0); 360 - } 361 - return 0; 362 - } 363 - 364 302 static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist) 365 303 { 366 304 struct test_suite *t; 367 305 unsigned int j, k; 368 306 int i = 0; 369 - int width = list_script_max_width(); 307 + int width = 0; 370 308 371 309 for_each_test(j, k, t) { 372 310 int len = strlen(test_description(t, -1)); ··· 380 440 } 381 441 } 382 442 } 383 - 384 - return run_shell_tests(argc, argv, i, width, skiplist); 385 - } 386 - 387 - static int perf_test__list_shell(int argc, const char **argv, int i) 388 - { 389 - const struct script_file *files, *file; 390 - 391 - files = list_script_files(); 392 - if (!files) 393 - return 0; 394 - for (file = files; file->file; file++) { 395 - int curr = i++; 396 - struct test_suite t = { 397 - .desc = file->desc 398 - }; 399 - 400 - if (!perf_test__matches(t.desc, curr, argc, argv)) 401 - continue; 402 - 403 - pr_info("%3d: %s\n", i, t.desc); 404 - } 405 443 return 0; 406 444 } 407 445 ··· 406 488 test_description(t, subi)); 407 489 } 408 490 } 409 - 410 - perf_test__list_shell(argc, argv, i); 411 - 412 491 return 0; 413 492 } 414 493 ··· 465 550 /* Unbuffered output */ 466 551 setvbuf(stdout, NULL, _IONBF, 0); 467 552 553 + tests[2] = create_script_test_suites(); 468 554 argc = parse_options_subcommand(argc, argv, test_options, test_subcommands, test_usage, 0); 469 555 if (argc >= 1 && !strcmp(argv[0], "list")) 470 556 return perf_test__list(argc - 1, argv + 1);
+75 -54
tools/perf/tests/tests-scripts.c
··· 27 27 #include "util/rlimit.h" 28 28 #include "util/util.h" 29 29 30 - 31 - /* 32 - * As this is a singleton built once for the run of the process, there is 33 - * no value in trying to free it and just let it stay around until process 34 - * exits when it's cleaned up. 35 - */ 36 - static size_t files_num = 0; 37 - static struct script_file *files = NULL; 38 - static int files_max_width = 0; 39 - 40 30 static int shell_tests__dir_fd(void) 41 31 { 42 32 char path[PATH_MAX], *exec_path; ··· 122 132 return newstr; 123 133 } 124 134 125 - static void append_script(int dir_fd, const char *name, char *desc) 135 + static int shell_test__run(struct test_suite *test, int subtest __maybe_unused) 136 + { 137 + const char *file = test->priv; 138 + int err; 139 + char *cmd = NULL; 140 + 141 + if (asprintf(&cmd, "%s%s", file, verbose ? " -v" : "") < 0) 142 + return TEST_FAIL; 143 + err = system(cmd); 144 + free(cmd); 145 + if (!err) 146 + return TEST_OK; 147 + 148 + return WEXITSTATUS(err) == 2 ? TEST_SKIP : TEST_FAIL; 149 + } 150 + 151 + static void append_script(int dir_fd, const char *name, char *desc, 152 + struct test_suite ***result, 153 + size_t *result_sz) 126 154 { 127 155 char filename[PATH_MAX], link[128]; 128 - struct script_file *files_tmp; 129 - size_t files_num_tmp, len; 130 - int width; 156 + struct test_suite *test_suite, **result_tmp; 157 + struct test_case *tests; 158 + size_t len; 131 159 132 160 snprintf(link, sizeof(link), "/proc/%d/fd/%d", getpid(), dir_fd); 133 161 len = readlink(link, filename, sizeof(filename)); ··· 155 147 } 156 148 filename[len++] = '/'; 157 149 strcpy(&filename[len], name); 158 - files_num_tmp = files_num + 1; 159 - if (files_num_tmp >= SIZE_MAX) { 160 - pr_err("Too many script files\n"); 161 - abort(); 150 + 151 + tests = calloc(2, sizeof(*tests)); 152 + if (!tests) { 153 + pr_err("Out of memory while building script test suite list\n"); 154 + return; 162 155 } 156 + tests[0].name = strdup_check(name); 157 + tests[0].desc = strdup_check(desc); 158 + tests[0].run_case = shell_test__run; 159 + 160 + test_suite = zalloc(sizeof(*test_suite)); 161 + if (!test_suite) { 162 + pr_err("Out of memory while building script test suite list\n"); 163 + free(tests); 164 + return; 165 + } 166 + test_suite->desc = desc; 167 + test_suite->test_cases = tests; 168 + test_suite->priv = strdup_check(filename); 163 169 /* Realloc is good enough, though we could realloc by chunks, not that 164 170 * anyone will ever measure performance here */ 165 - files_tmp = realloc(files, 166 - (files_num_tmp + 1) * sizeof(struct script_file)); 167 - if (files_tmp == NULL) { 168 - pr_err("Out of memory while building test list\n"); 169 - abort(); 171 + result_tmp = realloc(*result, (*result_sz + 1) * sizeof(*result_tmp)); 172 + if (result_tmp == NULL) { 173 + pr_err("Out of memory while building script test suite list\n"); 174 + free(tests); 175 + free(test_suite); 176 + return; 170 177 } 171 178 /* Add file to end and NULL terminate the struct array */ 172 - files = files_tmp; 173 - files_num = files_num_tmp; 174 - files[files_num - 1].file = strdup_check(filename); 175 - files[files_num - 1].desc = desc; 176 - files[files_num].file = NULL; 177 - files[files_num].desc = NULL; 178 - 179 - width = strlen(desc); /* Track max width of desc */ 180 - if (width > files_max_width) 181 - files_max_width = width; 179 + *result = result_tmp; 180 + (*result)[*result_sz] = test_suite; 181 + (*result_sz)++; 182 182 } 183 183 184 - static void append_scripts_in_dir(int dir_fd) 184 + static void append_scripts_in_dir(int dir_fd, 185 + struct test_suite ***result, 186 + size_t *result_sz) 185 187 { 186 188 struct dirent **entlist; 187 189 struct dirent *ent; ··· 210 192 char *desc = shell_test__description(dir_fd, ent->d_name); 211 193 212 194 if (desc) /* It has a desc line - valid script */ 213 - append_script(dir_fd, ent->d_name, desc); 195 + append_script(dir_fd, ent->d_name, desc, result, result_sz); 214 196 continue; 215 197 } 216 198 if (ent->d_type != DT_DIR) { ··· 223 205 continue; 224 206 } 225 207 fd = openat(dir_fd, ent->d_name, O_PATH); 226 - append_scripts_in_dir(fd); 208 + append_scripts_in_dir(fd, result, result_sz); 227 209 } 228 210 for (i = 0; i < n_dirs; i++) /* Clean up */ 229 211 zfree(&entlist[i]); 230 212 free(entlist); 231 213 } 232 214 233 - const struct script_file *list_script_files(void) 215 + struct test_suite **create_script_test_suites(void) 234 216 { 235 - int dir_fd; 217 + struct test_suite **result = NULL, **result_tmp; 218 + size_t result_sz = 0; 219 + int dir_fd = shell_tests__dir_fd(); /* Walk dir */ 236 220 237 - if (files) 238 - return files; /* Singleton - we already know our list */ 221 + /* 222 + * Append scripts if fd is good, otherwise return a NULL terminated zero 223 + * length array. 224 + */ 225 + if (dir_fd >= 0) 226 + append_scripts_in_dir(dir_fd, &result, &result_sz); 239 227 240 - dir_fd = shell_tests__dir_fd(); /* Walk dir */ 241 - if (dir_fd < 0) 242 - return NULL; 243 - 244 - append_scripts_in_dir(dir_fd); 245 - close(dir_fd); 246 - 247 - return files; 248 - } 249 - 250 - int list_script_max_width(void) 251 - { 252 - list_script_files(); /* Ensure we have scanned all scripts */ 253 - return files_max_width; 228 + result_tmp = realloc(result, (result_sz + 1) * sizeof(*result_tmp)); 229 + if (result_tmp == NULL) { 230 + pr_err("Out of memory while building script test suite list\n"); 231 + abort(); 232 + } 233 + /* NULL terminate the test suite array. */ 234 + result = result_tmp; 235 + result[result_sz] = NULL; 236 + if (dir_fd >= 0) 237 + close(dir_fd); 238 + return result; 254 239 }
+2 -8
tools/perf/tests/tests-scripts.h
··· 2 2 #ifndef TESTS_SCRIPTS_H 3 3 #define TESTS_SCRIPTS_H 4 4 5 - struct script_file { 6 - char *file; 7 - char *desc; 8 - }; 5 + #include "tests.h" 9 6 10 - /* List available script tests to run - singleton - never freed */ 11 - const struct script_file *list_script_files(void); 12 - /* Get maximum width of description string */ 13 - int list_script_max_width(void); 7 + struct test_suite **create_script_test_suites(void); 14 8 15 9 #endif /* TESTS_SCRIPTS_H */