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

perf tools: Print lost samples due to BPF filter

Print the actual dropped sample count in the event stat.

$ sudo perf record -o- -e cycles --filter 'period < 10000' \
-e instructions --filter 'ip > 0x8000000000000000' perf test -w noploop | \
perf report --stat -i-
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.058 MB - ]

Aggregated stats:
TOTAL events: 469
MMAP events: 268 (57.1%)
COMM events: 2 ( 0.4%)
EXIT events: 1 ( 0.2%)
SAMPLE events: 16 ( 3.4%)
MMAP2 events: 22 ( 4.7%)
LOST_SAMPLES events: 2 ( 0.4%)
KSYMBOL events: 89 (19.0%)
BPF_EVENT events: 39 ( 8.3%)
ATTR events: 2 ( 0.4%)
FINISHED_ROUND events: 1 ( 0.2%)
ID_INDEX events: 1 ( 0.2%)
THREAD_MAP events: 1 ( 0.2%)
CPU_MAP events: 1 ( 0.2%)
EVENT_UPDATE events: 2 ( 0.4%)
TIME_CONV events: 1 ( 0.2%)
FEATURE events: 20 ( 4.3%)
FINISHED_INIT events: 1 ( 0.2%)
cycles stats:
SAMPLE events: 2
LOST_SAMPLES (BPF) events: 4010
instructions stats:
SAMPLE events: 14
LOST_SAMPLES (BPF) events: 3990

Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Ian Rogers <irogers@google.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: KP Singh <kpsingh@kernel.org>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Song Liu <song@kernel.org>
Link: https://lore.kernel.org/r/20240820154504.128923-2-namhyung@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Namhyung Kim and committed by
Arnaldo Carvalho de Melo
1a5474a7 0fe2b18d

