diff options
-rw-r--r-- | tools/include/asm-generic/bitsperlong.h | 23 | ||||
-rw-r--r-- | tools/include/linux/compiler.h | 11 | ||||
-rw-r--r-- | tools/lib/api/fd/array.h | 1 | ||||
-rw-r--r-- | tools/lib/api/fs/fs.c | 7 | ||||
-rw-r--r-- | tools/lib/traceevent/event-parse.c | 3 | ||||
-rw-r--r-- | tools/objtool/Makefile | 2 | ||||
-rw-r--r-- | tools/objtool/builtin-check.c | 2 | ||||
-rw-r--r-- | tools/perf/Documentation/perf-record.txt | 22 | ||||
-rw-r--r-- | tools/perf/builtin-record.c | 113 | ||||
-rw-r--r-- | tools/perf/perf.c | 2 | ||||
-rw-r--r-- | tools/perf/perf.h | 2 | ||||
-rw-r--r-- | tools/perf/tests/backward-ring-buffer.c | 14 | ||||
-rw-r--r-- | tools/perf/util/evlist.c | 269 | ||||
-rw-r--r-- | tools/perf/util/evlist.h | 47 | ||||
-rw-r--r-- | tools/perf/util/evsel.c | 16 | ||||
-rw-r--r-- | tools/perf/util/evsel.h | 3 | ||||
-rw-r--r-- | tools/perf/util/parse-events.c | 20 | ||||
-rw-r--r-- | tools/perf/util/parse-events.h | 2 | ||||
-rw-r--r-- | tools/perf/util/parse-events.l | 2 | ||||
-rw-r--r-- | tools/perf/util/session.c | 22 | ||||
-rw-r--r-- | tools/perf/util/sort.c | 8 | ||||
-rw-r--r-- | tools/perf/util/util.h | 2 |
22 files changed, 441 insertions, 152 deletions
diff --git a/tools/include/asm-generic/bitsperlong.h b/tools/include/asm-generic/bitsperlong.h index cfd661c6fc17..45eca517efb3 100644 --- a/tools/include/asm-generic/bitsperlong.h +++ b/tools/include/asm-generic/bitsperlong.h | |||
@@ -3,31 +3,12 @@ | |||
3 | 3 | ||
4 | #include <uapi/asm-generic/bitsperlong.h> | 4 | #include <uapi/asm-generic/bitsperlong.h> |
5 | 5 | ||
6 | /* | ||
7 | * In the kernel, where this file comes from, we can rely on CONFIG_64BIT, | ||
8 | * here we have to make amends with what the various compilers provides us | ||
9 | * to figure out if we're on a 64-bit machine... | ||
10 | */ | ||
11 | #ifdef __SIZEOF_LONG__ | 6 | #ifdef __SIZEOF_LONG__ |
12 | # if __SIZEOF_LONG__ == 8 | 7 | #define BITS_PER_LONG (__CHAR_BIT__ * __SIZEOF_LONG__) |
13 | # define CONFIG_64BIT | ||
14 | # endif | ||
15 | #else | 8 | #else |
16 | # ifdef __WORDSIZE | 9 | #define BITS_PER_LONG __WORDSIZE |
17 | # if __WORDSIZE == 64 | ||
18 | # define CONFIG_64BIT | ||
19 | # endif | ||
20 | # else | ||
21 | # error Failed to determine BITS_PER_LONG value | ||
22 | # endif | ||
23 | #endif | 10 | #endif |
24 | 11 | ||
25 | #ifdef CONFIG_64BIT | ||
26 | #define BITS_PER_LONG 64 | ||
27 | #else | ||
28 | #define BITS_PER_LONG 32 | ||
29 | #endif /* CONFIG_64BIT */ | ||
30 | |||
31 | #if BITS_PER_LONG != __BITS_PER_LONG | 12 | #if BITS_PER_LONG != __BITS_PER_LONG |
32 | #error Inconsistent word size. Check asm/bitsperlong.h | 13 | #error Inconsistent word size. Check asm/bitsperlong.h |
33 | #endif | 14 | #endif |
diff --git a/tools/include/linux/compiler.h b/tools/include/linux/compiler.h index fa7208a32d76..e33fc1df3935 100644 --- a/tools/include/linux/compiler.h +++ b/tools/include/linux/compiler.h | |||
@@ -9,6 +9,17 @@ | |||
9 | # define __always_inline inline __attribute__((always_inline)) | 9 | # define __always_inline inline __attribute__((always_inline)) |
10 | #endif | 10 | #endif |
11 | 11 | ||
12 | #ifdef __ANDROID__ | ||
13 | /* | ||
14 | * FIXME: Big hammer to get rid of tons of: | ||
15 | * "warning: always_inline function might not be inlinable" | ||
16 | * | ||
17 | * At least on android-ndk-r12/platforms/android-24/arch-arm | ||
18 | */ | ||
19 | #undef __always_inline | ||
20 | #define __always_inline inline | ||
21 | #endif | ||
22 | |||
12 | #define __user | 23 | #define __user |
13 | 24 | ||
14 | #ifndef __attribute_const__ | 25 | #ifndef __attribute_const__ |
diff --git a/tools/lib/api/fd/array.h b/tools/lib/api/fd/array.h index e87fd800fa8d..71287dddc05f 100644 --- a/tools/lib/api/fd/array.h +++ b/tools/lib/api/fd/array.h | |||
@@ -22,6 +22,7 @@ struct fdarray { | |||
22 | struct pollfd *entries; | 22 | struct pollfd *entries; |
23 | union { | 23 | union { |
24 | int idx; | 24 | int idx; |
25 | void *ptr; | ||
25 | } *priv; | 26 | } *priv; |
26 | }; | 27 | }; |
27 | 28 | ||
diff --git a/tools/lib/api/fs/fs.c b/tools/lib/api/fs/fs.c index 08556cf2c70d..ba7094b945ff 100644 --- a/tools/lib/api/fs/fs.c +++ b/tools/lib/api/fs/fs.c | |||
@@ -283,6 +283,11 @@ int filename__read_int(const char *filename, int *value) | |||
283 | return err; | 283 | return err; |
284 | } | 284 | } |
285 | 285 | ||
286 | /* | ||
287 | * Parses @value out of @filename with strtoull. | ||
288 | * By using 0 for base, the strtoull detects the | ||
289 | * base automatically (see man strtoull). | ||
290 | */ | ||
286 | int filename__read_ull(const char *filename, unsigned long long *value) | 291 | int filename__read_ull(const char *filename, unsigned long long *value) |
287 | { | 292 | { |
288 | char line[64]; | 293 | char line[64]; |
@@ -292,7 +297,7 @@ int filename__read_ull(const char *filename, unsigned long long *value) | |||
292 | return -1; | 297 | return -1; |
293 | 298 | ||
294 | if (read(fd, line, sizeof(line)) > 0) { | 299 | if (read(fd, line, sizeof(line)) > 0) { |
295 | *value = strtoull(line, NULL, 10); | 300 | *value = strtoull(line, NULL, 0); |
296 | if (*value != ULLONG_MAX) | 301 | if (*value != ULLONG_MAX) |
297 | err = 0; | 302 | err = 0; |
298 | } | 303 | } |
diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c index 3a7bd175f73c..664c90c8e22b 100644 --- a/tools/lib/traceevent/event-parse.c +++ b/tools/lib/traceevent/event-parse.c | |||
@@ -23,6 +23,7 @@ | |||
23 | * Frederic Weisbecker gave his permission to relicense the code to | 23 | * Frederic Weisbecker gave his permission to relicense the code to |
24 | * the Lesser General Public License. | 24 | * the Lesser General Public License. |
25 | */ | 25 | */ |
26 | #include <inttypes.h> | ||
26 | #include <stdio.h> | 27 | #include <stdio.h> |
27 | #include <stdlib.h> | 28 | #include <stdlib.h> |
28 | #include <string.h> | 29 | #include <string.h> |
@@ -33,7 +34,7 @@ | |||
33 | #include <limits.h> | 34 | #include <limits.h> |
34 | #include <linux/string.h> | 35 | #include <linux/string.h> |
35 | 36 | ||
36 | #include <netinet/ip6.h> | 37 | #include <netinet/in.h> |
37 | #include "event-parse.h" | 38 | #include "event-parse.h" |
38 | #include "event-utils.h" | 39 | #include "event-utils.h" |
39 | 40 | ||
diff --git a/tools/objtool/Makefile b/tools/objtool/Makefile index 9a3110cac604..1f75b0a046cc 100644 --- a/tools/objtool/Makefile +++ b/tools/objtool/Makefile | |||
@@ -26,7 +26,7 @@ OBJTOOL_IN := $(OBJTOOL)-in.o | |||
26 | 26 | ||
27 | all: $(OBJTOOL) | 27 | all: $(OBJTOOL) |
28 | 28 | ||
29 | INCLUDES := -I$(srctree)/tools/include | 29 | INCLUDES := -I$(srctree)/tools/include -I$(srctree)/tools/arch/$(ARCH)/include/uapi |
30 | CFLAGS += -Wall -Werror $(EXTRA_WARNINGS) -fomit-frame-pointer -O2 -g $(INCLUDES) | 30 | CFLAGS += -Wall -Werror $(EXTRA_WARNINGS) -fomit-frame-pointer -O2 -g $(INCLUDES) |
31 | LDFLAGS += -lelf $(LIBSUBCMD) | 31 | LDFLAGS += -lelf $(LIBSUBCMD) |
32 | 32 | ||
diff --git a/tools/objtool/builtin-check.c b/tools/objtool/builtin-check.c index 92d84b277032..4ed30f45c6da 100644 --- a/tools/objtool/builtin-check.c +++ b/tools/objtool/builtin-check.c | |||
@@ -664,7 +664,7 @@ static int add_func_switch_tables(struct objtool_file *file, | |||
664 | struct symbol *func) | 664 | struct symbol *func) |
665 | { | 665 | { |
666 | struct instruction *insn, *prev_jump; | 666 | struct instruction *insn, *prev_jump; |
667 | struct rela *text_rela, *rodata_rela, *prev_rela; | 667 | struct rela *text_rela, *rodata_rela, *prev_rela = NULL; |
668 | int ret; | 668 | int ret; |
669 | 669 | ||
670 | prev_jump = NULL; | 670 | prev_jump = NULL; |
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt index 5b46b1d1a37c..69966abf65d1 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt | |||
@@ -367,6 +367,28 @@ options. | |||
367 | 'perf record --dry-run -e' can act as a BPF script compiler if llvm.dump-obj | 367 | 'perf record --dry-run -e' can act as a BPF script compiler if llvm.dump-obj |
368 | in config file is set to true. | 368 | in config file is set to true. |
369 | 369 | ||
370 | --tail-synthesize:: | ||
371 | Instead of collecting non-sample events (for example, fork, comm, mmap) at | ||
372 | the beginning of record, collect them during finalizing an output file. | ||
373 | The collected non-sample events reflects the status of the system when | ||
374 | record is finished. | ||
375 | |||
376 | --overwrite:: | ||
377 | Makes all events use an overwritable ring buffer. An overwritable ring | ||
378 | buffer works like a flight recorder: when it gets full, the kernel will | ||
379 | overwrite the oldest records, that thus will never make it to the | ||
380 | perf.data file. | ||
381 | |||
382 | When '--overwrite' and '--switch-output' are used perf records and drops | ||
383 | events until it receives a signal, meaning that something unusual was | ||
384 | detected that warrants taking a snapshot of the most current events, | ||
385 | those fitting in the ring buffer at that moment. | ||
386 | |||
387 | 'overwrite' attribute can also be set or canceled for an event using | ||
388 | config terms. For example: 'cycles/overwrite/' and 'instructions/no-overwrite/'. | ||
389 | |||
390 | Implies --tail-synthesize. | ||
391 | |||
370 | SEE ALSO | 392 | SEE ALSO |
371 | -------- | 393 | -------- |
372 | linkperf:perf-stat[1], linkperf:perf-list[1] | 394 | linkperf:perf-stat[1], linkperf:perf-list[1] |
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index d9f5cc3a3667..8f2c16d9275f 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
@@ -119,11 +119,10 @@ backward_rb_find_range(void *buf, int mask, u64 head, u64 *start, u64 *end) | |||
119 | } | 119 | } |
120 | 120 | ||
121 | static int | 121 | static int |
122 | rb_find_range(struct perf_evlist *evlist, | 122 | rb_find_range(void *data, int mask, u64 head, u64 old, |
123 | void *data, int mask, u64 head, u64 old, | 123 | u64 *start, u64 *end, bool backward) |
124 | u64 *start, u64 *end) | ||
125 | { | 124 | { |
126 | if (!evlist->backward) { | 125 | if (!backward) { |
127 | *start = old; | 126 | *start = old; |
128 | *end = head; | 127 | *end = head; |
129 | return 0; | 128 | return 0; |
@@ -132,9 +131,10 @@ rb_find_range(struct perf_evlist *evlist, | |||
132 | return backward_rb_find_range(data, mask, head, start, end); | 131 | return backward_rb_find_range(data, mask, head, start, end); |
133 | } | 132 | } |
134 | 133 | ||
135 | static int record__mmap_read(struct record *rec, struct perf_evlist *evlist, int idx) | 134 | static int |
135 | record__mmap_read(struct record *rec, struct perf_mmap *md, | ||
136 | bool overwrite, bool backward) | ||
136 | { | 137 | { |
137 | struct perf_mmap *md = &evlist->mmap[idx]; | ||
138 | u64 head = perf_mmap__read_head(md); | 138 | u64 head = perf_mmap__read_head(md); |
139 | u64 old = md->prev; | 139 | u64 old = md->prev; |
140 | u64 end = head, start = old; | 140 | u64 end = head, start = old; |
@@ -143,8 +143,8 @@ static int record__mmap_read(struct record *rec, struct perf_evlist *evlist, int | |||
143 | void *buf; | 143 | void *buf; |
144 | int rc = 0; | 144 | int rc = 0; |
145 | 145 | ||
146 | if (rb_find_range(evlist, data, md->mask, head, | 146 | if (rb_find_range(data, md->mask, head, |
147 | old, &start, &end)) | 147 | old, &start, &end, backward)) |
148 | return -1; | 148 | return -1; |
149 | 149 | ||
150 | if (start == end) | 150 | if (start == end) |
@@ -157,7 +157,7 @@ static int record__mmap_read(struct record *rec, struct perf_evlist *evlist, int | |||
157 | WARN_ONCE(1, "failed to keep up with mmap data. (warn only once)\n"); | 157 | WARN_ONCE(1, "failed to keep up with mmap data. (warn only once)\n"); |
158 | 158 | ||
159 | md->prev = head; | 159 | md->prev = head; |
160 | perf_evlist__mmap_consume(evlist, idx); | 160 | perf_mmap__consume(md, overwrite || backward); |
161 | return 0; | 161 | return 0; |
162 | } | 162 | } |
163 | 163 | ||
@@ -182,7 +182,7 @@ static int record__mmap_read(struct record *rec, struct perf_evlist *evlist, int | |||
182 | } | 182 | } |
183 | 183 | ||
184 | md->prev = head; | 184 | md->prev = head; |
185 | perf_evlist__mmap_consume(evlist, idx); | 185 | perf_mmap__consume(md, overwrite || backward); |
186 | out: | 186 | out: |
187 | return rc; | 187 | return rc; |
188 | } | 188 | } |
@@ -498,20 +498,30 @@ static struct perf_event_header finished_round_event = { | |||
498 | .type = PERF_RECORD_FINISHED_ROUND, | 498 | .type = PERF_RECORD_FINISHED_ROUND, |
499 | }; | 499 | }; |
500 | 500 | ||
501 | static int record__mmap_read_evlist(struct record *rec, struct perf_evlist *evlist) | 501 | static int record__mmap_read_evlist(struct record *rec, struct perf_evlist *evlist, |
502 | bool backward) | ||
502 | { | 503 | { |
503 | u64 bytes_written = rec->bytes_written; | 504 | u64 bytes_written = rec->bytes_written; |
504 | int i; | 505 | int i; |
505 | int rc = 0; | 506 | int rc = 0; |
507 | struct perf_mmap *maps; | ||
506 | 508 | ||
507 | if (!evlist) | 509 | if (!evlist) |
508 | return 0; | 510 | return 0; |
509 | 511 | ||
512 | maps = backward ? evlist->backward_mmap : evlist->mmap; | ||
513 | if (!maps) | ||
514 | return 0; | ||
515 | |||
516 | if (backward && evlist->bkw_mmap_state != BKW_MMAP_DATA_PENDING) | ||
517 | return 0; | ||
518 | |||
510 | for (i = 0; i < evlist->nr_mmaps; i++) { | 519 | for (i = 0; i < evlist->nr_mmaps; i++) { |
511 | struct auxtrace_mmap *mm = &evlist->mmap[i].auxtrace_mmap; | 520 | struct auxtrace_mmap *mm = &maps[i].auxtrace_mmap; |
512 | 521 | ||
513 | if (evlist->mmap[i].base) { | 522 | if (maps[i].base) { |
514 | if (record__mmap_read(rec, evlist, i) != 0) { | 523 | if (record__mmap_read(rec, &maps[i], |
524 | evlist->overwrite, backward) != 0) { | ||
515 | rc = -1; | 525 | rc = -1; |
516 | goto out; | 526 | goto out; |
517 | } | 527 | } |
@@ -531,6 +541,8 @@ static int record__mmap_read_evlist(struct record *rec, struct perf_evlist *evli | |||
531 | if (bytes_written != rec->bytes_written) | 541 | if (bytes_written != rec->bytes_written) |
532 | rc = record__write(rec, &finished_round_event, sizeof(finished_round_event)); | 542 | rc = record__write(rec, &finished_round_event, sizeof(finished_round_event)); |
533 | 543 | ||
544 | if (backward) | ||
545 | perf_evlist__toggle_bkw_mmap(evlist, BKW_MMAP_EMPTY); | ||
534 | out: | 546 | out: |
535 | return rc; | 547 | return rc; |
536 | } | 548 | } |
@@ -539,11 +551,11 @@ static int record__mmap_read_all(struct record *rec) | |||
539 | { | 551 | { |
540 | int err; | 552 | int err; |
541 | 553 | ||
542 | err = record__mmap_read_evlist(rec, rec->evlist); | 554 | err = record__mmap_read_evlist(rec, rec->evlist, false); |
543 | if (err) | 555 | if (err) |
544 | return err; | 556 | return err; |
545 | 557 | ||
546 | return err; | 558 | return record__mmap_read_evlist(rec, rec->evlist, true); |
547 | } | 559 | } |
548 | 560 | ||
549 | static void record__init_features(struct record *rec) | 561 | static void record__init_features(struct record *rec) |
@@ -592,13 +604,16 @@ record__finish_output(struct record *rec) | |||
592 | return; | 604 | return; |
593 | } | 605 | } |
594 | 606 | ||
595 | static int record__synthesize_workload(struct record *rec) | 607 | static int record__synthesize_workload(struct record *rec, bool tail) |
596 | { | 608 | { |
597 | struct { | 609 | struct { |
598 | struct thread_map map; | 610 | struct thread_map map; |
599 | struct thread_map_data map_data; | 611 | struct thread_map_data map_data; |
600 | } thread_map; | 612 | } thread_map; |
601 | 613 | ||
614 | if (rec->opts.tail_synthesize != tail) | ||
615 | return 0; | ||
616 | |||
602 | thread_map.map.nr = 1; | 617 | thread_map.map.nr = 1; |
603 | thread_map.map.map[0].pid = rec->evlist->workload.pid; | 618 | thread_map.map.map[0].pid = rec->evlist->workload.pid; |
604 | thread_map.map.map[0].comm = NULL; | 619 | thread_map.map.map[0].comm = NULL; |
@@ -609,7 +624,7 @@ static int record__synthesize_workload(struct record *rec) | |||
609 | rec->opts.proc_map_timeout); | 624 | rec->opts.proc_map_timeout); |
610 | } | 625 | } |
611 | 626 | ||
612 | static int record__synthesize(struct record *rec); | 627 | static int record__synthesize(struct record *rec, bool tail); |
613 | 628 | ||
614 | static int | 629 | static int |
615 | record__switch_output(struct record *rec, bool at_exit) | 630 | record__switch_output(struct record *rec, bool at_exit) |
@@ -620,6 +635,10 @@ record__switch_output(struct record *rec, bool at_exit) | |||
620 | /* Same Size: "2015122520103046"*/ | 635 | /* Same Size: "2015122520103046"*/ |
621 | char timestamp[] = "InvalidTimestamp"; | 636 | char timestamp[] = "InvalidTimestamp"; |
622 | 637 | ||
638 | record__synthesize(rec, true); | ||
639 | if (target__none(&rec->opts.target)) | ||
640 | record__synthesize_workload(rec, true); | ||
641 | |||
623 | rec->samples = 0; | 642 | rec->samples = 0; |
624 | record__finish_output(rec); | 643 | record__finish_output(rec); |
625 | err = fetch_current_timestamp(timestamp, sizeof(timestamp)); | 644 | err = fetch_current_timestamp(timestamp, sizeof(timestamp)); |
@@ -642,7 +661,7 @@ record__switch_output(struct record *rec, bool at_exit) | |||
642 | 661 | ||
643 | /* Output tracking events */ | 662 | /* Output tracking events */ |
644 | if (!at_exit) { | 663 | if (!at_exit) { |
645 | record__synthesize(rec); | 664 | record__synthesize(rec, false); |
646 | 665 | ||
647 | /* | 666 | /* |
648 | * In 'perf record --switch-output' without -a, | 667 | * In 'perf record --switch-output' without -a, |
@@ -654,7 +673,7 @@ record__switch_output(struct record *rec, bool at_exit) | |||
654 | * perf_event__synthesize_thread_map() for those events. | 673 | * perf_event__synthesize_thread_map() for those events. |
655 | */ | 674 | */ |
656 | if (target__none(&rec->opts.target)) | 675 | if (target__none(&rec->opts.target)) |
657 | record__synthesize_workload(rec); | 676 | record__synthesize_workload(rec, false); |
658 | } | 677 | } |
659 | return fd; | 678 | return fd; |
660 | } | 679 | } |
@@ -689,8 +708,12 @@ perf_event__synth_time_conv(const struct perf_event_mmap_page *pc __maybe_unused | |||
689 | static const struct perf_event_mmap_page * | 708 | static const struct perf_event_mmap_page * |
690 | perf_evlist__pick_pc(struct perf_evlist *evlist) | 709 | perf_evlist__pick_pc(struct perf_evlist *evlist) |
691 | { | 710 | { |
692 | if (evlist && evlist->mmap && evlist->mmap[0].base) | 711 | if (evlist) { |
693 | return evlist->mmap[0].base; | 712 | if (evlist->mmap && evlist->mmap[0].base) |
713 | return evlist->mmap[0].base; | ||
714 | if (evlist->backward_mmap && evlist->backward_mmap[0].base) | ||
715 | return evlist->backward_mmap[0].base; | ||
716 | } | ||
694 | return NULL; | 717 | return NULL; |
695 | } | 718 | } |
696 | 719 | ||
@@ -704,7 +727,7 @@ static const struct perf_event_mmap_page *record__pick_pc(struct record *rec) | |||
704 | return NULL; | 727 | return NULL; |
705 | } | 728 | } |
706 | 729 | ||
707 | static int record__synthesize(struct record *rec) | 730 | static int record__synthesize(struct record *rec, bool tail) |
708 | { | 731 | { |
709 | struct perf_session *session = rec->session; | 732 | struct perf_session *session = rec->session; |
710 | struct machine *machine = &session->machines.host; | 733 | struct machine *machine = &session->machines.host; |
@@ -714,6 +737,9 @@ static int record__synthesize(struct record *rec) | |||
714 | int fd = perf_data_file__fd(file); | 737 | int fd = perf_data_file__fd(file); |
715 | int err = 0; | 738 | int err = 0; |
716 | 739 | ||
740 | if (rec->opts.tail_synthesize != tail) | ||
741 | return 0; | ||
742 | |||
717 | if (file->is_pipe) { | 743 | if (file->is_pipe) { |
718 | err = perf_event__synthesize_attrs(tool, session, | 744 | err = perf_event__synthesize_attrs(tool, session, |
719 | process_synthesized_event); | 745 | process_synthesized_event); |
@@ -877,7 +903,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) | |||
877 | 903 | ||
878 | machine = &session->machines.host; | 904 | machine = &session->machines.host; |
879 | 905 | ||
880 | err = record__synthesize(rec); | 906 | err = record__synthesize(rec, false); |
881 | if (err < 0) | 907 | if (err < 0) |
882 | goto out_child; | 908 | goto out_child; |
883 | 909 | ||
@@ -937,6 +963,17 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) | |||
937 | for (;;) { | 963 | for (;;) { |
938 | unsigned long long hits = rec->samples; | 964 | unsigned long long hits = rec->samples; |
939 | 965 | ||
966 | /* | ||
967 | * rec->evlist->bkw_mmap_state is possible to be | ||
968 | * BKW_MMAP_EMPTY here: when done == true and | ||
969 | * hits != rec->samples in previous round. | ||
970 | * | ||
971 | * perf_evlist__toggle_bkw_mmap ensure we never | ||
972 | * convert BKW_MMAP_EMPTY to BKW_MMAP_DATA_PENDING. | ||
973 | */ | ||
974 | if (trigger_is_hit(&switch_output_trigger) || done || draining) | ||
975 | perf_evlist__toggle_bkw_mmap(rec->evlist, BKW_MMAP_DATA_PENDING); | ||
976 | |||
940 | if (record__mmap_read_all(rec) < 0) { | 977 | if (record__mmap_read_all(rec) < 0) { |
941 | trigger_error(&auxtrace_snapshot_trigger); | 978 | trigger_error(&auxtrace_snapshot_trigger); |
942 | trigger_error(&switch_output_trigger); | 979 | trigger_error(&switch_output_trigger); |
@@ -956,8 +993,26 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) | |||
956 | } | 993 | } |
957 | 994 | ||
958 | if (trigger_is_hit(&switch_output_trigger)) { | 995 | if (trigger_is_hit(&switch_output_trigger)) { |
996 | /* | ||
997 | * If switch_output_trigger is hit, the data in | ||
998 | * overwritable ring buffer should have been collected, | ||
999 | * so bkw_mmap_state should be set to BKW_MMAP_EMPTY. | ||
1000 | * | ||
1001 | * If SIGUSR2 raise after or during record__mmap_read_all(), | ||
1002 | * record__mmap_read_all() didn't collect data from | ||
1003 | * overwritable ring buffer. Read again. | ||
1004 | */ | ||
1005 | if (rec->evlist->bkw_mmap_state == BKW_MMAP_RUNNING) | ||
1006 | continue; | ||
959 | trigger_ready(&switch_output_trigger); | 1007 | trigger_ready(&switch_output_trigger); |
960 | 1008 | ||
1009 | /* | ||
1010 | * Reenable events in overwrite ring buffer after | ||
1011 | * record__mmap_read_all(): we should have collected | ||
1012 | * data from it. | ||
1013 | */ | ||
1014 | perf_evlist__toggle_bkw_mmap(rec->evlist, BKW_MMAP_RUNNING); | ||
1015 | |||
961 | if (!quiet) | 1016 | if (!quiet) |
962 | fprintf(stderr, "[ perf record: dump data: Woken up %ld times ]\n", | 1017 | fprintf(stderr, "[ perf record: dump data: Woken up %ld times ]\n", |
963 | waking); | 1018 | waking); |
@@ -1012,6 +1067,9 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) | |||
1012 | if (!quiet) | 1067 | if (!quiet) |
1013 | fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking); | 1068 | fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking); |
1014 | 1069 | ||
1070 | if (target__none(&rec->opts.target)) | ||
1071 | record__synthesize_workload(rec, true); | ||
1072 | |||
1015 | out_child: | 1073 | out_child: |
1016 | if (forks) { | 1074 | if (forks) { |
1017 | int exit_status; | 1075 | int exit_status; |
@@ -1030,6 +1088,7 @@ out_child: | |||
1030 | } else | 1088 | } else |
1031 | status = err; | 1089 | status = err; |
1032 | 1090 | ||
1091 | record__synthesize(rec, true); | ||
1033 | /* this will be recalculated during process_buildids() */ | 1092 | /* this will be recalculated during process_buildids() */ |
1034 | rec->samples = 0; | 1093 | rec->samples = 0; |
1035 | 1094 | ||
@@ -1354,6 +1413,9 @@ struct option __record_options[] = { | |||
1354 | OPT_BOOLEAN_SET('i', "no-inherit", &record.opts.no_inherit, | 1413 | OPT_BOOLEAN_SET('i', "no-inherit", &record.opts.no_inherit, |
1355 | &record.opts.no_inherit_set, | 1414 | &record.opts.no_inherit_set, |
1356 | "child tasks do not inherit counters"), | 1415 | "child tasks do not inherit counters"), |
1416 | OPT_BOOLEAN(0, "tail-synthesize", &record.opts.tail_synthesize, | ||
1417 | "synthesize non-sample events at the end of output"), | ||
1418 | OPT_BOOLEAN(0, "overwrite", &record.opts.overwrite, "use overwrite mode"), | ||
1357 | OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"), | 1419 | OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"), |
1358 | OPT_CALLBACK('m', "mmap-pages", &record.opts, "pages[,pages]", | 1420 | OPT_CALLBACK('m', "mmap-pages", &record.opts, "pages[,pages]", |
1359 | "number of mmap data pages and AUX area tracing mmap pages", | 1421 | "number of mmap data pages and AUX area tracing mmap pages", |
@@ -1564,6 +1626,9 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1564 | } | 1626 | } |
1565 | } | 1627 | } |
1566 | 1628 | ||
1629 | if (record.opts.overwrite) | ||
1630 | record.opts.tail_synthesize = true; | ||
1631 | |||
1567 | if (rec->evlist->nr_entries == 0 && | 1632 | if (rec->evlist->nr_entries == 0 && |
1568 | perf_evlist__add_default(rec->evlist) < 0) { | 1633 | perf_evlist__add_default(rec->evlist) < 0) { |
1569 | pr_err("Not enough memory for event selector list\n"); | 1634 | pr_err("Not enough memory for event selector list\n"); |
diff --git a/tools/perf/perf.c b/tools/perf/perf.c index 4b2ff021434c..64c06961bfe4 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c | |||
@@ -503,7 +503,7 @@ void pthread__unblock_sigwinch(void) | |||
503 | static void cache_line_size(int *cacheline_sizep) | 503 | static void cache_line_size(int *cacheline_sizep) |
504 | { | 504 | { |
505 | if (sysfs__read_int("devices/system/cpu/cpu0/cache/index0/coherency_line_size", cacheline_sizep)) | 505 | if (sysfs__read_int("devices/system/cpu/cpu0/cache/index0/coherency_line_size", cacheline_sizep)) |
506 | perror("cannot determine cache line size"); | 506 | pr_debug("cannot determine cache line size"); |
507 | } | 507 | } |
508 | #endif | 508 | #endif |
509 | 509 | ||
diff --git a/tools/perf/perf.h b/tools/perf/perf.h index cd8f1b150f9e..a7e0f1497244 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h | |||
@@ -59,6 +59,8 @@ struct record_opts { | |||
59 | bool record_switch_events; | 59 | bool record_switch_events; |
60 | bool all_kernel; | 60 | bool all_kernel; |
61 | bool all_user; | 61 | bool all_user; |
62 | bool tail_synthesize; | ||
63 | bool overwrite; | ||
62 | unsigned int freq; | 64 | unsigned int freq; |
63 | unsigned int mmap_pages; | 65 | unsigned int mmap_pages; |
64 | unsigned int auxtrace_mmap_pages; | 66 | unsigned int auxtrace_mmap_pages; |
diff --git a/tools/perf/tests/backward-ring-buffer.c b/tools/perf/tests/backward-ring-buffer.c index f20ea4c0d0cb..615780cbfe1d 100644 --- a/tools/perf/tests/backward-ring-buffer.c +++ b/tools/perf/tests/backward-ring-buffer.c | |||
@@ -31,8 +31,8 @@ static int count_samples(struct perf_evlist *evlist, int *sample_count, | |||
31 | for (i = 0; i < evlist->nr_mmaps; i++) { | 31 | for (i = 0; i < evlist->nr_mmaps; i++) { |
32 | union perf_event *event; | 32 | union perf_event *event; |
33 | 33 | ||
34 | perf_evlist__mmap_read_catchup(evlist, i); | 34 | perf_mmap__read_catchup(&evlist->backward_mmap[i]); |
35 | while ((event = perf_evlist__mmap_read_backward(evlist, i)) != NULL) { | 35 | while ((event = perf_mmap__read_backward(&evlist->backward_mmap[i])) != NULL) { |
36 | const u32 type = event->header.type; | 36 | const u32 type = event->header.type; |
37 | 37 | ||
38 | switch (type) { | 38 | switch (type) { |
@@ -108,7 +108,11 @@ int test__backward_ring_buffer(int subtest __maybe_unused) | |||
108 | } | 108 | } |
109 | 109 | ||
110 | bzero(&parse_error, sizeof(parse_error)); | 110 | bzero(&parse_error, sizeof(parse_error)); |
111 | err = parse_events(evlist, "syscalls:sys_enter_prctl", &parse_error); | 111 | /* |
112 | * Set backward bit, ring buffer should be writing from end. Record | ||
113 | * it in aux evlist | ||
114 | */ | ||
115 | err = parse_events(evlist, "syscalls:sys_enter_prctl/overwrite/", &parse_error); | ||
112 | if (err) { | 116 | if (err) { |
113 | pr_debug("Failed to parse tracepoint event, try use root\n"); | 117 | pr_debug("Failed to parse tracepoint event, try use root\n"); |
114 | ret = TEST_SKIP; | 118 | ret = TEST_SKIP; |
@@ -117,10 +121,6 @@ int test__backward_ring_buffer(int subtest __maybe_unused) | |||
117 | 121 | ||
118 | perf_evlist__config(evlist, &opts, NULL); | 122 | perf_evlist__config(evlist, &opts, NULL); |
119 | 123 | ||
120 | /* Set backward bit, ring buffer should be writing from end */ | ||
121 | evlist__for_each_entry(evlist, evsel) | ||
122 | evsel->attr.write_backward = 1; | ||
123 | |||
124 | err = perf_evlist__open(evlist); | 124 | err = perf_evlist__open(evlist); |
125 | if (err < 0) { | 125 | if (err < 0) { |
126 | pr_debug("perf_evlist__open: %s\n", | 126 | pr_debug("perf_evlist__open: %s\n", |
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 862e69c2690d..2a40b8e1def7 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include "evlist.h" | 15 | #include "evlist.h" |
16 | #include "evsel.h" | 16 | #include "evsel.h" |
17 | #include "debug.h" | 17 | #include "debug.h" |
18 | #include "asm/bug.h" | ||
18 | #include <unistd.h> | 19 | #include <unistd.h> |
19 | 20 | ||
20 | #include "parse-events.h" | 21 | #include "parse-events.h" |
@@ -27,8 +28,8 @@ | |||
27 | #include <linux/log2.h> | 28 | #include <linux/log2.h> |
28 | #include <linux/err.h> | 29 | #include <linux/err.h> |
29 | 30 | ||
30 | static void perf_evlist__mmap_put(struct perf_evlist *evlist, int idx); | 31 | static void perf_mmap__munmap(struct perf_mmap *map); |
31 | static void __perf_evlist__munmap(struct perf_evlist *evlist, int idx); | 32 | static void perf_mmap__put(struct perf_mmap *map); |
32 | 33 | ||
33 | #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) | 34 | #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) |
34 | #define SID(e, x, y) xyarray__entry(e->sample_id, x, y) | 35 | #define SID(e, x, y) xyarray__entry(e->sample_id, x, y) |
@@ -44,7 +45,7 @@ void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus, | |||
44 | perf_evlist__set_maps(evlist, cpus, threads); | 45 | perf_evlist__set_maps(evlist, cpus, threads); |
45 | fdarray__init(&evlist->pollfd, 64); | 46 | fdarray__init(&evlist->pollfd, 64); |
46 | evlist->workload.pid = -1; | 47 | evlist->workload.pid = -1; |
47 | evlist->backward = false; | 48 | evlist->bkw_mmap_state = BKW_MMAP_NOTREADY; |
48 | } | 49 | } |
49 | 50 | ||
50 | struct perf_evlist *perf_evlist__new(void) | 51 | struct perf_evlist *perf_evlist__new(void) |
@@ -122,6 +123,7 @@ static void perf_evlist__purge(struct perf_evlist *evlist) | |||
122 | void perf_evlist__exit(struct perf_evlist *evlist) | 123 | void perf_evlist__exit(struct perf_evlist *evlist) |
123 | { | 124 | { |
124 | zfree(&evlist->mmap); | 125 | zfree(&evlist->mmap); |
126 | zfree(&evlist->backward_mmap); | ||
125 | fdarray__exit(&evlist->pollfd); | 127 | fdarray__exit(&evlist->pollfd); |
126 | } | 128 | } |
127 | 129 | ||
@@ -465,7 +467,8 @@ int perf_evlist__alloc_pollfd(struct perf_evlist *evlist) | |||
465 | return 0; | 467 | return 0; |
466 | } | 468 | } |
467 | 469 | ||
468 | static int __perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd, int idx, short revent) | 470 | static int __perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd, |
471 | struct perf_mmap *map, short revent) | ||
469 | { | 472 | { |
470 | int pos = fdarray__add(&evlist->pollfd, fd, revent | POLLERR | POLLHUP); | 473 | int pos = fdarray__add(&evlist->pollfd, fd, revent | POLLERR | POLLHUP); |
471 | /* | 474 | /* |
@@ -473,7 +476,7 @@ static int __perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd, int idx | |||
473 | * close the associated evlist->mmap[] entry. | 476 | * close the associated evlist->mmap[] entry. |
474 | */ | 477 | */ |
475 | if (pos >= 0) { | 478 | if (pos >= 0) { |
476 | evlist->pollfd.priv[pos].idx = idx; | 479 | evlist->pollfd.priv[pos].ptr = map; |
477 | 480 | ||
478 | fcntl(fd, F_SETFL, O_NONBLOCK); | 481 | fcntl(fd, F_SETFL, O_NONBLOCK); |
479 | } | 482 | } |
@@ -483,15 +486,16 @@ static int __perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd, int idx | |||
483 | 486 | ||
484 | int perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd) | 487 | int perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd) |
485 | { | 488 | { |
486 | return __perf_evlist__add_pollfd(evlist, fd, -1, POLLIN); | 489 | return __perf_evlist__add_pollfd(evlist, fd, NULL, POLLIN); |
487 | } | 490 | } |
488 | 491 | ||
489 | static void perf_evlist__munmap_filtered(struct fdarray *fda, int fd, | 492 | static void perf_evlist__munmap_filtered(struct fdarray *fda, int fd, |
490 | void *arg __maybe_unused) | 493 | void *arg __maybe_unused) |
491 | { | 494 | { |
492 | struct perf_evlist *evlist = container_of(fda, struct perf_evlist, pollfd); | 495 | struct perf_mmap *map = fda->priv[fd].ptr; |
493 | 496 | ||
494 | perf_evlist__mmap_put(evlist, fda->priv[fd].idx); | 497 | if (map) |
498 | perf_mmap__put(map); | ||
495 | } | 499 | } |
496 | 500 | ||
497 | int perf_evlist__filter_pollfd(struct perf_evlist *evlist, short revents_and_mask) | 501 | int perf_evlist__filter_pollfd(struct perf_evlist *evlist, short revents_and_mask) |
@@ -688,8 +692,11 @@ static int perf_evlist__set_paused(struct perf_evlist *evlist, bool value) | |||
688 | { | 692 | { |
689 | int i; | 693 | int i; |
690 | 694 | ||
695 | if (!evlist->backward_mmap) | ||
696 | return 0; | ||
697 | |||
691 | for (i = 0; i < evlist->nr_mmaps; i++) { | 698 | for (i = 0; i < evlist->nr_mmaps; i++) { |
692 | int fd = evlist->mmap[i].fd; | 699 | int fd = evlist->backward_mmap[i].fd; |
693 | int err; | 700 | int err; |
694 | 701 | ||
695 | if (fd < 0) | 702 | if (fd < 0) |
@@ -701,12 +708,12 @@ static int perf_evlist__set_paused(struct perf_evlist *evlist, bool value) | |||
701 | return 0; | 708 | return 0; |
702 | } | 709 | } |
703 | 710 | ||
704 | int perf_evlist__pause(struct perf_evlist *evlist) | 711 | static int perf_evlist__pause(struct perf_evlist *evlist) |
705 | { | 712 | { |
706 | return perf_evlist__set_paused(evlist, true); | 713 | return perf_evlist__set_paused(evlist, true); |
707 | } | 714 | } |
708 | 715 | ||
709 | int perf_evlist__resume(struct perf_evlist *evlist) | 716 | static int perf_evlist__resume(struct perf_evlist *evlist) |
710 | { | 717 | { |
711 | return perf_evlist__set_paused(evlist, false); | 718 | return perf_evlist__set_paused(evlist, false); |
712 | } | 719 | } |
@@ -781,9 +788,8 @@ broken_event: | |||
781 | return event; | 788 | return event; |
782 | } | 789 | } |
783 | 790 | ||
784 | union perf_event *perf_evlist__mmap_read_forward(struct perf_evlist *evlist, int idx) | 791 | union perf_event *perf_mmap__read_forward(struct perf_mmap *md, bool check_messup) |
785 | { | 792 | { |
786 | struct perf_mmap *md = &evlist->mmap[idx]; | ||
787 | u64 head; | 793 | u64 head; |
788 | u64 old = md->prev; | 794 | u64 old = md->prev; |
789 | 795 | ||
@@ -795,13 +801,12 @@ union perf_event *perf_evlist__mmap_read_forward(struct perf_evlist *evlist, int | |||
795 | 801 | ||
796 | head = perf_mmap__read_head(md); | 802 | head = perf_mmap__read_head(md); |
797 | 803 | ||
798 | return perf_mmap__read(md, evlist->overwrite, old, head, &md->prev); | 804 | return perf_mmap__read(md, check_messup, old, head, &md->prev); |
799 | } | 805 | } |
800 | 806 | ||
801 | union perf_event * | 807 | union perf_event * |
802 | perf_evlist__mmap_read_backward(struct perf_evlist *evlist, int idx) | 808 | perf_mmap__read_backward(struct perf_mmap *md) |
803 | { | 809 | { |
804 | struct perf_mmap *md = &evlist->mmap[idx]; | ||
805 | u64 head, end; | 810 | u64 head, end; |
806 | u64 start = md->prev; | 811 | u64 start = md->prev; |
807 | 812 | ||
@@ -836,16 +841,38 @@ perf_evlist__mmap_read_backward(struct perf_evlist *evlist, int idx) | |||
836 | return perf_mmap__read(md, false, start, end, &md->prev); | 841 | return perf_mmap__read(md, false, start, end, &md->prev); |
837 | } | 842 | } |
838 | 843 | ||
839 | union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx) | 844 | union perf_event *perf_evlist__mmap_read_forward(struct perf_evlist *evlist, int idx) |
840 | { | 845 | { |
841 | if (!evlist->backward) | 846 | struct perf_mmap *md = &evlist->mmap[idx]; |
842 | return perf_evlist__mmap_read_forward(evlist, idx); | 847 | |
843 | return perf_evlist__mmap_read_backward(evlist, idx); | 848 | /* |
849 | * Check messup is required for forward overwritable ring buffer: | ||
850 | * memory pointed by md->prev can be overwritten in this case. | ||
851 | * No need for read-write ring buffer: kernel stop outputting when | ||
852 | * it hit md->prev (perf_mmap__consume()). | ||
853 | */ | ||
854 | return perf_mmap__read_forward(md, evlist->overwrite); | ||
844 | } | 855 | } |
845 | 856 | ||
846 | void perf_evlist__mmap_read_catchup(struct perf_evlist *evlist, int idx) | 857 | union perf_event *perf_evlist__mmap_read_backward(struct perf_evlist *evlist, int idx) |
847 | { | 858 | { |
848 | struct perf_mmap *md = &evlist->mmap[idx]; | 859 | struct perf_mmap *md = &evlist->mmap[idx]; |
860 | |||
861 | /* | ||
862 | * No need to check messup for backward ring buffer: | ||
863 | * We can always read arbitrary long data from a backward | ||
864 | * ring buffer unless we forget to pause it before reading. | ||
865 | */ | ||
866 | return perf_mmap__read_backward(md); | ||
867 | } | ||
868 | |||
869 | union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx) | ||
870 | { | ||
871 | return perf_evlist__mmap_read_forward(evlist, idx); | ||
872 | } | ||
873 | |||
874 | void perf_mmap__read_catchup(struct perf_mmap *md) | ||
875 | { | ||
849 | u64 head; | 876 | u64 head; |
850 | 877 | ||
851 | if (!atomic_read(&md->refcnt)) | 878 | if (!atomic_read(&md->refcnt)) |
@@ -855,38 +882,44 @@ void perf_evlist__mmap_read_catchup(struct perf_evlist *evlist, int idx) | |||
855 | md->prev = head; | 882 | md->prev = head; |
856 | } | 883 | } |
857 | 884 | ||
885 | void perf_evlist__mmap_read_catchup(struct perf_evlist *evlist, int idx) | ||
886 | { | ||
887 | perf_mmap__read_catchup(&evlist->mmap[idx]); | ||
888 | } | ||
889 | |||
858 | static bool perf_mmap__empty(struct perf_mmap *md) | 890 | static bool perf_mmap__empty(struct perf_mmap *md) |
859 | { | 891 | { |
860 | return perf_mmap__read_head(md) == md->prev && !md->auxtrace_mmap.base; | 892 | return perf_mmap__read_head(md) == md->prev && !md->auxtrace_mmap.base; |
861 | } | 893 | } |
862 | 894 | ||
863 | static void perf_evlist__mmap_get(struct perf_evlist *evlist, int idx) | 895 | static void perf_mmap__get(struct perf_mmap *map) |
864 | { | 896 | { |
865 | atomic_inc(&evlist->mmap[idx].refcnt); | 897 | atomic_inc(&map->refcnt); |
866 | } | 898 | } |
867 | 899 | ||
868 | static void perf_evlist__mmap_put(struct perf_evlist *evlist, int idx) | 900 | static void perf_mmap__put(struct perf_mmap *md) |
869 | { | 901 | { |
870 | struct perf_mmap *md = &evlist->mmap[idx]; | ||
871 | |||
872 | BUG_ON(md->base && atomic_read(&md->refcnt) == 0); | 902 | BUG_ON(md->base && atomic_read(&md->refcnt) == 0); |
873 | 903 | ||
874 | if (atomic_dec_and_test(&md->refcnt)) | 904 | if (atomic_dec_and_test(&md->refcnt)) |
875 | __perf_evlist__munmap(evlist, idx); | 905 | perf_mmap__munmap(md); |
876 | } | 906 | } |
877 | 907 | ||
878 | void perf_evlist__mmap_consume(struct perf_evlist *evlist, int idx) | 908 | void perf_mmap__consume(struct perf_mmap *md, bool overwrite) |
879 | { | 909 | { |
880 | struct perf_mmap *md = &evlist->mmap[idx]; | 910 | if (!overwrite) { |
881 | |||
882 | if (!evlist->overwrite) { | ||
883 | u64 old = md->prev; | 911 | u64 old = md->prev; |
884 | 912 | ||
885 | perf_mmap__write_tail(md, old); | 913 | perf_mmap__write_tail(md, old); |
886 | } | 914 | } |
887 | 915 | ||
888 | if (atomic_read(&md->refcnt) == 1 && perf_mmap__empty(md)) | 916 | if (atomic_read(&md->refcnt) == 1 && perf_mmap__empty(md)) |
889 | perf_evlist__mmap_put(evlist, idx); | 917 | perf_mmap__put(md); |
918 | } | ||
919 | |||
920 | void perf_evlist__mmap_consume(struct perf_evlist *evlist, int idx) | ||
921 | { | ||
922 | perf_mmap__consume(&evlist->mmap[idx], evlist->overwrite); | ||
890 | } | 923 | } |
891 | 924 | ||
892 | int __weak auxtrace_mmap__mmap(struct auxtrace_mmap *mm __maybe_unused, | 925 | int __weak auxtrace_mmap__mmap(struct auxtrace_mmap *mm __maybe_unused, |
@@ -917,44 +950,52 @@ void __weak auxtrace_mmap_params__set_idx( | |||
917 | { | 950 | { |
918 | } | 951 | } |
919 | 952 | ||
920 | static void __perf_evlist__munmap(struct perf_evlist *evlist, int idx) | 953 | static void perf_mmap__munmap(struct perf_mmap *map) |
921 | { | 954 | { |
922 | if (evlist->mmap[idx].base != NULL) { | 955 | if (map->base != NULL) { |
923 | munmap(evlist->mmap[idx].base, evlist->mmap_len); | 956 | munmap(map->base, perf_mmap__mmap_len(map)); |
924 | evlist->mmap[idx].base = NULL; | 957 | map->base = NULL; |
925 | evlist->mmap[idx].fd = -1; | 958 | map->fd = -1; |
926 | atomic_set(&evlist->mmap[idx].refcnt, 0); | 959 | atomic_set(&map->refcnt, 0); |
927 | } | 960 | } |
928 | auxtrace_mmap__munmap(&evlist->mmap[idx].auxtrace_mmap); | 961 | auxtrace_mmap__munmap(&map->auxtrace_mmap); |
929 | } | 962 | } |
930 | 963 | ||
931 | void perf_evlist__munmap(struct perf_evlist *evlist) | 964 | static void perf_evlist__munmap_nofree(struct perf_evlist *evlist) |
932 | { | 965 | { |
933 | int i; | 966 | int i; |
934 | 967 | ||
935 | if (evlist->mmap == NULL) | 968 | if (evlist->mmap) |
936 | return; | 969 | for (i = 0; i < evlist->nr_mmaps; i++) |
970 | perf_mmap__munmap(&evlist->mmap[i]); | ||
937 | 971 | ||
938 | for (i = 0; i < evlist->nr_mmaps; i++) | 972 | if (evlist->backward_mmap) |
939 | __perf_evlist__munmap(evlist, i); | 973 | for (i = 0; i < evlist->nr_mmaps; i++) |
974 | perf_mmap__munmap(&evlist->backward_mmap[i]); | ||
975 | } | ||
940 | 976 | ||
977 | void perf_evlist__munmap(struct perf_evlist *evlist) | ||
978 | { | ||
979 | perf_evlist__munmap_nofree(evlist); | ||
941 | zfree(&evlist->mmap); | 980 | zfree(&evlist->mmap); |
981 | zfree(&evlist->backward_mmap); | ||
942 | } | 982 | } |
943 | 983 | ||
944 | static int perf_evlist__alloc_mmap(struct perf_evlist *evlist) | 984 | static struct perf_mmap *perf_evlist__alloc_mmap(struct perf_evlist *evlist) |
945 | { | 985 | { |
946 | int i; | 986 | int i; |
987 | struct perf_mmap *map; | ||
947 | 988 | ||
948 | evlist->nr_mmaps = cpu_map__nr(evlist->cpus); | 989 | evlist->nr_mmaps = cpu_map__nr(evlist->cpus); |
949 | if (cpu_map__empty(evlist->cpus)) | 990 | if (cpu_map__empty(evlist->cpus)) |
950 | evlist->nr_mmaps = thread_map__nr(evlist->threads); | 991 | evlist->nr_mmaps = thread_map__nr(evlist->threads); |
951 | evlist->mmap = zalloc(evlist->nr_mmaps * sizeof(struct perf_mmap)); | 992 | map = zalloc(evlist->nr_mmaps * sizeof(struct perf_mmap)); |
952 | if (!evlist->mmap) | 993 | if (!map) |
953 | return -ENOMEM; | 994 | return NULL; |
954 | 995 | ||
955 | for (i = 0; i < evlist->nr_mmaps; i++) | 996 | for (i = 0; i < evlist->nr_mmaps; i++) |
956 | evlist->mmap[i].fd = -1; | 997 | map[i].fd = -1; |
957 | return 0; | 998 | return map; |
958 | } | 999 | } |
959 | 1000 | ||
960 | struct mmap_params { | 1001 | struct mmap_params { |
@@ -963,8 +1004,8 @@ struct mmap_params { | |||
963 | struct auxtrace_mmap_params auxtrace_mp; | 1004 | struct auxtrace_mmap_params auxtrace_mp; |
964 | }; | 1005 | }; |
965 | 1006 | ||
966 | static int __perf_evlist__mmap(struct perf_evlist *evlist, int idx, | 1007 | static int perf_mmap__mmap(struct perf_mmap *map, |
967 | struct mmap_params *mp, int fd) | 1008 | struct mmap_params *mp, int fd) |
968 | { | 1009 | { |
969 | /* | 1010 | /* |
970 | * The last one will be done at perf_evlist__mmap_consume(), so that we | 1011 | * The last one will be done at perf_evlist__mmap_consume(), so that we |
@@ -979,21 +1020,21 @@ static int __perf_evlist__mmap(struct perf_evlist *evlist, int idx, | |||
979 | * evlist layer can't just drop it when filtering events in | 1020 | * evlist layer can't just drop it when filtering events in |
980 | * perf_evlist__filter_pollfd(). | 1021 | * perf_evlist__filter_pollfd(). |
981 | */ | 1022 | */ |
982 | atomic_set(&evlist->mmap[idx].refcnt, 2); | 1023 | atomic_set(&map->refcnt, 2); |
983 | evlist->mmap[idx].prev = 0; | 1024 | map->prev = 0; |
984 | evlist->mmap[idx].mask = mp->mask; | 1025 | map->mask = mp->mask; |
985 | evlist->mmap[idx].base = mmap(NULL, evlist->mmap_len, mp->prot, | 1026 | map->base = mmap(NULL, perf_mmap__mmap_len(map), mp->prot, |
986 | MAP_SHARED, fd, 0); | 1027 | MAP_SHARED, fd, 0); |
987 | if (evlist->mmap[idx].base == MAP_FAILED) { | 1028 | if (map->base == MAP_FAILED) { |
988 | pr_debug2("failed to mmap perf event ring buffer, error %d\n", | 1029 | pr_debug2("failed to mmap perf event ring buffer, error %d\n", |
989 | errno); | 1030 | errno); |
990 | evlist->mmap[idx].base = NULL; | 1031 | map->base = NULL; |
991 | return -1; | 1032 | return -1; |
992 | } | 1033 | } |
993 | evlist->mmap[idx].fd = fd; | 1034 | map->fd = fd; |
994 | 1035 | ||
995 | if (auxtrace_mmap__mmap(&evlist->mmap[idx].auxtrace_mmap, | 1036 | if (auxtrace_mmap__mmap(&map->auxtrace_mmap, |
996 | &mp->auxtrace_mp, evlist->mmap[idx].base, fd)) | 1037 | &mp->auxtrace_mp, map->base, fd)) |
997 | return -1; | 1038 | return -1; |
998 | 1039 | ||
999 | return 0; | 1040 | return 0; |
@@ -1003,23 +1044,36 @@ static bool | |||
1003 | perf_evlist__should_poll(struct perf_evlist *evlist __maybe_unused, | 1044 | perf_evlist__should_poll(struct perf_evlist *evlist __maybe_unused, |
1004 | struct perf_evsel *evsel) | 1045 | struct perf_evsel *evsel) |
1005 | { | 1046 | { |
1006 | if (evsel->overwrite) | 1047 | if (evsel->attr.write_backward) |
1007 | return false; | 1048 | return false; |
1008 | return true; | 1049 | return true; |
1009 | } | 1050 | } |
1010 | 1051 | ||
1011 | static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx, | 1052 | static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx, |
1012 | struct mmap_params *mp, int cpu, | 1053 | struct mmap_params *mp, int cpu, |
1013 | int thread, int *output) | 1054 | int thread, int *_output, int *_output_backward) |
1014 | { | 1055 | { |
1015 | struct perf_evsel *evsel; | 1056 | struct perf_evsel *evsel; |
1016 | int revent; | 1057 | int revent; |
1017 | 1058 | ||
1018 | evlist__for_each_entry(evlist, evsel) { | 1059 | evlist__for_each_entry(evlist, evsel) { |
1060 | struct perf_mmap *maps = evlist->mmap; | ||
1061 | int *output = _output; | ||
1019 | int fd; | 1062 | int fd; |
1020 | 1063 | ||
1021 | if (evsel->overwrite != (evlist->overwrite && evlist->backward)) | 1064 | if (evsel->attr.write_backward) { |
1022 | continue; | 1065 | output = _output_backward; |
1066 | maps = evlist->backward_mmap; | ||
1067 | |||
1068 | if (!maps) { | ||
1069 | maps = perf_evlist__alloc_mmap(evlist); | ||
1070 | if (!maps) | ||
1071 | return -1; | ||
1072 | evlist->backward_mmap = maps; | ||
1073 | if (evlist->bkw_mmap_state == BKW_MMAP_NOTREADY) | ||
1074 | perf_evlist__toggle_bkw_mmap(evlist, BKW_MMAP_RUNNING); | ||
1075 | } | ||
1076 | } | ||
1023 | 1077 | ||
1024 | if (evsel->system_wide && thread) | 1078 | if (evsel->system_wide && thread) |
1025 | continue; | 1079 | continue; |
@@ -1028,13 +1082,14 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx, | |||
1028 | 1082 | ||
1029 | if (*output == -1) { | 1083 | if (*output == -1) { |
1030 | *output = fd; | 1084 | *output = fd; |
1031 | if (__perf_evlist__mmap(evlist, idx, mp, *output) < 0) | 1085 | |
1086 | if (perf_mmap__mmap(&maps[idx], mp, *output) < 0) | ||
1032 | return -1; | 1087 | return -1; |
1033 | } else { | 1088 | } else { |
1034 | if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, *output) != 0) | 1089 | if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, *output) != 0) |
1035 | return -1; | 1090 | return -1; |
1036 | 1091 | ||
1037 | perf_evlist__mmap_get(evlist, idx); | 1092 | perf_mmap__get(&maps[idx]); |
1038 | } | 1093 | } |
1039 | 1094 | ||
1040 | revent = perf_evlist__should_poll(evlist, evsel) ? POLLIN : 0; | 1095 | revent = perf_evlist__should_poll(evlist, evsel) ? POLLIN : 0; |
@@ -1047,8 +1102,8 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx, | |||
1047 | * Therefore don't add it for polling. | 1102 | * Therefore don't add it for polling. |
1048 | */ | 1103 | */ |
1049 | if (!evsel->system_wide && | 1104 | if (!evsel->system_wide && |
1050 | __perf_evlist__add_pollfd(evlist, fd, idx, revent) < 0) { | 1105 | __perf_evlist__add_pollfd(evlist, fd, &maps[idx], revent) < 0) { |
1051 | perf_evlist__mmap_put(evlist, idx); | 1106 | perf_mmap__put(&maps[idx]); |
1052 | return -1; | 1107 | return -1; |
1053 | } | 1108 | } |
1054 | 1109 | ||
@@ -1074,13 +1129,14 @@ static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, | |||
1074 | pr_debug2("perf event ring buffer mmapped per cpu\n"); | 1129 | pr_debug2("perf event ring buffer mmapped per cpu\n"); |
1075 | for (cpu = 0; cpu < nr_cpus; cpu++) { | 1130 | for (cpu = 0; cpu < nr_cpus; cpu++) { |
1076 | int output = -1; | 1131 | int output = -1; |
1132 | int output_backward = -1; | ||
1077 | 1133 | ||
1078 | auxtrace_mmap_params__set_idx(&mp->auxtrace_mp, evlist, cpu, | 1134 | auxtrace_mmap_params__set_idx(&mp->auxtrace_mp, evlist, cpu, |
1079 | true); | 1135 | true); |
1080 | 1136 | ||
1081 | for (thread = 0; thread < nr_threads; thread++) { | 1137 | for (thread = 0; thread < nr_threads; thread++) { |
1082 | if (perf_evlist__mmap_per_evsel(evlist, cpu, mp, cpu, | 1138 | if (perf_evlist__mmap_per_evsel(evlist, cpu, mp, cpu, |
1083 | thread, &output)) | 1139 | thread, &output, &output_backward)) |
1084 | goto out_unmap; | 1140 | goto out_unmap; |
1085 | } | 1141 | } |
1086 | } | 1142 | } |
@@ -1088,8 +1144,7 @@ static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, | |||
1088 | return 0; | 1144 | return 0; |
1089 | 1145 | ||
1090 | out_unmap: | 1146 | out_unmap: |
1091 | for (cpu = 0; cpu < nr_cpus; cpu++) | 1147 | perf_evlist__munmap_nofree(evlist); |
1092 | __perf_evlist__munmap(evlist, cpu); | ||
1093 | return -1; | 1148 | return -1; |
1094 | } | 1149 | } |
1095 | 1150 | ||
@@ -1102,20 +1157,20 @@ static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, | |||
1102 | pr_debug2("perf event ring buffer mmapped per thread\n"); | 1157 | pr_debug2("perf event ring buffer mmapped per thread\n"); |
1103 | for (thread = 0; thread < nr_threads; thread++) { | 1158 | for (thread = 0; thread < nr_threads; thread++) { |
1104 | int output = -1; | 1159 | int output = -1; |
1160 | int output_backward = -1; | ||
1105 | 1161 | ||
1106 | auxtrace_mmap_params__set_idx(&mp->auxtrace_mp, evlist, thread, | 1162 | auxtrace_mmap_params__set_idx(&mp->auxtrace_mp, evlist, thread, |
1107 | false); | 1163 | false); |
1108 | 1164 | ||
1109 | if (perf_evlist__mmap_per_evsel(evlist, thread, mp, 0, thread, | 1165 | if (perf_evlist__mmap_per_evsel(evlist, thread, mp, 0, thread, |
1110 | &output)) | 1166 | &output, &output_backward)) |
1111 | goto out_unmap; | 1167 | goto out_unmap; |
1112 | } | 1168 | } |
1113 | 1169 | ||
1114 | return 0; | 1170 | return 0; |
1115 | 1171 | ||
1116 | out_unmap: | 1172 | out_unmap: |
1117 | for (thread = 0; thread < nr_threads; thread++) | 1173 | perf_evlist__munmap_nofree(evlist); |
1118 | __perf_evlist__munmap(evlist, thread); | ||
1119 | return -1; | 1174 | return -1; |
1120 | } | 1175 | } |
1121 | 1176 | ||
@@ -1248,7 +1303,9 @@ int perf_evlist__mmap_ex(struct perf_evlist *evlist, unsigned int pages, | |||
1248 | .prot = PROT_READ | (overwrite ? 0 : PROT_WRITE), | 1303 | .prot = PROT_READ | (overwrite ? 0 : PROT_WRITE), |
1249 | }; | 1304 | }; |
1250 | 1305 | ||
1251 | if (evlist->mmap == NULL && perf_evlist__alloc_mmap(evlist) < 0) | 1306 | if (!evlist->mmap) |
1307 | evlist->mmap = perf_evlist__alloc_mmap(evlist); | ||
1308 | if (!evlist->mmap) | ||
1252 | return -ENOMEM; | 1309 | return -ENOMEM; |
1253 | 1310 | ||
1254 | if (evlist->pollfd.entries == NULL && perf_evlist__alloc_pollfd(evlist) < 0) | 1311 | if (evlist->pollfd.entries == NULL && perf_evlist__alloc_pollfd(evlist) < 0) |
@@ -1919,3 +1976,61 @@ perf_evlist__find_evsel_by_str(struct perf_evlist *evlist, | |||
1919 | 1976 | ||
1920 | return NULL; | 1977 | return NULL; |
1921 | } | 1978 | } |
1979 | |||
1980 | void perf_evlist__toggle_bkw_mmap(struct perf_evlist *evlist, | ||
1981 | enum bkw_mmap_state state) | ||
1982 | { | ||
1983 | enum bkw_mmap_state old_state = evlist->bkw_mmap_state; | ||
1984 | enum action { | ||
1985 | NONE, | ||
1986 | PAUSE, | ||
1987 | RESUME, | ||
1988 | } action = NONE; | ||
1989 | |||
1990 | if (!evlist->backward_mmap) | ||
1991 | return; | ||
1992 | |||
1993 | switch (old_state) { | ||
1994 | case BKW_MMAP_NOTREADY: { | ||
1995 | if (state != BKW_MMAP_RUNNING) | ||
1996 | goto state_err;; | ||
1997 | break; | ||
1998 | } | ||
1999 | case BKW_MMAP_RUNNING: { | ||
2000 | if (state != BKW_MMAP_DATA_PENDING) | ||
2001 | goto state_err; | ||
2002 | action = PAUSE; | ||
2003 | break; | ||
2004 | } | ||
2005 | case BKW_MMAP_DATA_PENDING: { | ||
2006 | if (state != BKW_MMAP_EMPTY) | ||
2007 | goto state_err; | ||
2008 | break; | ||
2009 | } | ||
2010 | case BKW_MMAP_EMPTY: { | ||
2011 | if (state != BKW_MMAP_RUNNING) | ||
2012 | goto state_err; | ||
2013 | action = RESUME; | ||
2014 | break; | ||
2015 | } | ||
2016 | default: | ||
2017 | WARN_ONCE(1, "Shouldn't get there\n"); | ||
2018 | } | ||
2019 | |||
2020 | evlist->bkw_mmap_state = state; | ||
2021 | |||
2022 | switch (action) { | ||
2023 | case PAUSE: | ||
2024 | perf_evlist__pause(evlist); | ||
2025 | break; | ||
2026 | case RESUME: | ||
2027 | perf_evlist__resume(evlist); | ||
2028 | break; | ||
2029 | case NONE: | ||
2030 | default: | ||
2031 | break; | ||
2032 | } | ||
2033 | |||
2034 | state_err: | ||
2035 | return; | ||
2036 | } | ||
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index afd087761a47..4fd034f22d2f 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h | |||
@@ -35,6 +35,40 @@ struct perf_mmap { | |||
35 | char event_copy[PERF_SAMPLE_MAX_SIZE] __attribute__((aligned(8))); | 35 | char event_copy[PERF_SAMPLE_MAX_SIZE] __attribute__((aligned(8))); |
36 | }; | 36 | }; |
37 | 37 | ||
38 | static inline size_t | ||
39 | perf_mmap__mmap_len(struct perf_mmap *map) | ||
40 | { | ||
41 | return map->mask + 1 + page_size; | ||
42 | } | ||
43 | |||
44 | /* | ||
45 | * State machine of bkw_mmap_state: | ||
46 | * | ||
47 | * .________________(forbid)_____________. | ||
48 | * | V | ||
49 | * NOTREADY --(0)--> RUNNING --(1)--> DATA_PENDING --(2)--> EMPTY | ||
50 | * ^ ^ | ^ | | ||
51 | * | |__(forbid)____/ |___(forbid)___/| | ||
52 | * | | | ||
53 | * \_________________(3)_______________/ | ||
54 | * | ||
55 | * NOTREADY : Backward ring buffers are not ready | ||
56 | * RUNNING : Backward ring buffers are recording | ||
57 | * DATA_PENDING : We are required to collect data from backward ring buffers | ||
58 | * EMPTY : We have collected data from backward ring buffers. | ||
59 | * | ||
60 | * (0): Setup backward ring buffer | ||
61 | * (1): Pause ring buffers for reading | ||
62 | * (2): Read from ring buffers | ||
63 | * (3): Resume ring buffers for recording | ||
64 | */ | ||
65 | enum bkw_mmap_state { | ||
66 | BKW_MMAP_NOTREADY, | ||
67 | BKW_MMAP_RUNNING, | ||
68 | BKW_MMAP_DATA_PENDING, | ||
69 | BKW_MMAP_EMPTY, | ||
70 | }; | ||
71 | |||
38 | struct perf_evlist { | 72 | struct perf_evlist { |
39 | struct list_head entries; | 73 | struct list_head entries; |
40 | struct hlist_head heads[PERF_EVLIST__HLIST_SIZE]; | 74 | struct hlist_head heads[PERF_EVLIST__HLIST_SIZE]; |
@@ -44,17 +78,18 @@ struct perf_evlist { | |||
44 | bool overwrite; | 78 | bool overwrite; |
45 | bool enabled; | 79 | bool enabled; |
46 | bool has_user_cpus; | 80 | bool has_user_cpus; |
47 | bool backward; | ||
48 | size_t mmap_len; | 81 | size_t mmap_len; |
49 | int id_pos; | 82 | int id_pos; |
50 | int is_pos; | 83 | int is_pos; |
51 | u64 combined_sample_type; | 84 | u64 combined_sample_type; |
85 | enum bkw_mmap_state bkw_mmap_state; | ||
52 | struct { | 86 | struct { |
53 | int cork_fd; | 87 | int cork_fd; |
54 | pid_t pid; | 88 | pid_t pid; |
55 | } workload; | 89 | } workload; |
56 | struct fdarray pollfd; | 90 | struct fdarray pollfd; |
57 | struct perf_mmap *mmap; | 91 | struct perf_mmap *mmap; |
92 | struct perf_mmap *backward_mmap; | ||
58 | struct thread_map *threads; | 93 | struct thread_map *threads; |
59 | struct cpu_map *cpus; | 94 | struct cpu_map *cpus; |
60 | struct perf_evsel *selected; | 95 | struct perf_evsel *selected; |
@@ -129,6 +164,14 @@ struct perf_evsel *perf_evlist__id2evsel_strict(struct perf_evlist *evlist, | |||
129 | 164 | ||
130 | struct perf_sample_id *perf_evlist__id2sid(struct perf_evlist *evlist, u64 id); | 165 | struct perf_sample_id *perf_evlist__id2sid(struct perf_evlist *evlist, u64 id); |
131 | 166 | ||
167 | void perf_evlist__toggle_bkw_mmap(struct perf_evlist *evlist, enum bkw_mmap_state state); | ||
168 | |||
169 | union perf_event *perf_mmap__read_forward(struct perf_mmap *map, bool check_messup); | ||
170 | union perf_event *perf_mmap__read_backward(struct perf_mmap *map); | ||
171 | |||
172 | void perf_mmap__read_catchup(struct perf_mmap *md); | ||
173 | void perf_mmap__consume(struct perf_mmap *md, bool overwrite); | ||
174 | |||
132 | union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx); | 175 | union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx); |
133 | 176 | ||
134 | union perf_event *perf_evlist__mmap_read_forward(struct perf_evlist *evlist, | 177 | union perf_event *perf_evlist__mmap_read_forward(struct perf_evlist *evlist, |
@@ -139,8 +182,6 @@ void perf_evlist__mmap_read_catchup(struct perf_evlist *evlist, int idx); | |||
139 | 182 | ||
140 | void perf_evlist__mmap_consume(struct perf_evlist *evlist, int idx); | 183 | void perf_evlist__mmap_consume(struct perf_evlist *evlist, int idx); |
141 | 184 | ||
142 | int perf_evlist__pause(struct perf_evlist *evlist); | ||
143 | int perf_evlist__resume(struct perf_evlist *evlist); | ||
144 | int perf_evlist__open(struct perf_evlist *evlist); | 185 | int perf_evlist__open(struct perf_evlist *evlist); |
145 | void perf_evlist__close(struct perf_evlist *evlist); | 186 | void perf_evlist__close(struct perf_evlist *evlist); |
146 | 187 | ||
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index ba0f59fa3d5d..8c54df61fe64 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
@@ -695,6 +695,9 @@ static void apply_config_terms(struct perf_evsel *evsel, | |||
695 | */ | 695 | */ |
696 | attr->inherit = term->val.inherit ? 1 : 0; | 696 | attr->inherit = term->val.inherit ? 1 : 0; |
697 | break; | 697 | break; |
698 | case PERF_EVSEL__CONFIG_TERM_OVERWRITE: | ||
699 | attr->write_backward = term->val.overwrite ? 1 : 0; | ||
700 | break; | ||
698 | default: | 701 | default: |
699 | break; | 702 | break; |
700 | } | 703 | } |
@@ -776,6 +779,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts, | |||
776 | 779 | ||
777 | attr->sample_id_all = perf_missing_features.sample_id_all ? 0 : 1; | 780 | attr->sample_id_all = perf_missing_features.sample_id_all ? 0 : 1; |
778 | attr->inherit = !opts->no_inherit; | 781 | attr->inherit = !opts->no_inherit; |
782 | attr->write_backward = opts->overwrite ? 1 : 0; | ||
779 | 783 | ||
780 | perf_evsel__set_sample_bit(evsel, IP); | 784 | perf_evsel__set_sample_bit(evsel, IP); |
781 | perf_evsel__set_sample_bit(evsel, TID); | 785 | perf_evsel__set_sample_bit(evsel, TID); |
@@ -1377,6 +1381,9 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, | |||
1377 | int pid = -1, err; | 1381 | int pid = -1, err; |
1378 | enum { NO_CHANGE, SET_TO_MAX, INCREASED_MAX } set_rlimit = NO_CHANGE; | 1382 | enum { NO_CHANGE, SET_TO_MAX, INCREASED_MAX } set_rlimit = NO_CHANGE; |
1379 | 1383 | ||
1384 | if (perf_missing_features.write_backward && evsel->attr.write_backward) | ||
1385 | return -EINVAL; | ||
1386 | |||
1380 | if (evsel->system_wide) | 1387 | if (evsel->system_wide) |
1381 | nthreads = 1; | 1388 | nthreads = 1; |
1382 | else | 1389 | else |
@@ -1407,11 +1414,6 @@ fallback_missing_features: | |||
1407 | if (perf_missing_features.lbr_flags) | 1414 | if (perf_missing_features.lbr_flags) |
1408 | evsel->attr.branch_sample_type &= ~(PERF_SAMPLE_BRANCH_NO_FLAGS | | 1415 | evsel->attr.branch_sample_type &= ~(PERF_SAMPLE_BRANCH_NO_FLAGS | |
1409 | PERF_SAMPLE_BRANCH_NO_CYCLES); | 1416 | PERF_SAMPLE_BRANCH_NO_CYCLES); |
1410 | if (perf_missing_features.write_backward) { | ||
1411 | if (evsel->overwrite) | ||
1412 | return -EINVAL; | ||
1413 | evsel->attr.write_backward = false; | ||
1414 | } | ||
1415 | retry_sample_id: | 1417 | retry_sample_id: |
1416 | if (perf_missing_features.sample_id_all) | 1418 | if (perf_missing_features.sample_id_all) |
1417 | evsel->attr.sample_id_all = 0; | 1419 | evsel->attr.sample_id_all = 0; |
@@ -1513,7 +1515,7 @@ try_fallback: | |||
1513 | */ | 1515 | */ |
1514 | if (!perf_missing_features.write_backward && evsel->attr.write_backward) { | 1516 | if (!perf_missing_features.write_backward && evsel->attr.write_backward) { |
1515 | perf_missing_features.write_backward = true; | 1517 | perf_missing_features.write_backward = true; |
1516 | goto fallback_missing_features; | 1518 | goto out_close; |
1517 | } else if (!perf_missing_features.clockid_wrong && evsel->attr.use_clockid) { | 1519 | } else if (!perf_missing_features.clockid_wrong && evsel->attr.use_clockid) { |
1518 | perf_missing_features.clockid_wrong = true; | 1520 | perf_missing_features.clockid_wrong = true; |
1519 | goto fallback_missing_features; | 1521 | goto fallback_missing_features; |
@@ -2422,7 +2424,7 @@ int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target, | |||
2422 | "We found oprofile daemon running, please stop it and try again."); | 2424 | "We found oprofile daemon running, please stop it and try again."); |
2423 | break; | 2425 | break; |
2424 | case EINVAL: | 2426 | case EINVAL: |
2425 | if (evsel->overwrite && perf_missing_features.write_backward) | 2427 | if (evsel->attr.write_backward && perf_missing_features.write_backward) |
2426 | return scnprintf(msg, size, "Reading from overwrite event is not supported by this kernel."); | 2428 | return scnprintf(msg, size, "Reading from overwrite event is not supported by this kernel."); |
2427 | if (perf_missing_features.clockid) | 2429 | if (perf_missing_features.clockid) |
2428 | return scnprintf(msg, size, "clockid feature not supported."); | 2430 | return scnprintf(msg, size, "clockid feature not supported."); |
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index d73391e8740e..8a4a6c9f1480 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h | |||
@@ -45,6 +45,7 @@ enum { | |||
45 | PERF_EVSEL__CONFIG_TERM_STACK_USER, | 45 | PERF_EVSEL__CONFIG_TERM_STACK_USER, |
46 | PERF_EVSEL__CONFIG_TERM_INHERIT, | 46 | PERF_EVSEL__CONFIG_TERM_INHERIT, |
47 | PERF_EVSEL__CONFIG_TERM_MAX_STACK, | 47 | PERF_EVSEL__CONFIG_TERM_MAX_STACK, |
48 | PERF_EVSEL__CONFIG_TERM_OVERWRITE, | ||
48 | PERF_EVSEL__CONFIG_TERM_MAX, | 49 | PERF_EVSEL__CONFIG_TERM_MAX, |
49 | }; | 50 | }; |
50 | 51 | ||
@@ -59,6 +60,7 @@ struct perf_evsel_config_term { | |||
59 | u64 stack_user; | 60 | u64 stack_user; |
60 | int max_stack; | 61 | int max_stack; |
61 | bool inherit; | 62 | bool inherit; |
63 | bool overwrite; | ||
62 | } val; | 64 | } val; |
63 | }; | 65 | }; |
64 | 66 | ||
@@ -114,7 +116,6 @@ struct perf_evsel { | |||
114 | bool tracking; | 116 | bool tracking; |
115 | bool per_pkg; | 117 | bool per_pkg; |
116 | bool precise_max; | 118 | bool precise_max; |
117 | bool overwrite; | ||
118 | /* parse modifier helper */ | 119 | /* parse modifier helper */ |
119 | int exclude_GH; | 120 | int exclude_GH; |
120 | int nr_members; | 121 | int nr_members; |
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 375af0e02831..6c913c3914fb 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c | |||
@@ -902,6 +902,8 @@ static const char *config_term_names[__PARSE_EVENTS__TERM_TYPE_NR] = { | |||
902 | [PARSE_EVENTS__TERM_TYPE_NOINHERIT] = "no-inherit", | 902 | [PARSE_EVENTS__TERM_TYPE_NOINHERIT] = "no-inherit", |
903 | [PARSE_EVENTS__TERM_TYPE_INHERIT] = "inherit", | 903 | [PARSE_EVENTS__TERM_TYPE_INHERIT] = "inherit", |
904 | [PARSE_EVENTS__TERM_TYPE_MAX_STACK] = "max-stack", | 904 | [PARSE_EVENTS__TERM_TYPE_MAX_STACK] = "max-stack", |
905 | [PARSE_EVENTS__TERM_TYPE_OVERWRITE] = "overwrite", | ||
906 | [PARSE_EVENTS__TERM_TYPE_NOOVERWRITE] = "no-overwrite", | ||
905 | }; | 907 | }; |
906 | 908 | ||
907 | static bool config_term_shrinked; | 909 | static bool config_term_shrinked; |
@@ -994,6 +996,12 @@ do { \ | |||
994 | case PARSE_EVENTS__TERM_TYPE_NOINHERIT: | 996 | case PARSE_EVENTS__TERM_TYPE_NOINHERIT: |
995 | CHECK_TYPE_VAL(NUM); | 997 | CHECK_TYPE_VAL(NUM); |
996 | break; | 998 | break; |
999 | case PARSE_EVENTS__TERM_TYPE_OVERWRITE: | ||
1000 | CHECK_TYPE_VAL(NUM); | ||
1001 | break; | ||
1002 | case PARSE_EVENTS__TERM_TYPE_NOOVERWRITE: | ||
1003 | CHECK_TYPE_VAL(NUM); | ||
1004 | break; | ||
997 | case PARSE_EVENTS__TERM_TYPE_NAME: | 1005 | case PARSE_EVENTS__TERM_TYPE_NAME: |
998 | CHECK_TYPE_VAL(STR); | 1006 | CHECK_TYPE_VAL(STR); |
999 | break; | 1007 | break; |
@@ -1046,6 +1054,8 @@ static int config_term_tracepoint(struct perf_event_attr *attr, | |||
1046 | case PARSE_EVENTS__TERM_TYPE_INHERIT: | 1054 | case PARSE_EVENTS__TERM_TYPE_INHERIT: |
1047 | case PARSE_EVENTS__TERM_TYPE_NOINHERIT: | 1055 | case PARSE_EVENTS__TERM_TYPE_NOINHERIT: |
1048 | case PARSE_EVENTS__TERM_TYPE_MAX_STACK: | 1056 | case PARSE_EVENTS__TERM_TYPE_MAX_STACK: |
1057 | case PARSE_EVENTS__TERM_TYPE_OVERWRITE: | ||
1058 | case PARSE_EVENTS__TERM_TYPE_NOOVERWRITE: | ||
1049 | return config_term_common(attr, term, err); | 1059 | return config_term_common(attr, term, err); |
1050 | default: | 1060 | default: |
1051 | if (err) { | 1061 | if (err) { |
@@ -1118,6 +1128,12 @@ do { \ | |||
1118 | case PARSE_EVENTS__TERM_TYPE_MAX_STACK: | 1128 | case PARSE_EVENTS__TERM_TYPE_MAX_STACK: |
1119 | ADD_CONFIG_TERM(MAX_STACK, max_stack, term->val.num); | 1129 | ADD_CONFIG_TERM(MAX_STACK, max_stack, term->val.num); |
1120 | break; | 1130 | break; |
1131 | case PARSE_EVENTS__TERM_TYPE_OVERWRITE: | ||
1132 | ADD_CONFIG_TERM(OVERWRITE, overwrite, term->val.num ? 1 : 0); | ||
1133 | break; | ||
1134 | case PARSE_EVENTS__TERM_TYPE_NOOVERWRITE: | ||
1135 | ADD_CONFIG_TERM(OVERWRITE, overwrite, term->val.num ? 0 : 1); | ||
1136 | break; | ||
1121 | default: | 1137 | default: |
1122 | break; | 1138 | break; |
1123 | } | 1139 | } |
@@ -2412,9 +2428,9 @@ static void config_terms_list(char *buf, size_t buf_sz) | |||
2412 | char *parse_events_formats_error_string(char *additional_terms) | 2428 | char *parse_events_formats_error_string(char *additional_terms) |
2413 | { | 2429 | { |
2414 | char *str; | 2430 | char *str; |
2415 | /* "branch_type" is the longest name */ | 2431 | /* "no-overwrite" is the longest name */ |
2416 | char static_terms[__PARSE_EVENTS__TERM_TYPE_NR * | 2432 | char static_terms[__PARSE_EVENTS__TERM_TYPE_NR * |
2417 | (sizeof("branch_type") - 1)]; | 2433 | (sizeof("no-overwrite") - 1)]; |
2418 | 2434 | ||
2419 | config_terms_list(static_terms, sizeof(static_terms)); | 2435 | config_terms_list(static_terms, sizeof(static_terms)); |
2420 | /* valid terms */ | 2436 | /* valid terms */ |
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index b4aa7eb2df73..d1edbf8cc66a 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h | |||
@@ -69,6 +69,8 @@ enum { | |||
69 | PARSE_EVENTS__TERM_TYPE_NOINHERIT, | 69 | PARSE_EVENTS__TERM_TYPE_NOINHERIT, |
70 | PARSE_EVENTS__TERM_TYPE_INHERIT, | 70 | PARSE_EVENTS__TERM_TYPE_INHERIT, |
71 | PARSE_EVENTS__TERM_TYPE_MAX_STACK, | 71 | PARSE_EVENTS__TERM_TYPE_MAX_STACK, |
72 | PARSE_EVENTS__TERM_TYPE_NOOVERWRITE, | ||
73 | PARSE_EVENTS__TERM_TYPE_OVERWRITE, | ||
72 | __PARSE_EVENTS__TERM_TYPE_NR, | 74 | __PARSE_EVENTS__TERM_TYPE_NR, |
73 | }; | 75 | }; |
74 | 76 | ||
diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l index 3c15b33b2e84..7a2519435da0 100644 --- a/tools/perf/util/parse-events.l +++ b/tools/perf/util/parse-events.l | |||
@@ -202,6 +202,8 @@ stack-size { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_STACKSIZE); } | |||
202 | max-stack { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_MAX_STACK); } | 202 | max-stack { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_MAX_STACK); } |
203 | inherit { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_INHERIT); } | 203 | inherit { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_INHERIT); } |
204 | no-inherit { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NOINHERIT); } | 204 | no-inherit { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NOINHERIT); } |
205 | overwrite { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_OVERWRITE); } | ||
206 | no-overwrite { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NOOVERWRITE); } | ||
205 | , { return ','; } | 207 | , { return ','; } |
206 | "/" { BEGIN(INITIAL); return '/'; } | 208 | "/" { BEGIN(INITIAL); return '/'; } |
207 | {name_minus} { return str(yyscanner, PE_NAME); } | 209 | {name_minus} { return str(yyscanner, PE_NAME); } |
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 078d49626494..5d61242a6e64 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
@@ -1499,10 +1499,27 @@ int perf_session__register_idle_thread(struct perf_session *session) | |||
1499 | return err; | 1499 | return err; |
1500 | } | 1500 | } |
1501 | 1501 | ||
1502 | static void | ||
1503 | perf_session__warn_order(const struct perf_session *session) | ||
1504 | { | ||
1505 | const struct ordered_events *oe = &session->ordered_events; | ||
1506 | struct perf_evsel *evsel; | ||
1507 | bool should_warn = true; | ||
1508 | |||
1509 | evlist__for_each_entry(session->evlist, evsel) { | ||
1510 | if (evsel->attr.write_backward) | ||
1511 | should_warn = false; | ||
1512 | } | ||
1513 | |||
1514 | if (!should_warn) | ||
1515 | return; | ||
1516 | if (oe->nr_unordered_events != 0) | ||
1517 | ui__warning("%u out of order events recorded.\n", oe->nr_unordered_events); | ||
1518 | } | ||
1519 | |||
1502 | static void perf_session__warn_about_errors(const struct perf_session *session) | 1520 | static void perf_session__warn_about_errors(const struct perf_session *session) |
1503 | { | 1521 | { |
1504 | const struct events_stats *stats = &session->evlist->stats; | 1522 | const struct events_stats *stats = &session->evlist->stats; |
1505 | const struct ordered_events *oe = &session->ordered_events; | ||
1506 | 1523 | ||
1507 | if (session->tool->lost == perf_event__process_lost && | 1524 | if (session->tool->lost == perf_event__process_lost && |
1508 | stats->nr_events[PERF_RECORD_LOST] != 0) { | 1525 | stats->nr_events[PERF_RECORD_LOST] != 0) { |
@@ -1559,8 +1576,7 @@ static void perf_session__warn_about_errors(const struct perf_session *session) | |||
1559 | stats->nr_unprocessable_samples); | 1576 | stats->nr_unprocessable_samples); |
1560 | } | 1577 | } |
1561 | 1578 | ||
1562 | if (oe->nr_unordered_events != 0) | 1579 | perf_session__warn_order(session); |
1563 | ui__warning("%u out of order events recorded.\n", oe->nr_unordered_events); | ||
1564 | 1580 | ||
1565 | events_stats__auxtrace_error_warn(stats); | 1581 | events_stats__auxtrace_error_warn(stats); |
1566 | 1582 | ||
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 5854b4660a49..947d21f38398 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c | |||
@@ -2381,6 +2381,9 @@ static int sort_dimension__add(struct perf_hpp_list *list, const char *tok, | |||
2381 | if (sort__mode != SORT_MODE__MEMORY) | 2381 | if (sort__mode != SORT_MODE__MEMORY) |
2382 | return -EINVAL; | 2382 | return -EINVAL; |
2383 | 2383 | ||
2384 | if (sd->entry == &sort_mem_dcacheline && cacheline_size == 0) | ||
2385 | return -EINVAL; | ||
2386 | |||
2384 | if (sd->entry == &sort_mem_daddr_sym) | 2387 | if (sd->entry == &sort_mem_daddr_sym) |
2385 | list->sym = 1; | 2388 | list->sym = 1; |
2386 | 2389 | ||
@@ -2424,7 +2427,10 @@ static int setup_sort_list(struct perf_hpp_list *list, char *str, | |||
2424 | if (*tok) { | 2427 | if (*tok) { |
2425 | ret = sort_dimension__add(list, tok, evlist, level); | 2428 | ret = sort_dimension__add(list, tok, evlist, level); |
2426 | if (ret == -EINVAL) { | 2429 | if (ret == -EINVAL) { |
2427 | error("Invalid --sort key: `%s'", tok); | 2430 | if (!cacheline_size && !strncasecmp(tok, "dcacheline", strlen(tok))) |
2431 | error("The \"dcacheline\" --sort key needs to know the cacheline size and it couldn't be determined on this system"); | ||
2432 | else | ||
2433 | error("Invalid --sort key: `%s'", tok); | ||
2428 | break; | 2434 | break; |
2429 | } else if (ret == -ESRCH) { | 2435 | } else if (ret == -ESRCH) { |
2430 | error("Unknown --sort key: `%s'", tok); | 2436 | error("Unknown --sort key: `%s'", tok); |
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index 6178cab82374..843cbba8f9d3 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h | |||
@@ -360,7 +360,7 @@ void print_binary(unsigned char *data, size_t len, | |||
360 | size_t bytes_per_line, print_binary_t printer, | 360 | size_t bytes_per_line, print_binary_t printer, |
361 | void *extra); | 361 | void *extra); |
362 | 362 | ||
363 | #ifndef __GLIBC__ | 363 | #if !defined(__GLIBC__) && !defined(__ANDROID__) |
364 | extern int sched_getcpu(void); | 364 | extern int sched_getcpu(void); |
365 | #endif | 365 | #endif |
366 | 366 | ||