linux-perf-users.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Namhyung Kim <namhyung@kernel.org>
To: Jakub Brnak <jbrnak@redhat.com>
Cc: vmolnaro@redhat.com, acme@kernel.org, acme@redhat.com,
	irogers@google.com, linux-perf-users@vger.kernel.org,
	mpetlan@redhat.com
Subject: Re: [PATCH v3 2/7] perf tests: Create a structure for shell tests
Date: Fri, 25 Jul 2025 23:03:59 -0700	[thread overview]
Message-ID: <aIRvz9ZfK2rnblQt@google.com> (raw)
In-Reply-To: <20250721132642.40906-3-jbrnak@redhat.com>

On Mon, Jul 21, 2025 at 03:26:37PM +0200, Jakub Brnak wrote:
> From: Veronika Molnarova <vmolnaro@redhat.com>
> 
> The general structure of test suites with test cases has been implemented
> for C tests for some time, while shell tests were just all put into a list
> without any possible structuring.
> 
> Provide the same possibility of test suite structure for shell tests. The
> suite is created for each subdirectory located in the 'perf/tests/shell'
> directory that contains at least one test script. All of the deeper levels
> of subdirectories will be merged with the first level of test cases.
> The name of the test suite is the name of the subdirectory, where the test
> cases are located. For all of the test scripts that are not in any
> subdirectory, a test suite with a single test case is created as it has
> been till now.
> 
> The new structure of the shell tests for 'perf test list':
>     77: build id cache operations
>     78: coresight
>     78:1: CoreSight / ASM Pure Loop
>     78:2: CoreSight / Memcpy 16k 10 Threads
>     78:3: CoreSight / Thread Loop 10 Threads - Check TID
>     78:4: CoreSight / Thread Loop 2 Threads - Check TID
>     78:5: CoreSight / Unroll Loop Thread 10
>     79: daemon operations
>     80: perf diff tests

I like the idea!  But there are too many coding style issues.  Can you
please follow the style for the kernel?

Thanks,
Namhyung

