lttng-modules v0.19-stable: setup_trace_write: Fix recursive locking
[lttng-modules.git] / ltt-ascii.c
1 /*
2 * LTT ascii binary buffer to ascii converter.
3 *
4 * Copyright 2008 - 2009 Lai Jiangshan (laijs@cn.fujitsu.com)
5 * Copyright 2009 - Mathieu Desnoyers mathieu.desnoyers@polymtl.ca
6 *
7 * Dual LGPL v2.1/GPL v2 license.
8 */
9
10 /*
11 * TODO
12 *
13 * Move to new switch behavior: Wait for data for the duration of the
14 * timer interval + safety, if none is coming, consider that no activity occured
15 * in the buffer.
16 *
17 * Fix case when having a text file open and destroying trace.
18 *
19 * - Automate periodical switch:
20 *
21 * The debugfs file "switch_timer" receives a timer period as parameter
22 * (e.g. echo 100 > switch_timer) to activate the timer per channel. This can
23 * also be accessed through the internal API _before the trace session starts_.
24 * This timer will insure that we periodically have subbuffers to read, and
25 * therefore that the merge-sort does not wait endlessly for a subbuffer.
26 *
27 * - If a channel is switched and read without data, make sure it is still
28 * considered afterward (not removed from the queue).
29 *
30 * - Create a ascii/tracename/ALL file to merge-sort all active channels.
31 * - Create a ascii/tracename/README file to contain the text output legend.
32 * - Remove leading zeroes from timestamps.
33 * - Enhance pretty-printing to make sure all types used for addesses output in
34 * the form 0xAB00000000 (not decimal). This is true for %p and 0x%...X.
35 * - Hotplug support
36 */
37
38
39
40
41 #include <linux/module.h>
42 #include <linux/seq_file.h>
43 #include <linux/debugfs.h>
44 #include <linux/module.h>
45 #include <linux/string.h>
46 #include <linux/delay.h>
47 #include <linux/slab.h>
48 #include <linux/cpu.h>
49 #include <linux/fs.h>
50
51 #include "ltt-tracer.h"
52 #include "ltt-relay.h"
53 #include "ltt-relay-lockless.h"
54
55 #if 0
56 #define DEBUGP printk
57 #else
58 #define DEBUGP(fmt , a...)
59 #endif
60
61 struct dentry *ltt_ascii_dir_dentry;
62 EXPORT_SYMBOL_GPL(ltt_ascii_dir_dentry);
63
64 struct ltt_relay_iter;
65
66 struct ltt_relay_cpu_iter {
67 /* cpu buffer information */
68 struct ltt_chanbuf *buf;
69 struct ltt_relay_iter *iter;
70 int sb_ref; /* holding a reference to a subbuffer */
71 long read_sb_offset; /* offset of the subbuffer read */
72
73 /* current event information */
74 struct ltt_subbuffer_header *header;
75 long hdr_offset; /* event header offset */
76 long payload_offset; /* event payload offset */
77 u64 tsc; /* full 64-bits timestamp value */
78 u32 data_size;
79 u16 chID; /* channel ID, const */
80 u16 eID;
81 };
82
83 struct ltt_relay_iter {
84 struct ltt_relay_cpu_iter iter_cpu[NR_CPUS];
85 struct ltt_chan *chan;
86 loff_t pos;
87 int cpu;
88 int nr_refs;
89 };
90
91 /*
92 * offset of 0 in subbuffer means "subbuf size" (filled subbuffer).
93 */
94 static int is_subbuffer_offset_end(struct ltt_relay_cpu_iter *citer,
95 long offset)
96 {
97 struct ltt_chan *chan = container_of(citer->buf->a.chan,
98 struct ltt_chan, a);
99 long sub_offset = SUBBUF_OFFSET(offset - 1, chan) + 1;
100
101 return (sub_offset <= citer->header->data_size);
102 }
103
104 static u64 calculate_tsc(u64 pre_tsc, u64 read_tsc, unsigned int rflags)
105 {
106 u64 new_tsc = read_tsc;
107
108 if (rflags != LTT_RFLAG_ID_SIZE_TSC) {
109 BUG_ON(read_tsc >> LTT_TSC_BITS);
110
111 new_tsc = (pre_tsc & ~LTT_TSC_MASK) + read_tsc;
112 if (read_tsc < (pre_tsc & LTT_TSC_MASK))
113 new_tsc += 1UL << LTT_TSC_BITS;
114 }
115
116 return new_tsc;
117 }
118
119 /*
120 * calculate payload offset */
121 static inline long calculate_payload_offset(long offset, u16 chID, u16 eID)
122 {
123 const char *fmt;
124
125 if (!ltt_get_alignment())
126 return offset;
127
128 fmt = marker_get_fmt_from_id(chID, eID);
129 BUG_ON(!fmt);
130
131 return offset + ltt_fmt_largest_align(offset, fmt);
132 }
133
134 static void update_new_event(struct ltt_relay_cpu_iter *citer, long hdr_offset)
135 {
136 u64 read_tsc;
137 unsigned int rflags;
138 long tmp_offset;
139
140 WARN_ON_ONCE(hdr_offset != citer->hdr_offset);
141
142 tmp_offset = ltt_read_event_header(&citer->buf->a, hdr_offset,
143 &read_tsc, &citer->data_size,
144 &citer->eID, &rflags);
145 citer->payload_offset = calculate_payload_offset(tmp_offset,
146 citer->chID,
147 citer->eID);
148
149 citer->tsc = calculate_tsc(citer->tsc, read_tsc, rflags);
150 }
151
152 static void update_event_size(struct ltt_relay_cpu_iter *citer, long hdr_offset)
153 {
154 char output[1];
155 const char *fmt;
156 size_t data_size;
157
158 if (citer->data_size != INT_MAX)
159 return;
160
161 fmt = marker_get_fmt_from_id(citer->chID, citer->eID);
162 BUG_ON(!fmt);
163 ltt_serialize_printf(citer->buf, citer->payload_offset,
164 &data_size, output, 0, fmt);
165 citer->data_size = data_size;
166 }
167
168 static void update_cpu_iter(struct ltt_relay_cpu_iter *citer, long hdr_offset)
169 {
170 if (unlikely((!citer->sb_ref)
171 || is_subbuffer_offset_end(citer, hdr_offset))) {
172 citer->header = NULL;
173 return;
174 }
175 update_new_event(citer, hdr_offset);
176 update_event_size(citer, hdr_offset);
177 }
178
179 /*
180 * returns 0 if we get a subbuffer reference.
181 * else, the buffer has not available data, try again later.
182 */
183 static int subbuffer_start(struct ltt_relay_cpu_iter *citer, long *offset)
184 {
185 int ret;
186 struct ltt_relay_iter *iter = citer->iter;
187
188 ret = ltt_chanbuf_get_subbuf(citer->buf, offset);
189 if (!ret) {
190 citer->header = ltt_relay_read_offset_address(&citer->buf->a,
191 *offset);
192 citer->hdr_offset = (*offset) + ltt_sb_header_size();
193 citer->tsc = citer->header->cycle_count_begin;
194 iter->nr_refs++;
195 citer->sb_ref = 1;
196 return 0;
197 } else {
198 if (ltt_chanbuf_is_finalized(citer->buf))
199 return -ENODATA;
200 else
201 return -EAGAIN;
202 }
203 }
204
205 static void subbuffer_stop(struct ltt_relay_cpu_iter *citer,
206 long offset)
207 {
208 int ret;
209 struct ltt_relay_iter *iter = citer->iter;
210
211 WARN_ON_ONCE(!citer->sb_ref);
212 ret = ltt_chanbuf_put_subbuf(citer->buf, offset);
213 WARN_ON_ONCE(ret);
214 citer->sb_ref = 0;
215 iter->nr_refs--;
216 }
217
218 static void ltt_relay_advance_cpu_iter(struct ltt_relay_cpu_iter *citer)
219 {
220 long old_offset = citer->payload_offset;
221 long new_offset = citer->payload_offset;
222 int ret;
223
224 /* find that whether we read all data in this subbuffer */
225 if (unlikely(is_subbuffer_offset_end(citer,
226 old_offset + citer->data_size))) {
227 DEBUGP(KERN_DEBUG "LTT ASCII stop cpu %d offset %lX\n",
228 citer->buf->a.cpu, citer->read_sb_offset);
229 subbuffer_stop(citer, citer->read_sb_offset);
230 for (;;) {
231 ret = subbuffer_start(citer, &citer->read_sb_offset);
232 DEBUGP(KERN_DEBUG
233 "LTT ASCII start cpu %d ret %d offset %lX\n",
234 citer->buf->a.cpu, ret, citer->read_sb_offset);
235 if (!ret || ret == -ENODATA) {
236 break; /* got data, or finalized */
237 } else { /* -EAGAIN */
238 if (signal_pending(current))
239 break;
240 schedule_timeout_interruptible(1);
241 //TODO: check for no-data delay. take ref. break
242 }
243 }
244 } else {
245 new_offset += citer->data_size;
246 citer->hdr_offset = new_offset + ltt_align(new_offset, sizeof(struct ltt_event_header));
247 DEBUGP(KERN_DEBUG
248 "LTT ASCII old_offset %lX new_offset %lX cpu %d\n",
249 old_offset, new_offset, citer->buf->a.cpu);
250 }
251
252 update_cpu_iter(citer, citer->hdr_offset);
253 }
254
255 static int cpu_iter_eof(struct ltt_relay_cpu_iter *citer)
256 {
257 return !citer->sb_ref;
258 }
259
260 static int ltt_relay_iter_eof(struct ltt_relay_iter *iter)
261 {
262 return iter->nr_refs == 0;
263 }
264
265 static void ltt_relay_advance_iter(struct ltt_relay_iter *iter)
266 {
267 int i;
268 struct ltt_relay_cpu_iter *curr, *min = NULL;
269 iter->cpu = -1;
270
271 /*
272 * find the event with the minimum tsc.
273 * TODO: use min-heep for 4096CPUS
274 */
275 for_each_possible_cpu(i) {
276 curr = &iter->iter_cpu[i];
277
278 if (!curr->buf->a.allocated || !curr->header)
279 continue;
280
281 if (cpu_iter_eof(curr))
282 continue;
283
284 if (!min || curr->tsc < min->tsc) {
285 min = curr;
286 iter->cpu = i;
287 }
288 }
289
290 /* update cpu_iter for next ltt_relay_advance_iter() */
291 if (min)
292 ltt_relay_advance_cpu_iter(min);
293 }
294
295 static void *ascii_next(struct seq_file *m, void *v, loff_t *ppos)
296 {
297 struct ltt_relay_iter *iter = m->private;
298
299 WARN_ON_ONCE(!iter->nr_refs);
300 BUG_ON(v != iter);
301
302 ltt_relay_advance_iter(iter);
303 return (ltt_relay_iter_eof(iter) || signal_pending(current))
304 ? NULL : iter;
305 }
306
307 static void *ascii_start(struct seq_file *m, loff_t *ppos)
308 {
309 struct ltt_relay_iter *iter = m->private;
310
311 ltt_relay_advance_iter(iter);
312 return (ltt_relay_iter_eof(iter) || signal_pending(current))
313 ? NULL : iter;
314 }
315
316 static void ascii_stop(struct seq_file *m, void *v)
317 {
318 }
319
320 static
321 int seq_serialize(struct seq_file *m, struct ltt_chanbuf *buf,
322 size_t buf_offset, const char *fmt, size_t *data_size)
323 {
324 int len;
325
326 if (m->count < m->size) {
327 len = ltt_serialize_printf(buf, buf_offset, data_size,
328 m->buf + m->count,
329 m->size - m->count, fmt);
330 if (m->count + len < m->size) {
331 m->count += len;
332 return 0;
333 }
334 }
335
336 m->count = m->size;
337 return -1;
338 }
339
340 static int ascii_show(struct seq_file *m, void *v)
341 {
342 struct ltt_relay_iter *iter = v;
343 struct ltt_relay_cpu_iter *citer;
344 const char *name;
345 const char *fmt;
346 unsigned long long tsc;
347 size_t data_size;
348
349 if (iter->cpu == -1)
350 return 0;
351
352 citer = &iter->iter_cpu[iter->cpu];
353 WARN_ON_ONCE(!citer->sb_ref);
354 /*
355 * Nothing to show, we are at the end of the last subbuffer currently
356 * having data.
357 */
358 if (!citer->header)
359 return 0;
360
361 tsc = citer->tsc;
362 name = marker_get_name_from_id(citer->chID, citer->eID);
363 fmt = marker_get_fmt_from_id(citer->chID, citer->eID);
364
365 if (!name || !fmt)
366 return 0;
367
368 seq_printf(m, "event:%16.16s: cpu:%2d time:%20.20llu ",
369 name, iter->cpu, tsc);
370 seq_serialize(m, citer->buf, citer->payload_offset, fmt, &data_size);
371 seq_puts(m, "\n");
372 if (citer->data_size == INT_MAX)
373 citer->data_size = data_size;
374
375 return 0;
376 }
377
378 static struct seq_operations ascii_seq_ops = {
379 .start = ascii_start,
380 .next = ascii_next,
381 .stop = ascii_stop,
382 .show = ascii_show,
383 };
384
385 /* FIXME : cpu hotplug support */
386 static int ltt_relay_iter_open_channel(struct ltt_relay_iter *iter,
387 struct ltt_chan *chan)
388 {
389 int i, ret;
390 u16 chID = ltt_channels_get_index_from_name(chan->a.filename);
391
392 /* we don't need lock relay_channels_mutex */
393 for_each_possible_cpu(i) {
394 struct ltt_relay_cpu_iter *citer = &iter->iter_cpu[i];
395
396 citer->buf = per_cpu_ptr(chan->a.buf, i);
397 if (!citer->buf->a.allocated)
398 continue;
399
400 citer->iter = iter; /* easy lazy parent info */
401 citer->chID = chID;
402
403 ret = ltt_chanbuf_open_read(citer->buf);
404 if (ret) {
405 /* Failed to open a percpu buffer, close everything. */
406 citer->buf = NULL;
407 goto error;
408 }
409
410 for (;;) {
411 ret = subbuffer_start(citer,
412 &citer->read_sb_offset);
413 DEBUGP(KERN_DEBUG
414 "LTT ASCII open start "
415 "cpu %d ret %d offset %lX\n",
416 citer->buf->a.cpu, ret, citer->read_sb_offset);
417 if (!ret || ret == -ENODATA) {
418 break; /* got data, or finalized */
419 } else { /* -EAGAIN */
420 if (signal_pending(current))
421 break;
422 schedule_timeout_interruptible(1);
423 }
424 }
425 update_cpu_iter(citer, citer->hdr_offset);
426 }
427 if (!iter->nr_refs) {
428 ret = -ENODATA;
429 goto error;
430 }
431
432 return 0;
433
434 error:
435 for_each_possible_cpu(i) {
436 struct ltt_relay_cpu_iter *citer = &iter->iter_cpu[i];
437
438 if (!citer->buf)
439 break;
440
441 if (citer->buf->a.allocated)
442 ltt_chanbuf_release_read(citer->buf);
443 }
444 return ret;
445 }
446
447 /* FIXME : cpu hotplug support */
448 static int ltt_relay_iter_release_channel(struct ltt_relay_iter *iter)
449 {
450 int i;
451
452 for_each_possible_cpu(i) {
453 struct ltt_relay_cpu_iter *citer = &iter->iter_cpu[i];
454
455 if (citer->sb_ref) {
456 WARN_ON_ONCE(!citer->buf->a.allocated);
457 DEBUGP(KERN_DEBUG
458 "LTT ASCII release stop cpu %d offset %lX\n",
459 citer->buf->a.cpu, citer->read_sb_offset);
460 subbuffer_stop(&iter->iter_cpu[i],
461 citer->read_sb_offset);
462 }
463 if (citer->buf->a.allocated)
464 ltt_chanbuf_release_read(citer->buf);
465 }
466 WARN_ON_ONCE(iter->nr_refs);
467 return 0;
468 }
469
470 static int ltt_relay_ascii_open(struct inode *inode, struct file *file)
471 {
472 int ret;
473 struct ltt_chan *chan = inode->i_private;
474 struct ltt_relay_iter *iter = kzalloc(sizeof(*iter), GFP_KERNEL);
475 if (!iter)
476 return -ENOMEM;
477
478 iter->chan = chan;
479 ret = ltt_relay_iter_open_channel(iter, chan);
480 if (ret)
481 goto error_free_alloc;
482
483 ret = seq_open(file, &ascii_seq_ops);
484 if (ret)
485 goto error_release_channel;
486 ((struct seq_file *)file->private_data)->private = iter;
487 return 0;
488
489 error_release_channel:
490 ltt_relay_iter_release_channel(iter);
491 error_free_alloc:
492 kfree(iter);
493 return ret;
494 }
495
496 static int ltt_relay_ascii_release(struct inode *inode, struct file *file)
497 {
498 struct seq_file *seq = file->private_data;
499 struct ltt_relay_iter *iter = seq->private;
500
501 ltt_relay_iter_release_channel(iter);
502 kfree(iter);
503 return 0;
504 }
505
506 static struct file_operations ltt_ascii_fops =
507 {
508 .read = seq_read,
509 .open = ltt_relay_ascii_open,
510 .release = ltt_relay_ascii_release,
511 .llseek = no_llseek,
512 .owner = THIS_MODULE,
513 };
514
515 int ltt_ascii_create(struct ltt_chan *chan)
516 {
517 struct dentry *dentry;
518
519 dentry = debugfs_create_file(chan->a.filename,
520 S_IRUSR | S_IRGRP,
521 chan->a.trace->dentry.ascii_root,
522 chan, &ltt_ascii_fops);
523 if (IS_ERR(dentry))
524 return PTR_ERR(dentry);
525
526 if (!dentry)
527 return -EEXIST;
528
529 chan->a.ascii_dentry = dentry;
530 dentry->d_inode->i_private = chan;
531 return 0;
532 }
533 EXPORT_SYMBOL_GPL(ltt_ascii_create);
534
535 void ltt_ascii_remove(struct ltt_chan *chan)
536 {
537 struct dentry *dentry;
538
539 dentry = dget(chan->a.ascii_dentry);
540 debugfs_remove(dentry);
541 /* TODO: wait / wakeup instead */
542 /*
543 * Wait for every reference to the dentry to be gone,
544 * except us.
545 */
546 while (ACCESS_ONCE(dentry->d_count) != 1)
547 msleep(100);
548 dput(dentry);
549 }
550 EXPORT_SYMBOL_GPL(ltt_ascii_remove);
551
552 int ltt_ascii_create_dir(struct ltt_trace *new_trace)
553 {
554 new_trace->dentry.ascii_root = debugfs_create_dir(new_trace->trace_name,
555 ltt_ascii_dir_dentry);
556 if (!new_trace->dentry.ascii_root)
557 return -EEXIST;
558 return 0;
559 }
560 EXPORT_SYMBOL_GPL(ltt_ascii_create_dir);
561
562 void ltt_ascii_remove_dir(struct ltt_trace *trace)
563 {
564 debugfs_remove(trace->dentry.ascii_root);
565 }
566 EXPORT_SYMBOL_GPL(ltt_ascii_remove_dir);
567
568 __init int ltt_ascii_init(void)
569 {
570 ltt_ascii_dir_dentry = debugfs_create_dir(LTT_ASCII, get_ltt_root());
571
572 return ltt_ascii_dir_dentry ? 0 : -EFAULT;
573 }
574
575 __exit void ltt_ascii_exit(void)
576 {
577 debugfs_remove(ltt_ascii_dir_dentry);
578 put_ltt_root();
579 }
580
581 MODULE_LICENSE("GPL and additional rights");
582 MODULE_AUTHOR("Lai Jiangshan@FNST and Mathieu Desnoyers");
583 MODULE_DESCRIPTION("Linux Trace Toolkit Next Generation Ascii Converter");
This page took 0.039735 seconds and 4 git commands to generate.