* [PATCH v2 0/2] perf test: Display remaining tests while waiting @ 2024-07-01 4:42 Ian Rogers 2024-07-01 4:42 ` [PATCH v2 1/2] tools subcmd: Add non-waitpid check_if_command_finished() Ian Rogers 2024-07-01 4:42 ` [PATCH v2 2/2] perf test: Display number of remaining tests Ian Rogers 0 siblings, 2 replies; 12+ messages in thread From: Ian Rogers @ 2024-07-01 4:42 UTC (permalink / raw) To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo, Namhyung Kim, Mark Rutland, Alexander Shishkin, Jiri Olsa, Ian Rogers, Adrian Hunter, Kan Liang, James Clark, linux-kernel, linux-perf-users The v1 patch series: https://lore.kernel.org/lkml/20240405070931.1231245-1-irogers@google.com/ was partially merged. The check_if_command_finished wasn't working as intended as stdout/stderr could be lost due to waitpid being called. Modify this function to not use waitpid and use procfs instead. Keeping the output test display logic in 1 place should simplify improving parallel and sequential output. Namhyung was experiencing issues with this in: https://lore.kernel.org/lkml/20240628215751.1512250-1-namhyung@kernel.org/ Ian Rogers (2): tools subcmd: Add non-waitpid check_if_command_finished() perf test: Display number of remaining tests tools/lib/subcmd/run-command.c | 33 ++++++++++++++ tools/perf/tests/builtin-test.c | 77 ++++++++++++++++++++++----------- tools/perf/util/color.h | 1 + 3 files changed, 86 insertions(+), 25 deletions(-) -- 2.45.2.803.g4e1b14247a-goog ^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH v2 1/2] tools subcmd: Add non-waitpid check_if_command_finished() 2024-07-01 4:42 [PATCH v2 0/2] perf test: Display remaining tests while waiting Ian Rogers @ 2024-07-01 4:42 ` Ian Rogers 2024-07-03 3:23 ` Namhyung Kim 2024-07-01 4:42 ` [PATCH v2 2/2] perf test: Display number of remaining tests Ian Rogers 1 sibling, 1 reply; 12+ messages in thread From: Ian Rogers @ 2024-07-01 4:42 UTC (permalink / raw) To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo, Namhyung Kim, Mark Rutland, Alexander Shishkin, Jiri Olsa, Ian Rogers, Adrian Hunter, Kan Liang, James Clark, linux-kernel, linux-perf-users Using waitpid can cause stdout/stderr of the child process to be lost. Use Linux's /prod/<pid>/status file to determine if the process has reached the zombie state. Use the 'status' file rather than 'stat' to avoid issues around skipping the process name. Signed-off-by: Ian Rogers <irogers@google.com> --- tools/lib/subcmd/run-command.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/tools/lib/subcmd/run-command.c b/tools/lib/subcmd/run-command.c index 4e3a557a2f37..ec06683e77a0 100644 --- a/tools/lib/subcmd/run-command.c +++ b/tools/lib/subcmd/run-command.c @@ -2,6 +2,7 @@ #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> +#include <ctype.h> #include <fcntl.h> #include <string.h> #include <linux/string.h> @@ -217,8 +218,40 @@ static int wait_or_whine(struct child_process *cmd, bool block) int check_if_command_finished(struct child_process *cmd) { +#ifdef __linux__ + char filename[FILENAME_MAX + 12]; + char status_line[256]; + FILE *status_file; + + /* + * Check by reading /proc/<pid>/status as calling waitpid causes + * stdout/stderr to be closed and data lost. + */ + sprintf(filename, "/proc/%d/status", cmd->pid); + status_file = fopen(filename, "r"); + if (status_file == NULL) { + /* Open failed assume finish_command was called. */ + return true; + } + while (fgets(status_line, sizeof(status_line), status_file) != NULL) { + char *p; + + if (strncmp(status_line, "State:", 6)) + continue; + + fclose(status_file); + p = status_line + 6; + while (isspace(*p)) + p++; + return *p == 'Z'; + } + /* Read failed assume finish_command was called. */ + fclose(status_file); + return true; +#else wait_or_whine(cmd, /*block=*/false); return cmd->finished; +#endif } int finish_command(struct child_process *cmd) -- 2.45.2.803.g4e1b14247a-goog ^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH v2 1/2] tools subcmd: Add non-waitpid check_if_command_finished() 2024-07-01 4:42 ` [PATCH v2 1/2] tools subcmd: Add non-waitpid check_if_command_finished() Ian Rogers @ 2024-07-03 3:23 ` Namhyung Kim 2024-07-03 4:24 ` Ian Rogers 0 siblings, 1 reply; 12+ messages in thread From: Namhyung Kim @ 2024-07-03 3:23 UTC (permalink / raw) To: Ian Rogers Cc: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo, Mark Rutland, Alexander Shishkin, Jiri Olsa, Adrian Hunter, Kan Liang, James Clark, linux-kernel, linux-perf-users Hi Ian, On Sun, Jun 30, 2024 at 09:42:35PM -0700, Ian Rogers wrote: > Using waitpid can cause stdout/stderr of the child process to be > lost. Use Linux's /prod/<pid>/status file to determine if the process > has reached the zombie state. Use the 'status' file rather than 'stat' > to avoid issues around skipping the process name. > > Signed-off-by: Ian Rogers <irogers@google.com> > --- > tools/lib/subcmd/run-command.c | 33 +++++++++++++++++++++++++++++++++ > 1 file changed, 33 insertions(+) > > diff --git a/tools/lib/subcmd/run-command.c b/tools/lib/subcmd/run-command.c > index 4e3a557a2f37..ec06683e77a0 100644 > --- a/tools/lib/subcmd/run-command.c > +++ b/tools/lib/subcmd/run-command.c > @@ -2,6 +2,7 @@ > #include <unistd.h> > #include <sys/types.h> > #include <sys/stat.h> > +#include <ctype.h> > #include <fcntl.h> > #include <string.h> > #include <linux/string.h> > @@ -217,8 +218,40 @@ static int wait_or_whine(struct child_process *cmd, bool block) > > int check_if_command_finished(struct child_process *cmd) > { > +#ifdef __linux__ Is this really necessary? I don't think we plan to support other OS.. Thanks, Namhyung > + char filename[FILENAME_MAX + 12]; > + char status_line[256]; > + FILE *status_file; > + > + /* > + * Check by reading /proc/<pid>/status as calling waitpid causes > + * stdout/stderr to be closed and data lost. > + */ > + sprintf(filename, "/proc/%d/status", cmd->pid); > + status_file = fopen(filename, "r"); > + if (status_file == NULL) { > + /* Open failed assume finish_command was called. */ > + return true; > + } > + while (fgets(status_line, sizeof(status_line), status_file) != NULL) { > + char *p; > + > + if (strncmp(status_line, "State:", 6)) > + continue; > + > + fclose(status_file); > + p = status_line + 6; > + while (isspace(*p)) > + p++; > + return *p == 'Z'; > + } > + /* Read failed assume finish_command was called. */ > + fclose(status_file); > + return true; > +#else > wait_or_whine(cmd, /*block=*/false); > return cmd->finished; > +#endif > } > > int finish_command(struct child_process *cmd) > -- > 2.45.2.803.g4e1b14247a-goog > ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v2 1/2] tools subcmd: Add non-waitpid check_if_command_finished() 2024-07-03 3:23 ` Namhyung Kim @ 2024-07-03 4:24 ` Ian Rogers 2024-07-12 20:33 ` Namhyung Kim 0 siblings, 1 reply; 12+ messages in thread From: Ian Rogers @ 2024-07-03 4:24 UTC (permalink / raw) To: Namhyung Kim Cc: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo, Mark Rutland, Alexander Shishkin, Jiri Olsa, Adrian Hunter, Kan Liang, James Clark, linux-kernel, linux-perf-users On Tue, Jul 2, 2024 at 8:24 PM Namhyung Kim <namhyung@kernel.org> wrote: > > Hi Ian, > > On Sun, Jun 30, 2024 at 09:42:35PM -0700, Ian Rogers wrote: > > Using waitpid can cause stdout/stderr of the child process to be > > lost. Use Linux's /prod/<pid>/status file to determine if the process > > has reached the zombie state. Use the 'status' file rather than 'stat' > > to avoid issues around skipping the process name. > > > > Signed-off-by: Ian Rogers <irogers@google.com> > > --- > > tools/lib/subcmd/run-command.c | 33 +++++++++++++++++++++++++++++++++ > > 1 file changed, 33 insertions(+) > > > > diff --git a/tools/lib/subcmd/run-command.c b/tools/lib/subcmd/run-command.c > > index 4e3a557a2f37..ec06683e77a0 100644 > > --- a/tools/lib/subcmd/run-command.c > > +++ b/tools/lib/subcmd/run-command.c > > @@ -2,6 +2,7 @@ > > #include <unistd.h> > > #include <sys/types.h> > > #include <sys/stat.h> > > +#include <ctype.h> > > #include <fcntl.h> > > #include <string.h> > > #include <linux/string.h> > > @@ -217,8 +218,40 @@ static int wait_or_whine(struct child_process *cmd, bool block) > > > > int check_if_command_finished(struct child_process *cmd) > > { > > +#ifdef __linux__ > > Is this really necessary? I don't think we plan to support other OS.. I don't think it'd be unreasonable to say run "perf report" on Windows, or using wasm inside a web browser. Part of the reason for doing things this way was to keep the WNOHANG logic although this change no longer uses it for __linux__. Thanks, Ian > Thanks, > Namhyung > > > > + char filename[FILENAME_MAX + 12]; > > + char status_line[256]; > > + FILE *status_file; > > + > > + /* > > + * Check by reading /proc/<pid>/status as calling waitpid causes > > + * stdout/stderr to be closed and data lost. > > + */ > > + sprintf(filename, "/proc/%d/status", cmd->pid); > > + status_file = fopen(filename, "r"); > > + if (status_file == NULL) { > > + /* Open failed assume finish_command was called. */ > > + return true; > > + } > > + while (fgets(status_line, sizeof(status_line), status_file) != NULL) { > > + char *p; > > + > > + if (strncmp(status_line, "State:", 6)) > > + continue; > > + > > + fclose(status_file); > > + p = status_line + 6; > > + while (isspace(*p)) > > + p++; > > + return *p == 'Z'; > > + } > > + /* Read failed assume finish_command was called. */ > > + fclose(status_file); > > + return true; > > +#else > > wait_or_whine(cmd, /*block=*/false); > > return cmd->finished; > > +#endif > > } > > > > int finish_command(struct child_process *cmd) > > -- > > 2.45.2.803.g4e1b14247a-goog > > ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v2 1/2] tools subcmd: Add non-waitpid check_if_command_finished() 2024-07-03 4:24 ` Ian Rogers @ 2024-07-12 20:33 ` Namhyung Kim 2024-07-12 21:19 ` Ian Rogers 0 siblings, 1 reply; 12+ messages in thread From: Namhyung Kim @ 2024-07-12 20:33 UTC (permalink / raw) To: Ian Rogers Cc: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo, Mark Rutland, Alexander Shishkin, Jiri Olsa, Adrian Hunter, Kan Liang, James Clark, linux-kernel, linux-perf-users Hi Ian, On Tue, Jul 02, 2024 at 09:24:50PM -0700, Ian Rogers wrote: > On Tue, Jul 2, 2024 at 8:24 PM Namhyung Kim <namhyung@kernel.org> wrote: > > > > Hi Ian, > > > > On Sun, Jun 30, 2024 at 09:42:35PM -0700, Ian Rogers wrote: > > > Using waitpid can cause stdout/stderr of the child process to be > > > lost. Use Linux's /prod/<pid>/status file to determine if the process > > > has reached the zombie state. Use the 'status' file rather than 'stat' > > > to avoid issues around skipping the process name. > > > > > > Signed-off-by: Ian Rogers <irogers@google.com> > > > --- > > > tools/lib/subcmd/run-command.c | 33 +++++++++++++++++++++++++++++++++ > > > 1 file changed, 33 insertions(+) > > > > > > diff --git a/tools/lib/subcmd/run-command.c b/tools/lib/subcmd/run-command.c > > > index 4e3a557a2f37..ec06683e77a0 100644 > > > --- a/tools/lib/subcmd/run-command.c > > > +++ b/tools/lib/subcmd/run-command.c > > > @@ -2,6 +2,7 @@ > > > #include <unistd.h> > > > #include <sys/types.h> > > > #include <sys/stat.h> > > > +#include <ctype.h> > > > #include <fcntl.h> > > > #include <string.h> > > > #include <linux/string.h> > > > @@ -217,8 +218,40 @@ static int wait_or_whine(struct child_process *cmd, bool block) > > > > > > int check_if_command_finished(struct child_process *cmd) > > > { > > > +#ifdef __linux__ > > > > Is this really necessary? I don't think we plan to support other OS.. > > I don't think it'd be unreasonable to say run "perf report" on > Windows, or using wasm inside a web browser. Part of the reason for > doing things this way was to keep the WNOHANG logic although this > change no longer uses it for __linux__. I'm not sure we are ready to run it on other platforms. So I think it's better simply remove it for now. Thanks, Namhyung > > > + char filename[FILENAME_MAX + 12]; > > > + char status_line[256]; > > > + FILE *status_file; > > > + > > > + /* > > > + * Check by reading /proc/<pid>/status as calling waitpid causes > > > + * stdout/stderr to be closed and data lost. > > > + */ > > > + sprintf(filename, "/proc/%d/status", cmd->pid); > > > + status_file = fopen(filename, "r"); > > > + if (status_file == NULL) { > > > + /* Open failed assume finish_command was called. */ > > > + return true; > > > + } > > > + while (fgets(status_line, sizeof(status_line), status_file) != NULL) { > > > + char *p; > > > + > > > + if (strncmp(status_line, "State:", 6)) > > > + continue; > > > + > > > + fclose(status_file); > > > + p = status_line + 6; > > > + while (isspace(*p)) > > > + p++; > > > + return *p == 'Z'; > > > + } > > > + /* Read failed assume finish_command was called. */ > > > + fclose(status_file); > > > + return true; > > > +#else > > > wait_or_whine(cmd, /*block=*/false); > > > return cmd->finished; > > > +#endif > > > } > > > > > > int finish_command(struct child_process *cmd) > > > -- > > > 2.45.2.803.g4e1b14247a-goog > > > ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v2 1/2] tools subcmd: Add non-waitpid check_if_command_finished() 2024-07-12 20:33 ` Namhyung Kim @ 2024-07-12 21:19 ` Ian Rogers 2024-07-13 14:59 ` Namhyung Kim 0 siblings, 1 reply; 12+ messages in thread From: Ian Rogers @ 2024-07-12 21:19 UTC (permalink / raw) To: Namhyung Kim Cc: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo, Mark Rutland, Alexander Shishkin, Jiri Olsa, Adrian Hunter, Kan Liang, James Clark, linux-kernel, linux-perf-users On Fri, Jul 12, 2024 at 1:33 PM Namhyung Kim <namhyung@kernel.org> wrote: > > Hi Ian, > > On Tue, Jul 02, 2024 at 09:24:50PM -0700, Ian Rogers wrote: > > On Tue, Jul 2, 2024 at 8:24 PM Namhyung Kim <namhyung@kernel.org> wrote: > > > > > > Hi Ian, > > > > > > On Sun, Jun 30, 2024 at 09:42:35PM -0700, Ian Rogers wrote: > > > > Using waitpid can cause stdout/stderr of the child process to be > > > > lost. Use Linux's /prod/<pid>/status file to determine if the process > > > > has reached the zombie state. Use the 'status' file rather than 'stat' > > > > to avoid issues around skipping the process name. > > > > > > > > Signed-off-by: Ian Rogers <irogers@google.com> > > > > --- > > > > tools/lib/subcmd/run-command.c | 33 +++++++++++++++++++++++++++++++++ > > > > 1 file changed, 33 insertions(+) > > > > > > > > diff --git a/tools/lib/subcmd/run-command.c b/tools/lib/subcmd/run-command.c > > > > index 4e3a557a2f37..ec06683e77a0 100644 > > > > --- a/tools/lib/subcmd/run-command.c > > > > +++ b/tools/lib/subcmd/run-command.c > > > > @@ -2,6 +2,7 @@ > > > > #include <unistd.h> > > > > #include <sys/types.h> > > > > #include <sys/stat.h> > > > > +#include <ctype.h> > > > > #include <fcntl.h> > > > > #include <string.h> > > > > #include <linux/string.h> > > > > @@ -217,8 +218,40 @@ static int wait_or_whine(struct child_process *cmd, bool block) > > > > > > > > int check_if_command_finished(struct child_process *cmd) > > > > { > > > > +#ifdef __linux__ > > > > > > Is this really necessary? I don't think we plan to support other OS.. > > > > I don't think it'd be unreasonable to say run "perf report" on > > Windows, or using wasm inside a web browser. Part of the reason for > > doing things this way was to keep the WNOHANG logic although this > > change no longer uses it for __linux__. > > I'm not sure we are ready to run it on other platforms. So I think > it's better simply remove it for now. So in the office hours there was some discussion with a potential new contributor whose development platform is OS/X. It's fairly obvious this code can't work on anything but Linux and using #error feels annoying. The waitpid code is tested and has a known issue, but I think it is better than just breaking anyone not on Linux. Thanks, Ian > Thanks, > Namhyung > > > > > > + char filename[FILENAME_MAX + 12]; > > > > + char status_line[256]; > > > > + FILE *status_file; > > > > + > > > > + /* > > > > + * Check by reading /proc/<pid>/status as calling waitpid causes > > > > + * stdout/stderr to be closed and data lost. > > > > + */ > > > > + sprintf(filename, "/proc/%d/status", cmd->pid); > > > > + status_file = fopen(filename, "r"); > > > > + if (status_file == NULL) { > > > > + /* Open failed assume finish_command was called. */ > > > > + return true; > > > > + } > > > > + while (fgets(status_line, sizeof(status_line), status_file) != NULL) { > > > > + char *p; > > > > + > > > > + if (strncmp(status_line, "State:", 6)) > > > > + continue; > > > > + > > > > + fclose(status_file); > > > > + p = status_line + 6; > > > > + while (isspace(*p)) > > > > + p++; > > > > + return *p == 'Z'; > > > > + } > > > > + /* Read failed assume finish_command was called. */ > > > > + fclose(status_file); > > > > + return true; > > > > +#else > > > > wait_or_whine(cmd, /*block=*/false); > > > > return cmd->finished; > > > > +#endif > > > > } > > > > > > > > int finish_command(struct child_process *cmd) > > > > -- > > > > 2.45.2.803.g4e1b14247a-goog > > > > ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v2 1/2] tools subcmd: Add non-waitpid check_if_command_finished() 2024-07-12 21:19 ` Ian Rogers @ 2024-07-13 14:59 ` Namhyung Kim 2024-07-14 18:13 ` Ian Rogers 0 siblings, 1 reply; 12+ messages in thread From: Namhyung Kim @ 2024-07-13 14:59 UTC (permalink / raw) To: Ian Rogers Cc: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo, Mark Rutland, Alexander Shishkin, Jiri Olsa, Adrian Hunter, Kan Liang, James Clark, linux-kernel, linux-perf-users On Fri, Jul 12, 2024 at 02:19:58PM -0700, Ian Rogers wrote: > On Fri, Jul 12, 2024 at 1:33 PM Namhyung Kim <namhyung@kernel.org> wrote: > > > > Hi Ian, > > > > On Tue, Jul 02, 2024 at 09:24:50PM -0700, Ian Rogers wrote: > > > On Tue, Jul 2, 2024 at 8:24 PM Namhyung Kim <namhyung@kernel.org> wrote: > > > > > > > > Hi Ian, > > > > > > > > On Sun, Jun 30, 2024 at 09:42:35PM -0700, Ian Rogers wrote: > > > > > Using waitpid can cause stdout/stderr of the child process to be > > > > > lost. Use Linux's /prod/<pid>/status file to determine if the process > > > > > has reached the zombie state. Use the 'status' file rather than 'stat' > > > > > to avoid issues around skipping the process name. > > > > > > > > > > Signed-off-by: Ian Rogers <irogers@google.com> > > > > > --- > > > > > tools/lib/subcmd/run-command.c | 33 +++++++++++++++++++++++++++++++++ > > > > > 1 file changed, 33 insertions(+) > > > > > > > > > > diff --git a/tools/lib/subcmd/run-command.c b/tools/lib/subcmd/run-command.c > > > > > index 4e3a557a2f37..ec06683e77a0 100644 > > > > > --- a/tools/lib/subcmd/run-command.c > > > > > +++ b/tools/lib/subcmd/run-command.c > > > > > @@ -2,6 +2,7 @@ > > > > > #include <unistd.h> > > > > > #include <sys/types.h> > > > > > #include <sys/stat.h> > > > > > +#include <ctype.h> > > > > > #include <fcntl.h> > > > > > #include <string.h> > > > > > #include <linux/string.h> > > > > > @@ -217,8 +218,40 @@ static int wait_or_whine(struct child_process *cmd, bool block) > > > > > > > > > > int check_if_command_finished(struct child_process *cmd) > > > > > { > > > > > +#ifdef __linux__ > > > > > > > > Is this really necessary? I don't think we plan to support other OS.. > > > > > > I don't think it'd be unreasonable to say run "perf report" on > > > Windows, or using wasm inside a web browser. Part of the reason for > > > doing things this way was to keep the WNOHANG logic although this > > > change no longer uses it for __linux__. > > > > I'm not sure we are ready to run it on other platforms. So I think > > it's better simply remove it for now. > > So in the office hours there was some discussion with a potential new > contributor whose development platform is OS/X. It's fairly obvious > this code can't work on anything but Linux and using #error feels > annoying. The waitpid code is tested and has a known issue, but I > think it is better than just breaking anyone not on Linux. I feel like it's a potential issue and should be handled by the potentiall contributor. Until that happens, we can assume Linux and keep the code minimal. Thanks, Namhyung > > > > > > > + char filename[FILENAME_MAX + 12]; > > > > > + char status_line[256]; > > > > > + FILE *status_file; > > > > > + > > > > > + /* > > > > > + * Check by reading /proc/<pid>/status as calling waitpid causes > > > > > + * stdout/stderr to be closed and data lost. > > > > > + */ > > > > > + sprintf(filename, "/proc/%d/status", cmd->pid); > > > > > + status_file = fopen(filename, "r"); > > > > > + if (status_file == NULL) { > > > > > + /* Open failed assume finish_command was called. */ > > > > > + return true; > > > > > + } > > > > > + while (fgets(status_line, sizeof(status_line), status_file) != NULL) { > > > > > + char *p; > > > > > + > > > > > + if (strncmp(status_line, "State:", 6)) > > > > > + continue; > > > > > + > > > > > + fclose(status_file); > > > > > + p = status_line + 6; > > > > > + while (isspace(*p)) > > > > > + p++; > > > > > + return *p == 'Z'; > > > > > + } > > > > > + /* Read failed assume finish_command was called. */ > > > > > + fclose(status_file); > > > > > + return true; > > > > > +#else > > > > > wait_or_whine(cmd, /*block=*/false); > > > > > return cmd->finished; > > > > > +#endif > > > > > } > > > > > > > > > > int finish_command(struct child_process *cmd) > > > > > -- > > > > > 2.45.2.803.g4e1b14247a-goog > > > > > ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v2 1/2] tools subcmd: Add non-waitpid check_if_command_finished() 2024-07-13 14:59 ` Namhyung Kim @ 2024-07-14 18:13 ` Ian Rogers 0 siblings, 0 replies; 12+ messages in thread From: Ian Rogers @ 2024-07-14 18:13 UTC (permalink / raw) To: Namhyung Kim Cc: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo, Mark Rutland, Alexander Shishkin, Jiri Olsa, Adrian Hunter, Kan Liang, James Clark, linux-kernel, linux-perf-users On Sat, Jul 13, 2024 at 8:00 AM Namhyung Kim <namhyung@kernel.org> wrote: > > On Fri, Jul 12, 2024 at 02:19:58PM -0700, Ian Rogers wrote: > > On Fri, Jul 12, 2024 at 1:33 PM Namhyung Kim <namhyung@kernel.org> wrote: > > > > > > Hi Ian, > > > > > > On Tue, Jul 02, 2024 at 09:24:50PM -0700, Ian Rogers wrote: > > > > On Tue, Jul 2, 2024 at 8:24 PM Namhyung Kim <namhyung@kernel.org> wrote: > > > > > > > > > > Hi Ian, > > > > > > > > > > On Sun, Jun 30, 2024 at 09:42:35PM -0700, Ian Rogers wrote: > > > > > > Using waitpid can cause stdout/stderr of the child process to be > > > > > > lost. Use Linux's /prod/<pid>/status file to determine if the process > > > > > > has reached the zombie state. Use the 'status' file rather than 'stat' > > > > > > to avoid issues around skipping the process name. > > > > > > > > > > > > Signed-off-by: Ian Rogers <irogers@google.com> > > > > > > --- > > > > > > tools/lib/subcmd/run-command.c | 33 +++++++++++++++++++++++++++++++++ > > > > > > 1 file changed, 33 insertions(+) > > > > > > > > > > > > diff --git a/tools/lib/subcmd/run-command.c b/tools/lib/subcmd/run-command.c > > > > > > index 4e3a557a2f37..ec06683e77a0 100644 > > > > > > --- a/tools/lib/subcmd/run-command.c > > > > > > +++ b/tools/lib/subcmd/run-command.c > > > > > > @@ -2,6 +2,7 @@ > > > > > > #include <unistd.h> > > > > > > #include <sys/types.h> > > > > > > #include <sys/stat.h> > > > > > > +#include <ctype.h> > > > > > > #include <fcntl.h> > > > > > > #include <string.h> > > > > > > #include <linux/string.h> > > > > > > @@ -217,8 +218,40 @@ static int wait_or_whine(struct child_process *cmd, bool block) > > > > > > > > > > > > int check_if_command_finished(struct child_process *cmd) > > > > > > { > > > > > > +#ifdef __linux__ > > > > > > > > > > Is this really necessary? I don't think we plan to support other OS.. > > > > > > > > I don't think it'd be unreasonable to say run "perf report" on > > > > Windows, or using wasm inside a web browser. Part of the reason for > > > > doing things this way was to keep the WNOHANG logic although this > > > > change no longer uses it for __linux__. > > > > > > I'm not sure we are ready to run it on other platforms. So I think > > > it's better simply remove it for now. > > > > So in the office hours there was some discussion with a potential new > > contributor whose development platform is OS/X. It's fairly obvious > > this code can't work on anything but Linux and using #error feels > > annoying. The waitpid code is tested and has a known issue, but I > > think it is better than just breaking anyone not on Linux. > > I feel like it's a potential issue and should be handled by the > potentiall contributor. Until that happens, we can assume Linux > and keep the code minimal. I'm not clear what the issue is. Arnaldo took the WNOHANG waitpid contribution but I asked him to drop it due to losing stdout/stderr in parallel mode due to the waitpid closing these file descriptors early - we're not running in parallel mode by default any more. Reading procfs to determine zombie state is clearly a Linux only thing, hence the ifdef. I'm keen to keep to any extent possible the perf tool running on non-Linux platforms, for example, gathering a data file on a server or embedded system then wanting to do perf report on a different machine which may not be running Linux. libsubcmd is used throughout the tool and we have many subprocesses for pagers, objdump, addr2line, etc. I don't agree with making such a core library Linux only and there's no obligation for the maintainers to take these patches. I disagree with a minimal patch. Thanks, Ian > Thanks, > Namhyung > > > > > > > > > > + char filename[FILENAME_MAX + 12]; > > > > > > + char status_line[256]; > > > > > > + FILE *status_file; > > > > > > + > > > > > > + /* > > > > > > + * Check by reading /proc/<pid>/status as calling waitpid causes > > > > > > + * stdout/stderr to be closed and data lost. > > > > > > + */ > > > > > > + sprintf(filename, "/proc/%d/status", cmd->pid); > > > > > > + status_file = fopen(filename, "r"); > > > > > > + if (status_file == NULL) { > > > > > > + /* Open failed assume finish_command was called. */ > > > > > > + return true; > > > > > > + } > > > > > > + while (fgets(status_line, sizeof(status_line), status_file) != NULL) { > > > > > > + char *p; > > > > > > + > > > > > > + if (strncmp(status_line, "State:", 6)) > > > > > > + continue; > > > > > > + > > > > > > + fclose(status_file); > > > > > > + p = status_line + 6; > > > > > > + while (isspace(*p)) > > > > > > + p++; > > > > > > + return *p == 'Z'; > > > > > > + } > > > > > > + /* Read failed assume finish_command was called. */ > > > > > > + fclose(status_file); > > > > > > + return true; > > > > > > +#else > > > > > > wait_or_whine(cmd, /*block=*/false); > > > > > > return cmd->finished; > > > > > > +#endif > > > > > > } > > > > > > > > > > > > int finish_command(struct child_process *cmd) > > > > > > -- > > > > > > 2.45.2.803.g4e1b14247a-goog > > > > > > ^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH v2 2/2] perf test: Display number of remaining tests 2024-07-01 4:42 [PATCH v2 0/2] perf test: Display remaining tests while waiting Ian Rogers 2024-07-01 4:42 ` [PATCH v2 1/2] tools subcmd: Add non-waitpid check_if_command_finished() Ian Rogers @ 2024-07-01 4:42 ` Ian Rogers 2024-07-03 3:39 ` Namhyung Kim 1 sibling, 1 reply; 12+ messages in thread From: Ian Rogers @ 2024-07-01 4:42 UTC (permalink / raw) To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo, Namhyung Kim, Mark Rutland, Alexander Shishkin, Jiri Olsa, Ian Rogers, Adrian Hunter, Kan Liang, James Clark, linux-kernel, linux-perf-users Before polling or sleeping to wait for a test to complete, print out ": Running (<num> remaining)" where the number of remaining tests is determined by iterating over the remaining tests and seeing which return true for check_if_command_finished. After the delay, erase the line and either update it with the new number of remaining tests, or print the test's result. This allows a user to know a test is running and in parallel mode (default) how many of the tests are waiting to complete. If color mode is disabled then avoid displaying the "Running" message. Signed-off-by: Ian Rogers <irogers@google.com> --- tools/perf/tests/builtin-test.c | 77 ++++++++++++++++++++++----------- tools/perf/util/color.h | 1 + 2 files changed, 53 insertions(+), 25 deletions(-) diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c index c3d84b67ca8e..23be9139f229 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c @@ -241,7 +241,10 @@ static int run_test_child(struct child_process *process) return -err; } -static int print_test_result(struct test_suite *t, int i, int subtest, int result, int width) +#define TEST_RUNNING -3 + +static int print_test_result(struct test_suite *t, int i, int subtest, int result, int width, + int remaining) { if (has_subtests(t)) { int subw = width > 2 ? width - 2 : width; @@ -251,6 +254,9 @@ static int print_test_result(struct test_suite *t, int i, int subtest, int resul pr_info("%3d: %-*s:", i + 1, width, test_description(t, subtest)); switch (result) { + case TEST_RUNNING: + color_fprintf(stderr, PERF_COLOR_YELLOW, " Running (%d remaining)\n", remaining); + break; case TEST_OK: pr_info(" Ok\n"); break; @@ -272,13 +278,15 @@ static int print_test_result(struct test_suite *t, int i, int subtest, int resul return 0; } -static int finish_test(struct child_test *child_test, int width) +static int finish_test(struct child_test **child_tests, int running_test, int child_test_num, + int width) { + struct child_test *child_test = child_tests[running_test]; struct test_suite *t = child_test->test; int i = child_test->test_num; int subi = child_test->subtest; int err = child_test->process.err; - bool err_done = err <= 0; + bool err_done = false; struct strbuf err_output = STRBUF_INIT; int ret; @@ -293,7 +301,7 @@ static int finish_test(struct child_test *child_test, int width) * Busy loop reading from the child's stdout/stderr that are set to be * non-blocking until EOF. */ - if (!err_done) + if (err > 0) fcntl(err, F_SETFL, O_NONBLOCK); if (verbose > 1) { if (has_subtests(t)) @@ -307,29 +315,48 @@ static int finish_test(struct child_test *child_test, int width) .events = POLLIN | POLLERR | POLLHUP | POLLNVAL, }, }; - char buf[512]; - ssize_t len; - - /* Poll to avoid excessive spinning, timeout set for 100ms. */ - poll(pfds, ARRAY_SIZE(pfds), /*timeout=*/100); - if (!err_done && pfds[0].revents) { - errno = 0; - len = read(err, buf, sizeof(buf) - 1); - - if (len <= 0) { - err_done = errno != EAGAIN; - } else { - buf[len] = '\0'; - if (verbose > 1) - fprintf(stdout, "%s", buf); - else + if (perf_use_color_default) { + int tests_in_progress = running_test; + + for (int y = running_test; y < child_test_num; y++) { + if (check_if_command_finished(&child_tests[y]->process)) + tests_in_progress++; + } + print_test_result(t, i, subi, TEST_RUNNING, width, + child_test_num - tests_in_progress); + } + + err_done = true; + if (err <= 0) { + /* No child stderr to poll, sleep for 10ms for child to complete. */ + usleep(10 * 1000); + } else { + /* Poll to avoid excessive spinning, timeout set for 100ms. */ + poll(pfds, ARRAY_SIZE(pfds), /*timeout=*/100); + if (pfds[0].revents) { + char buf[512]; + ssize_t len; + + len = read(err, buf, sizeof(buf) - 1); + + if (len > 0) { + err_done = false; + buf[len] = '\0'; strbuf_addstr(&err_output, buf); + } } } + if (err_done) + err_done = check_if_command_finished(&child_test->process); + + if (perf_use_color_default) { + /* Erase "Running (.. remaining)" line printed before poll/sleep. */ + fprintf(debug_file(), PERF_COLOR_DELETE_LINE); + } } /* Clean up child process. */ ret = finish_command(&child_test->process); - if (verbose == 1 && ret == TEST_FAIL) { + if (verbose > 1 || (verbose == 1 && ret == TEST_FAIL)) { /* Add header for test that was skipped above. */ if (has_subtests(t)) pr_info("%3d.%1d: %s:\n", i + 1, subi + 1, test_description(t, subi)); @@ -338,7 +365,7 @@ static int finish_test(struct child_test *child_test, int width) fprintf(stderr, "%s", err_output.buf); } strbuf_release(&err_output); - print_test_result(t, i, subi, ret, width); + print_test_result(t, i, subi, ret, width, /*remaining=*/0); if (err > 0) close(err); return 0; @@ -354,7 +381,7 @@ static int start_test(struct test_suite *test, int i, int subi, struct child_tes pr_debug("--- start ---\n"); err = test_function(test, subi)(test, subi); pr_debug("---- end ----\n"); - print_test_result(test, i, subi, err, width); + print_test_result(test, i, subi, err, width, /*remaining=*/0); return 0; } @@ -379,7 +406,7 @@ static int start_test(struct test_suite *test, int i, int subi, struct child_tes err = start_command(&(*child)->process); if (err || !sequential) return err; - return finish_test(*child, width); + return finish_test(child, /*running_test=*/0, /*child_test_num=*/1, width); } #define for_each_test(j, k, t) \ @@ -464,7 +491,7 @@ static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist) } for (i = 0; i < child_test_num; i++) { if (!sequential) { - int ret = finish_test(child_tests[i], width); + int ret = finish_test(child_tests, i, child_test_num, width); if (ret) return ret; diff --git a/tools/perf/util/color.h b/tools/perf/util/color.h index 01f7bed21c9b..4b9f8d5d4439 100644 --- a/tools/perf/util/color.h +++ b/tools/perf/util/color.h @@ -22,6 +22,7 @@ #define MIN_GREEN 0.5 #define MIN_RED 5.0 +#define PERF_COLOR_DELETE_LINE "\033[A\33[2K\r" /* * This variable stores the value of color.ui */ -- 2.45.2.803.g4e1b14247a-goog ^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH v2 2/2] perf test: Display number of remaining tests 2024-07-01 4:42 ` [PATCH v2 2/2] perf test: Display number of remaining tests Ian Rogers @ 2024-07-03 3:39 ` Namhyung Kim 2024-07-03 4:30 ` Ian Rogers 0 siblings, 1 reply; 12+ messages in thread From: Namhyung Kim @ 2024-07-03 3:39 UTC (permalink / raw) To: Ian Rogers Cc: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo, Mark Rutland, Alexander Shishkin, Jiri Olsa, Adrian Hunter, Kan Liang, James Clark, linux-kernel, linux-perf-users On Sun, Jun 30, 2024 at 09:42:36PM -0700, Ian Rogers wrote: > Before polling or sleeping to wait for a test to complete, print out > ": Running (<num> remaining)" where the number of remaining tests is > determined by iterating over the remaining tests and seeing which > return true for check_if_command_finished. After the delay, erase the > line and either update it with the new number of remaining tests, or > print the test's result. This allows a user to know a test is running > and in parallel mode (default) how many of the tests are waiting to It's not default anymore. :) > complete. If color mode is disabled then avoid displaying the > "Running" message. > > Signed-off-by: Ian Rogers <irogers@google.com> > --- > tools/perf/tests/builtin-test.c | 77 ++++++++++++++++++++++----------- > tools/perf/util/color.h | 1 + > 2 files changed, 53 insertions(+), 25 deletions(-) > > diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c > index c3d84b67ca8e..23be9139f229 100644 > --- a/tools/perf/tests/builtin-test.c > +++ b/tools/perf/tests/builtin-test.c > @@ -241,7 +241,10 @@ static int run_test_child(struct child_process *process) > return -err; > } > > -static int print_test_result(struct test_suite *t, int i, int subtest, int result, int width) > +#define TEST_RUNNING -3 > + > +static int print_test_result(struct test_suite *t, int i, int subtest, int result, int width, > + int remaining) > { > if (has_subtests(t)) { > int subw = width > 2 ? width - 2 : width; > @@ -251,6 +254,9 @@ static int print_test_result(struct test_suite *t, int i, int subtest, int resul > pr_info("%3d: %-*s:", i + 1, width, test_description(t, subtest)); > > switch (result) { > + case TEST_RUNNING: > + color_fprintf(stderr, PERF_COLOR_YELLOW, " Running (%d remaining)\n", remaining); > + break; > case TEST_OK: > pr_info(" Ok\n"); > break; > @@ -272,13 +278,15 @@ static int print_test_result(struct test_suite *t, int i, int subtest, int resul > return 0; > } > > -static int finish_test(struct child_test *child_test, int width) > +static int finish_test(struct child_test **child_tests, int running_test, int child_test_num, > + int width) > { > + struct child_test *child_test = child_tests[running_test]; > struct test_suite *t = child_test->test; > int i = child_test->test_num; > int subi = child_test->subtest; > int err = child_test->process.err; > - bool err_done = err <= 0; > + bool err_done = false; > struct strbuf err_output = STRBUF_INIT; > int ret; > > @@ -293,7 +301,7 @@ static int finish_test(struct child_test *child_test, int width) > * Busy loop reading from the child's stdout/stderr that are set to be > * non-blocking until EOF. > */ > - if (!err_done) > + if (err > 0) > fcntl(err, F_SETFL, O_NONBLOCK); > if (verbose > 1) { > if (has_subtests(t)) > @@ -307,29 +315,48 @@ static int finish_test(struct child_test *child_test, int width) > .events = POLLIN | POLLERR | POLLHUP | POLLNVAL, > }, > }; > - char buf[512]; > - ssize_t len; > - > - /* Poll to avoid excessive spinning, timeout set for 100ms. */ > - poll(pfds, ARRAY_SIZE(pfds), /*timeout=*/100); > - if (!err_done && pfds[0].revents) { > - errno = 0; > - len = read(err, buf, sizeof(buf) - 1); > - > - if (len <= 0) { > - err_done = errno != EAGAIN; > - } else { > - buf[len] = '\0'; > - if (verbose > 1) > - fprintf(stdout, "%s", buf); > - else > + if (perf_use_color_default) { > + int tests_in_progress = running_test; > + > + for (int y = running_test; y < child_test_num; y++) { > + if (check_if_command_finished(&child_tests[y]->process)) > + tests_in_progress++; > + } > + print_test_result(t, i, subi, TEST_RUNNING, width, > + child_test_num - tests_in_progress); > + } > + > + err_done = true; > + if (err <= 0) { > + /* No child stderr to poll, sleep for 10ms for child to complete. */ > + usleep(10 * 1000); > + } else { > + /* Poll to avoid excessive spinning, timeout set for 100ms. */ > + poll(pfds, ARRAY_SIZE(pfds), /*timeout=*/100); When I tested this patch, I saw it refreshes too often in parallel mode. Maybe 100ms is too short? I don't know if it's from usleep (10ms) or here. Thanks, Namhyung > + if (pfds[0].revents) { > + char buf[512]; > + ssize_t len; > + > + len = read(err, buf, sizeof(buf) - 1); > + > + if (len > 0) { > + err_done = false; > + buf[len] = '\0'; > strbuf_addstr(&err_output, buf); > + } > } > } > + if (err_done) > + err_done = check_if_command_finished(&child_test->process); > + > + if (perf_use_color_default) { > + /* Erase "Running (.. remaining)" line printed before poll/sleep. */ > + fprintf(debug_file(), PERF_COLOR_DELETE_LINE); > + } > } > /* Clean up child process. */ > ret = finish_command(&child_test->process); > - if (verbose == 1 && ret == TEST_FAIL) { > + if (verbose > 1 || (verbose == 1 && ret == TEST_FAIL)) { > /* Add header for test that was skipped above. */ > if (has_subtests(t)) > pr_info("%3d.%1d: %s:\n", i + 1, subi + 1, test_description(t, subi)); > @@ -338,7 +365,7 @@ static int finish_test(struct child_test *child_test, int width) > fprintf(stderr, "%s", err_output.buf); > } > strbuf_release(&err_output); > - print_test_result(t, i, subi, ret, width); > + print_test_result(t, i, subi, ret, width, /*remaining=*/0); > if (err > 0) > close(err); > return 0; > @@ -354,7 +381,7 @@ static int start_test(struct test_suite *test, int i, int subi, struct child_tes > pr_debug("--- start ---\n"); > err = test_function(test, subi)(test, subi); > pr_debug("---- end ----\n"); > - print_test_result(test, i, subi, err, width); > + print_test_result(test, i, subi, err, width, /*remaining=*/0); > return 0; > } > > @@ -379,7 +406,7 @@ static int start_test(struct test_suite *test, int i, int subi, struct child_tes > err = start_command(&(*child)->process); > if (err || !sequential) > return err; > - return finish_test(*child, width); > + return finish_test(child, /*running_test=*/0, /*child_test_num=*/1, width); > } > > #define for_each_test(j, k, t) \ > @@ -464,7 +491,7 @@ static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist) > } > for (i = 0; i < child_test_num; i++) { > if (!sequential) { > - int ret = finish_test(child_tests[i], width); > + int ret = finish_test(child_tests, i, child_test_num, width); > > if (ret) > return ret; > diff --git a/tools/perf/util/color.h b/tools/perf/util/color.h > index 01f7bed21c9b..4b9f8d5d4439 100644 > --- a/tools/perf/util/color.h > +++ b/tools/perf/util/color.h > @@ -22,6 +22,7 @@ > #define MIN_GREEN 0.5 > #define MIN_RED 5.0 > > +#define PERF_COLOR_DELETE_LINE "\033[A\33[2K\r" > /* > * This variable stores the value of color.ui > */ > -- > 2.45.2.803.g4e1b14247a-goog > ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v2 2/2] perf test: Display number of remaining tests 2024-07-03 3:39 ` Namhyung Kim @ 2024-07-03 4:30 ` Ian Rogers 2024-07-03 21:23 ` Namhyung Kim 0 siblings, 1 reply; 12+ messages in thread From: Ian Rogers @ 2024-07-03 4:30 UTC (permalink / raw) To: Namhyung Kim Cc: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo, Mark Rutland, Alexander Shishkin, Jiri Olsa, Adrian Hunter, Kan Liang, James Clark, linux-kernel, linux-perf-users On Tue, Jul 2, 2024 at 8:40 PM Namhyung Kim <namhyung@kernel.org> wrote: > > On Sun, Jun 30, 2024 at 09:42:36PM -0700, Ian Rogers wrote: > > Before polling or sleeping to wait for a test to complete, print out > > ": Running (<num> remaining)" where the number of remaining tests is > > determined by iterating over the remaining tests and seeing which > > return true for check_if_command_finished. After the delay, erase the > > line and either update it with the new number of remaining tests, or > > print the test's result. This allows a user to know a test is running > > and in parallel mode (default) how many of the tests are waiting to > > It's not default anymore. :) > > > > complete. If color mode is disabled then avoid displaying the > > "Running" message. > > > > Signed-off-by: Ian Rogers <irogers@google.com> > > --- > > tools/perf/tests/builtin-test.c | 77 ++++++++++++++++++++++----------- > > tools/perf/util/color.h | 1 + > > 2 files changed, 53 insertions(+), 25 deletions(-) > > > > diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c > > index c3d84b67ca8e..23be9139f229 100644 > > --- a/tools/perf/tests/builtin-test.c > > +++ b/tools/perf/tests/builtin-test.c > > @@ -241,7 +241,10 @@ static int run_test_child(struct child_process *process) > > return -err; > > } > > > > -static int print_test_result(struct test_suite *t, int i, int subtest, int result, int width) > > +#define TEST_RUNNING -3 > > + > > +static int print_test_result(struct test_suite *t, int i, int subtest, int result, int width, > > + int remaining) > > { > > if (has_subtests(t)) { > > int subw = width > 2 ? width - 2 : width; > > @@ -251,6 +254,9 @@ static int print_test_result(struct test_suite *t, int i, int subtest, int resul > > pr_info("%3d: %-*s:", i + 1, width, test_description(t, subtest)); > > > > switch (result) { > > + case TEST_RUNNING: > > + color_fprintf(stderr, PERF_COLOR_YELLOW, " Running (%d remaining)\n", remaining); > > + break; > > case TEST_OK: > > pr_info(" Ok\n"); > > break; > > @@ -272,13 +278,15 @@ static int print_test_result(struct test_suite *t, int i, int subtest, int resul > > return 0; > > } > > > > -static int finish_test(struct child_test *child_test, int width) > > +static int finish_test(struct child_test **child_tests, int running_test, int child_test_num, > > + int width) > > { > > + struct child_test *child_test = child_tests[running_test]; > > struct test_suite *t = child_test->test; > > int i = child_test->test_num; > > int subi = child_test->subtest; > > int err = child_test->process.err; > > - bool err_done = err <= 0; > > + bool err_done = false; > > struct strbuf err_output = STRBUF_INIT; > > int ret; > > > > @@ -293,7 +301,7 @@ static int finish_test(struct child_test *child_test, int width) > > * Busy loop reading from the child's stdout/stderr that are set to be > > * non-blocking until EOF. > > */ > > - if (!err_done) > > + if (err > 0) > > fcntl(err, F_SETFL, O_NONBLOCK); > > if (verbose > 1) { > > if (has_subtests(t)) > > @@ -307,29 +315,48 @@ static int finish_test(struct child_test *child_test, int width) > > .events = POLLIN | POLLERR | POLLHUP | POLLNVAL, > > }, > > }; > > - char buf[512]; > > - ssize_t len; > > - > > - /* Poll to avoid excessive spinning, timeout set for 100ms. */ > > - poll(pfds, ARRAY_SIZE(pfds), /*timeout=*/100); > > - if (!err_done && pfds[0].revents) { > > - errno = 0; > > - len = read(err, buf, sizeof(buf) - 1); > > - > > - if (len <= 0) { > > - err_done = errno != EAGAIN; > > - } else { > > - buf[len] = '\0'; > > - if (verbose > 1) > > - fprintf(stdout, "%s", buf); > > - else > > + if (perf_use_color_default) { > > + int tests_in_progress = running_test; > > + > > + for (int y = running_test; y < child_test_num; y++) { > > + if (check_if_command_finished(&child_tests[y]->process)) > > + tests_in_progress++; > > + } > > + print_test_result(t, i, subi, TEST_RUNNING, width, > > + child_test_num - tests_in_progress); > > + } > > + > > + err_done = true; > > + if (err <= 0) { > > + /* No child stderr to poll, sleep for 10ms for child to complete. */ > > + usleep(10 * 1000); > > + } else { > > + /* Poll to avoid excessive spinning, timeout set for 100ms. */ > > + poll(pfds, ARRAY_SIZE(pfds), /*timeout=*/100); > > When I tested this patch, I saw it refreshes too often in parallel mode. > Maybe 100ms is too short? I don't know if it's from usleep (10ms) or > here. It's usually the poll and I suspect it is the test writing a lot of output. I agree it can look a little flickery but it is also responsive in terms of not waiting too long before moving to the next test. I think it is possible to improve on the code here, the main thing I was after was making the output writing self contained and not split between start test and finish test, as that won't work well in the parallel case. Thanks, Ian > Thanks, > Namhyung > > > > + if (pfds[0].revents) { > > + char buf[512]; > > + ssize_t len; > > + > > + len = read(err, buf, sizeof(buf) - 1); > > + > > + if (len > 0) { > > + err_done = false; > > + buf[len] = '\0'; > > strbuf_addstr(&err_output, buf); > > + } > > } > > } > > + if (err_done) > > + err_done = check_if_command_finished(&child_test->process); > > + > > + if (perf_use_color_default) { > > + /* Erase "Running (.. remaining)" line printed before poll/sleep. */ > > + fprintf(debug_file(), PERF_COLOR_DELETE_LINE); > > + } > > } > > /* Clean up child process. */ > > ret = finish_command(&child_test->process); > > - if (verbose == 1 && ret == TEST_FAIL) { > > + if (verbose > 1 || (verbose == 1 && ret == TEST_FAIL)) { > > /* Add header for test that was skipped above. */ > > if (has_subtests(t)) > > pr_info("%3d.%1d: %s:\n", i + 1, subi + 1, test_description(t, subi)); > > @@ -338,7 +365,7 @@ static int finish_test(struct child_test *child_test, int width) > > fprintf(stderr, "%s", err_output.buf); > > } > > strbuf_release(&err_output); > > - print_test_result(t, i, subi, ret, width); > > + print_test_result(t, i, subi, ret, width, /*remaining=*/0); > > if (err > 0) > > close(err); > > return 0; > > @@ -354,7 +381,7 @@ static int start_test(struct test_suite *test, int i, int subi, struct child_tes > > pr_debug("--- start ---\n"); > > err = test_function(test, subi)(test, subi); > > pr_debug("---- end ----\n"); > > - print_test_result(test, i, subi, err, width); > > + print_test_result(test, i, subi, err, width, /*remaining=*/0); > > return 0; > > } > > > > @@ -379,7 +406,7 @@ static int start_test(struct test_suite *test, int i, int subi, struct child_tes > > err = start_command(&(*child)->process); > > if (err || !sequential) > > return err; > > - return finish_test(*child, width); > > + return finish_test(child, /*running_test=*/0, /*child_test_num=*/1, width); > > } > > > > #define for_each_test(j, k, t) \ > > @@ -464,7 +491,7 @@ static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist) > > } > > for (i = 0; i < child_test_num; i++) { > > if (!sequential) { > > - int ret = finish_test(child_tests[i], width); > > + int ret = finish_test(child_tests, i, child_test_num, width); > > > > if (ret) > > return ret; > > diff --git a/tools/perf/util/color.h b/tools/perf/util/color.h > > index 01f7bed21c9b..4b9f8d5d4439 100644 > > --- a/tools/perf/util/color.h > > +++ b/tools/perf/util/color.h > > @@ -22,6 +22,7 @@ > > #define MIN_GREEN 0.5 > > #define MIN_RED 5.0 > > > > +#define PERF_COLOR_DELETE_LINE "\033[A\33[2K\r" > > /* > > * This variable stores the value of color.ui > > */ > > -- > > 2.45.2.803.g4e1b14247a-goog > > ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v2 2/2] perf test: Display number of remaining tests 2024-07-03 4:30 ` Ian Rogers @ 2024-07-03 21:23 ` Namhyung Kim 0 siblings, 0 replies; 12+ messages in thread From: Namhyung Kim @ 2024-07-03 21:23 UTC (permalink / raw) To: Ian Rogers Cc: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo, Mark Rutland, Alexander Shishkin, Jiri Olsa, Adrian Hunter, Kan Liang, James Clark, linux-kernel, linux-perf-users On Tue, Jul 02, 2024 at 09:30:44PM -0700, Ian Rogers wrote: > On Tue, Jul 2, 2024 at 8:40 PM Namhyung Kim <namhyung@kernel.org> wrote: > > > > On Sun, Jun 30, 2024 at 09:42:36PM -0700, Ian Rogers wrote: > > > Before polling or sleeping to wait for a test to complete, print out > > > ": Running (<num> remaining)" where the number of remaining tests is > > > determined by iterating over the remaining tests and seeing which > > > return true for check_if_command_finished. After the delay, erase the > > > line and either update it with the new number of remaining tests, or > > > print the test's result. This allows a user to know a test is running > > > and in parallel mode (default) how many of the tests are waiting to > > > > It's not default anymore. :) > > > > > > > complete. If color mode is disabled then avoid displaying the > > > "Running" message. > > > > > > Signed-off-by: Ian Rogers <irogers@google.com> > > > --- > > > tools/perf/tests/builtin-test.c | 77 ++++++++++++++++++++++----------- > > > tools/perf/util/color.h | 1 + > > > 2 files changed, 53 insertions(+), 25 deletions(-) > > > > > > diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c > > > index c3d84b67ca8e..23be9139f229 100644 > > > --- a/tools/perf/tests/builtin-test.c > > > +++ b/tools/perf/tests/builtin-test.c > > > @@ -241,7 +241,10 @@ static int run_test_child(struct child_process *process) > > > return -err; > > > } > > > > > > -static int print_test_result(struct test_suite *t, int i, int subtest, int result, int width) > > > +#define TEST_RUNNING -3 > > > + > > > +static int print_test_result(struct test_suite *t, int i, int subtest, int result, int width, > > > + int remaining) > > > { > > > if (has_subtests(t)) { > > > int subw = width > 2 ? width - 2 : width; > > > @@ -251,6 +254,9 @@ static int print_test_result(struct test_suite *t, int i, int subtest, int resul > > > pr_info("%3d: %-*s:", i + 1, width, test_description(t, subtest)); > > > > > > switch (result) { > > > + case TEST_RUNNING: > > > + color_fprintf(stderr, PERF_COLOR_YELLOW, " Running (%d remaining)\n", remaining); > > > + break; > > > case TEST_OK: > > > pr_info(" Ok\n"); > > > break; > > > @@ -272,13 +278,15 @@ static int print_test_result(struct test_suite *t, int i, int subtest, int resul > > > return 0; > > > } > > > > > > -static int finish_test(struct child_test *child_test, int width) > > > +static int finish_test(struct child_test **child_tests, int running_test, int child_test_num, > > > + int width) > > > { > > > + struct child_test *child_test = child_tests[running_test]; > > > struct test_suite *t = child_test->test; > > > int i = child_test->test_num; > > > int subi = child_test->subtest; > > > int err = child_test->process.err; > > > - bool err_done = err <= 0; > > > + bool err_done = false; > > > struct strbuf err_output = STRBUF_INIT; > > > int ret; > > > > > > @@ -293,7 +301,7 @@ static int finish_test(struct child_test *child_test, int width) > > > * Busy loop reading from the child's stdout/stderr that are set to be > > > * non-blocking until EOF. > > > */ > > > - if (!err_done) > > > + if (err > 0) > > > fcntl(err, F_SETFL, O_NONBLOCK); > > > if (verbose > 1) { > > > if (has_subtests(t)) > > > @@ -307,29 +315,48 @@ static int finish_test(struct child_test *child_test, int width) > > > .events = POLLIN | POLLERR | POLLHUP | POLLNVAL, > > > }, > > > }; > > > - char buf[512]; > > > - ssize_t len; > > > - > > > - /* Poll to avoid excessive spinning, timeout set for 100ms. */ > > > - poll(pfds, ARRAY_SIZE(pfds), /*timeout=*/100); > > > - if (!err_done && pfds[0].revents) { > > > - errno = 0; > > > - len = read(err, buf, sizeof(buf) - 1); > > > - > > > - if (len <= 0) { > > > - err_done = errno != EAGAIN; > > > - } else { > > > - buf[len] = '\0'; > > > - if (verbose > 1) > > > - fprintf(stdout, "%s", buf); > > > - else > > > + if (perf_use_color_default) { > > > + int tests_in_progress = running_test; > > > + > > > + for (int y = running_test; y < child_test_num; y++) { > > > + if (check_if_command_finished(&child_tests[y]->process)) > > > + tests_in_progress++; > > > + } > > > + print_test_result(t, i, subi, TEST_RUNNING, width, > > > + child_test_num - tests_in_progress); > > > + } > > > + > > > + err_done = true; > > > + if (err <= 0) { > > > + /* No child stderr to poll, sleep for 10ms for child to complete. */ > > > + usleep(10 * 1000); > > > + } else { > > > + /* Poll to avoid excessive spinning, timeout set for 100ms. */ > > > + poll(pfds, ARRAY_SIZE(pfds), /*timeout=*/100); > > > > When I tested this patch, I saw it refreshes too often in parallel mode. > > Maybe 100ms is too short? I don't know if it's from usleep (10ms) or > > here. > > It's usually the poll and I suspect it is the test writing a lot of > output. I agree it can look a little flickery but it is also > responsive in terms of not waiting too long before moving to the next > test. I think it is possible to improve on the code here, the main > thing I was after was making the output writing self contained and not > split between start test and finish test, as that won't work well in > the parallel case. Is it possible to skip the rewriting if nothing is changed? Thanks, Namhyung ^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2024-07-14 18:14 UTC | newest] Thread overview: 12+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2024-07-01 4:42 [PATCH v2 0/2] perf test: Display remaining tests while waiting Ian Rogers 2024-07-01 4:42 ` [PATCH v2 1/2] tools subcmd: Add non-waitpid check_if_command_finished() Ian Rogers 2024-07-03 3:23 ` Namhyung Kim 2024-07-03 4:24 ` Ian Rogers 2024-07-12 20:33 ` Namhyung Kim 2024-07-12 21:19 ` Ian Rogers 2024-07-13 14:59 ` Namhyung Kim 2024-07-14 18:13 ` Ian Rogers 2024-07-01 4:42 ` [PATCH v2 2/2] perf test: Display number of remaining tests Ian Rogers 2024-07-03 3:39 ` Namhyung Kim 2024-07-03 4:30 ` Ian Rogers 2024-07-03 21:23 ` Namhyung Kim
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).