Commit | Line | Data |
---|---|---|
b1acd2b3 JD |
1 | #ifdef LTTNGTOP_MMAP_LIVE |
2 | ||
3 | static | |
4 | ssize_t read_subbuffer(struct lttng_consumer_stream *kconsumerd_fd, | |
5 | struct lttng_consumer_local_data *ctx) | |
6 | { | |
7 | unsigned long len; | |
8 | int err; | |
9 | long ret = 0; | |
10 | int infd = helper_get_lttng_consumer_stream_wait_fd(kconsumerd_fd); | |
11 | ||
12 | if (helper_get_lttng_consumer_stream_output(kconsumerd_fd) == LTTNG_EVENT_SPLICE) { | |
13 | /* Get the next subbuffer */ | |
14 | err = helper_kernctl_get_next_subbuf(infd); | |
15 | if (err != 0) { | |
16 | ret = errno; | |
17 | perror("Reserving sub buffer failed (everything is normal, " | |
18 | "it is due to concurrency)"); | |
19 | goto end; | |
20 | } | |
21 | /* read the whole subbuffer */ | |
22 | err = helper_kernctl_get_padded_subbuf_size(infd, &len); | |
23 | if (err != 0) { | |
24 | ret = errno; | |
25 | perror("Getting sub-buffer len failed."); | |
26 | goto end; | |
27 | } | |
28 | ||
29 | /* splice the subbuffer to the tracefile */ | |
30 | ret = helper_lttng_consumer_on_read_subbuffer_splice(ctx, kconsumerd_fd, len, 0); | |
31 | if (ret < 0) { | |
32 | /* | |
33 | * display the error but continue processing to try | |
34 | * to release the subbuffer | |
35 | */ | |
36 | fprintf(stderr,"Error splicing to tracefile\n"); | |
37 | } | |
38 | err = helper_kernctl_put_next_subbuf(infd); | |
39 | if (err != 0) { | |
40 | ret = errno; | |
41 | perror("Reserving sub buffer failed (everything is normal, " | |
42 | "it is due to concurrency)"); | |
43 | goto end; | |
44 | } | |
45 | sem_post(&metadata_available); | |
46 | } | |
47 | ||
48 | end: | |
49 | return 0; | |
50 | } | |
51 | ||
52 | static | |
53 | int on_update_fd(int key, uint32_t state) | |
54 | { | |
55 | /* let the lib handle the metadata FD */ | |
56 | if (key == sessiond_metadata) | |
57 | return 0; | |
58 | return 1; | |
59 | } | |
60 | ||
61 | static | |
62 | int on_recv_fd(struct lttng_consumer_stream *kconsumerd_fd) | |
63 | { | |
64 | int ret; | |
65 | struct bt_mmap_stream *new_mmap_stream; | |
66 | ||
67 | /* Opening the tracefile in write mode */ | |
68 | if (helper_get_lttng_consumer_stream_path_name(kconsumerd_fd) != NULL) { | |
69 | ret = open(helper_get_lttng_consumer_stream_path_name(kconsumerd_fd), | |
70 | O_WRONLY|O_CREAT|O_TRUNC, S_IRWXU|S_IRWXG|S_IRWXO); | |
71 | if (ret < 0) { | |
72 | perror("open"); | |
73 | goto end; | |
74 | } | |
75 | helper_set_lttng_consumer_stream_out_fd(kconsumerd_fd, ret); | |
76 | } | |
77 | ||
78 | if (helper_get_lttng_consumer_stream_output(kconsumerd_fd) == LTTNG_EVENT_MMAP) { | |
79 | new_mmap_stream = malloc(sizeof(struct bt_mmap_stream)); | |
80 | new_mmap_stream->fd = helper_get_lttng_consumer_stream_wait_fd( | |
81 | kconsumerd_fd); | |
82 | bt_list_add(&new_mmap_stream->list, &mmap_list.head); | |
83 | ||
84 | g_ptr_array_add(lttng_consumer_stream_array, kconsumerd_fd); | |
85 | /* keep mmap FDs internally */ | |
86 | ret = 1; | |
87 | } else { | |
88 | consumerd_metadata = helper_get_lttng_consumer_stream_wait_fd(kconsumerd_fd); | |
89 | sessiond_metadata = helper_get_lttng_consumer_stream_key(kconsumerd_fd); | |
90 | ret = 0; | |
91 | } | |
92 | ||
93 | reload_trace = 1; | |
94 | ||
95 | end: | |
96 | return ret; | |
97 | } | |
98 | ||
99 | static | |
100 | void live_consume(struct bt_context **bt_ctx) | |
101 | { | |
102 | int ret; | |
103 | FILE *metadata_fp; | |
104 | ||
105 | sem_wait(&metadata_available); | |
106 | if (access("/tmp/livesession/kernel/metadata", F_OK) != 0) { | |
107 | fprintf(stderr,"no metadata\n"); | |
108 | goto end; | |
109 | } | |
110 | metadata_fp = fopen("/tmp/livesession/kernel/metadata", "r"); | |
111 | ||
112 | *bt_ctx = bt_context_create(); | |
113 | ret = bt_context_add_trace(*bt_ctx, NULL, "ctf", | |
114 | lttngtop_ctf_packet_seek, &mmap_list, metadata_fp); | |
115 | if (ret < 0) { | |
116 | printf("Error adding trace\n"); | |
117 | goto end; | |
118 | } | |
119 | ||
120 | end: | |
121 | return; | |
122 | } | |
123 | ||
124 | static | |
125 | int setup_consumer(char *command_sock_path, pthread_t *threads, | |
126 | struct lttng_consumer_local_data *ctx) | |
127 | { | |
128 | int ret = 0; | |
129 | ||
130 | ctx = helper_lttng_consumer_create(HELPER_LTTNG_CONSUMER_KERNEL, | |
131 | read_subbuffer, NULL, on_recv_fd, on_update_fd); | |
132 | if (!ctx) | |
133 | goto end; | |
134 | ||
135 | unlink(command_sock_path); | |
136 | helper_lttng_consumer_set_command_sock_path(ctx, command_sock_path); | |
137 | helper_lttng_consumer_init(); | |
138 | ||
139 | /* Create the thread to manage the receive of fd */ | |
140 | ret = pthread_create(&threads[0], NULL, helper_lttng_consumer_thread_sessiond_poll, | |
141 | (void *) ctx); | |
142 | if (ret != 0) { | |
143 | perror("pthread_create receive fd"); | |
144 | goto end; | |
145 | } | |
146 | /* Create thread to manage the polling/writing of traces */ | |
147 | ret = pthread_create(&threads[1], NULL, helper_lttng_consumer_thread_metadata_poll, | |
148 | (void *) ctx); | |
149 | if (ret != 0) { | |
150 | perror("pthread_create poll fd"); | |
151 | goto end; | |
152 | } | |
153 | ||
154 | end: | |
155 | return ret; | |
156 | } | |
157 | ||
158 | static | |
159 | int enable_kprobes(struct lttng_handle *handle, char *channel_name) | |
160 | { | |
161 | struct lttng_event ev; | |
162 | struct kprobes *kprobe; | |
163 | int ret = 0; | |
164 | int i; | |
165 | ||
166 | for (i = 0; i < lttngtop.kprobes_table->len; i++) { | |
167 | kprobe = g_ptr_array_index(lttngtop.kprobes_table, i); | |
168 | ||
169 | memset(&ev, '\0', sizeof(struct lttng_event)); | |
170 | ev.type = LTTNG_EVENT_PROBE; | |
171 | if (kprobe->symbol_name) | |
172 | sprintf(ev.attr.probe.symbol_name, "%s", kprobe->symbol_name); | |
173 | sprintf(ev.name, "%s", kprobe->probe_name); | |
174 | ev.attr.probe.addr = kprobe->probe_addr; | |
175 | ev.attr.probe.offset = kprobe->probe_offset; | |
176 | if ((ret = lttng_enable_event(handle, &ev, channel_name)) < 0) { | |
177 | fprintf(stderr,"error enabling kprobes : %s\n", | |
178 | helper_lttcomm_get_readable_code(ret)); | |
179 | goto end; | |
180 | } | |
181 | } | |
182 | ||
183 | end: | |
184 | return ret; | |
185 | } | |
186 | ||
187 | static | |
188 | int setup_live_tracing() | |
189 | { | |
190 | struct lttng_domain dom; | |
191 | struct lttng_channel chan; | |
192 | char *channel_name = "mmapchan"; | |
193 | struct lttng_event ev; | |
194 | int ret = 0; | |
195 | char *command_sock_path = "/tmp/consumerd_sock"; | |
196 | static pthread_t threads[2]; /* recv_fd, poll */ | |
197 | struct lttng_event_context kctxpid, kctxcomm, kctxppid, kctxtid, | |
198 | kctxperf1, kctxperf2; | |
199 | ||
200 | struct lttng_handle *handle; | |
201 | ||
202 | BT_INIT_LIST_HEAD(&mmap_list.head); | |
203 | ||
204 | lttng_consumer_stream_array = g_ptr_array_new(); | |
205 | ||
206 | if ((ret = setup_consumer(command_sock_path, threads, ctx)) < 0) { | |
207 | fprintf(stderr,"error setting up consumer\n"); | |
208 | goto error; | |
209 | } | |
210 | ||
211 | available_snapshots = g_ptr_array_new(); | |
212 | ||
213 | /* setup the session */ | |
214 | dom.type = LTTNG_DOMAIN_KERNEL; | |
215 | ||
216 | ret = unlink("/tmp/livesession"); | |
217 | ||
218 | lttng_destroy_session("test"); | |
219 | if ((ret = lttng_create_session("test", "/tmp/livesession")) < 0) { | |
220 | fprintf(stderr,"error creating the session : %s\n", | |
221 | helper_lttcomm_get_readable_code(ret)); | |
222 | goto error; | |
223 | } | |
224 | ||
225 | if ((handle = lttng_create_handle("test", &dom)) == NULL) { | |
226 | fprintf(stderr,"error creating handle\n"); | |
227 | goto error_session; | |
228 | } | |
229 | ||
230 | /* | |
231 | * FIXME : need to let the | |
232 | * helper_lttng_consumer_thread_receive_fds create the | |
233 | * socket. | |
234 | * Cleaner solution ? | |
235 | */ | |
236 | while (access(command_sock_path, F_OK)) { | |
237 | sleep(0.1); | |
238 | } | |
239 | ||
240 | if ((ret = lttng_register_consumer(handle, command_sock_path)) < 0) { | |
241 | fprintf(stderr,"error registering consumer : %s\n", | |
242 | helper_lttcomm_get_readable_code(ret)); | |
243 | goto error_session; | |
244 | } | |
245 | ||
246 | strcpy(chan.name, channel_name); | |
247 | chan.attr.overwrite = 0; | |
248 | if (opt_tid && opt_textdump) { | |
249 | chan.attr.subbuf_size = 32768; | |
250 | chan.attr.num_subbuf = 8; | |
251 | } else { | |
252 | //chan.attr.subbuf_size = 1048576; /* 1MB */ | |
253 | chan.attr.subbuf_size = 2097152; /* 1MB */ | |
254 | chan.attr.num_subbuf = 4; | |
255 | } | |
256 | chan.attr.switch_timer_interval = 0; | |
257 | chan.attr.read_timer_interval = 200; | |
258 | chan.attr.output = LTTNG_EVENT_MMAP; | |
259 | ||
260 | if ((ret = lttng_enable_channel(handle, &chan)) < 0) { | |
261 | fprintf(stderr,"error creating channel : %s\n", | |
262 | helper_lttcomm_get_readable_code(ret)); | |
263 | goto error_session; | |
264 | } | |
265 | ||
266 | memset(&ev, '\0', sizeof(struct lttng_event)); | |
267 | ev.type = LTTNG_EVENT_TRACEPOINT; | |
268 | sprintf(ev.name, "sched_switch"); | |
269 | if ((ret = lttng_enable_event(handle, &ev, channel_name)) < 0) { | |
270 | fprintf(stderr,"error enabling event %s : %s\n", | |
271 | ev.name, | |
272 | helper_lttcomm_get_readable_code(ret)); | |
273 | goto error_session; | |
274 | } | |
275 | sprintf(ev.name, "sched_process_free"); | |
276 | if ((ret = lttng_enable_event(handle, &ev, channel_name)) < 0) { | |
277 | fprintf(stderr,"error enabling event %s : %s\n", | |
278 | ev.name, | |
279 | helper_lttcomm_get_readable_code(ret)); | |
280 | goto error_session; | |
281 | } | |
282 | sprintf(ev.name, "lttng_statedump_process_state"); | |
283 | if ((ret = lttng_enable_event(handle, &ev, channel_name)) < 0) { | |
284 | fprintf(stderr,"error enabling event %s : %s\n", | |
285 | ev.name, | |
286 | helper_lttcomm_get_readable_code(ret)); | |
287 | goto error_session; | |
288 | } | |
289 | sprintf(ev.name, "lttng_statedump_file_descriptor"); | |
290 | if ((ret = lttng_enable_event(handle, &ev, channel_name)) < 0) { | |
291 | fprintf(stderr,"error enabling event %s : %s\n", | |
292 | ev.name, | |
293 | helper_lttcomm_get_readable_code(ret)); | |
294 | goto error_session; | |
295 | } | |
296 | ||
297 | memset(&ev, '\0', sizeof(struct lttng_event)); | |
298 | ev.type = LTTNG_EVENT_SYSCALL; | |
299 | if ((ret = lttng_enable_event(handle, &ev, channel_name)) < 0) { | |
300 | fprintf(stderr,"error enabling syscalls : %s\n", | |
301 | helper_lttcomm_get_readable_code(ret)); | |
302 | goto error_session; | |
303 | } | |
304 | ||
305 | if (lttngtop.kprobes_table) { | |
306 | ret = enable_kprobes(handle, channel_name); | |
307 | if (ret < 0) { | |
308 | goto error_session; | |
309 | } | |
310 | } | |
311 | ||
312 | kctxperf1.ctx = LTTNG_EVENT_CONTEXT_PERF_COUNTER; | |
313 | kctxperf1.u.perf_counter.type = 0; /* PERF_TYPE_HARDWARE */ | |
314 | kctxperf1.u.perf_counter.config = 5; /* PERF_COUNT_HW_BRANCH_MISSES */ | |
315 | sprintf(kctxperf1.u.perf_counter.name, "perf_branch_misses"); | |
316 | ret = lttng_add_context(handle, &kctxperf1, NULL, NULL); | |
317 | if (ret < 0) { | |
318 | fprintf(stderr, "error enabling context %s\n", | |
319 | kctxtid.u.perf_counter.name); | |
320 | } | |
321 | ||
322 | kctxperf2.ctx = LTTNG_EVENT_CONTEXT_PERF_COUNTER; | |
323 | kctxperf2.u.perf_counter.type = 1; /* PERF_TYPE_SOFTWARE */ | |
324 | kctxperf2.u.perf_counter.config = 6; /* PERF_COUNT_SW_PAGE_FAULTS_MAJ */ | |
325 | sprintf(kctxperf2.u.perf_counter.name, "perf_major_faults"); | |
326 | ret = lttng_add_context(handle, &kctxperf2, NULL, NULL); | |
327 | if (ret < 0) { | |
328 | fprintf(stderr, "error enabling context %s\n", | |
329 | kctxtid.u.perf_counter.name); | |
330 | } | |
331 | ||
332 | kctxpid.ctx = LTTNG_EVENT_CONTEXT_PID; | |
333 | lttng_add_context(handle, &kctxpid, NULL, NULL); | |
334 | kctxtid.ctx = LTTNG_EVENT_CONTEXT_TID; | |
335 | lttng_add_context(handle, &kctxtid, NULL, NULL); | |
336 | kctxppid.ctx = LTTNG_EVENT_CONTEXT_PPID; | |
337 | lttng_add_context(handle, &kctxppid, NULL, NULL); | |
338 | kctxcomm.ctx = LTTNG_EVENT_CONTEXT_PROCNAME; | |
339 | lttng_add_context(handle, &kctxcomm, NULL, NULL); | |
340 | kctxpid.ctx = LTTNG_EVENT_CONTEXT_VPID; | |
341 | lttng_add_context(handle, &kctxpid, NULL, NULL); | |
342 | kctxtid.ctx = LTTNG_EVENT_CONTEXT_VTID; | |
343 | lttng_add_context(handle, &kctxtid, NULL, NULL); | |
344 | kctxtid.ctx = LTTNG_EVENT_CONTEXT_HOSTNAME; | |
345 | lttng_add_context(handle, &kctxtid, NULL, NULL); | |
346 | ||
347 | ||
348 | if ((ret = lttng_start_tracing("test")) < 0) { | |
349 | fprintf(stderr,"error starting tracing : %s\n", | |
350 | helper_lttcomm_get_readable_code(ret)); | |
351 | goto error_session; | |
352 | } | |
353 | ||
354 | helper_kernctl_buffer_flush(consumerd_metadata); | |
355 | ||
356 | /* block until metadata is ready */ | |
357 | sem_init(&metadata_available, 0, 0); | |
358 | ||
359 | return 0; | |
360 | ||
361 | error_session: | |
362 | lttng_destroy_session("test"); | |
363 | error: | |
364 | return -1; | |
365 | } | |
366 | ||
367 | int mmap_live_loop(struct bt_context *bt_ctx, | |
368 | struct bt_mmap_stream_list mmap_list) | |
369 | { | |
370 | struct bt_mmap_stream *mmap_info; | |
371 | ||
372 | ret = setup_live_tracing(); | |
373 | if (ret < 0) { | |
374 | goto end; | |
375 | } | |
376 | ||
377 | while (!quit) { | |
378 | reload_trace = 0; | |
379 | live_consume(&bt_ctx); | |
380 | ret = check_requirements(bt_ctx); | |
381 | if (ret < 0) { | |
382 | fprintf(stderr, "[error] some mandatory contexts were missing, exiting.\n"); | |
383 | goto end; | |
384 | } | |
385 | iter_trace(bt_ctx); | |
386 | /* | |
387 | * FIXME : pb with cleanup in libbabeltrace | |
388 | ret = bt_context_remove_trace(bt_ctx, 0); | |
389 | if (ret != 0) { | |
390 | fprintf(stderr, "error removing trace\n"); | |
391 | goto error; | |
392 | } | |
393 | */ | |
394 | if (bt_ctx) { | |
395 | bt_context_put(bt_ctx); | |
396 | } | |
397 | ||
398 | /* | |
399 | * since we receive all FDs every time there is an | |
400 | * update and the FD number is different every time, | |
401 | * we don't know which one are valid. | |
402 | * so we check if all FDs are usable with a simple | |
403 | * ioctl call. | |
404 | */ | |
405 | bt_list_for_each_entry(mmap_info, &mmap_list.head, list) { | |
406 | unsigned long mmap_len; | |
407 | ||
408 | ret = helper_kernctl_get_mmap_len(mmap_info->fd, &mmap_len); | |
409 | if (ret != 0) { | |
410 | bt_list_del(&mmap_info->list); | |
411 | } | |
412 | } | |
413 | sem_post(&metadata_available); | |
414 | } | |
415 | ||
416 | } | |
417 | ||
418 | void mmap_live_flush(struct bt_mmap_stream_list mmap_list) | |
419 | { | |
420 | struct bt_mmap_stream *mmap_info; | |
421 | ||
422 | bt_list_for_each_entry(mmap_info, &mmap_list.head, list) | |
423 | helper_kernctl_buffer_flush(mmap_info->fd); | |
424 | } | |
425 | #endif /* LTTNGTOP_MMAP_LIVE */ |