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

perf intel-tpebs: Filter non-workload samples

If perf is running with a benchmark then we want the retirement
latency samples associated with the benchmark rather than from the
system as a whole.

Use the workload's PID to filter out samples that aren't from the
workload or its children.

Signed-off-by: Ian Rogers <irogers@google.com>
Tested-by: Weilin Wang <weilin.wang@intel.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: James Clark <james.clark@linaro.org>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: https://lore.kernel.org/r/20250430200108.243234-1-irogers@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Ian Rogers and committed by
Arnaldo Carvalho de Melo
bcfab08d 1c5721ca

+58 -1
+58 -1
tools/perf/util/intel-tpebs.c
··· 3 3 * intel_tpebs.c: Intel TPEBS support 4 4 */ 5 5 6 - 6 + #include <api/fs/fs.h> 7 7 #include <sys/param.h> 8 8 #include <subcmd/run-command.h> 9 9 #include <thread.h> ··· 121 121 return ret; 122 122 } 123 123 124 + static bool is_child_pid(pid_t parent, pid_t child) 125 + { 126 + if (parent < 0 || child < 0) 127 + return false; 128 + 129 + while (true) { 130 + char path[PATH_MAX]; 131 + char line[256]; 132 + FILE *fp; 133 + 134 + new_child: 135 + if (parent == child) 136 + return true; 137 + 138 + if (child <= 0) 139 + return false; 140 + 141 + scnprintf(path, sizeof(path), "%s/%d/status", procfs__mountpoint(), child); 142 + fp = fopen(path, "r"); 143 + if (!fp) { 144 + /* Presumably the process went away. Assume not a child. */ 145 + return false; 146 + } 147 + while (fgets(line, sizeof(line), fp) != NULL) { 148 + if (strncmp(line, "PPid:", 5) == 0) { 149 + fclose(fp); 150 + if (sscanf(line + 5, "%d", &child) != 1) { 151 + /* Unexpected error parsing. */ 152 + return false; 153 + } 154 + goto new_child; 155 + } 156 + } 157 + /* Unexpected EOF. */ 158 + fclose(fp); 159 + return false; 160 + } 161 + } 162 + 163 + static bool should_ignore_sample(const struct perf_sample *sample, const struct tpebs_retire_lat *t) 164 + { 165 + pid_t workload_pid = t->evsel->evlist->workload.pid; 166 + pid_t sample_pid = sample->pid; 167 + 168 + if (workload_pid < 0 || workload_pid == sample_pid) 169 + return false; 170 + 171 + if (!t->evsel->core.attr.inherit) 172 + return true; 173 + 174 + return !is_child_pid(workload_pid, sample_pid); 175 + } 176 + 124 177 static int process_sample_event(const struct perf_tool *tool __maybe_unused, 125 178 union perf_event *event __maybe_unused, 126 179 struct perf_sample *sample, ··· 192 139 if (!t) { 193 140 mutex_unlock(tpebs_mtx_get()); 194 141 return -EINVAL; 142 + } 143 + if (should_ignore_sample(sample, t)) { 144 + mutex_unlock(tpebs_mtx_get()); 145 + return 0; 195 146 } 196 147 /* 197 148 * Need to handle per core results? We are assuming average retire