On Wed, Jun 03, 2026 at 04:21:44PM -0300, Arnaldo Carvalho de Melo wrote:
On Tue, Jun 02, 2026 at 03:26:44PM +0100, James Clark wrote:
Add a --workload-ctl=fifo:ctl-fifo[,ack-fifo] option for 'perf test -w'. When set, run_workload() opens the named FIFO, writes enable before invoking the builtin workload, writes disable before returning, and waits for ack responses when an ack FIFO is provided to ensure that the workload doesn't run until the events are enabled.
This can be used to limit the scope of the recording to only the workload execution and avoid recording Perf setup and teardown code if Perf record is started with events disabled (-D 1).
I see no mention to the equivalent in 'perf record', from its man page:
Nevermind, I should've read it completely :-\
- Arnaldo
--control=fifo:ctl-fifo[,ack-fifo]:: --control=fd:ctl-fd[,ack-fd]:: ctl-fifo / ack-fifo are opened and used as ctl-fd / ack-fd as follows. Listen on ctl-fd descriptor for command to control measurement.
Available commands:
'enable' : enable events
'disable' : disable events
'enable name' : enable event 'name'
'disable name' : disable event 'name'
'snapshot' : AUX area tracing snapshot).
'stop' : stop perf record
'ping' : ping
'evlist [-v|-g|-F] : display all events
-F Show just the sample frequency used for each event. -v Show all fields. -g Show event group information.
Can this be shared code?
- Arnaldo
Assisted-by: Codex:GPT-5.5 Signed-off-by: James Clark james.clark@linaro.org
tools/perf/Documentation/perf-test.txt | 6 ++ tools/perf/tests/builtin-test.c | 184 ++++++++++++++++++++++++++++++++- 2 files changed, 188 insertions(+), 2 deletions(-)
diff --git a/tools/perf/Documentation/perf-test.txt b/tools/perf/Documentation/perf-test.txt index 32da0d1fa86a..1faf30d4a7be 100644 --- a/tools/perf/Documentation/perf-test.txt +++ b/tools/perf/Documentation/perf-test.txt @@ -69,3 +69,9 @@ OPTIONS --list-workloads:: List the available workloads to use with -w/--workload.
+--workload-ctl=fifo:ctl-fifo[,ack-fifo]::
- Write 'enable' to ctl-fifo before running the workload and 'disable'
- before returning. If ack-fifo is provided, the workload runner waits for
- an 'ack' response after each command. This scopes the recording to only
- the workload if used with 'perf record -D 1 --control ...'.
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c index f2c135891477..d5df3efdce3b 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c @@ -50,6 +50,7 @@ static bool sequential; static unsigned int runs_per_test = 1; const char *dso_to_test; const char *test_objdump_path = "objdump"; +static const char *workload_control; /*
- List of architecture specific tests. Not a weak symbol as the array length is
@@ -161,6 +162,11 @@ static struct test_workload *workloads[] = { #endif }; +struct workload_control {
- int ctl_fd;
- int ack_fd;
+};
#define workloads__for_each(workload) \ for (unsigned i = 0; i < ARRAY_SIZE(workloads) && ({ workload = workloads[i]; 1; }); i++) @@ -711,13 +717,185 @@ static int workloads__fprintf_list(FILE *fp) return printed; } +static int perf_control_open_fifo(struct workload_control *ctl, const char *str) +{
- char *s, *p;
- int ret;
- if (strncmp(str, "fifo:", 5))
return -EINVAL;- str += 5;
- if (!*str || *str == ',')
return -EINVAL;- s = strdup(str);
- if (!s)
return -ENOMEM;- p = strchr(s, ',');
- if (p)
*p = '\0';- ctl->ctl_fd = open(s, O_WRONLY | O_CLOEXEC);
- if (ctl->ctl_fd < 0) {
ret = -errno;pr_err("Failed to open workload control FIFO '%s': %m\n", s);free(s);return ret;- }
- if (p && *++p) {
ctl->ack_fd = open(p, O_RDONLY | O_CLOEXEC);if (ctl->ack_fd < 0) {ret = -errno;pr_err("Failed to open workload control ack FIFO '%s': %m\n", p);close(ctl->ctl_fd);ctl->ctl_fd = -1;free(s);return ret;}- }
- free(s);
- return 0;
+}
+static int perf_control_open(struct workload_control *ctl) +{
- int ret;
- if (!workload_control)
return 0;- ret = perf_control_open_fifo(ctl, workload_control);
- if (ret == -EINVAL) {
pr_err("Unsupported workload control spec '%s', expected fifo:ctl-fifo[,ack-fifo]\n",workload_control);- }
- return ret;
+}
+static void perf_control_close(struct workload_control *ctl) +{
- if (ctl->ctl_fd >= 0) {
close(ctl->ctl_fd);ctl->ctl_fd = -1;- }
- if (ctl->ack_fd >= 0) {
close(ctl->ack_fd);ctl->ack_fd = -1;- }
+}
+static int perf_control_write_cmd(int fd, const char *cmd) +{
- size_t len = strlen(cmd);
- ssize_t ret;
- while (len) {
ret = write(fd, cmd, len);if (ret < 0) {if (errno == EINTR)continue;pr_err("Failed to write perf control command '%s': %m\n", cmd);return -1;}if (!ret) {pr_err("Failed to write perf control command '%s': short write\n", cmd);return -1;}cmd += ret;len -= ret;- }
- return 0;
+}
+static int perf_control_read_ack(int fd) +{
- char buf[16];
- ssize_t ret;
- do {
ret = read(fd, buf, sizeof(buf) - 1);- } while (ret < 0 && errno == EINTR);
- if (ret < 0) {
pr_err("Failed to read perf control ack: %m\n");return -1;- }
- if (!ret) {
pr_err("Unexpected EOF while reading perf control ack\n");return -1;- }
- buf[ret] = '\0';
- for (ssize_t i = 0; i < ret; i++) {
if (buf[i] == '\n' || buf[i] == '\0') {buf[i] = '\0';break;}- }
- if (strcmp(buf, "ack")) {
pr_err("Unexpected perf control ack: %s\n", buf);return -1;- }
- return 0;
+}
+static int perf_control_send(struct workload_control *ctl, const char *cmd) +{
- if (ctl->ctl_fd < 0)
return 0;- if (perf_control_write_cmd(ctl->ctl_fd, cmd))
return -1;- if (ctl->ack_fd >= 0 && perf_control_read_ack(ctl->ack_fd))
return -1;- return 0;
+}
static int run_workload(const char *work, int argc, const char **argv) { struct test_workload *twl; workloads__for_each(twl) {
if (!strcmp(twl->name, work))return twl->func(argc, argv);
struct workload_control ctl = {.ctl_fd = -1,.ack_fd = -1,};int control_ret, ret;if (strcmp(twl->name, work))continue;ret = perf_control_open(&ctl);if (ret)return ret;if (perf_control_send(&ctl, "enable\n")) {perf_control_close(&ctl);return -1;}ret = twl->func(argc, argv);control_ret = perf_control_send(&ctl, "disable\n");perf_control_close(&ctl);if (control_ret)return -1; }return ret;pr_info("No workload found: %s\n", work); @@ -799,6 +977,8 @@ int cmd_test(int argc, const char **argv) OPT_UINTEGER('r', "runs-per-test", &runs_per_test, "Run each test the given number of times, default 1"), OPT_STRING('w', "workload", &workload, "work", "workload to run for testing, use '--list-workloads' to list the available ones."),
- OPT_STRING(0, "workload-ctl", &workload_control, "fifo:ctl-fifo[,ack-fifo]",
OPT_BOOLEAN(0, "list-workloads", &list_workloads, "List the available builtin workloads to use with -w/--workload"), OPT_STRING(0, "dso", &dso_to_test, "dso", "dso to test"), OPT_STRING(0, "objdump", &test_objdump_path, "path","Write enable to the fifo just before running the workload and disable after, with optional ack from ack-fifo"),-- 2.34.1