diff options
author | Kan Liang <kan.liang@intel.com> | 2015-05-10 15:13:15 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2015-06-07 10:09:06 -0400 |
commit | c4937a91ea56b546234b0608a413ebad90536d26 (patch) | |
tree | 5bcefc489a99022a8ffb70d5328703286a42885d | |
parent | f38b0dbb491a6987e198aa6b428db8692a6480f8 (diff) |
perf tools: handle PERF_RECORD_LOST_SAMPLES
This patch modifies the perf tool to handle the new RECORD type,
PERF_RECORD_LOST_SAMPLES.
The number of lost-sample events is stored in
.nr_events[PERF_RECORD_LOST_SAMPLES]. The exact number of samples
which the kernel dropped is stored in total_lost_samples.
When the percentage of dropped samples is greater than 5%, a warning
is printed.
Here are some examples:
Eg 1, Recording different frequently-occurring events is safe with the
patch. Only a very low drop rate is associated with such actions.
$ perf record -e '{cycles:p,instructions:p}' -c 20003 --no-time ~/tchain ~/tchain
$ perf report -D | tail
SAMPLE events: 120243
MMAP2 events: 5
LOST_SAMPLES events: 24
FINISHED_ROUND events: 15
cycles:p stats:
TOTAL events: 59348
SAMPLE events: 59348
instructions:p stats:
TOTAL events: 60895
SAMPLE events: 60895
$ perf report --stdio --group
# To display the perf.data header info, please use --header/--header-only options.
#
#
# Total Lost Samples: 24
#
# Samples: 120K of event 'anon group { cycles:p, instructions:p }'
# Event count (approx.): 24048600000
#
# Overhead Command Shared Object Symbol
# ................ ........... ................
..................................
#
99.74% 99.86% tchain_edit tchain_edit [.] f3
0.09% 0.02% tchain_edit tchain_edit [.] f2
0.04% 0.00% tchain_edit [kernel.vmlinux] [k] ixgbe_read_reg
Eg 2, Recording the same thing multiple times can lead to high drop
rate, but it is not a useful configuration.
$ perf record -e '{cycles:p,cycles:p}' -c 20003 --no-time ~/tchain
Warning: Processed 600592 samples and lost 99.73% samples!
[perf record: Woken up 148 times to write data]
[perf record: Captured and wrote 36.922 MB perf.data (1206322 samples)]
[perf record: Woken up 1 times to write data]
[perf record: Captured and wrote 0.121 MB perf.data (1629 samples)]
Signed-off-by: Kan Liang <kan.liang@intel.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: acme@infradead.org
Cc: eranian@google.com
Link: http://lkml.kernel.org/r/1431285195-14269-9-git-send-email-kan.liang@intel.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r-- | tools/perf/builtin-report.c | 1 | ||||
-rw-r--r-- | tools/perf/util/event.c | 9 | ||||
-rw-r--r-- | tools/perf/util/event.h | 17 | ||||
-rw-r--r-- | tools/perf/util/machine.c | 10 | ||||
-rw-r--r-- | tools/perf/util/machine.h | 2 | ||||
-rw-r--r-- | tools/perf/util/session.c | 19 | ||||
-rw-r--r-- | tools/perf/util/tool.h | 1 |
7 files changed, 59 insertions, 0 deletions
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 56025d90622f..628090b478ab 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
@@ -320,6 +320,7 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist, | |||
320 | { | 320 | { |
321 | struct perf_evsel *pos; | 321 | struct perf_evsel *pos; |
322 | 322 | ||
323 | fprintf(stdout, "#\n# Total Lost Samples: %lu\n#\n", evlist->stats.total_lost_samples); | ||
323 | evlist__for_each(evlist, pos) { | 324 | evlist__for_each(evlist, pos) { |
324 | struct hists *hists = evsel__hists(pos); | 325 | struct hists *hists = evsel__hists(pos); |
325 | const char *evname = perf_evsel__name(pos); | 326 | const char *evname = perf_evsel__name(pos); |
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index c1925968a8af..793b1503d437 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c | |||
@@ -25,6 +25,7 @@ static const char *perf_event__names[] = { | |||
25 | [PERF_RECORD_SAMPLE] = "SAMPLE", | 25 | [PERF_RECORD_SAMPLE] = "SAMPLE", |
26 | [PERF_RECORD_AUX] = "AUX", | 26 | [PERF_RECORD_AUX] = "AUX", |
27 | [PERF_RECORD_ITRACE_START] = "ITRACE_START", | 27 | [PERF_RECORD_ITRACE_START] = "ITRACE_START", |
28 | [PERF_RECORD_LOST_SAMPLES] = "LOST_SAMPLES", | ||
28 | [PERF_RECORD_HEADER_ATTR] = "ATTR", | 29 | [PERF_RECORD_HEADER_ATTR] = "ATTR", |
29 | [PERF_RECORD_HEADER_EVENT_TYPE] = "EVENT_TYPE", | 30 | [PERF_RECORD_HEADER_EVENT_TYPE] = "EVENT_TYPE", |
30 | [PERF_RECORD_HEADER_TRACING_DATA] = "TRACING_DATA", | 31 | [PERF_RECORD_HEADER_TRACING_DATA] = "TRACING_DATA", |
@@ -712,6 +713,14 @@ int perf_event__process_itrace_start(struct perf_tool *tool __maybe_unused, | |||
712 | return machine__process_itrace_start_event(machine, event); | 713 | return machine__process_itrace_start_event(machine, event); |
713 | } | 714 | } |
714 | 715 | ||
716 | int perf_event__process_lost_samples(struct perf_tool *tool __maybe_unused, | ||
717 | union perf_event *event, | ||
718 | struct perf_sample *sample, | ||
719 | struct machine *machine) | ||
720 | { | ||
721 | return machine__process_lost_samples_event(machine, event, sample); | ||
722 | } | ||
723 | |||
715 | size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp) | 724 | size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp) |
716 | { | 725 | { |
717 | return fprintf(fp, " %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64 "]: %c %s\n", | 726 | return fprintf(fp, " %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64 "]: %c %s\n", |
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 97179abc80a1..5dc51ada05df 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h | |||
@@ -52,6 +52,11 @@ struct lost_event { | |||
52 | u64 lost; | 52 | u64 lost; |
53 | }; | 53 | }; |
54 | 54 | ||
55 | struct lost_samples_event { | ||
56 | struct perf_event_header header; | ||
57 | u64 lost; | ||
58 | }; | ||
59 | |||
55 | /* | 60 | /* |
56 | * PERF_FORMAT_ENABLED | PERF_FORMAT_RUNNING | PERF_FORMAT_ID | 61 | * PERF_FORMAT_ENABLED | PERF_FORMAT_RUNNING | PERF_FORMAT_ID |
57 | */ | 62 | */ |
@@ -235,6 +240,12 @@ enum auxtrace_error_type { | |||
235 | * total_lost tells exactly how many events the kernel in fact lost, i.e. it is | 240 | * total_lost tells exactly how many events the kernel in fact lost, i.e. it is |
236 | * the sum of all struct lost_event.lost fields reported. | 241 | * the sum of all struct lost_event.lost fields reported. |
237 | * | 242 | * |
243 | * The kernel discards mixed up samples and sends the number in a | ||
244 | * PERF_RECORD_LOST_SAMPLES event. The number of lost-samples events is stored | ||
245 | * in .nr_events[PERF_RECORD_LOST_SAMPLES] while total_lost_samples tells | ||
246 | * exactly how many samples the kernel in fact dropped, i.e. it is the sum of | ||
247 | * all struct lost_samples_event.lost fields reported. | ||
248 | * | ||
238 | * The total_period is needed because by default auto-freq is used, so | 249 | * The total_period is needed because by default auto-freq is used, so |
239 | * multipling nr_events[PERF_EVENT_SAMPLE] by a frequency isn't possible to get | 250 | * multipling nr_events[PERF_EVENT_SAMPLE] by a frequency isn't possible to get |
240 | * the total number of low level events, it is necessary to to sum all struct | 251 | * the total number of low level events, it is necessary to to sum all struct |
@@ -244,6 +255,7 @@ struct events_stats { | |||
244 | u64 total_period; | 255 | u64 total_period; |
245 | u64 total_non_filtered_period; | 256 | u64 total_non_filtered_period; |
246 | u64 total_lost; | 257 | u64 total_lost; |
258 | u64 total_lost_samples; | ||
247 | u64 total_invalid_chains; | 259 | u64 total_invalid_chains; |
248 | u32 nr_events[PERF_RECORD_HEADER_MAX]; | 260 | u32 nr_events[PERF_RECORD_HEADER_MAX]; |
249 | u32 nr_non_filtered_samples; | 261 | u32 nr_non_filtered_samples; |
@@ -342,6 +354,7 @@ union perf_event { | |||
342 | struct comm_event comm; | 354 | struct comm_event comm; |
343 | struct fork_event fork; | 355 | struct fork_event fork; |
344 | struct lost_event lost; | 356 | struct lost_event lost; |
357 | struct lost_samples_event lost_samples; | ||
345 | struct read_event read; | 358 | struct read_event read; |
346 | struct throttle_event throttle; | 359 | struct throttle_event throttle; |
347 | struct sample_event sample; | 360 | struct sample_event sample; |
@@ -390,6 +403,10 @@ int perf_event__process_lost(struct perf_tool *tool, | |||
390 | union perf_event *event, | 403 | union perf_event *event, |
391 | struct perf_sample *sample, | 404 | struct perf_sample *sample, |
392 | struct machine *machine); | 405 | struct machine *machine); |
406 | int perf_event__process_lost_samples(struct perf_tool *tool, | ||
407 | union perf_event *event, | ||
408 | struct perf_sample *sample, | ||
409 | struct machine *machine); | ||
393 | int perf_event__process_aux(struct perf_tool *tool, | 410 | int perf_event__process_aux(struct perf_tool *tool, |
394 | union perf_event *event, | 411 | union perf_event *event, |
395 | struct perf_sample *sample, | 412 | struct perf_sample *sample, |
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 9e02c86f39f5..f15ed24a22ac 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c | |||
@@ -482,6 +482,14 @@ int machine__process_lost_event(struct machine *machine __maybe_unused, | |||
482 | return 0; | 482 | return 0; |
483 | } | 483 | } |
484 | 484 | ||
485 | int machine__process_lost_samples_event(struct machine *machine __maybe_unused, | ||
486 | union perf_event *event, struct perf_sample *sample) | ||
487 | { | ||
488 | dump_printf(": id:%" PRIu64 ": lost samples :%" PRIu64 "\n", | ||
489 | sample->id, event->lost_samples.lost); | ||
490 | return 0; | ||
491 | } | ||
492 | |||
485 | static struct dso* | 493 | static struct dso* |
486 | machine__module_dso(struct machine *machine, struct kmod_path *m, | 494 | machine__module_dso(struct machine *machine, struct kmod_path *m, |
487 | const char *filename) | 495 | const char *filename) |
@@ -1419,6 +1427,8 @@ int machine__process_event(struct machine *machine, union perf_event *event, | |||
1419 | ret = machine__process_aux_event(machine, event); break; | 1427 | ret = machine__process_aux_event(machine, event); break; |
1420 | case PERF_RECORD_ITRACE_START: | 1428 | case PERF_RECORD_ITRACE_START: |
1421 | ret = machine__process_itrace_start_event(machine, event); | 1429 | ret = machine__process_itrace_start_event(machine, event); |
1430 | case PERF_RECORD_LOST_SAMPLES: | ||
1431 | ret = machine__process_lost_samples_event(machine, event, sample); break; | ||
1422 | break; | 1432 | break; |
1423 | default: | 1433 | default: |
1424 | ret = -1; | 1434 | ret = -1; |
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h index 39a0ca06cbd8..8e1f796fd137 100644 --- a/tools/perf/util/machine.h +++ b/tools/perf/util/machine.h | |||
@@ -81,6 +81,8 @@ int machine__process_fork_event(struct machine *machine, union perf_event *event | |||
81 | struct perf_sample *sample); | 81 | struct perf_sample *sample); |
82 | int machine__process_lost_event(struct machine *machine, union perf_event *event, | 82 | int machine__process_lost_event(struct machine *machine, union perf_event *event, |
83 | struct perf_sample *sample); | 83 | struct perf_sample *sample); |
84 | int machine__process_lost_samples_event(struct machine *machine, union perf_event *event, | ||
85 | struct perf_sample *sample); | ||
84 | int machine__process_aux_event(struct machine *machine, | 86 | int machine__process_aux_event(struct machine *machine, |
85 | union perf_event *event); | 87 | union perf_event *event); |
86 | int machine__process_itrace_start_event(struct machine *machine, | 88 | int machine__process_itrace_start_event(struct machine *machine, |
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 39fe09d5a87e..88d87bf3049f 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
@@ -325,6 +325,8 @@ void perf_tool__fill_defaults(struct perf_tool *tool) | |||
325 | tool->exit = process_event_stub; | 325 | tool->exit = process_event_stub; |
326 | if (tool->lost == NULL) | 326 | if (tool->lost == NULL) |
327 | tool->lost = perf_event__process_lost; | 327 | tool->lost = perf_event__process_lost; |
328 | if (tool->lost_samples == NULL) | ||
329 | tool->lost_samples = perf_event__process_lost_samples; | ||
328 | if (tool->aux == NULL) | 330 | if (tool->aux == NULL) |
329 | tool->aux = perf_event__process_aux; | 331 | tool->aux = perf_event__process_aux; |
330 | if (tool->itrace_start == NULL) | 332 | if (tool->itrace_start == NULL) |
@@ -606,6 +608,7 @@ static perf_event__swap_op perf_event__swap_ops[] = { | |||
606 | [PERF_RECORD_SAMPLE] = perf_event__all64_swap, | 608 | [PERF_RECORD_SAMPLE] = perf_event__all64_swap, |
607 | [PERF_RECORD_AUX] = perf_event__aux_swap, | 609 | [PERF_RECORD_AUX] = perf_event__aux_swap, |
608 | [PERF_RECORD_ITRACE_START] = perf_event__itrace_start_swap, | 610 | [PERF_RECORD_ITRACE_START] = perf_event__itrace_start_swap, |
611 | [PERF_RECORD_LOST_SAMPLES] = perf_event__all64_swap, | ||
609 | [PERF_RECORD_HEADER_ATTR] = perf_event__hdr_attr_swap, | 612 | [PERF_RECORD_HEADER_ATTR] = perf_event__hdr_attr_swap, |
610 | [PERF_RECORD_HEADER_EVENT_TYPE] = perf_event__event_type_swap, | 613 | [PERF_RECORD_HEADER_EVENT_TYPE] = perf_event__event_type_swap, |
611 | [PERF_RECORD_HEADER_TRACING_DATA] = perf_event__tracing_data_swap, | 614 | [PERF_RECORD_HEADER_TRACING_DATA] = perf_event__tracing_data_swap, |
@@ -1049,6 +1052,10 @@ static int machines__deliver_event(struct machines *machines, | |||
1049 | if (tool->lost == perf_event__process_lost) | 1052 | if (tool->lost == perf_event__process_lost) |
1050 | evlist->stats.total_lost += event->lost.lost; | 1053 | evlist->stats.total_lost += event->lost.lost; |
1051 | return tool->lost(tool, event, sample, machine); | 1054 | return tool->lost(tool, event, sample, machine); |
1055 | case PERF_RECORD_LOST_SAMPLES: | ||
1056 | if (tool->lost_samples == perf_event__process_lost_samples) | ||
1057 | evlist->stats.total_lost_samples += event->lost_samples.lost; | ||
1058 | return tool->lost_samples(tool, event, sample, machine); | ||
1052 | case PERF_RECORD_READ: | 1059 | case PERF_RECORD_READ: |
1053 | return tool->read(tool, event, sample, evsel, machine); | 1060 | return tool->read(tool, event, sample, evsel, machine); |
1054 | case PERF_RECORD_THROTTLE: | 1061 | case PERF_RECORD_THROTTLE: |
@@ -1286,6 +1293,18 @@ static void perf_session__warn_about_errors(const struct perf_session *session) | |||
1286 | stats->nr_events[PERF_RECORD_LOST]); | 1293 | stats->nr_events[PERF_RECORD_LOST]); |
1287 | } | 1294 | } |
1288 | 1295 | ||
1296 | if (session->tool->lost_samples == perf_event__process_lost_samples) { | ||
1297 | double drop_rate; | ||
1298 | |||
1299 | drop_rate = (double)stats->total_lost_samples / | ||
1300 | (double) (stats->nr_events[PERF_RECORD_SAMPLE] + stats->total_lost_samples); | ||
1301 | if (drop_rate > 0.05) { | ||
1302 | ui__warning("Processed %lu samples and lost %3.2f%% samples!\n\n", | ||
1303 | stats->nr_events[PERF_RECORD_SAMPLE] + stats->total_lost_samples, | ||
1304 | drop_rate * 100.0); | ||
1305 | } | ||
1306 | } | ||
1307 | |||
1289 | if (stats->nr_unknown_events != 0) { | 1308 | if (stats->nr_unknown_events != 0) { |
1290 | ui__warning("Found %u unknown events!\n\n" | 1309 | ui__warning("Found %u unknown events!\n\n" |
1291 | "Is this an older tool processing a perf.data " | 1310 | "Is this an older tool processing a perf.data " |
diff --git a/tools/perf/util/tool.h b/tools/perf/util/tool.h index 7f282ad1d2bd..c307dd438286 100644 --- a/tools/perf/util/tool.h +++ b/tools/perf/util/tool.h | |||
@@ -43,6 +43,7 @@ struct perf_tool { | |||
43 | fork, | 43 | fork, |
44 | exit, | 44 | exit, |
45 | lost, | 45 | lost, |
46 | lost_samples, | ||
46 | aux, | 47 | aux, |
47 | itrace_start, | 48 | itrace_start, |
48 | throttle, | 49 | throttle, |