aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/evsel.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util/evsel.c')
-rw-r--r--tools/perf/util/evsel.c276
1 files changed, 248 insertions, 28 deletions
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 2eaae140def2..ffdd94e9c9c3 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -8,7 +8,10 @@
8 */ 8 */
9 9
10#include <byteswap.h> 10#include <byteswap.h>
11#include <linux/bitops.h>
11#include "asm/bug.h" 12#include "asm/bug.h"
13#include "debugfs.h"
14#include "event-parse.h"
12#include "evsel.h" 15#include "evsel.h"
13#include "evlist.h" 16#include "evlist.h"
14#include "util.h" 17#include "util.h"
@@ -16,9 +19,10 @@
16#include "thread_map.h" 19#include "thread_map.h"
17#include "target.h" 20#include "target.h"
18#include "../../../include/linux/hw_breakpoint.h" 21#include "../../../include/linux/hw_breakpoint.h"
22#include "../../include/linux/perf_event.h"
23#include "perf_regs.h"
19 24
20#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) 25#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
21#define GROUP_FD(group_fd, cpu) (*(int *)xyarray__entry(group_fd, cpu, 0))
22 26
23static int __perf_evsel__sample_size(u64 sample_type) 27static int __perf_evsel__sample_size(u64 sample_type)
24{ 28{
@@ -66,7 +70,80 @@ struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx)
66 return evsel; 70 return evsel;
67} 71}
68 72
69static const char *perf_evsel__hw_names[PERF_COUNT_HW_MAX] = { 73struct event_format *event_format__new(const char *sys, const char *name)
74{
75 int fd, n;
76 char *filename;
77 void *bf = NULL, *nbf;
78 size_t size = 0, alloc_size = 0;
79 struct event_format *format = NULL;
80
81 if (asprintf(&filename, "%s/%s/%s/format", tracing_events_path, sys, name) < 0)
82 goto out;
83
84 fd = open(filename, O_RDONLY);
85 if (fd < 0)
86 goto out_free_filename;
87
88 do {
89 if (size == alloc_size) {
90 alloc_size += BUFSIZ;
91 nbf = realloc(bf, alloc_size);
92 if (nbf == NULL)
93 goto out_free_bf;
94 bf = nbf;
95 }
96
97 n = read(fd, bf + size, BUFSIZ);
98 if (n < 0)
99 goto out_free_bf;
100 size += n;
101 } while (n > 0);
102
103 pevent_parse_format(&format, bf, size, sys);
104
105out_free_bf:
106 free(bf);
107 close(fd);
108out_free_filename:
109 free(filename);
110out:
111 return format;
112}
113
114struct perf_evsel *perf_evsel__newtp(const char *sys, const char *name, int idx)
115{
116 struct perf_evsel *evsel = zalloc(sizeof(*evsel));
117
118 if (evsel != NULL) {
119 struct perf_event_attr attr = {
120 .type = PERF_TYPE_TRACEPOINT,
121 .sample_type = (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME |
122 PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD),
123 };
124
125 if (asprintf(&evsel->name, "%s:%s", sys, name) < 0)
126 goto out_free;
127
128 evsel->tp_format = event_format__new(sys, name);
129 if (evsel->tp_format == NULL)
130 goto out_free;
131
132 event_attr_init(&attr);
133 attr.config = evsel->tp_format->id;
134 attr.sample_period = 1;
135 perf_evsel__init(evsel, &attr, idx);
136 }
137
138 return evsel;
139
140out_free:
141 free(evsel->name);
142 free(evsel);
143 return NULL;
144}
145
146const char *perf_evsel__hw_names[PERF_COUNT_HW_MAX] = {
70 "cycles", 147 "cycles",
71 "instructions", 148 "instructions",
72 "cache-references", 149 "cache-references",
@@ -129,12 +206,12 @@ static int perf_evsel__hw_name(struct perf_evsel *evsel, char *bf, size_t size)
129 return r + perf_evsel__add_modifiers(evsel, bf + r, size - r); 206 return r + perf_evsel__add_modifiers(evsel, bf + r, size - r);
130} 207}
131 208
132static const char *perf_evsel__sw_names[PERF_COUNT_SW_MAX] = { 209const char *perf_evsel__sw_names[PERF_COUNT_SW_MAX] = {
133 "cpu-clock", 210 "cpu-clock",
134 "task-clock", 211 "task-clock",
135 "page-faults", 212 "page-faults",
136 "context-switches", 213 "context-switches",
137 "CPU-migrations", 214 "cpu-migrations",
138 "minor-faults", 215 "minor-faults",
139 "major-faults", 216 "major-faults",
140 "alignment-faults", 217 "alignment-faults",
@@ -317,7 +394,8 @@ const char *perf_evsel__name(struct perf_evsel *evsel)
317 break; 394 break;
318 395
319 default: 396 default:
320 scnprintf(bf, sizeof(bf), "%s", "unknown attr type"); 397 scnprintf(bf, sizeof(bf), "unknown attr type: %d",
398 evsel->attr.type);
321 break; 399 break;
322 } 400 }
323 401
@@ -367,9 +445,18 @@ void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts,
367 attr->mmap_data = track; 445 attr->mmap_data = track;
368 } 446 }
369 447
370 if (opts->call_graph) 448 if (opts->call_graph) {
371 attr->sample_type |= PERF_SAMPLE_CALLCHAIN; 449 attr->sample_type |= PERF_SAMPLE_CALLCHAIN;
372 450
451 if (opts->call_graph == CALLCHAIN_DWARF) {
452 attr->sample_type |= PERF_SAMPLE_REGS_USER |
453 PERF_SAMPLE_STACK_USER;
454 attr->sample_regs_user = PERF_REGS_MASK;
455 attr->sample_stack_user = opts->stack_dump_size;
456 attr->exclude_callchain_user = 1;
457 }
458 }
459
373 if (perf_target__has_cpu(&opts->target)) 460 if (perf_target__has_cpu(&opts->target))
374 attr->sample_type |= PERF_SAMPLE_CPU; 461 attr->sample_type |= PERF_SAMPLE_CPU;
375 462
@@ -421,6 +508,24 @@ int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
421 return evsel->fd != NULL ? 0 : -ENOMEM; 508 return evsel->fd != NULL ? 0 : -ENOMEM;
422} 509}
423 510
511int perf_evsel__set_filter(struct perf_evsel *evsel, int ncpus, int nthreads,
512 const char *filter)
513{
514 int cpu, thread;
515
516 for (cpu = 0; cpu < ncpus; cpu++) {
517 for (thread = 0; thread < nthreads; thread++) {
518 int fd = FD(evsel, cpu, thread),
519 err = ioctl(fd, PERF_EVENT_IOC_SET_FILTER, filter);
520
521 if (err)
522 return err;
523 }
524 }
525
526 return 0;
527}
528
424int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads) 529int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads)
425{ 530{
426 evsel->sample_id = xyarray__new(ncpus, nthreads, sizeof(struct perf_sample_id)); 531 evsel->sample_id = xyarray__new(ncpus, nthreads, sizeof(struct perf_sample_id));
@@ -481,6 +586,9 @@ void perf_evsel__delete(struct perf_evsel *evsel)
481{ 586{
482 perf_evsel__exit(evsel); 587 perf_evsel__exit(evsel);
483 close_cgroup(evsel->cgrp); 588 close_cgroup(evsel->cgrp);
589 free(evsel->group_name);
590 if (evsel->tp_format)
591 pevent_free_format(evsel->tp_format);
484 free(evsel->name); 592 free(evsel->name);
485 free(evsel); 593 free(evsel);
486} 594}
@@ -556,9 +664,28 @@ int __perf_evsel__read(struct perf_evsel *evsel,
556 return 0; 664 return 0;
557} 665}
558 666
667static int get_group_fd(struct perf_evsel *evsel, int cpu, int thread)
668{
669 struct perf_evsel *leader = evsel->leader;
670 int fd;
671
672 if (!leader)
673 return -1;
674
675 /*
676 * Leader must be already processed/open,
677 * if not it's a bug.
678 */
679 BUG_ON(!leader->fd);
680
681 fd = FD(leader, cpu, thread);
682 BUG_ON(fd == -1);
683
684 return fd;
685}
686
559static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, 687static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
560 struct thread_map *threads, bool group, 688 struct thread_map *threads)
561 struct xyarray *group_fds)
562{ 689{
563 int cpu, thread; 690 int cpu, thread;
564 unsigned long flags = 0; 691 unsigned long flags = 0;
@@ -574,13 +701,15 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
574 } 701 }
575 702
576 for (cpu = 0; cpu < cpus->nr; cpu++) { 703 for (cpu = 0; cpu < cpus->nr; cpu++) {
577 int group_fd = group_fds ? GROUP_FD(group_fds, cpu) : -1;
578 704
579 for (thread = 0; thread < threads->nr; thread++) { 705 for (thread = 0; thread < threads->nr; thread++) {
706 int group_fd;
580 707
581 if (!evsel->cgrp) 708 if (!evsel->cgrp)
582 pid = threads->map[thread]; 709 pid = threads->map[thread];
583 710
711 group_fd = get_group_fd(evsel, cpu, thread);
712
584 FD(evsel, cpu, thread) = sys_perf_event_open(&evsel->attr, 713 FD(evsel, cpu, thread) = sys_perf_event_open(&evsel->attr,
585 pid, 714 pid,
586 cpus->map[cpu], 715 cpus->map[cpu],
@@ -589,9 +718,6 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
589 err = -errno; 718 err = -errno;
590 goto out_close; 719 goto out_close;
591 } 720 }
592
593 if (group && group_fd == -1)
594 group_fd = FD(evsel, cpu, thread);
595 } 721 }
596 } 722 }
597 723
@@ -635,8 +761,7 @@ static struct {
635}; 761};
636 762
637int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, 763int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
638 struct thread_map *threads, bool group, 764 struct thread_map *threads)
639 struct xyarray *group_fd)
640{ 765{
641 if (cpus == NULL) { 766 if (cpus == NULL) {
642 /* Work around old compiler warnings about strict aliasing */ 767 /* Work around old compiler warnings about strict aliasing */
@@ -646,30 +771,28 @@ int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
646 if (threads == NULL) 771 if (threads == NULL)
647 threads = &empty_thread_map.map; 772 threads = &empty_thread_map.map;
648 773
649 return __perf_evsel__open(evsel, cpus, threads, group, group_fd); 774 return __perf_evsel__open(evsel, cpus, threads);
650} 775}
651 776
652int perf_evsel__open_per_cpu(struct perf_evsel *evsel, 777int perf_evsel__open_per_cpu(struct perf_evsel *evsel,
653 struct cpu_map *cpus, bool group, 778 struct cpu_map *cpus)
654 struct xyarray *group_fd)
655{ 779{
656 return __perf_evsel__open(evsel, cpus, &empty_thread_map.map, group, 780 return __perf_evsel__open(evsel, cpus, &empty_thread_map.map);
657 group_fd);
658} 781}
659 782
660int perf_evsel__open_per_thread(struct perf_evsel *evsel, 783int perf_evsel__open_per_thread(struct perf_evsel *evsel,
661 struct thread_map *threads, bool group, 784 struct thread_map *threads)
662 struct xyarray *group_fd)
663{ 785{
664 return __perf_evsel__open(evsel, &empty_cpu_map.map, threads, group, 786 return __perf_evsel__open(evsel, &empty_cpu_map.map, threads);
665 group_fd);
666} 787}
667 788
668static int perf_event__parse_id_sample(const union perf_event *event, u64 type, 789static int perf_evsel__parse_id_sample(const struct perf_evsel *evsel,
669 struct perf_sample *sample, 790 const union perf_event *event,
670 bool swapped) 791 struct perf_sample *sample)
671{ 792{
793 u64 type = evsel->attr.sample_type;
672 const u64 *array = event->sample.array; 794 const u64 *array = event->sample.array;
795 bool swapped = evsel->needs_swap;
673 union u64_swap u; 796 union u64_swap u;
674 797
675 array += ((event->header.size - 798 array += ((event->header.size -
@@ -730,9 +853,11 @@ static bool sample_overlap(const union perf_event *event,
730} 853}
731 854
732int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, 855int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
733 struct perf_sample *data, bool swapped) 856 struct perf_sample *data)
734{ 857{
735 u64 type = evsel->attr.sample_type; 858 u64 type = evsel->attr.sample_type;
859 u64 regs_user = evsel->attr.sample_regs_user;
860 bool swapped = evsel->needs_swap;
736 const u64 *array; 861 const u64 *array;
737 862
738 /* 863 /*
@@ -749,7 +874,7 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
749 if (event->header.type != PERF_RECORD_SAMPLE) { 874 if (event->header.type != PERF_RECORD_SAMPLE) {
750 if (!evsel->attr.sample_id_all) 875 if (!evsel->attr.sample_id_all)
751 return 0; 876 return 0;
752 return perf_event__parse_id_sample(event, type, data, swapped); 877 return perf_evsel__parse_id_sample(evsel, event, data);
753 } 878 }
754 879
755 array = event->sample.array; 880 array = event->sample.array;
@@ -869,6 +994,32 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
869 sz /= sizeof(u64); 994 sz /= sizeof(u64);
870 array += sz; 995 array += sz;
871 } 996 }
997
998 if (type & PERF_SAMPLE_REGS_USER) {
999 /* First u64 tells us if we have any regs in sample. */
1000 u64 avail = *array++;
1001
1002 if (avail) {
1003 data->user_regs.regs = (u64 *)array;
1004 array += hweight_long(regs_user);
1005 }
1006 }
1007
1008 if (type & PERF_SAMPLE_STACK_USER) {
1009 u64 size = *array++;
1010
1011 data->user_stack.offset = ((char *)(array - 1)
1012 - (char *) event);
1013
1014 if (!size) {
1015 data->user_stack.size = 0;
1016 } else {
1017 data->user_stack.data = (char *)array;
1018 array += size / sizeof(*array);
1019 data->user_stack.size = *array;
1020 }
1021 }
1022
872 return 0; 1023 return 0;
873} 1024}
874 1025
@@ -947,3 +1098,72 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type,
947 1098
948 return 0; 1099 return 0;
949} 1100}
1101
1102struct format_field *perf_evsel__field(struct perf_evsel *evsel, const char *name)
1103{
1104 return pevent_find_field(evsel->tp_format, name);
1105}
1106
1107void *perf_evsel__rawptr(struct perf_evsel *evsel, struct perf_sample *sample,
1108 const char *name)
1109{
1110 struct format_field *field = perf_evsel__field(evsel, name);
1111 int offset;
1112
1113 if (!field)
1114 return NULL;
1115
1116 offset = field->offset;
1117
1118 if (field->flags & FIELD_IS_DYNAMIC) {
1119 offset = *(int *)(sample->raw_data + field->offset);
1120 offset &= 0xffff;
1121 }
1122
1123 return sample->raw_data + offset;
1124}
1125
1126u64 perf_evsel__intval(struct perf_evsel *evsel, struct perf_sample *sample,
1127 const char *name)
1128{
1129 struct format_field *field = perf_evsel__field(evsel, name);
1130 void *ptr;
1131 u64 value;
1132
1133 if (!field)
1134 return 0;
1135
1136 ptr = sample->raw_data + field->offset;
1137
1138 switch (field->size) {
1139 case 1:
1140 return *(u8 *)ptr;
1141 case 2:
1142 value = *(u16 *)ptr;
1143 break;
1144 case 4:
1145 value = *(u32 *)ptr;
1146 break;
1147 case 8:
1148 value = *(u64 *)ptr;
1149 break;
1150 default:
1151 return 0;
1152 }
1153
1154 if (!evsel->needs_swap)
1155 return value;
1156
1157 switch (field->size) {
1158 case 2:
1159 return bswap_16(value);
1160 case 4:
1161 return bswap_32(value);
1162 case 8:
1163 return bswap_64(value);
1164 default:
1165 return 0;
1166 }
1167
1168 return 0;
1169}