aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util')
-rw-r--r--tools/perf/util/cpumap.c123
-rw-r--r--tools/perf/util/cpumap.h10
-rw-r--r--tools/perf/util/evsel.c186
-rw-r--r--tools/perf/util/evsel.h115
-rw-r--r--tools/perf/util/header.c15
-rw-r--r--tools/perf/util/header.h3
-rw-r--r--tools/perf/util/parse-events.c58
-rw-r--r--tools/perf/util/parse-events.h18
-rw-r--r--tools/perf/util/session.c22
-rw-r--r--tools/perf/util/session.h1
-rw-r--r--tools/perf/util/thread.c43
-rw-r--r--tools/perf/util/thread.h15
-rw-r--r--tools/perf/util/trace-event-info.c30
-rw-r--r--tools/perf/util/trace-event.h5
-rw-r--r--tools/perf/util/util.c17
-rw-r--r--tools/perf/util/util.h1
-rw-r--r--tools/perf/util/xyarray.c20
-rw-r--r--tools/perf/util/xyarray.h20
18 files changed, 586 insertions, 116 deletions
diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c
index 0f9b8d7a7d7..3ccaa104338 100644
--- a/tools/perf/util/cpumap.c
+++ b/tools/perf/util/cpumap.c
@@ -4,32 +4,53 @@
4#include <assert.h> 4#include <assert.h>
5#include <stdio.h> 5#include <stdio.h>
6 6
7int cpumap[MAX_NR_CPUS]; 7static struct cpu_map *cpu_map__default_new(void)
8
9static int default_cpu_map(void)
10{ 8{
11 int nr_cpus, i; 9 struct cpu_map *cpus;
10 int nr_cpus;
12 11
13 nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); 12 nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
14 assert(nr_cpus <= MAX_NR_CPUS); 13 if (nr_cpus < 0)
15 assert((int)nr_cpus >= 0); 14 return NULL;
15
16 cpus = malloc(sizeof(*cpus) + nr_cpus * sizeof(int));
17 if (cpus != NULL) {
18 int i;
19 for (i = 0; i < nr_cpus; ++i)
20 cpus->map[i] = i;
16 21
17 for (i = 0; i < nr_cpus; ++i) 22 cpus->nr = nr_cpus;
18 cpumap[i] = i; 23 }
19 24
20 return nr_cpus; 25 return cpus;
21} 26}
22 27
23static int read_all_cpu_map(void) 28static struct cpu_map *cpu_map__trim_new(int nr_cpus, int *tmp_cpus)
24{ 29{
30 size_t payload_size = nr_cpus * sizeof(int);
31 struct cpu_map *cpus = malloc(sizeof(*cpus) + payload_size);
32
33 if (cpus != NULL) {
34 cpus->nr = nr_cpus;
35 memcpy(cpus->map, tmp_cpus, payload_size);
36 }
37
38 return cpus;
39}
40
41static struct cpu_map *cpu_map__read_all_cpu_map(void)
42{
43 struct cpu_map *cpus = NULL;
25 FILE *onlnf; 44 FILE *onlnf;
26 int nr_cpus = 0; 45 int nr_cpus = 0;
46 int *tmp_cpus = NULL, *tmp;
47 int max_entries = 0;
27 int n, cpu, prev; 48 int n, cpu, prev;
28 char sep; 49 char sep;
29 50
30 onlnf = fopen("/sys/devices/system/cpu/online", "r"); 51 onlnf = fopen("/sys/devices/system/cpu/online", "r");
31 if (!onlnf) 52 if (!onlnf)
32 return default_cpu_map(); 53 return cpu_map__default_new();
33 54
34 sep = 0; 55 sep = 0;
35 prev = -1; 56 prev = -1;
@@ -38,12 +59,28 @@ static int read_all_cpu_map(void)
38 if (n <= 0) 59 if (n <= 0)
39 break; 60 break;
40 if (prev >= 0) { 61 if (prev >= 0) {
41 assert(nr_cpus + cpu - prev - 1 < MAX_NR_CPUS); 62 int new_max = nr_cpus + cpu - prev - 1;
63
64 if (new_max >= max_entries) {
65 max_entries = new_max + MAX_NR_CPUS / 2;
66 tmp = realloc(tmp_cpus, max_entries * sizeof(int));
67 if (tmp == NULL)
68 goto out_free_tmp;
69 tmp_cpus = tmp;
70 }
71
42 while (++prev < cpu) 72 while (++prev < cpu)
43 cpumap[nr_cpus++] = prev; 73 tmp_cpus[nr_cpus++] = prev;
74 }
75 if (nr_cpus == max_entries) {
76 max_entries += MAX_NR_CPUS;
77 tmp = realloc(tmp_cpus, max_entries * sizeof(int));
78 if (tmp == NULL)
79 goto out_free_tmp;
80 tmp_cpus = tmp;
44 } 81 }
45 assert (nr_cpus < MAX_NR_CPUS); 82
46 cpumap[nr_cpus++] = cpu; 83 tmp_cpus[nr_cpus++] = cpu;
47 if (n == 2 && sep == '-') 84 if (n == 2 && sep == '-')
48 prev = cpu; 85 prev = cpu;
49 else 86 else
@@ -51,24 +88,31 @@ static int read_all_cpu_map(void)
51 if (n == 1 || sep == '\n') 88 if (n == 1 || sep == '\n')
52 break; 89 break;
53 } 90 }
54 fclose(onlnf);
55 if (nr_cpus > 0)
56 return nr_cpus;
57 91
58 return default_cpu_map(); 92 if (nr_cpus > 0)
93 cpus = cpu_map__trim_new(nr_cpus, tmp_cpus);
94 else
95 cpus = cpu_map__default_new();
96out_free_tmp:
97 free(tmp_cpus);
98 fclose(onlnf);
99 return cpus;
59} 100}
60 101
61int read_cpu_map(const char *cpu_list) 102struct cpu_map *cpu_map__new(const char *cpu_list)
62{ 103{
104 struct cpu_map *cpus = NULL;
63 unsigned long start_cpu, end_cpu = 0; 105 unsigned long start_cpu, end_cpu = 0;
64 char *p = NULL; 106 char *p = NULL;
65 int i, nr_cpus = 0; 107 int i, nr_cpus = 0;
108 int *tmp_cpus = NULL, *tmp;
109 int max_entries = 0;
66 110
67 if (!cpu_list) 111 if (!cpu_list)
68 return read_all_cpu_map(); 112 return cpu_map__read_all_cpu_map();
69 113
70 if (!isdigit(*cpu_list)) 114 if (!isdigit(*cpu_list))
71 goto invalid; 115 goto out;
72 116
73 while (isdigit(*cpu_list)) { 117 while (isdigit(*cpu_list)) {
74 p = NULL; 118 p = NULL;
@@ -94,21 +138,42 @@ int read_cpu_map(const char *cpu_list)
94 for (; start_cpu <= end_cpu; start_cpu++) { 138 for (; start_cpu <= end_cpu; start_cpu++) {
95 /* check for duplicates */ 139 /* check for duplicates */
96 for (i = 0; i < nr_cpus; i++) 140 for (i = 0; i < nr_cpus; i++)
97 if (cpumap[i] == (int)start_cpu) 141 if (tmp_cpus[i] == (int)start_cpu)
98 goto invalid; 142 goto invalid;
99 143
100 assert(nr_cpus < MAX_NR_CPUS); 144 if (nr_cpus == max_entries) {
101 cpumap[nr_cpus++] = (int)start_cpu; 145 max_entries += MAX_NR_CPUS;
146 tmp = realloc(tmp_cpus, max_entries * sizeof(int));
147 if (tmp == NULL)
148 goto invalid;
149 tmp_cpus = tmp;
150 }
151 tmp_cpus[nr_cpus++] = (int)start_cpu;
102 } 152 }
103 if (*p) 153 if (*p)
104 ++p; 154 ++p;
105 155
106 cpu_list = p; 156 cpu_list = p;
107 } 157 }
108 if (nr_cpus > 0)
109 return nr_cpus;
110 158
111 return default_cpu_map(); 159 if (nr_cpus > 0)
160 cpus = cpu_map__trim_new(nr_cpus, tmp_cpus);
161 else
162 cpus = cpu_map__default_new();
112invalid: 163invalid:
113 return -1; 164 free(tmp_cpus);
165out:
166 return cpus;
167}
168
169struct cpu_map *cpu_map__dummy_new(void)
170{
171 struct cpu_map *cpus = malloc(sizeof(*cpus) + sizeof(int));
172
173 if (cpus != NULL) {
174 cpus->nr = 1;
175 cpus->map[0] = -1;
176 }
177
178 return cpus;
114} 179}
diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h
index 3e60f56e490..f7a4f42f630 100644
--- a/tools/perf/util/cpumap.h
+++ b/tools/perf/util/cpumap.h
@@ -1,7 +1,13 @@
1#ifndef __PERF_CPUMAP_H 1#ifndef __PERF_CPUMAP_H
2#define __PERF_CPUMAP_H 2#define __PERF_CPUMAP_H
3 3
4extern int read_cpu_map(const char *cpu_list); 4struct cpu_map {
5extern int cpumap[]; 5 int nr;
6 int map[];
7};
8
9struct cpu_map *cpu_map__new(const char *cpu_list);
10struct cpu_map *cpu_map__dummy_new(void);
11void *cpu_map__delete(struct cpu_map *map);
6 12
7#endif /* __PERF_CPUMAP_H */ 13#endif /* __PERF_CPUMAP_H */
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
new file mode 100644
index 00000000000..c95267e63c5
--- /dev/null
+++ b/tools/perf/util/evsel.c
@@ -0,0 +1,186 @@
1#include "evsel.h"
2#include "../perf.h"
3#include "util.h"
4#include "cpumap.h"
5#include "thread.h"
6
7#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
8
9struct perf_evsel *perf_evsel__new(u32 type, u64 config, int idx)
10{
11 struct perf_evsel *evsel = zalloc(sizeof(*evsel));
12
13 if (evsel != NULL) {
14 evsel->idx = idx;
15 evsel->attr.type = type;
16 evsel->attr.config = config;
17 INIT_LIST_HEAD(&evsel->node);
18 }
19
20 return evsel;
21}
22
23int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
24{
25 evsel->fd = xyarray__new(ncpus, nthreads, sizeof(int));
26 return evsel->fd != NULL ? 0 : -ENOMEM;
27}
28
29int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus)
30{
31 evsel->counts = zalloc((sizeof(*evsel->counts) +
32 (ncpus * sizeof(struct perf_counts_values))));
33 return evsel->counts != NULL ? 0 : -ENOMEM;
34}
35
36void perf_evsel__free_fd(struct perf_evsel *evsel)
37{
38 xyarray__delete(evsel->fd);
39 evsel->fd = NULL;
40}
41
42void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
43{
44 int cpu, thread;
45
46 for (cpu = 0; cpu < ncpus; cpu++)
47 for (thread = 0; thread < nthreads; ++thread) {
48 close(FD(evsel, cpu, thread));
49 FD(evsel, cpu, thread) = -1;
50 }
51}
52
53void perf_evsel__delete(struct perf_evsel *evsel)
54{
55 assert(list_empty(&evsel->node));
56 xyarray__delete(evsel->fd);
57 free(evsel);
58}
59
60int __perf_evsel__read_on_cpu(struct perf_evsel *evsel,
61 int cpu, int thread, bool scale)
62{
63 struct perf_counts_values count;
64 size_t nv = scale ? 3 : 1;
65
66 if (FD(evsel, cpu, thread) < 0)
67 return -EINVAL;
68
69 if (evsel->counts == NULL && perf_evsel__alloc_counts(evsel, cpu + 1) < 0)
70 return -ENOMEM;
71
72 if (readn(FD(evsel, cpu, thread), &count, nv * sizeof(u64)) < 0)
73 return -errno;
74
75 if (scale) {
76 if (count.run == 0)
77 count.val = 0;
78 else if (count.run < count.ena)
79 count.val = (u64)((double)count.val * count.ena / count.run + 0.5);
80 } else
81 count.ena = count.run = 0;
82
83 evsel->counts->cpu[cpu] = count;
84 return 0;
85}
86
87int __perf_evsel__read(struct perf_evsel *evsel,
88 int ncpus, int nthreads, bool scale)
89{
90 size_t nv = scale ? 3 : 1;
91 int cpu, thread;
92 struct perf_counts_values *aggr = &evsel->counts->aggr, count;
93
94 aggr->val = 0;
95
96 for (cpu = 0; cpu < ncpus; cpu++) {
97 for (thread = 0; thread < nthreads; thread++) {
98 if (FD(evsel, cpu, thread) < 0)
99 continue;
100
101 if (readn(FD(evsel, cpu, thread),
102 &count, nv * sizeof(u64)) < 0)
103 return -errno;
104
105 aggr->val += count.val;
106 if (scale) {
107 aggr->ena += count.ena;
108 aggr->run += count.run;
109 }
110 }
111 }
112
113 evsel->counts->scaled = 0;
114 if (scale) {
115 if (aggr->run == 0) {
116 evsel->counts->scaled = -1;
117 aggr->val = 0;
118 return 0;
119 }
120
121 if (aggr->run < aggr->ena) {
122 evsel->counts->scaled = 1;
123 aggr->val = (u64)((double)aggr->val * aggr->ena / aggr->run + 0.5);
124 }
125 } else
126 aggr->ena = aggr->run = 0;
127
128 return 0;
129}
130
131int perf_evsel__open_per_cpu(struct perf_evsel *evsel, struct cpu_map *cpus)
132{
133 int cpu;
134
135 if (evsel->fd == NULL && perf_evsel__alloc_fd(evsel, cpus->nr, 1) < 0)
136 return -1;
137
138 for (cpu = 0; cpu < cpus->nr; cpu++) {
139 FD(evsel, cpu, 0) = sys_perf_event_open(&evsel->attr, -1,
140 cpus->map[cpu], -1, 0);
141 if (FD(evsel, cpu, 0) < 0)
142 goto out_close;
143 }
144
145 return 0;
146
147out_close:
148 while (--cpu >= 0) {
149 close(FD(evsel, cpu, 0));
150 FD(evsel, cpu, 0) = -1;
151 }
152 return -1;
153}
154
155int perf_evsel__open_per_thread(struct perf_evsel *evsel, struct thread_map *threads)
156{
157 int thread;
158
159 if (evsel->fd == NULL && perf_evsel__alloc_fd(evsel, 1, threads->nr))
160 return -1;
161
162 for (thread = 0; thread < threads->nr; thread++) {
163 FD(evsel, 0, thread) = sys_perf_event_open(&evsel->attr,
164 threads->map[thread], -1, -1, 0);
165 if (FD(evsel, 0, thread) < 0)
166 goto out_close;
167 }
168
169 return 0;
170
171out_close:
172 while (--thread >= 0) {
173 close(FD(evsel, 0, thread));
174 FD(evsel, 0, thread) = -1;
175 }
176 return -1;
177}
178
179int perf_evsel__open(struct perf_evsel *evsel,
180 struct cpu_map *cpus, struct thread_map *threads)
181{
182 if (threads == NULL)
183 return perf_evsel__open_per_cpu(evsel, cpus);
184
185 return perf_evsel__open_per_thread(evsel, threads);
186}
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
new file mode 100644
index 00000000000..863d78d5ef1
--- /dev/null
+++ b/tools/perf/util/evsel.h
@@ -0,0 +1,115 @@
1#ifndef __PERF_EVSEL_H
2#define __PERF_EVSEL_H 1
3
4#include <linux/list.h>
5#include <stdbool.h>
6#include <linux/perf_event.h>
7#include "types.h"
8#include "xyarray.h"
9
10struct perf_counts_values {
11 union {
12 struct {
13 u64 val;
14 u64 ena;
15 u64 run;
16 };
17 u64 values[3];
18 };
19};
20
21struct perf_counts {
22 s8 scaled;
23 struct perf_counts_values aggr;
24 struct perf_counts_values cpu[];
25};
26
27struct perf_evsel {
28 struct list_head node;
29 struct perf_event_attr attr;
30 char *filter;
31 struct xyarray *fd;
32 struct perf_counts *counts;
33 int idx;
34 void *priv;
35};
36
37struct cpu_map;
38struct thread_map;
39
40struct perf_evsel *perf_evsel__new(u32 type, u64 config, int idx);
41void perf_evsel__delete(struct perf_evsel *evsel);
42
43int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
44int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus);
45void perf_evsel__free_fd(struct perf_evsel *evsel);
46void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
47
48int perf_evsel__open_per_cpu(struct perf_evsel *evsel, struct cpu_map *cpus);
49int perf_evsel__open_per_thread(struct perf_evsel *evsel, struct thread_map *threads);
50int perf_evsel__open(struct perf_evsel *evsel,
51 struct cpu_map *cpus, struct thread_map *threads);
52
53#define perf_evsel__match(evsel, t, c) \
54 (evsel->attr.type == PERF_TYPE_##t && \
55 evsel->attr.config == PERF_COUNT_##c)
56
57int __perf_evsel__read_on_cpu(struct perf_evsel *evsel,
58 int cpu, int thread, bool scale);
59
60/**
61 * perf_evsel__read_on_cpu - Read out the results on a CPU and thread
62 *
63 * @evsel - event selector to read value
64 * @cpu - CPU of interest
65 * @thread - thread of interest
66 */
67static inline int perf_evsel__read_on_cpu(struct perf_evsel *evsel,
68 int cpu, int thread)
69{
70 return __perf_evsel__read_on_cpu(evsel, cpu, thread, false);
71}
72
73/**
74 * perf_evsel__read_on_cpu_scaled - Read out the results on a CPU and thread, scaled
75 *
76 * @evsel - event selector to read value
77 * @cpu - CPU of interest
78 * @thread - thread of interest
79 */
80static inline int perf_evsel__read_on_cpu_scaled(struct perf_evsel *evsel,
81 int cpu, int thread)
82{
83 return __perf_evsel__read_on_cpu(evsel, cpu, thread, true);
84}
85
86int __perf_evsel__read(struct perf_evsel *evsel, int ncpus, int nthreads,
87 bool scale);
88
89/**
90 * perf_evsel__read - Read the aggregate results on all CPUs
91 *
92 * @evsel - event selector to read value
93 * @ncpus - Number of cpus affected, from zero
94 * @nthreads - Number of threads affected, from zero
95 */
96static inline int perf_evsel__read(struct perf_evsel *evsel,
97 int ncpus, int nthreads)
98{
99 return __perf_evsel__read(evsel, ncpus, nthreads, false);
100}
101
102/**
103 * perf_evsel__read_scaled - Read the aggregate results on all CPUs, scaled
104 *
105 * @evsel - event selector to read value
106 * @ncpus - Number of cpus affected, from zero
107 * @nthreads - Number of threads affected, from zero
108 */
109static inline int perf_evsel__read_scaled(struct perf_evsel *evsel,
110 int ncpus, int nthreads)
111{
112 return __perf_evsel__read(evsel, ncpus, nthreads, true);
113}
114
115#endif /* __PERF_EVSEL_H */
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 4b8c8397a94..989fa2dee2f 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -463,7 +463,7 @@ static int perf_header__adds_write(struct perf_header *self, int fd)
463 463
464 /* Write trace info */ 464 /* Write trace info */
465 trace_sec->offset = lseek(fd, 0, SEEK_CUR); 465 trace_sec->offset = lseek(fd, 0, SEEK_CUR);
466 read_tracing_data(fd, attrs, nr_counters); 466 read_tracing_data(fd, &evsel_list);
467 trace_sec->size = lseek(fd, 0, SEEK_CUR) - trace_sec->offset; 467 trace_sec->size = lseek(fd, 0, SEEK_CUR) - trace_sec->offset;
468 } 468 }
469 469
@@ -606,7 +606,7 @@ int perf_header__write(struct perf_header *self, int fd, bool at_exit)
606static int perf_header__getbuffer64(struct perf_header *self, 606static int perf_header__getbuffer64(struct perf_header *self,
607 int fd, void *buf, size_t size) 607 int fd, void *buf, size_t size)
608{ 608{
609 if (do_read(fd, buf, size) <= 0) 609 if (readn(fd, buf, size) <= 0)
610 return -1; 610 return -1;
611 611
612 if (self->needs_swap) 612 if (self->needs_swap)
@@ -662,7 +662,7 @@ int perf_file_header__read(struct perf_file_header *self,
662{ 662{
663 lseek(fd, 0, SEEK_SET); 663 lseek(fd, 0, SEEK_SET);
664 664
665 if (do_read(fd, self, sizeof(*self)) <= 0 || 665 if (readn(fd, self, sizeof(*self)) <= 0 ||
666 memcmp(&self->magic, __perf_magic, sizeof(self->magic))) 666 memcmp(&self->magic, __perf_magic, sizeof(self->magic)))
667 return -1; 667 return -1;
668 668
@@ -823,7 +823,7 @@ static int perf_file_header__read_pipe(struct perf_pipe_file_header *self,
823 struct perf_header *ph, int fd, 823 struct perf_header *ph, int fd,
824 bool repipe) 824 bool repipe)
825{ 825{
826 if (do_read(fd, self, sizeof(*self)) <= 0 || 826 if (readn(fd, self, sizeof(*self)) <= 0 ||
827 memcmp(&self->magic, __perf_magic, sizeof(self->magic))) 827 memcmp(&self->magic, __perf_magic, sizeof(self->magic)))
828 return -1; 828 return -1;
829 829
@@ -1133,8 +1133,7 @@ int event__process_event_type(event_t *self,
1133 return 0; 1133 return 0;
1134} 1134}
1135 1135
1136int event__synthesize_tracing_data(int fd, struct perf_event_attr *pattrs, 1136int event__synthesize_tracing_data(int fd, struct list_head *pattrs,
1137 int nb_events,
1138 event__handler_t process, 1137 event__handler_t process,
1139 struct perf_session *session __unused) 1138 struct perf_session *session __unused)
1140{ 1139{
@@ -1145,7 +1144,7 @@ int event__synthesize_tracing_data(int fd, struct perf_event_attr *pattrs,
1145 memset(&ev, 0, sizeof(ev)); 1144 memset(&ev, 0, sizeof(ev));
1146 1145
1147 ev.tracing_data.header.type = PERF_RECORD_HEADER_TRACING_DATA; 1146 ev.tracing_data.header.type = PERF_RECORD_HEADER_TRACING_DATA;
1148 size = read_tracing_data_size(fd, pattrs, nb_events); 1147 size = read_tracing_data_size(fd, pattrs);
1149 if (size <= 0) 1148 if (size <= 0)
1150 return size; 1149 return size;
1151 aligned_size = ALIGN(size, sizeof(u64)); 1150 aligned_size = ALIGN(size, sizeof(u64));
@@ -1155,7 +1154,7 @@ int event__synthesize_tracing_data(int fd, struct perf_event_attr *pattrs,
1155 1154
1156 process(&ev, NULL, session); 1155 process(&ev, NULL, session);
1157 1156
1158 err = read_tracing_data(fd, pattrs, nb_events); 1157 err = read_tracing_data(fd, pattrs);
1159 write_padded(fd, NULL, 0, padding); 1158 write_padded(fd, NULL, 0, padding);
1160 1159
1161 return aligned_size; 1160 return aligned_size;
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 6335965e1f9..33f16be7b72 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -113,8 +113,7 @@ int event__synthesize_event_types(event__handler_t process,
113int event__process_event_type(event_t *self, 113int event__process_event_type(event_t *self,
114 struct perf_session *session); 114 struct perf_session *session);
115 115
116int event__synthesize_tracing_data(int fd, struct perf_event_attr *pattrs, 116int event__synthesize_tracing_data(int fd, struct list_head *pattrs,
117 int nb_events,
118 event__handler_t process, 117 event__handler_t process,
119 struct perf_session *session); 118 struct perf_session *session);
120int event__process_tracing_data(event_t *self, 119int event__process_tracing_data(event_t *self,
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index c305305a388..3a142e90d60 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -1,6 +1,7 @@
1#include "../../../include/linux/hw_breakpoint.h" 1#include "../../../include/linux/hw_breakpoint.h"
2#include "util.h" 2#include "util.h"
3#include "../perf.h" 3#include "../perf.h"
4#include "evsel.h"
4#include "parse-options.h" 5#include "parse-options.h"
5#include "parse-events.h" 6#include "parse-events.h"
6#include "exec_cmd.h" 7#include "exec_cmd.h"
@@ -12,8 +13,7 @@
12 13
13int nr_counters; 14int nr_counters;
14 15
15struct perf_event_attr attrs[MAX_COUNTERS]; 16LIST_HEAD(evsel_list);
16char *filters[MAX_COUNTERS];
17 17
18struct event_symbol { 18struct event_symbol {
19 u8 type; 19 u8 type;
@@ -266,10 +266,10 @@ static char *event_cache_name(u8 cache_type, u8 cache_op, u8 cache_result)
266 return name; 266 return name;
267} 267}
268 268
269const char *event_name(int counter) 269const char *event_name(struct perf_evsel *evsel)
270{ 270{
271 u64 config = attrs[counter].config; 271 u64 config = evsel->attr.config;
272 int type = attrs[counter].type; 272 int type = evsel->attr.type;
273 273
274 return __event_name(type, config); 274 return __event_name(type, config);
275} 275}
@@ -814,9 +814,6 @@ int parse_events(const struct option *opt __used, const char *str, int unset __u
814 return -1; 814 return -1;
815 815
816 for (;;) { 816 for (;;) {
817 if (nr_counters == MAX_COUNTERS)
818 return -1;
819
820 memset(&attr, 0, sizeof(attr)); 817 memset(&attr, 0, sizeof(attr));
821 ret = parse_event_symbols(&str, &attr); 818 ret = parse_event_symbols(&str, &attr);
822 if (ret == EVT_FAILED) 819 if (ret == EVT_FAILED)
@@ -826,8 +823,13 @@ int parse_events(const struct option *opt __used, const char *str, int unset __u
826 return -1; 823 return -1;
827 824
828 if (ret != EVT_HANDLED_ALL) { 825 if (ret != EVT_HANDLED_ALL) {
829 attrs[nr_counters] = attr; 826 struct perf_evsel *evsel;
830 nr_counters++; 827 evsel = perf_evsel__new(attr.type, attr.config,
828 nr_counters);
829 if (evsel == NULL)
830 return -1;
831 list_add_tail(&evsel->node, &evsel_list);
832 ++nr_counters;
831 } 833 }
832 834
833 if (*str == 0) 835 if (*str == 0)
@@ -844,21 +846,22 @@ int parse_events(const struct option *opt __used, const char *str, int unset __u
844int parse_filter(const struct option *opt __used, const char *str, 846int parse_filter(const struct option *opt __used, const char *str,
845 int unset __used) 847 int unset __used)
846{ 848{
847 int i = nr_counters - 1; 849 struct perf_evsel *last = NULL;
848 int len = strlen(str);
849 850
850 if (i < 0 || attrs[i].type != PERF_TYPE_TRACEPOINT) { 851 if (!list_empty(&evsel_list))
852 last = list_entry(evsel_list.prev, struct perf_evsel, node);
853
854 if (last == NULL || last->attr.type != PERF_TYPE_TRACEPOINT) {
851 fprintf(stderr, 855 fprintf(stderr,
852 "-F option should follow a -e tracepoint option\n"); 856 "-F option should follow a -e tracepoint option\n");
853 return -1; 857 return -1;
854 } 858 }
855 859
856 filters[i] = malloc(len + 1); 860 last->filter = strdup(str);
857 if (!filters[i]) { 861 if (last->filter == NULL) {
858 fprintf(stderr, "not enough memory to hold filter string\n"); 862 fprintf(stderr, "not enough memory to hold filter string\n");
859 return -1; 863 return -1;
860 } 864 }
861 strcpy(filters[i], str);
862 865
863 return 0; 866 return 0;
864} 867}
@@ -967,3 +970,26 @@ void print_events(void)
967 970
968 exit(129); 971 exit(129);
969} 972}
973
974int perf_evsel_list__create_default(void)
975{
976 struct perf_evsel *evsel = perf_evsel__new(PERF_TYPE_HARDWARE,
977 PERF_COUNT_HW_CPU_CYCLES, 0);
978 if (evsel == NULL)
979 return -ENOMEM;
980
981 list_add(&evsel->node, &evsel_list);
982 ++nr_counters;
983 return 0;
984}
985
986void perf_evsel_list__delete(void)
987{
988 struct perf_evsel *pos, *n;
989
990 list_for_each_entry_safe(pos, n, &evsel_list, node) {
991 list_del_init(&pos->node);
992 perf_evsel__delete(pos);
993 }
994 nr_counters = 0;
995}
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index fc4ab3fe877..0a0abc1d10e 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -4,6 +4,16 @@
4 * Parse symbolic events/counts passed in as options: 4 * Parse symbolic events/counts passed in as options:
5 */ 5 */
6 6
7#include <linux/perf_event.h>
8
9struct list_head;
10struct perf_evsel;
11
12extern struct list_head evsel_list;
13
14int perf_evsel_list__create_default(void);
15void perf_evsel_list__delete(void);
16
7struct option; 17struct option;
8 18
9struct tracepoint_path { 19struct tracepoint_path {
@@ -13,14 +23,11 @@ struct tracepoint_path {
13}; 23};
14 24
15extern struct tracepoint_path *tracepoint_id_to_path(u64 config); 25extern struct tracepoint_path *tracepoint_id_to_path(u64 config);
16extern bool have_tracepoints(struct perf_event_attr *pattrs, int nb_events); 26extern bool have_tracepoints(struct list_head *evsel_list);
17 27
18extern int nr_counters; 28extern int nr_counters;
19 29
20extern struct perf_event_attr attrs[MAX_COUNTERS]; 30const char *event_name(struct perf_evsel *event);
21extern char *filters[MAX_COUNTERS];
22
23extern const char *event_name(int ctr);
24extern const char *__event_name(int type, u64 config); 31extern const char *__event_name(int type, u64 config);
25 32
26extern int parse_events(const struct option *opt, const char *str, int unset); 33extern int parse_events(const struct option *opt, const char *str, int unset);
@@ -33,5 +40,4 @@ extern void print_events(void);
33extern char debugfs_path[]; 40extern char debugfs_path[];
34extern int valid_debugfs_mount(const char *debugfs); 41extern int valid_debugfs_mount(const char *debugfs);
35 42
36
37#endif /* __PERF_PARSE_EVENTS_H */ 43#endif /* __PERF_PARSE_EVENTS_H */
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 0f7e544544f..b163dfd6cbc 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -838,23 +838,6 @@ static struct thread *perf_session__register_idle_thread(struct perf_session *se
838 return thread; 838 return thread;
839} 839}
840 840
841int do_read(int fd, void *buf, size_t size)
842{
843 void *buf_start = buf;
844
845 while (size) {
846 int ret = read(fd, buf, size);
847
848 if (ret <= 0)
849 return ret;
850
851 size -= ret;
852 buf += ret;
853 }
854
855 return buf - buf_start;
856}
857
858#define session_done() (*(volatile int *)(&session_done)) 841#define session_done() (*(volatile int *)(&session_done))
859volatile int session_done; 842volatile int session_done;
860 843
@@ -872,7 +855,7 @@ static int __perf_session__process_pipe_events(struct perf_session *self,
872 855
873 head = 0; 856 head = 0;
874more: 857more:
875 err = do_read(self->fd, &event, sizeof(struct perf_event_header)); 858 err = readn(self->fd, &event, sizeof(struct perf_event_header));
876 if (err <= 0) { 859 if (err <= 0) {
877 if (err == 0) 860 if (err == 0)
878 goto done; 861 goto done;
@@ -892,8 +875,7 @@ more:
892 p += sizeof(struct perf_event_header); 875 p += sizeof(struct perf_event_header);
893 876
894 if (size - sizeof(struct perf_event_header)) { 877 if (size - sizeof(struct perf_event_header)) {
895 err = do_read(self->fd, p, 878 err = readn(self->fd, p, size - sizeof(struct perf_event_header));
896 size - sizeof(struct perf_event_header));
897 if (err <= 0) { 879 if (err <= 0) {
898 if (err == 0) { 880 if (err == 0) {
899 pr_err("unexpected end of event stream\n"); 881 pr_err("unexpected end of event stream\n");
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index ffe4b98db8f..decd83f274f 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -109,7 +109,6 @@ void mem_bswap_64(void *src, int byte_size);
109 109
110int perf_session__create_kernel_maps(struct perf_session *self); 110int perf_session__create_kernel_maps(struct perf_session *self);
111 111
112int do_read(int fd, void *buf, size_t size);
113void perf_session__update_sample_type(struct perf_session *self); 112void perf_session__update_sample_type(struct perf_session *self);
114void perf_session__set_sample_id_all(struct perf_session *session, bool value); 113void perf_session__set_sample_id_all(struct perf_session *session, bool value);
115void perf_session__set_sample_type(struct perf_session *session, u64 type); 114void perf_session__set_sample_type(struct perf_session *session, u64 type);
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index 8c72d888e44..00f4eade2e3 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -16,35 +16,50 @@ static int filter(const struct dirent *dir)
16 return 1; 16 return 1;
17} 17}
18 18
19int find_all_tid(int pid, pid_t ** all_tid) 19struct thread_map *thread_map__new_by_pid(pid_t pid)
20{ 20{
21 struct thread_map *threads;
21 char name[256]; 22 char name[256];
22 int items; 23 int items;
23 struct dirent **namelist = NULL; 24 struct dirent **namelist = NULL;
24 int ret = 0;
25 int i; 25 int i;
26 26
27 sprintf(name, "/proc/%d/task", pid); 27 sprintf(name, "/proc/%d/task", pid);
28 items = scandir(name, &namelist, filter, NULL); 28 items = scandir(name, &namelist, filter, NULL);
29 if (items <= 0) 29 if (items <= 0)
30 return -ENOENT; 30 return NULL;
31 *all_tid = malloc(sizeof(pid_t) * items);
32 if (!*all_tid) {
33 ret = -ENOMEM;
34 goto failure;
35 }
36
37 for (i = 0; i < items; i++)
38 (*all_tid)[i] = atoi(namelist[i]->d_name);
39 31
40 ret = items; 32 threads = malloc(sizeof(*threads) + sizeof(pid_t) * items);
33 if (threads != NULL) {
34 for (i = 0; i < items; i++)
35 threads->map[i] = atoi(namelist[i]->d_name);
36 threads->nr = items;
37 }
41 38
42failure:
43 for (i=0; i<items; i++) 39 for (i=0; i<items; i++)
44 free(namelist[i]); 40 free(namelist[i]);
45 free(namelist); 41 free(namelist);
46 42
47 return ret; 43 return threads;
44}
45
46struct thread_map *thread_map__new_by_tid(pid_t tid)
47{
48 struct thread_map *threads = malloc(sizeof(*threads) + sizeof(pid_t));
49
50 if (threads != NULL) {
51 threads->map[0] = tid;
52 threads->nr = 1;
53 }
54
55 return threads;
56}
57
58struct thread_map *thread_map__new(pid_t pid, pid_t tid)
59{
60 if (pid != -1)
61 return thread_map__new_by_pid(pid);
62 return thread_map__new_by_tid(tid);
48} 63}
49 64
50static struct thread *thread__new(pid_t pid) 65static struct thread *thread__new(pid_t pid)
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index 688500ff826..d7574101054 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -18,11 +18,24 @@ struct thread {
18 int comm_len; 18 int comm_len;
19}; 19};
20 20
21struct thread_map {
22 int nr;
23 int map[];
24};
25
21struct perf_session; 26struct perf_session;
22 27
23void thread__delete(struct thread *self); 28void thread__delete(struct thread *self);
24 29
25int find_all_tid(int pid, pid_t ** all_tid); 30struct thread_map *thread_map__new_by_pid(pid_t pid);
31struct thread_map *thread_map__new_by_tid(pid_t tid);
32struct thread_map *thread_map__new(pid_t pid, pid_t tid);
33
34static inline void thread_map__delete(struct thread_map *threads)
35{
36 free(threads);
37}
38
26int thread__set_comm(struct thread *self, const char *comm); 39int thread__set_comm(struct thread *self, const char *comm);
27int thread__comm_len(struct thread *self); 40int thread__comm_len(struct thread *self);
28struct thread *perf_session__findnew(struct perf_session *self, pid_t pid); 41struct thread *perf_session__findnew(struct perf_session *self, pid_t pid);
diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c
index b1572601286..35729f4c40c 100644
--- a/tools/perf/util/trace-event-info.c
+++ b/tools/perf/util/trace-event-info.c
@@ -34,11 +34,13 @@
34#include <ctype.h> 34#include <ctype.h>
35#include <errno.h> 35#include <errno.h>
36#include <stdbool.h> 36#include <stdbool.h>
37#include <linux/list.h>
37#include <linux/kernel.h> 38#include <linux/kernel.h>
38 39
39#include "../perf.h" 40#include "../perf.h"
40#include "trace-event.h" 41#include "trace-event.h"
41#include "debugfs.h" 42#include "debugfs.h"
43#include "evsel.h"
42 44
43#define VERSION "0.5" 45#define VERSION "0.5"
44 46
@@ -469,16 +471,17 @@ out:
469} 471}
470 472
471static struct tracepoint_path * 473static struct tracepoint_path *
472get_tracepoints_path(struct perf_event_attr *pattrs, int nb_events) 474get_tracepoints_path(struct list_head *pattrs)
473{ 475{
474 struct tracepoint_path path, *ppath = &path; 476 struct tracepoint_path path, *ppath = &path;
475 int i, nr_tracepoints = 0; 477 struct perf_evsel *pos;
478 int nr_tracepoints = 0;
476 479
477 for (i = 0; i < nb_events; i++) { 480 list_for_each_entry(pos, pattrs, node) {
478 if (pattrs[i].type != PERF_TYPE_TRACEPOINT) 481 if (pos->attr.type != PERF_TYPE_TRACEPOINT)
479 continue; 482 continue;
480 ++nr_tracepoints; 483 ++nr_tracepoints;
481 ppath->next = tracepoint_id_to_path(pattrs[i].config); 484 ppath->next = tracepoint_id_to_path(pos->attr.config);
482 if (!ppath->next) 485 if (!ppath->next)
483 die("%s\n", "No memory to alloc tracepoints list"); 486 die("%s\n", "No memory to alloc tracepoints list");
484 ppath = ppath->next; 487 ppath = ppath->next;
@@ -487,21 +490,21 @@ get_tracepoints_path(struct perf_event_attr *pattrs, int nb_events)
487 return nr_tracepoints > 0 ? path.next : NULL; 490 return nr_tracepoints > 0 ? path.next : NULL;
488} 491}
489 492
490bool have_tracepoints(struct perf_event_attr *pattrs, int nb_events) 493bool have_tracepoints(struct list_head *pattrs)
491{ 494{
492 int i; 495 struct perf_evsel *pos;
493 496
494 for (i = 0; i < nb_events; i++) 497 list_for_each_entry(pos, pattrs, node)
495 if (pattrs[i].type == PERF_TYPE_TRACEPOINT) 498 if (pos->attr.type == PERF_TYPE_TRACEPOINT)
496 return true; 499 return true;
497 500
498 return false; 501 return false;
499} 502}
500 503
501int read_tracing_data(int fd, struct perf_event_attr *pattrs, int nb_events) 504int read_tracing_data(int fd, struct list_head *pattrs)
502{ 505{
503 char buf[BUFSIZ]; 506 char buf[BUFSIZ];
504 struct tracepoint_path *tps = get_tracepoints_path(pattrs, nb_events); 507 struct tracepoint_path *tps = get_tracepoints_path(pattrs);
505 508
506 /* 509 /*
507 * What? No tracepoints? No sense writing anything here, bail out. 510 * What? No tracepoints? No sense writing anything here, bail out.
@@ -545,14 +548,13 @@ int read_tracing_data(int fd, struct perf_event_attr *pattrs, int nb_events)
545 return 0; 548 return 0;
546} 549}
547 550
548ssize_t read_tracing_data_size(int fd, struct perf_event_attr *pattrs, 551ssize_t read_tracing_data_size(int fd, struct list_head *pattrs)
549 int nb_events)
550{ 552{
551 ssize_t size; 553 ssize_t size;
552 int err = 0; 554 int err = 0;
553 555
554 calc_data_size = 1; 556 calc_data_size = 1;
555 err = read_tracing_data(fd, pattrs, nb_events); 557 err = read_tracing_data(fd, pattrs);
556 size = calc_data_size - 1; 558 size = calc_data_size - 1;
557 calc_data_size = 0; 559 calc_data_size = 0;
558 560
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h
index b3e86b1e444..b5f12ca24d9 100644
--- a/tools/perf/util/trace-event.h
+++ b/tools/perf/util/trace-event.h
@@ -262,9 +262,8 @@ raw_field_value(struct event *event, const char *name, void *data);
262void *raw_field_ptr(struct event *event, const char *name, void *data); 262void *raw_field_ptr(struct event *event, const char *name, void *data);
263unsigned long long eval_flag(const char *flag); 263unsigned long long eval_flag(const char *flag);
264 264
265int read_tracing_data(int fd, struct perf_event_attr *pattrs, int nb_events); 265int read_tracing_data(int fd, struct list_head *pattrs);
266ssize_t read_tracing_data_size(int fd, struct perf_event_attr *pattrs, 266ssize_t read_tracing_data_size(int fd, struct list_head *pattrs);
267 int nb_events);
268 267
269/* taken from kernel/trace/trace.h */ 268/* taken from kernel/trace/trace.h */
270enum trace_flag_type { 269enum trace_flag_type {
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index 214265674dd..5b3ea49aa63 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -114,3 +114,20 @@ unsigned long convert_unit(unsigned long value, char *unit)
114 114
115 return value; 115 return value;
116} 116}
117
118int readn(int fd, void *buf, size_t n)
119{
120 void *buf_start = buf;
121
122 while (n) {
123 int ret = read(fd, buf, n);
124
125 if (ret <= 0)
126 return ret;
127
128 n -= ret;
129 buf += ret;
130 }
131
132 return buf - buf_start;
133}
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index 7562707ddd1..e833f26f3bf 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -265,6 +265,7 @@ void argv_free(char **argv);
265bool strglobmatch(const char *str, const char *pat); 265bool strglobmatch(const char *str, const char *pat);
266bool strlazymatch(const char *str, const char *pat); 266bool strlazymatch(const char *str, const char *pat);
267unsigned long convert_unit(unsigned long value, char *unit); 267unsigned long convert_unit(unsigned long value, char *unit);
268int readn(int fd, void *buf, size_t size);
268 269
269#define _STR(x) #x 270#define _STR(x) #x
270#define STR(x) _STR(x) 271#define STR(x) _STR(x)
diff --git a/tools/perf/util/xyarray.c b/tools/perf/util/xyarray.c
new file mode 100644
index 00000000000..22afbf6c536
--- /dev/null
+++ b/tools/perf/util/xyarray.c
@@ -0,0 +1,20 @@
1#include "xyarray.h"
2#include "util.h"
3
4struct xyarray *xyarray__new(int xlen, int ylen, size_t entry_size)
5{
6 size_t row_size = ylen * entry_size;
7 struct xyarray *xy = zalloc(sizeof(*xy) + xlen * row_size);
8
9 if (xy != NULL) {
10 xy->entry_size = entry_size;
11 xy->row_size = row_size;
12 }
13
14 return xy;
15}
16
17void xyarray__delete(struct xyarray *xy)
18{
19 free(xy);
20}
diff --git a/tools/perf/util/xyarray.h b/tools/perf/util/xyarray.h
new file mode 100644
index 00000000000..c488a07275d
--- /dev/null
+++ b/tools/perf/util/xyarray.h
@@ -0,0 +1,20 @@
1#ifndef _PERF_XYARRAY_H_
2#define _PERF_XYARRAY_H_ 1
3
4#include <sys/types.h>
5
6struct xyarray {
7 size_t row_size;
8 size_t entry_size;
9 char contents[];
10};
11
12struct xyarray *xyarray__new(int xlen, int ylen, size_t entry_size);
13void xyarray__delete(struct xyarray *xy);
14
15static inline void *xyarray__entry(struct xyarray *xy, int x, int y)
16{
17 return &xy->contents[x * xy->row_size + y * xy->entry_size];
18}
19
20#endif /* _PERF_XYARRAY_H_ */