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

perf stat: Read tool events last

When reading a metric like memory bandwidth on multiple sockets, the
additional sockets will be on CPUS > 0. Because of the affinity
reading, the counters are read on CPU 0 along with the time, then the
later sockets are read. This can lead to the later sockets having a
bandwidth larger than is possible for the period of time. To avoid
this move the reading of tool events to occur after all other events
are read.

Signed-off-by: Ian Rogers <irogers@google.com>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>

authored by

Ian Rogers and committed by
Namhyung Kim
51d87d97 87cc0b44

+39 -6
+39 -6
tools/perf/builtin-stat.c
··· 366 366 return 0; 367 367 } 368 368 369 - static int read_affinity_counters(void) 369 + static int read_counters_with_affinity(void) 370 370 { 371 371 struct evlist_cpu_iterator evlist_cpu_itr; 372 372 struct affinity saved_affinity, *affinity; ··· 385 385 struct evsel *counter = evlist_cpu_itr.evsel; 386 386 387 387 if (evsel__is_bpf(counter)) 388 + continue; 389 + 390 + if (evsel__is_tool(counter)) 388 391 continue; 389 392 390 393 if (!counter->err) ··· 415 412 return 0; 416 413 } 417 414 418 - static int read_counters(void) 415 + static int read_tool_counters(void) 419 416 { 420 - if (!stat_config.stop_read_counter) { 421 - if (read_bpf_map_counters() || 422 - read_affinity_counters()) 423 - return -1; 417 + struct evsel *counter; 418 + 419 + evlist__for_each_entry(evsel_list, counter) { 420 + int idx; 421 + 422 + if (!evsel__is_tool(counter)) 423 + continue; 424 + 425 + perf_cpu_map__for_each_idx(idx, counter->core.cpus) { 426 + if (!counter->err) 427 + counter->err = read_counter_cpu(counter, idx); 428 + } 424 429 } 425 430 return 0; 431 + } 432 + 433 + static int read_counters(void) 434 + { 435 + int ret; 436 + 437 + if (stat_config.stop_read_counter) 438 + return 0; 439 + 440 + // Read all BPF counters first. 441 + ret = read_bpf_map_counters(); 442 + if (ret) 443 + return ret; 444 + 445 + // Read non-BPF and non-tool counters next. 446 + ret = read_counters_with_affinity(); 447 + if (ret) 448 + return ret; 449 + 450 + // Read the tool counters last. This way the duration_time counter 451 + // should always be greater than any other counter's enabled time. 452 + return read_tool_counters(); 426 453 } 427 454 428 455 static void process_counters(void)