> 
> Signed-off-by: Michael Petlan <mpetlan@redhat.com>
> Signed-off-by: Veronika Molnarova <vmolnaro@redhat.com>
> Signed-off-by: Jakub Brnak <jbrnak@redhat.com>
> ---
>  tools/perf/tests/tests-scripts.c | 223 +++++++++++++++++++++++++------
>  tools/perf/tests/tests-scripts.h |   4 +
>  2 files changed, 189 insertions(+), 38 deletions(-)
> 
> diff --git a/tools/perf/tests/tests-scripts.c b/tools/perf/tests/tests-scripts.c
> index f18c4cd337c8..21a6ede330e9 100644
> --- a/tools/perf/tests/tests-scripts.c
> +++ b/tools/perf/tests/tests-scripts.c
> @@ -151,14 +151,45 @@ static char *strdup_check(const char *str)
>  	return newstr;
>  }
>  
> -static int shell_test__run(struct test_suite *test, int subtest __maybe_unused)
> +/* Free the whole structure of test_suite with its test_cases */
> +static void free_suite(struct test_suite *suite) {
> +	if (suite->test_cases){
> +		int num = 0;
> +		while (suite->test_cases[num].name){ /* Last case has name set to NULL */
> +			free((void*) suite->test_cases[num].name);
> +			free((void*) suite->test_cases[num].desc);
> +			num++;
> +		}
> +		free(suite->test_cases);
> +	}
> +	if (suite->desc)
> +		free((void*) suite->desc);
> +	if (suite->priv){
> +		struct shell_info *test_info = suite->priv;
> +		free((void*) test_info->base_path);
> +		free(test_info);
> +	}
> +
> +	free(suite);
> +}
> +
> +static int shell_test__run(struct test_suite *test, int subtest)
>  {
> -	const char *file = test->priv;
> +	const char *file;
>  	int err;
>  	char *cmd = NULL;
>  
> +	/* Get absolute file path */
> +	if (subtest >= 0) {
> +		file = test->test_cases[subtest].name;
> +	}
> +	else {		/* Single test case */
> +		file = test->test_cases[0].name;
> +	}
> +
>  	if (asprintf(&cmd, "%s%s", file, verbose ? " -v" : "") < 0)
>  		return TEST_FAIL;
> +
>  	err = system(cmd);
>  	free(cmd);
>  	if (!err)
> @@ -167,63 +198,154 @@ static int shell_test__run(struct test_suite *test, int subtest __maybe_unused)
>  	return WEXITSTATUS(err) == 2 ? TEST_SKIP : TEST_FAIL;
>  }
>  
> -static void append_script(int dir_fd, const char *name, char *desc,
> -			  struct test_suite ***result,
> -			  size_t *result_sz)
> +static struct test_suite* prepare_test_suite(int dir_fd)
>  {
> -	char filename[PATH_MAX], link[128];
> -	struct test_suite *test_suite, **result_tmp;
> -	struct test_case *tests;
> +	char dirpath[PATH_MAX], link[128];
>  	ssize_t len;
> -	char *exclusive;
> +	struct test_suite *test_suite = NULL;
> +	struct shell_info *test_info;
>  
> +	/* Get dir absolute path */
>  	snprintf(link, sizeof(link), "/proc/%d/fd/%d", getpid(), dir_fd);
> -	len = readlink(link, filename, sizeof(filename));
> +	len = readlink(link, dirpath, sizeof(dirpath));
>  	if (len < 0) {
>  		pr_err("Failed to readlink %s", link);
> -		return;
> +		return NULL;
>  	}
> -	filename[len++] = '/';
> -	strcpy(&filename[len], name);
> +	dirpath[len++] = '/';
> +	dirpath[len] = '\0';
>  
> -	tests = calloc(2, sizeof(*tests));
> -	if (!tests) {
> -		pr_err("Out of memory while building script test suite list\n");
> -		return;
> -	}
> -	tests[0].name = strdup_check(name);
> -	exclusive = strstr(desc, " (exclusive)");
> -	if (exclusive != NULL) {
> -		tests[0].exclusive = true;
> -		exclusive[0] = '\0';
> -	}
> -	tests[0].desc = strdup_check(desc);
> -	tests[0].run_case = shell_test__run;
>  	test_suite = zalloc(sizeof(*test_suite));
>  	if (!test_suite) {
>  		pr_err("Out of memory while building script test suite list\n");
> -		free(tests);
> -		return;
> +		return NULL;
>  	}
> -	test_suite->desc = desc;
> -	test_suite->test_cases = tests;
> -	test_suite->priv = strdup_check(filename);
> +
> +	test_info = zalloc(sizeof(*test_info));
> +	if (!test_info) {
> +		pr_err("Out of memory while building script test suite list\n");
> +		return NULL;
> +	}
> +
> +	test_info->base_path = strdup_check(dirpath);		/* Absolute path to dir */
> +
> +	test_suite->priv = test_info;
> +	test_suite->desc = NULL;
> +	test_suite->test_cases = NULL;
> +
> +	return test_suite;
> +}
> +
> +static void append_suite(struct test_suite ***result,
> +			  size_t *result_sz, struct test_suite *test_suite)
> +{
> +	struct test_suite **result_tmp;
> +
>  	/* Realloc is good enough, though we could realloc by chunks, not that
>  	 * anyone will ever measure performance here */
>  	result_tmp = realloc(*result, (*result_sz + 1) * sizeof(*result_tmp));
>  	if (result_tmp == NULL) {
>  		pr_err("Out of memory while building script test suite list\n");
> -		free(tests);
> -		free(test_suite);
> +		free_suite(test_suite);
>  		return;
>  	}
> +
>  	/* Add file to end and NULL terminate the struct array */
>  	*result = result_tmp;
>  	(*result)[*result_sz] = test_suite;
>  	(*result_sz)++;
>  }
>  
> -static void append_scripts_in_dir(int dir_fd,
> +static void append_script_to_suite(int dir_fd, const char *name, char *desc,
> +					struct test_suite *test_suite, size_t *tc_count)
> +{
> +	char file_name[PATH_MAX], link[128];
> +	struct test_case *tests;
> +	size_t len;
> +	char *exclusive;
> +
> +	if (!test_suite)
> +		return;
> +
> +	/* Requires an empty test case at the end */
> +	tests = realloc(test_suite->test_cases, (*tc_count + 2) * sizeof(*tests));
> +	if (!tests) {
> +		pr_err("Out of memory while building script test suite list\n");
> +		return;
> +	}
> +
> +	/* Get path to the test script */
> +	snprintf(link, sizeof(link), "/proc/%d/fd/%d", getpid(), dir_fd);
> +	len = readlink(link, file_name, sizeof(file_name));
> +	if (len < 0) {
> +		pr_err("Failed to readlink %s", link);
> +		return;
> +	}
> +	file_name[len++] = '/';
> +	strcpy(&file_name[len], name);
> +
> +	tests[(*tc_count)].name = strdup_check(file_name);	/* Get path to the script from base dir */
> +	tests[(*tc_count)].exclusive = false;
> +	exclusive = strstr(desc, " (exclusive)");
> +	if (exclusive != NULL) {
> +		tests[(*tc_count)].exclusive = true;
> +		exclusive[0] = '\0';
> +	}
> +	tests[(*tc_count)].desc = desc;
> +	tests[(*tc_count)].skip_reason = NULL;	/* Unused */
> +	tests[(*tc_count)++].run_case = shell_test__run;
> +
> +	tests[(*tc_count)].name = NULL;		/* End the test cases */
> +
> +	test_suite->test_cases = tests;
> +}
> +
> +static void append_scripts_in_subdir(int dir_fd,
> +				  struct test_suite *suite,
> +				  size_t *tc_count)
> +{
> +	struct dirent **entlist;
> +	struct dirent *ent;
> +	int n_dirs, i;
> +
> +	/* List files, sorted by alpha */
> +	n_dirs = scandirat(dir_fd, ".", &entlist, NULL, alphasort);
> +	if (n_dirs == -1)
> +		return;
> +	for (i = 0; i < n_dirs && (ent = entlist[i]); i++) {
> +		int fd;
> +
> +		if (ent->d_name[0] == '.')
> +			continue; /* Skip hidden files */
> +		if (is_test_script(dir_fd, ent->d_name)) { /* It's a test */
> +			char *desc = shell_test__description(dir_fd, ent->d_name);
> +
> +			if (desc) /* It has a desc line - valid script */
> +				append_script_to_suite(dir_fd, ent->d_name, desc, suite, tc_count);
> +			continue;
> +		}
> +
> +		if (ent->d_type != DT_DIR) {
> +			struct stat st;
> +
> +			if (ent->d_type != DT_UNKNOWN)
> +				continue;
> +			fstatat(dir_fd, ent->d_name, &st, 0);
> +			if (!S_ISDIR(st.st_mode))
> +				continue;
> +		}
> +
> +		fd = openat(dir_fd, ent->d_name, O_PATH);
> +
> +		/* Recurse into the dir */
> +		append_scripts_in_subdir(fd, suite, tc_count);
> +	}
> +	for (i = 0; i < n_dirs; i++) /* Clean up */
> +		zfree(&entlist[i]);
> +	free(entlist);
> +}
> +
> +static void append_suits_in_dir(int dir_fd,
>  				  struct test_suite ***result,
>  				  size_t *result_sz)
>  {
> @@ -237,16 +359,27 @@ static void append_scripts_in_dir(int dir_fd,
>  		return;
>  	for (i = 0; i < n_dirs && (ent = entlist[i]); i++) {
>  		int fd;
> +		struct test_suite *test_suite;
> +		size_t cases_count = 0;
>  
>  		if (ent->d_name[0] == '.')
>  			continue; /* Skip hidden files */
>  		if (is_test_script(dir_fd, ent->d_name)) { /* It's a test */
>  			char *desc = shell_test__description(dir_fd, ent->d_name);
>  
> -			if (desc) /* It has a desc line - valid script */
> -				append_script(dir_fd, ent->d_name, desc, result, result_sz);
> +			if (desc) { /* It has a desc line - valid script */
> +				test_suite = prepare_test_suite(dir_fd); /* Create a test suite with a single test case */
> +				append_script_to_suite(dir_fd, ent->d_name, desc, test_suite, &cases_count);
> +				test_suite->desc = strdup_check(desc);
> +
> +				if (cases_count)
> +					append_suite(result, result_sz, test_suite);
> +				else /* Wasn't able to create the test case */
> +					free_suite(test_suite);
> +			}
>  			continue;
>  		}
> +
>  		if (ent->d_type != DT_DIR) {
>  			struct stat st;
>  
> @@ -258,8 +391,22 @@ static void append_scripts_in_dir(int dir_fd,
>  		}
>  		if (strncmp(ent->d_name, "base_", 5) == 0)
>  			continue; /* Skip scripts that have a separate driver. */
> +
> +		/* Scan subdir for test cases*/
>  		fd = openat(dir_fd, ent->d_name, O_PATH);
> -		append_scripts_in_dir(fd, result, result_sz);
> +		test_suite = prepare_test_suite(fd);	/* Prepare a testsuite with its path */
> +		if (!test_suite)
> +			continue;
> +
> +		append_scripts_in_subdir(fd, test_suite, &cases_count);
> +		if (cases_count == 0){
> +			free_suite(test_suite);
> +			continue;
> +		}
> +
> +		test_suite->desc = strdup_check(ent->d_name);	/* If no setup, set name to the directory */
> +
> +		append_suite(result, result_sz, test_suite);
>  		close(fd);
>  	}
>  	for (i = 0; i < n_dirs; i++) /* Clean up */
> @@ -278,7 +425,7 @@ struct test_suite **create_script_test_suites(void)
>  	 * length array.
>  	 */
>  	if (dir_fd >= 0)
> -		append_scripts_in_dir(dir_fd, &result, &result_sz);
> +		append_suits_in_dir(dir_fd, &result, &result_sz);
>  
>  	result_tmp = realloc(result, (result_sz + 1) * sizeof(*result_tmp));
>  	if (result_tmp == NULL) {
> diff --git a/tools/perf/tests/tests-scripts.h b/tools/perf/tests/tests-scripts.h
> index b553ad26ea17..60a1a19a45c9 100644
> --- a/tools/perf/tests/tests-scripts.h
> +++ b/tools/perf/tests/tests-scripts.h
> @@ -4,6 +4,10 @@
>  
>  #include "tests.h"
>  
> +struct shell_info {
> +	const char *base_path;
> +};
> +
>  struct test_suite **create_script_test_suites(void);
>  
>  #endif /* TESTS_SCRIPTS_H */
> -- 
> 2.50.1
> 

  parent reply	other threads:[~2025-07-26  6:04 UTC|newest]

Thread overview: 43+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-12-20 22:03 [PATCH 00/10] Introduce structure for shell tests vmolnaro
2024-12-20 22:03 ` [PATCH 01/10] perf test perftool_testsuite: Add missing description vmolnaro
2024-12-20 22:03 ` [PATCH 02/10] perf test perftool_testsuite: Return correct value for skipping vmolnaro
2024-12-20 22:03 ` [PATCH 03/10] perf test perftool_testsuite: Use absolute paths vmolnaro
2024-12-20 22:03 ` [PATCH 04/10] perf tests: Create a structure for shell tests vmolnaro
2024-12-20 22:03 ` [PATCH 05/10] perf testsuite: Fix perf-report tests installation vmolnaro
2024-12-20 22:03 ` [PATCH 06/10] perf test: Provide setup for the shell test suite vmolnaro
2024-12-20 22:03 ` [PATCH 07/10] perftool-testsuite: Add empty setup for base_probe vmolnaro
2024-12-20 22:03 ` [PATCH 08/10] perf test: Introduce storing logs for shell tests vmolnaro
2024-12-20 22:03 ` [PATCH 09/10] perf test: Format log directories " vmolnaro
2024-12-20 22:03 ` [PATCH 10/10] perf test: Remove perftool drivers vmolnaro
2025-01-13 15:24 ` [PATCH 00/10] Introduce structure for shell tests Arnaldo Carvalho de Melo
2025-01-13 18:25   ` [PATCH v2 " vmolnaro
2025-07-21 13:26     ` [PATCH v3 0/7] " Jakub Brnak
2025-07-21 13:26       ` [PATCH v3 1/7] perf test perftool_testsuite: Use absolute paths Jakub Brnak
2025-07-26  6:00         ` Namhyung Kim
2025-08-21 11:01           ` Jakub Brnak
2025-07-21 13:26       ` [PATCH v3 2/7] perf tests: Create a structure for shell tests Jakub Brnak
2025-07-21 19:39         ` Ian Rogers
2025-07-26  6:03         ` Namhyung Kim [this message]
2025-08-21 11:15           ` Jakub Brnak
2025-07-21 13:26       ` [PATCH v3 3/7] perf test: Provide setup for the shell test suite Jakub Brnak
2025-07-26  6:07         ` Namhyung Kim
2025-08-04 14:39           ` Michael Petlan
2025-07-21 13:26       ` [PATCH v3 4/7] perftool-testsuite: Add empty setup for base_probe Jakub Brnak
2025-07-21 13:26       ` [PATCH v3 5/7] perf test: Introduce storing logs for shell tests Jakub Brnak
2025-07-21 19:43         ` Ian Rogers
2025-07-26  6:17         ` Namhyung Kim
2025-07-21 13:26       ` [PATCH v3 6/7] perf test: Format log directories " Jakub Brnak
2025-07-26  6:21         ` Namhyung Kim
2025-07-21 13:26       ` [PATCH v3 7/7] perf test: Remove perftool drivers Jakub Brnak
2025-07-21 19:46         ` Ian Rogers
2025-07-31 12:54       ` [PATCH v3 0/7] Introduce structure for shell tests tejas05
2025-01-13 18:25   ` [PATCH v2 01/10] perf test perftool_testsuite: Add missing description vmolnaro
2025-01-13 18:25   ` [PATCH v2 02/10] perf test perftool_testsuite: Return correct value for skipping vmolnaro
2025-01-13 18:25   ` [PATCH v2 03/10] perf test perftool_testsuite: Use absolute paths vmolnaro
2025-01-13 18:25   ` [PATCH v2 04/10] perf tests: Create a structure for shell tests vmolnaro
2025-01-13 18:26   ` [PATCH v2 05/10] perf testsuite: Fix perf-report tests installation vmolnaro
2025-01-13 18:26   ` [PATCH v2 06/10] perf test: Provide setup for the shell test suite vmolnaro
2025-01-13 18:26   ` [PATCH v2 07/10] perftool-testsuite: Add empty setup for base_probe vmolnaro
2025-01-13 18:26   ` [PATCH v2 08/10] perf test: Introduce storing logs for shell tests vmolnaro
2025-01-13 18:26   ` [PATCH v2 09/10] perf test: Format log directories " vmolnaro
2025-01-13 18:26   ` [PATCH v2 10/10] perf test: Remove perftool drivers vmolnaro

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=aIRvz9ZfK2rnblQt@google.com \
    --to=namhyung@kernel.org \
    --cc=acme@kernel.org \
    --cc=acme@redhat.com \
    --cc=irogers@google.com \
    --cc=jbrnak@redhat.com \
    --cc=linux-perf-users@vger.kernel.org \
    --cc=mpetlan@redhat.com \
    --cc=vmolnaro@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).