+45 -13
+7 -2
tools/perf/builtin-report.c
··· 795 795 796 796 evsel = evlist__id2evsel(rep->session->evlist, sample->id); 797 797 if (evsel) { 798 - hists__inc_nr_lost_samples(evsel__hists(evsel), 799 - event->lost_samples.lost); 798 + struct hists *hists = evsel__hists(evsel); 799 + u32 count = event->lost_samples.lost; 800 + 801 + if (event->header.misc & PERF_RECORD_MISC_LOST_SAMPLES_BPF) 802 + hists__inc_nr_dropped_samples(hists, count); 803 + else 804 + hists__inc_nr_lost_samples(hists, count); 800 805 } 801 806 return 0; 802 807 }
+2 -2
tools/perf/ui/stdio/hist.c
··· 913 913 continue; 914 914 915 915 if (i && total) { 916 - ret += fprintf(fp, "%16s events: %10d (%4.1f%%)\n", 916 + ret += fprintf(fp, "%20s events: %10d (%4.1f%%)\n", 917 917 name, stats->nr_events[i], 918 918 100.0 * stats->nr_events[i] / total); 919 919 } else { 920 - ret += fprintf(fp, "%16s events: %10d\n", 920 + ret += fprintf(fp, "%20s events: %10d\n", 921 921 name, stats->nr_events[i]); 922 922 } 923 923 }
+14 -1
tools/perf/util/events_stats.h
··· 18 18 * PERF_RECORD_LOST_SAMPLES event. The number of lost-samples events is stored 19 19 * in .nr_events[PERF_RECORD_LOST_SAMPLES] while total_lost_samples tells 20 20 * exactly how many samples the kernel in fact dropped, i.e. it is the sum of 21 - * all struct perf_record_lost_samples.lost fields reported. 21 + * all struct perf_record_lost_samples.lost fields reported without setting the 22 + * misc field in the header. 23 + * 24 + * The BPF program can discard samples according to the filter expressions given 25 + * by the user. This number is kept in a BPF map and dumped at the end of perf 26 + * record in a PERF_RECORD_LOST_SAMPLES event. To differentiate it from other 27 + * lost samples, perf tools sets PERF_RECORD_MISC_LOST_SAMPLES_BPF flag in the 28 + * header.misc field. The number of dropped-samples events is stored in 29 + * .nr_events[PERF_RECORD_LOST_SAMPLES] while total_dropped_samples tells 30 + * exactly how many samples the BPF program in fact dropped, i.e. it is the sum 31 + * of all struct perf_record_lost_samples.lost fields reported with the misc 32 + * field set in the header. 22 33 * 23 34 * The total_period is needed because by default auto-freq is used, so 24 35 * multiplying nr_events[PERF_EVENT_SAMPLE] by a frequency isn't possible to get ··· 39 28 struct events_stats { 40 29 u64 total_lost; 41 30 u64 total_lost_samples; 31 + u64 total_dropped_samples; 42 32 u64 total_aux_lost; 43 33 u64 total_aux_partial; 44 34 u64 total_aux_collision; ··· 60 48 u32 nr_samples; 61 49 u32 nr_non_filtered_samples; 62 50 u32 nr_lost_samples; 51 + u32 nr_dropped_samples; 63 52 }; 64 53 65 54 void events_stats__inc(struct events_stats *stats, u32 type);
+15 -4
tools/perf/util/hist.c
··· 2385 2385 hists->stats.nr_lost_samples += lost; 2386 2386 } 2387 2387 2388 + void hists__inc_nr_dropped_samples(struct hists *hists, u32 lost) 2389 + { 2390 + hists->stats.nr_dropped_samples += lost; 2391 + } 2392 + 2388 2393 static struct hist_entry *hists__add_dummy_entry(struct hists *hists, 2389 2394 struct hist_entry *pair) 2390 2395 { ··· 2734 2729 2735 2730 evlist__for_each_entry(evlist, pos) { 2736 2731 struct hists *hists = evsel__hists(pos); 2732 + u64 total_samples = hists->stats.nr_samples; 2737 2733 2738 - if (symbol_conf.skip_empty && !hists->stats.nr_samples && 2739 - !hists->stats.nr_lost_samples) 2734 + total_samples += hists->stats.nr_lost_samples; 2735 + total_samples += hists->stats.nr_dropped_samples; 2736 + 2737 + if (symbol_conf.skip_empty && total_samples == 0) 2740 2738 continue; 2741 2739 2742 2740 ret += fprintf(fp, "%s stats:\n", evsel__name(pos)); 2743 2741 if (hists->stats.nr_samples) 2744 - ret += fprintf(fp, "%16s events: %10d\n", 2742 + ret += fprintf(fp, "%20s events: %10d\n", 2745 2743 "SAMPLE", hists->stats.nr_samples); 2746 2744 if (hists->stats.nr_lost_samples) 2747 - ret += fprintf(fp, "%16s events: %10d\n", 2745 + ret += fprintf(fp, "%20s events: %10d\n", 2748 2746 "LOST_SAMPLES", hists->stats.nr_lost_samples); 2747 + if (hists->stats.nr_dropped_samples) 2748 + ret += fprintf(fp, "%20s events: %10d\n", 2749 + "LOST_SAMPLES (BPF)", hists->stats.nr_dropped_samples); 2749 2750 } 2750 2751 2751 2752 return ret;
+1
tools/perf/util/hist.h
··· 372 372 void hists__inc_nr_events(struct hists *hists); 373 373 void hists__inc_nr_samples(struct hists *hists, bool filtered); 374 374 void hists__inc_nr_lost_samples(struct hists *hists, u32 lost); 375 + void hists__inc_nr_dropped_samples(struct hists *hists, u32 lost); 375 376 376 377 size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, 377 378 int max_cols, float min_pcnt, FILE *fp,
+3 -2
tools/perf/util/machine.c
··· 642 642 int machine__process_lost_samples_event(struct machine *machine __maybe_unused, 643 643 union perf_event *event, struct perf_sample *sample) 644 644 { 645 - dump_printf(": id:%" PRIu64 ": lost samples :%" PRI_lu64 "\n", 646 - sample->id, event->lost_samples.lost); 645 + dump_printf(": id:%" PRIu64 ": lost samples :%" PRI_lu64 "%s\n", 646 + sample->id, event->lost_samples.lost, 647 + event->header.misc & PERF_RECORD_MISC_LOST_SAMPLES_BPF ? " (BPF)" : ""); 647 648 return 0; 648 649 } 649 650
+3 -2
tools/perf/util/session.c
··· 1290 1290 evlist->stats.total_lost += event->lost.lost; 1291 1291 return tool->lost(tool, event, sample, machine); 1292 1292 case PERF_RECORD_LOST_SAMPLES: 1293 - if (tool->lost_samples == perf_event__process_lost_samples && 1294 - !(event->header.misc & PERF_RECORD_MISC_LOST_SAMPLES_BPF)) 1293 + if (event->header.misc & PERF_RECORD_MISC_LOST_SAMPLES_BPF) 1294 + evlist->stats.total_dropped_samples += event->lost_samples.lost; 1295 + else if (tool->lost_samples == perf_event__process_lost_samples) 1295 1296 evlist->stats.total_lost_samples += event->lost_samples.lost; 1296 1297 return tool->lost_samples(tool, event, sample, machine); 1297 1298 case PERF_RECORD_READ: