perf tools: Reorganize event processing routines, lotsa dups killed
[linux-2.6.git] / tools / perf / util / data_map.c
1 #include "data_map.h"
2 #include "symbol.h"
3 #include "util.h"
4 #include "debug.h"
5
6
7 static struct perf_file_handler *curr_handler;
8 static unsigned long    mmap_window = 32;
9 static char             __cwd[PATH_MAX];
10
11 static int process_event_stub(event_t *event __used)
12 {
13         dump_printf(": unhandled!\n");
14         return 0;
15 }
16
17 void register_perf_file_handler(struct perf_file_handler *handler)
18 {
19         if (!handler->process_sample_event)
20                 handler->process_sample_event = process_event_stub;
21         if (!handler->process_mmap_event)
22                 handler->process_mmap_event = process_event_stub;
23         if (!handler->process_comm_event)
24                 handler->process_comm_event = process_event_stub;
25         if (!handler->process_fork_event)
26                 handler->process_fork_event = process_event_stub;
27         if (!handler->process_exit_event)
28                 handler->process_exit_event = process_event_stub;
29         if (!handler->process_lost_event)
30                 handler->process_lost_event = process_event_stub;
31         if (!handler->process_read_event)
32                 handler->process_read_event = process_event_stub;
33         if (!handler->process_throttle_event)
34                 handler->process_throttle_event = process_event_stub;
35         if (!handler->process_unthrottle_event)
36                 handler->process_unthrottle_event = process_event_stub;
37
38         curr_handler = handler;
39 }
40
41 static const char *event__name[] = {
42         [0]                      = "TOTAL",
43         [PERF_RECORD_MMAP]       = "MMAP",
44         [PERF_RECORD_LOST]       = "LOST",
45         [PERF_RECORD_COMM]       = "COMM",
46         [PERF_RECORD_EXIT]       = "EXIT",
47         [PERF_RECORD_THROTTLE]   = "THROTTLE",
48         [PERF_RECORD_UNTHROTTLE] = "UNTHROTTLE",
49         [PERF_RECORD_FORK]       = "FORK",
50         [PERF_RECORD_READ]       = "READ",
51         [PERF_RECORD_SAMPLE]     = "SAMPLE",
52 };
53
54 unsigned long event__total[PERF_RECORD_MAX];
55
56 void event__print_totals(void)
57 {
58         int i;
59         for (i = 0; i < PERF_RECORD_MAX; ++i)
60                 pr_info("%10s events: %10ld\n",
61                         event__name[i], event__total[i]);
62 }
63
64 static int
65 process_event(event_t *event, unsigned long offset, unsigned long head)
66 {
67         trace_event(event);
68
69         if (event->header.type < PERF_RECORD_MAX) {
70                 dump_printf("%p [%p]: PERF_RECORD_%s",
71                             (void *)(offset + head),
72                             (void *)(long)(event->header.size),
73                             event__name[event->header.type]);
74                 ++event__total[0];
75                 ++event__total[event->header.type];
76         }
77
78         switch (event->header.type) {
79         case PERF_RECORD_SAMPLE:
80                 return curr_handler->process_sample_event(event);
81         case PERF_RECORD_MMAP:
82                 return curr_handler->process_mmap_event(event);
83         case PERF_RECORD_COMM:
84                 return curr_handler->process_comm_event(event);
85         case PERF_RECORD_FORK:
86                 return curr_handler->process_fork_event(event);
87         case PERF_RECORD_EXIT:
88                 return curr_handler->process_exit_event(event);
89         case PERF_RECORD_LOST:
90                 return curr_handler->process_lost_event(event);
91         case PERF_RECORD_READ:
92                 return curr_handler->process_read_event(event);
93         case PERF_RECORD_THROTTLE:
94                 return curr_handler->process_throttle_event(event);
95         case PERF_RECORD_UNTHROTTLE:
96                 return curr_handler->process_unthrottle_event(event);
97         default:
98                 curr_handler->total_unknown++;
99                 return -1;
100         }
101 }
102
103 int perf_header__read_build_ids(int input, off_t offset, off_t size)
104 {
105         struct build_id_event bev;
106         char filename[PATH_MAX];
107         off_t limit = offset + size;
108         int err = -1;
109
110         while (offset < limit) {
111                 struct dso *dso;
112                 ssize_t len;
113
114                 if (read(input, &bev, sizeof(bev)) != sizeof(bev))
115                         goto out;
116
117                 len = bev.header.size - sizeof(bev);
118                 if (read(input, filename, len) != len)
119                         goto out;
120
121                 dso = dsos__findnew(filename);
122                 if (dso != NULL)
123                         dso__set_build_id(dso, &bev.build_id);
124
125                 offset += bev.header.size;
126         }
127         err = 0;
128 out:
129         return err;
130 }
131
132 int mmap_dispatch_perf_file(struct perf_header **pheader,
133                             const char *input_name,
134                             int force,
135                             int full_paths,
136                             int *cwdlen,
137                             char **cwd)
138 {
139         int err;
140         struct perf_header *header;
141         unsigned long head, shift;
142         unsigned long offset = 0;
143         struct stat input_stat;
144         size_t  page_size;
145         u64 sample_type;
146         event_t *event;
147         uint32_t size;
148         int input;
149         char *buf;
150
151         if (curr_handler == NULL) {
152                 pr_debug("Forgot to register perf file handler\n");
153                 return -EINVAL;
154         }
155
156         page_size = getpagesize();
157
158         input = open(input_name, O_RDONLY);
159         if (input < 0) {
160                 pr_err("Failed to open file: %s", input_name);
161                 if (!strcmp(input_name, "perf.data"))
162                         pr_err("  (try 'perf record' first)");
163                 pr_err("\n");
164                 return -errno;
165         }
166
167         if (fstat(input, &input_stat) < 0) {
168                 pr_err("failed to stat file");
169                 err = -errno;
170                 goto out_close;
171         }
172
173         err = -EACCES;
174         if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
175                 pr_err("file: %s not owned by current user or root\n",
176                         input_name);
177                 goto out_close;
178         }
179
180         if (input_stat.st_size == 0) {
181                 pr_info("zero-sized file, nothing to do!\n");
182                 goto done;
183         }
184
185         err = -ENOMEM;
186         header = perf_header__new();
187         if (header == NULL)
188                 goto out_close;
189
190         err = perf_header__read(header, input);
191         if (err < 0)
192                 goto out_delete;
193         *pheader = header;
194         head = header->data_offset;
195
196         sample_type = perf_header__sample_type(header);
197
198         err = -EINVAL;
199         if (curr_handler->sample_type_check &&
200             curr_handler->sample_type_check(sample_type) < 0)
201                 goto out_delete;
202
203         if (!full_paths) {
204                 if (getcwd(__cwd, sizeof(__cwd)) == NULL) {
205                         pr_err("failed to get the current directory\n");
206                         err = -errno;
207                         goto out_delete;
208                 }
209                 *cwd = __cwd;
210                 *cwdlen = strlen(*cwd);
211         } else {
212                 *cwd = NULL;
213                 *cwdlen = 0;
214         }
215
216         shift = page_size * (head / page_size);
217         offset += shift;
218         head -= shift;
219
220 remap:
221         buf = mmap(NULL, page_size * mmap_window, PROT_READ,
222                    MAP_SHARED, input, offset);
223         if (buf == MAP_FAILED) {
224                 pr_err("failed to mmap file\n");
225                 err = -errno;
226                 goto out_delete;
227         }
228
229 more:
230         event = (event_t *)(buf + head);
231
232         size = event->header.size;
233         if (!size)
234                 size = 8;
235
236         if (head + event->header.size >= page_size * mmap_window) {
237                 int munmap_ret;
238
239                 shift = page_size * (head / page_size);
240
241                 munmap_ret = munmap(buf, page_size * mmap_window);
242                 assert(munmap_ret == 0);
243
244                 offset += shift;
245                 head -= shift;
246                 goto remap;
247         }
248
249         size = event->header.size;
250
251         dump_printf("\n%p [%p]: event: %d\n",
252                         (void *)(offset + head),
253                         (void *)(long)event->header.size,
254                         event->header.type);
255
256         if (!size || process_event(event, offset, head) < 0) {
257
258                 dump_printf("%p [%p]: skipping unknown header type: %d\n",
259                         (void *)(offset + head),
260                         (void *)(long)(event->header.size),
261                         event->header.type);
262
263                 /*
264                  * assume we lost track of the stream, check alignment, and
265                  * increment a single u64 in the hope to catch on again 'soon'.
266                  */
267
268                 if (unlikely(head & 7))
269                         head &= ~7ULL;
270
271                 size = 8;
272         }
273
274         head += size;
275
276         if (offset + head >= header->data_offset + header->data_size)
277                 goto done;
278
279         if (offset + head < (unsigned long)input_stat.st_size)
280                 goto more;
281
282 done:
283         err = 0;
284 out_close:
285         close(input);
286
287         return err;
288 out_delete:
289         perf_header__delete(header);
290         goto out_close;
291 }