perf session: Pass the perf_session to the event handling operations
[linux-3.10.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                               struct perf_session *session __used)
13 {
14         dump_printf(": unhandled!\n");
15         return 0;
16 }
17
18 void register_perf_file_handler(struct perf_file_handler *handler)
19 {
20         if (!handler->process_sample_event)
21                 handler->process_sample_event = process_event_stub;
22         if (!handler->process_mmap_event)
23                 handler->process_mmap_event = process_event_stub;
24         if (!handler->process_comm_event)
25                 handler->process_comm_event = process_event_stub;
26         if (!handler->process_fork_event)
27                 handler->process_fork_event = process_event_stub;
28         if (!handler->process_exit_event)
29                 handler->process_exit_event = process_event_stub;
30         if (!handler->process_lost_event)
31                 handler->process_lost_event = process_event_stub;
32         if (!handler->process_read_event)
33                 handler->process_read_event = process_event_stub;
34         if (!handler->process_throttle_event)
35                 handler->process_throttle_event = process_event_stub;
36         if (!handler->process_unthrottle_event)
37                 handler->process_unthrottle_event = process_event_stub;
38
39         curr_handler = handler;
40 }
41
42 static const char *event__name[] = {
43         [0]                      = "TOTAL",
44         [PERF_RECORD_MMAP]       = "MMAP",
45         [PERF_RECORD_LOST]       = "LOST",
46         [PERF_RECORD_COMM]       = "COMM",
47         [PERF_RECORD_EXIT]       = "EXIT",
48         [PERF_RECORD_THROTTLE]   = "THROTTLE",
49         [PERF_RECORD_UNTHROTTLE] = "UNTHROTTLE",
50         [PERF_RECORD_FORK]       = "FORK",
51         [PERF_RECORD_READ]       = "READ",
52         [PERF_RECORD_SAMPLE]     = "SAMPLE",
53 };
54
55 unsigned long event__total[PERF_RECORD_MAX];
56
57 void event__print_totals(void)
58 {
59         int i;
60         for (i = 0; i < PERF_RECORD_MAX; ++i)
61                 pr_info("%10s events: %10ld\n",
62                         event__name[i], event__total[i]);
63 }
64
65 static int process_event(event_t *event, struct perf_session *session,
66                          unsigned long offset, unsigned long head)
67 {
68         trace_event(event);
69
70         if (event->header.type < PERF_RECORD_MAX) {
71                 dump_printf("%p [%p]: PERF_RECORD_%s",
72                             (void *)(offset + head),
73                             (void *)(long)(event->header.size),
74                             event__name[event->header.type]);
75                 ++event__total[0];
76                 ++event__total[event->header.type];
77         }
78
79         switch (event->header.type) {
80         case PERF_RECORD_SAMPLE:
81                 return curr_handler->process_sample_event(event, session);
82         case PERF_RECORD_MMAP:
83                 return curr_handler->process_mmap_event(event, session);
84         case PERF_RECORD_COMM:
85                 return curr_handler->process_comm_event(event, session);
86         case PERF_RECORD_FORK:
87                 return curr_handler->process_fork_event(event, session);
88         case PERF_RECORD_EXIT:
89                 return curr_handler->process_exit_event(event, session);
90         case PERF_RECORD_LOST:
91                 return curr_handler->process_lost_event(event, session);
92         case PERF_RECORD_READ:
93                 return curr_handler->process_read_event(event, session);
94         case PERF_RECORD_THROTTLE:
95                 return curr_handler->process_throttle_event(event, session);
96         case PERF_RECORD_UNTHROTTLE:
97                 return curr_handler->process_unthrottle_event(event, session);
98         default:
99                 curr_handler->total_unknown++;
100                 return -1;
101         }
102 }
103
104 int perf_header__read_build_ids(int input, u64 offset, u64 size)
105 {
106         struct build_id_event bev;
107         char filename[PATH_MAX];
108         u64 limit = offset + size;
109         int err = -1;
110
111         while (offset < limit) {
112                 struct dso *dso;
113                 ssize_t len;
114
115                 if (read(input, &bev, sizeof(bev)) != sizeof(bev))
116                         goto out;
117
118                 len = bev.header.size - sizeof(bev);
119                 if (read(input, filename, len) != len)
120                         goto out;
121
122                 dso = dsos__findnew(filename);
123                 if (dso != NULL)
124                         dso__set_build_id(dso, &bev.build_id);
125
126                 offset += bev.header.size;
127         }
128         err = 0;
129 out:
130         return err;
131 }
132
133 int perf_session__process_events(struct perf_session *self,
134                                  int full_paths, int *cwdlen, char **cwd)
135 {
136         int err;
137         unsigned long head, shift;
138         unsigned long offset = 0;
139         size_t  page_size;
140         u64 sample_type;
141         event_t *event;
142         uint32_t size;
143         char *buf;
144
145         if (curr_handler == NULL) {
146                 pr_debug("Forgot to register perf file handler\n");
147                 return -EINVAL;
148         }
149
150         page_size = getpagesize();
151
152         head = self->header.data_offset;
153         sample_type = perf_header__sample_type(&self->header);
154
155         err = -EINVAL;
156         if (curr_handler->sample_type_check &&
157             curr_handler->sample_type_check(sample_type) < 0)
158                 goto out_err;
159
160         if (!full_paths) {
161                 if (getcwd(__cwd, sizeof(__cwd)) == NULL) {
162                         pr_err("failed to get the current directory\n");
163                         err = -errno;
164                         goto out_err;
165                 }
166                 *cwd = __cwd;
167                 *cwdlen = strlen(*cwd);
168         } else {
169                 *cwd = NULL;
170                 *cwdlen = 0;
171         }
172
173         shift = page_size * (head / page_size);
174         offset += shift;
175         head -= shift;
176
177 remap:
178         buf = mmap(NULL, page_size * mmap_window, PROT_READ,
179                    MAP_SHARED, self->fd, offset);
180         if (buf == MAP_FAILED) {
181                 pr_err("failed to mmap file\n");
182                 err = -errno;
183                 goto out_err;
184         }
185
186 more:
187         event = (event_t *)(buf + head);
188
189         size = event->header.size;
190         if (!size)
191                 size = 8;
192
193         if (head + event->header.size >= page_size * mmap_window) {
194                 int munmap_ret;
195
196                 shift = page_size * (head / page_size);
197
198                 munmap_ret = munmap(buf, page_size * mmap_window);
199                 assert(munmap_ret == 0);
200
201                 offset += shift;
202                 head -= shift;
203                 goto remap;
204         }
205
206         size = event->header.size;
207
208         dump_printf("\n%p [%p]: event: %d\n",
209                         (void *)(offset + head),
210                         (void *)(long)event->header.size,
211                         event->header.type);
212
213         if (!size || process_event(event, self, offset, head) < 0) {
214
215                 dump_printf("%p [%p]: skipping unknown header type: %d\n",
216                         (void *)(offset + head),
217                         (void *)(long)(event->header.size),
218                         event->header.type);
219
220                 /*
221                  * assume we lost track of the stream, check alignment, and
222                  * increment a single u64 in the hope to catch on again 'soon'.
223                  */
224
225                 if (unlikely(head & 7))
226                         head &= ~7ULL;
227
228                 size = 8;
229         }
230
231         head += size;
232
233         if (offset + head >= self->header.data_offset + self->header.data_size)
234                 goto done;
235
236         if (offset + head < self->size)
237                 goto more;
238
239 done:
240         err = 0;
241 out_err:
242         return err;
243 }