blob: aacb814a4eff88b18d84232f135688b1ed9392bb [file] [log] [blame]
Frederic Weisbecker016e92f2009-10-07 12:47:31 +02001#include "data_map.h"
2#include "symbol.h"
3#include "util.h"
4#include "debug.h"
5
6
7static struct perf_file_handler *curr_handler;
8static unsigned long mmap_window = 32;
9static char __cwd[PATH_MAX];
10
11static int
12process_event_stub(event_t *event __used,
13 unsigned long offset __used,
14 unsigned long head __used)
15{
16 return 0;
17}
18
19void register_perf_file_handler(struct perf_file_handler *handler)
20{
21 if (!handler->process_sample_event)
22 handler->process_sample_event = process_event_stub;
23 if (!handler->process_mmap_event)
24 handler->process_mmap_event = process_event_stub;
25 if (!handler->process_comm_event)
26 handler->process_comm_event = process_event_stub;
27 if (!handler->process_fork_event)
28 handler->process_fork_event = process_event_stub;
29 if (!handler->process_exit_event)
30 handler->process_exit_event = process_event_stub;
31 if (!handler->process_lost_event)
32 handler->process_lost_event = process_event_stub;
33 if (!handler->process_read_event)
34 handler->process_read_event = process_event_stub;
35 if (!handler->process_throttle_event)
36 handler->process_throttle_event = process_event_stub;
37 if (!handler->process_unthrottle_event)
38 handler->process_unthrottle_event = process_event_stub;
39
40 curr_handler = handler;
41}
42
43static int
44process_event(event_t *event, unsigned long offset, unsigned long head)
45{
46 trace_event(event);
47
48 switch (event->header.type) {
49 case PERF_RECORD_SAMPLE:
50 return curr_handler->process_sample_event(event, offset, head);
51 case PERF_RECORD_MMAP:
52 return curr_handler->process_mmap_event(event, offset, head);
53 case PERF_RECORD_COMM:
54 return curr_handler->process_comm_event(event, offset, head);
55 case PERF_RECORD_FORK:
56 return curr_handler->process_fork_event(event, offset, head);
57 case PERF_RECORD_EXIT:
58 return curr_handler->process_exit_event(event, offset, head);
59 case PERF_RECORD_LOST:
60 return curr_handler->process_lost_event(event, offset, head);
61 case PERF_RECORD_READ:
62 return curr_handler->process_read_event(event, offset, head);
63 case PERF_RECORD_THROTTLE:
64 return curr_handler->process_throttle_event(event, offset, head);
65 case PERF_RECORD_UNTHROTTLE:
66 return curr_handler->process_unthrottle_event(event, offset, head);
67 default:
68 curr_handler->total_unknown++;
69 return -1;
70 }
71}
72
Frederic Weisbecker9e827dd2009-11-11 04:51:07 +010073int perf_header__read_build_ids(int input, off_t size)
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -020074{
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -020075 struct build_id_event bev;
76 char filename[PATH_MAX];
Frederic Weisbecker9e827dd2009-11-11 04:51:07 +010077 off_t offset = lseek(input, 0, SEEK_CUR);
78 off_t limit = offset + size;
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -020079 int err = -1;
80
Frederic Weisbecker9e827dd2009-11-11 04:51:07 +010081 while (offset < limit) {
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -020082 struct dso *dso;
83 ssize_t len;
84
85 if (read(input, &bev, sizeof(bev)) != sizeof(bev))
86 goto out;
87
88 len = bev.header.size - sizeof(bev);
89 if (read(input, filename, len) != len)
90 goto out;
91
92 dso = dsos__findnew(filename);
93 if (dso != NULL)
94 dso__set_build_id(dso, &bev.build_id);
95
96 offset += bev.header.size;
97 }
98 err = 0;
99out:
100 return err;
101}
102
Frederic Weisbecker016e92f2009-10-07 12:47:31 +0200103int mmap_dispatch_perf_file(struct perf_header **pheader,
104 const char *input_name,
105 int force,
106 int full_paths,
107 int *cwdlen,
108 char **cwd)
109{
110 int ret, rc = EXIT_FAILURE;
111 struct perf_header *header;
112 unsigned long head, shift;
113 unsigned long offset = 0;
114 struct stat input_stat;
115 size_t page_size;
116 u64 sample_type;
117 event_t *event;
118 uint32_t size;
119 int input;
120 char *buf;
121
122 if (!curr_handler)
123 die("Forgot to register perf file handler");
124
125 page_size = getpagesize();
126
127 input = open(input_name, O_RDONLY);
128 if (input < 0) {
129 fprintf(stderr, " failed to open file: %s", input_name);
130 if (!strcmp(input_name, "perf.data"))
131 fprintf(stderr, " (try 'perf record' first)");
132 fprintf(stderr, "\n");
133 exit(-1);
134 }
135
136 ret = fstat(input, &input_stat);
137 if (ret < 0) {
138 perror("failed to stat file");
139 exit(-1);
140 }
141
142 if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
143 fprintf(stderr, "file: %s not owned by current user or root\n",
144 input_name);
145 exit(-1);
146 }
147
148 if (!input_stat.st_size) {
149 fprintf(stderr, "zero-sized file, nothing to do!\n");
150 exit(0);
151 }
152
153 *pheader = perf_header__read(input);
154 header = *pheader;
155 head = header->data_offset;
156
157 sample_type = perf_header__sample_type(header);
158
159 if (curr_handler->sample_type_check)
160 if (curr_handler->sample_type_check(sample_type) < 0)
161 exit(-1);
162
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200163 if (load_kernel(NULL) < 0) {
Frederic Weisbecker016e92f2009-10-07 12:47:31 +0200164 perror("failed to load kernel symbols");
165 return EXIT_FAILURE;
166 }
167
168 if (!full_paths) {
169 if (getcwd(__cwd, sizeof(__cwd)) == NULL) {
170 perror("failed to get the current directory");
171 return EXIT_FAILURE;
172 }
173 *cwd = __cwd;
174 *cwdlen = strlen(*cwd);
175 } else {
176 *cwd = NULL;
177 *cwdlen = 0;
178 }
179
180 shift = page_size * (head / page_size);
181 offset += shift;
182 head -= shift;
183
184remap:
185 buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
186 MAP_SHARED, input, offset);
187 if (buf == MAP_FAILED) {
188 perror("failed to mmap file");
189 exit(-1);
190 }
191
192more:
193 event = (event_t *)(buf + head);
194
195 size = event->header.size;
196 if (!size)
197 size = 8;
198
199 if (head + event->header.size >= page_size * mmap_window) {
200 int munmap_ret;
201
202 shift = page_size * (head / page_size);
203
204 munmap_ret = munmap(buf, page_size * mmap_window);
205 assert(munmap_ret == 0);
206
207 offset += shift;
208 head -= shift;
209 goto remap;
210 }
211
212 size = event->header.size;
213
214 dump_printf("\n%p [%p]: event: %d\n",
215 (void *)(offset + head),
216 (void *)(long)event->header.size,
217 event->header.type);
218
219 if (!size || process_event(event, offset, head) < 0) {
220
221 dump_printf("%p [%p]: skipping unknown header type: %d\n",
222 (void *)(offset + head),
223 (void *)(long)(event->header.size),
224 event->header.type);
225
226 /*
227 * assume we lost track of the stream, check alignment, and
228 * increment a single u64 in the hope to catch on again 'soon'.
229 */
230
231 if (unlikely(head & 7))
232 head &= ~7ULL;
233
234 size = 8;
235 }
236
237 head += size;
238
239 if (offset + head >= header->data_offset + header->data_size)
240 goto done;
241
242 if (offset + head < (unsigned long)input_stat.st_size)
243 goto more;
244
245done:
246 rc = EXIT_SUCCESS;
247 close(input);
248
249 return rc;
250}
251
252