ppc update
[lttv.git] / ltt-usertrace / ltt / ltt-usertrace-fast.h
1
2 /* LTTng user-space "fast" tracing header
3 *
4 * Copyright 2006 Mathieu Desnoyers
5 *
6 */
7
8 #ifndef _LTT_USERTRACE_FAST_H
9 #define _LTT_USERTRACE_FAST_H
10
11 #ifdef LTT_TRACE
12 #ifdef LTT_TRACE_FAST
13
14 #include <errno.h>
15 #include <pthread.h>
16 #include <stdint.h>
17 #include <syscall.h>
18 #include <semaphore.h>
19 #include <signal.h>
20
21 #include <ltt/ltt-facility-id-user_generic.h>
22
23 #ifndef LTT_N_SUBBUFS
24 #define LTT_N_SUBBUFS 2
25 #endif //LTT_N_SUBBUFS
26
27 #ifndef LTT_SUBBUF_SIZE_PROCESS
28 #define LTT_SUBBUF_SIZE_PROCESS 1048576
29 #endif //LTT_BUF_SIZE_CPU
30
31 #define LTT_BUF_SIZE_PROCESS (LTT_SUBBUF_SIZE_PROCESS * LTT_N_SUBBUFS)
32
33 #ifndef LTT_USERTRACE_ROOT
34 #define LTT_USERTRACE_ROOT "/tmp/ltt-usertrace"
35 #endif //LTT_USERTRACE_ROOT
36
37
38 /* Buffer offset macros */
39
40 #define BUFFER_OFFSET(offset, buf) (offset & (buf->alloc_size-1))
41 #define SUBBUF_OFFSET(offset, buf) (offset & (buf->subbuf_size-1))
42 #define SUBBUF_ALIGN(offset, buf) \
43 (((offset) + buf->subbuf_size) & (~(buf->subbuf_size-1)))
44 #define SUBBUF_TRUNC(offset, buf) \
45 ((offset) & (~(buf->subbuf_size-1)))
46 #define SUBBUF_INDEX(offset, buf) \
47 (BUFFER_OFFSET(offset,buf)/buf->subbuf_size)
48
49
50 #define LTT_TRACER_MAGIC_NUMBER 0x00D6B7ED
51 #define LTT_TRACER_VERSION_MAJOR 0
52 #define LTT_TRACER_VERSION_MINOR 7
53
54 #ifndef atomic_cmpxchg
55 #define atomic_cmpxchg(v, old, new) ((int)cmpxchg(&((v)->counter), old, new))
56 #endif //atomic_cmpxchg
57
58 struct ltt_trace_header {
59 uint32_t magic_number;
60 uint32_t arch_type;
61 uint32_t arch_variant;
62 uint32_t float_word_order; /* Only useful for user space traces */
63 uint8_t arch_size;
64 //uint32_t system_type;
65 uint8_t major_version;
66 uint8_t minor_version;
67 uint8_t flight_recorder;
68 uint8_t has_heartbeat;
69 uint8_t has_alignment; /* Event header alignment */
70 uint32_t freq_scale;
71 uint64_t start_freq;
72 uint64_t start_tsc;
73 uint64_t start_monotonic;
74 uint64_t start_time_sec;
75 uint64_t start_time_usec;
76 } __attribute((packed));
77
78
79 struct ltt_block_start_header {
80 struct {
81 uint64_t cycle_count;
82 uint64_t freq; /* khz */
83 } begin;
84 struct {
85 uint64_t cycle_count;
86 uint64_t freq; /* khz */
87 } end;
88 uint32_t lost_size; /* Size unused at the end of the buffer */
89 uint32_t buf_size; /* The size of this sub-buffer */
90 struct ltt_trace_header trace;
91 } __attribute((packed));
92
93
94
95 struct ltt_buf {
96 void *start;
97 atomic_t offset;
98 atomic_t consumed;
99 atomic_t reserve_count[LTT_N_SUBBUFS];
100 atomic_t commit_count[LTT_N_SUBBUFS];
101
102 atomic_t events_lost;
103 atomic_t corrupted_subbuffers;
104 sem_t writer_sem; /* semaphore on which the writer waits */
105 unsigned int alloc_size;
106 unsigned int subbuf_size;
107 };
108
109 struct ltt_trace_info {
110 int init;
111 int filter;
112 pid_t daemon_id;
113 int nesting;
114 struct {
115 struct ltt_buf process;
116 char process_buf[LTT_BUF_SIZE_PROCESS] __attribute__ ((aligned (8)));
117 } channel;
118 };
119
120
121 struct ltt_event_header_nohb {
122 uint64_t timestamp;
123 unsigned char facility_id;
124 unsigned char event_id;
125 uint16_t event_size;
126 } __attribute((packed));
127
128 extern __thread struct ltt_trace_info *thread_trace_info;
129
130 void ltt_thread_init(void);
131
132 void __attribute__((no_instrument_function))
133 ltt_usertrace_fast_buffer_switch(void);
134
135 /* Get the offset of the channel in the ltt_trace_struct */
136 #define GET_CHANNEL_INDEX(chan) \
137 (unsigned int)&((struct ltt_trace_info*)NULL)->channel.chan
138
139 /* ltt_get_index_from_facility
140 *
141 * Get channel index from facility and event id.
142 *
143 * @fID : facility ID
144 * @eID : event number
145 *
146 * Get the channel index into which events must be written for the given
147 * facility and event number. We get this structure offset as soon as possible
148 * and remember it so we pass through this logic only once per trace call (not
149 * for every trace).
150 */
151 static inline unsigned int __attribute__((no_instrument_function))
152 ltt_get_index_from_facility(ltt_facility_t fID,
153 uint8_t eID)
154 {
155 return GET_CHANNEL_INDEX(process);
156 }
157
158
159 static inline struct ltt_buf * __attribute__((no_instrument_function))
160 ltt_get_channel_from_index(
161 struct ltt_trace_info *trace, unsigned int index)
162 {
163 return (struct ltt_buf *)((void*)trace+index);
164 }
165
166
167 /*
168 * ltt_get_header_size
169 *
170 * Calculate alignment offset for arch size void*. This is the
171 * alignment offset of the event header.
172 *
173 * Important note :
174 * The event header must be a size multiple of the void* size. This is necessary
175 * to be able to calculate statically the alignment offset of the variable
176 * length data fields that follows. The total offset calculated here :
177 *
178 * Alignment of header struct on arch size
179 * + sizeof(header struct)
180 * + padding added to end of struct to align on arch size.
181 * */
182 static inline unsigned char __attribute__((no_instrument_function))
183 ltt_get_header_size(struct ltt_trace_info *trace,
184 void *address,
185 size_t *before_hdr_pad,
186 size_t *after_hdr_pad,
187 size_t *header_size)
188 {
189 unsigned int padding;
190 unsigned int header;
191
192 header = sizeof(struct ltt_event_header_nohb);
193
194 /* Padding before the header. Calculated dynamically */
195 *before_hdr_pad = ltt_align((unsigned long)address, header);
196 padding = *before_hdr_pad;
197
198 /* Padding after header, considering header aligned on ltt_align.
199 * Calculated statically if header size if known. */
200 *after_hdr_pad = ltt_align(header, sizeof(void*));
201 padding += *after_hdr_pad;
202
203 *header_size = header;
204
205 return header+padding;
206 }
207
208
209 /* ltt_write_event_header
210 *
211 * Writes the event header to the pointer.
212 *
213 * @channel : pointer to the channel structure
214 * @ptr : buffer pointer
215 * @fID : facility ID
216 * @eID : event ID
217 * @event_size : size of the event, excluding the event header.
218 * @offset : offset of the beginning of the header, for alignment.
219 * Calculated by ltt_get_event_header_size.
220 * @tsc : time stamp counter.
221 */
222 static inline void __attribute__((no_instrument_function))
223 ltt_write_event_header(
224 struct ltt_trace_info *trace, struct ltt_buf *buf,
225 void *ptr, ltt_facility_t fID, uint32_t eID, size_t event_size,
226 size_t offset, uint64_t tsc)
227 {
228 struct ltt_event_header_nohb *nohb;
229
230 event_size = min(event_size, 0xFFFFU);
231 nohb = (struct ltt_event_header_nohb *)(ptr+offset);
232 nohb->timestamp = (uint64_t)tsc;
233 nohb->facility_id = fID;
234 nohb->event_id = eID;
235 nohb->event_size = (uint16_t)event_size;
236 }
237
238
239
240 static inline uint64_t __attribute__((no_instrument_function))
241 ltt_get_timestamp()
242 {
243 return get_cycles();
244 }
245
246 static inline unsigned int __attribute__((no_instrument_function))
247 ltt_subbuf_header_len(struct ltt_buf *buf)
248 {
249 return sizeof(struct ltt_block_start_header);
250 }
251
252
253
254 static inline void __attribute__((no_instrument_function))
255 ltt_write_trace_header(struct ltt_trace_header *header)
256 {
257 header->magic_number = LTT_TRACER_MAGIC_NUMBER;
258 header->major_version = LTT_TRACER_VERSION_MAJOR;
259 header->minor_version = LTT_TRACER_VERSION_MINOR;
260 header->float_word_order = 0; //FIXME
261 header->arch_type = 0; //FIXME LTT_ARCH_TYPE;
262 header->arch_size = sizeof(void*);
263 header->arch_variant = 0; //FIXME LTT_ARCH_VARIANT;
264 header->flight_recorder = 0;
265 header->has_heartbeat = 0;
266
267 #ifndef LTT_PACK
268 header->has_alignment = sizeof(void*);
269 #else
270 header->has_alignment = 0;
271 #endif
272
273 //FIXME
274 header->freq_scale = 0;
275 header->start_freq = 0;
276 header->start_tsc = 0;
277 header->start_monotonic = 0;
278 header->start_time_sec = 0;
279 header->start_time_usec = 0;
280 }
281
282
283 static inline void __attribute__((no_instrument_function))
284 ltt_buffer_begin_callback(struct ltt_buf *buf,
285 uint64_t tsc, unsigned int subbuf_idx)
286 {
287 struct ltt_block_start_header *header =
288 (struct ltt_block_start_header*)
289 (buf->start + (subbuf_idx*buf->subbuf_size));
290
291 header->begin.cycle_count = tsc;
292 header->begin.freq = 0; //ltt_frequency();
293
294 header->lost_size = 0xFFFFFFFF; // for debugging...
295
296 header->buf_size = buf->subbuf_size;
297
298 ltt_write_trace_header(&header->trace);
299
300 }
301
302
303
304 static inline void __attribute__((no_instrument_function))
305 ltt_buffer_end_callback(struct ltt_buf *buf,
306 uint64_t tsc, unsigned int offset, unsigned int subbuf_idx)
307 {
308 struct ltt_block_start_header *header =
309 (struct ltt_block_start_header*)
310 (buf->start + (subbuf_idx*buf->subbuf_size));
311 /* offset is assumed to never be 0 here : never deliver a completely
312 * empty subbuffer. */
313 /* The lost size is between 0 and subbuf_size-1 */
314 header->lost_size = SUBBUF_OFFSET((buf->subbuf_size - offset),
315 buf);
316 header->end.cycle_count = tsc;
317 header->end.freq = 0; //ltt_frequency();
318 }
319
320
321 static inline void __attribute__((no_instrument_function))
322 ltt_deliver_callback(struct ltt_buf *buf,
323 unsigned subbuf_idx,
324 void *subbuf)
325 {
326 ltt_usertrace_fast_buffer_switch();
327 }
328
329
330 /* ltt_reserve_slot
331 *
332 * Atomic slot reservation in a LTTng buffer. It will take care of
333 * sub-buffer switching.
334 *
335 * Parameters:
336 *
337 * @trace : the trace structure to log to.
338 * @buf : the buffer to reserve space into.
339 * @data_size : size of the variable length data to log.
340 * @slot_size : pointer to total size of the slot (out)
341 * @tsc : pointer to the tsc at the slot reservation (out)
342 * @before_hdr_pad : dynamic padding before the event header.
343 * @after_hdr_pad : dynamic padding after the event header.
344 *
345 * Return : NULL if not enough space, else returns the pointer
346 * to the beginning of the reserved slot. */
347 static inline void * __attribute__((no_instrument_function)) ltt_reserve_slot(
348 struct ltt_trace_info *trace,
349 struct ltt_buf *ltt_buf,
350 unsigned int data_size,
351 size_t *slot_size,
352 uint64_t *tsc,
353 size_t *before_hdr_pad,
354 size_t *after_hdr_pad,
355 size_t *header_size)
356 {
357 int offset_begin, offset_end, offset_old;
358 //int has_switch;
359 int begin_switch, end_switch_current, end_switch_old;
360 int reserve_commit_diff = 0;
361 unsigned int size;
362 int consumed_old, consumed_new;
363 int commit_count, reserve_count;
364 int ret;
365
366 do {
367 offset_old = atomic_read(&ltt_buf->offset);
368 offset_begin = offset_old;
369 //has_switch = 0;
370 begin_switch = 0;
371 end_switch_current = 0;
372 end_switch_old = 0;
373 *tsc = ltt_get_timestamp();
374 if(*tsc == 0) {
375 /* Error in getting the timestamp, event lost */
376 atomic_inc(&ltt_buf->events_lost);
377 return NULL;
378 }
379
380 if(SUBBUF_OFFSET(offset_begin, ltt_buf) == 0) {
381 begin_switch = 1; /* For offset_begin */
382 } else {
383 size = ltt_get_header_size(trace, ltt_buf->start + offset_begin,
384 before_hdr_pad, after_hdr_pad, header_size)
385 + data_size;
386
387 if((SUBBUF_OFFSET(offset_begin, ltt_buf)+size)>ltt_buf->subbuf_size) {
388 //has_switch = 1;
389 end_switch_old = 1; /* For offset_old */
390 begin_switch = 1; /* For offset_begin */
391 }
392 }
393
394 if(begin_switch) {
395 if(end_switch_old) {
396 offset_begin = SUBBUF_ALIGN(offset_begin, ltt_buf);
397 }
398 offset_begin = offset_begin + ltt_subbuf_header_len(ltt_buf);
399 /* Test new buffer integrity */
400 reserve_commit_diff =
401 atomic_read(&ltt_buf->reserve_count[SUBBUF_INDEX(offset_begin,
402 ltt_buf)])
403 - atomic_read(&ltt_buf->commit_count[SUBBUF_INDEX(offset_begin,
404 ltt_buf)]);
405 if(reserve_commit_diff == 0) {
406 /* Next buffer not corrupted. */
407 //if((SUBBUF_TRUNC(offset_begin, ltt_buf)
408 // - SUBBUF_TRUNC(atomic_read(&ltt_buf->consumed), ltt_buf))
409 // >= ltt_buf->alloc_size) {
410 /* sem_wait is not signal safe. Disable signals around it. */
411 {
412 sigset_t oldset, set;
413
414 /* Disable signals */
415 ret = sigfillset(&set);
416 if(ret) perror("LTT Error in sigfillset\n");
417
418 ret = pthread_sigmask(SIG_BLOCK, &set, &oldset);
419 if(ret) perror("LTT Error in pthread_sigmask\n");
420
421 sem_wait(&ltt_buf->writer_sem);
422
423 /* Enable signals */
424 ret = pthread_sigmask(SIG_SETMASK, &oldset, NULL);
425 if(ret) perror("LTT Error in pthread_sigmask\n");
426 }
427
428 /* go on with the write */
429
430 //} else {
431 // /* next buffer not corrupted, we are either in overwrite mode or
432 // * the buffer is not full. It's safe to write in this new subbuffer.*/
433 //}
434 } else {
435 /* Next subbuffer corrupted. Force pushing reader even in normal
436 * mode. It's safe to write in this new subbuffer. */
437 sem_post(&ltt_buf->writer_sem);
438 }
439 size = ltt_get_header_size(trace, ltt_buf->start + offset_begin,
440 before_hdr_pad, after_hdr_pad, header_size) + data_size;
441 if((SUBBUF_OFFSET(offset_begin,ltt_buf)+size)>ltt_buf->subbuf_size) {
442 /* Event too big for subbuffers, report error, don't complete
443 * the sub-buffer switch. */
444 atomic_inc(&ltt_buf->events_lost);
445 return NULL;
446 } else {
447 /* We just made a successful buffer switch and the event fits in the
448 * new subbuffer. Let's write. */
449 }
450 } else {
451 /* Event fits in the current buffer and we are not on a switch boundary.
452 * It's safe to write */
453 }
454 offset_end = offset_begin + size;
455
456 if((SUBBUF_OFFSET(offset_end, ltt_buf)) == 0) {
457 /* The offset_end will fall at the very beginning of the next subbuffer.
458 */
459 end_switch_current = 1; /* For offset_begin */
460 }
461
462 } while(atomic_cmpxchg(&ltt_buf->offset, offset_old, offset_end)
463 != offset_old);
464
465
466 /* Push the reader if necessary */
467 do {
468 consumed_old = atomic_read(&ltt_buf->consumed);
469 /* If buffer is in overwrite mode, push the reader consumed count if
470 the write position has reached it and we are not at the first
471 iteration (don't push the reader farther than the writer).
472 This operation can be done concurrently by many writers in the
473 same buffer, the writer being at the fartest write position sub-buffer
474 index in the buffer being the one which will win this loop. */
475 /* If the buffer is not in overwrite mode, pushing the reader only
476 happen if a sub-buffer is corrupted */
477 if((SUBBUF_TRUNC(offset_end-1, ltt_buf)
478 - SUBBUF_TRUNC(consumed_old, ltt_buf))
479 >= ltt_buf->alloc_size)
480 consumed_new = SUBBUF_ALIGN(consumed_old, ltt_buf);
481 else {
482 consumed_new = consumed_old;
483 break;
484 }
485 } while(atomic_cmpxchg(&ltt_buf->consumed, consumed_old, consumed_new)
486 != consumed_old);
487
488 if(consumed_old != consumed_new) {
489 /* Reader pushed : we are the winner of the push, we can therefore
490 reequilibrate reserve and commit. Atomic increment of the commit
491 count permits other writers to play around with this variable
492 before us. We keep track of corrupted_subbuffers even in overwrite mode :
493 we never want to write over a non completely committed sub-buffer :
494 possible causes : the buffer size is too low compared to the unordered
495 data input, or there is a writer who died between the reserve and the
496 commit. */
497 if(reserve_commit_diff) {
498 /* We have to alter the sub-buffer commit count : a sub-buffer is
499 corrupted. We do not deliver it. */
500 atomic_add(reserve_commit_diff,
501 &ltt_buf->commit_count[SUBBUF_INDEX(offset_begin, ltt_buf)]);
502 atomic_inc(&ltt_buf->corrupted_subbuffers);
503 }
504 }
505
506
507 if(end_switch_old) {
508 /* old subbuffer */
509 /* Concurrency safe because we are the last and only thread to alter this
510 sub-buffer. As long as it is not delivered and read, no other thread can
511 alter the offset, alter the reserve_count or call the
512 client_buffer_end_callback on this sub-buffer.
513 The only remaining threads could be the ones with pending commits. They
514 will have to do the deliver themself.
515 Not concurrency safe in overwrite mode. We detect corrupted subbuffers
516 with commit and reserve counts. We keep a corrupted sub-buffers count
517 and push the readers across these sub-buffers.
518 Not concurrency safe if a writer is stalled in a subbuffer and
519 another writer switches in, finding out it's corrupted. The result will
520 be than the old (uncommited) subbuffer will be declared corrupted, and
521 that the new subbuffer will be declared corrupted too because of the
522 commit count adjustment.
523 Note : offset_old should never be 0 here.*/
524 ltt_buffer_end_callback(ltt_buf, *tsc, offset_old,
525 SUBBUF_INDEX((offset_old-1), ltt_buf));
526 /* Setting this reserve_count will allow the sub-buffer to be delivered by
527 the last committer. */
528 reserve_count =
529 atomic_add_return((SUBBUF_OFFSET((offset_old-1), ltt_buf)+1),
530 &ltt_buf->reserve_count[SUBBUF_INDEX((offset_old-1), ltt_buf)]);
531 if(reserve_count
532 == atomic_read(&ltt_buf->commit_count[SUBBUF_INDEX((offset_old-1),
533 ltt_buf)])) {
534 ltt_deliver_callback(ltt_buf, SUBBUF_INDEX((offset_old-1), ltt_buf),
535 NULL);
536 }
537 }
538
539 if(begin_switch) {
540 /* New sub-buffer */
541 /* This code can be executed unordered : writers may already have written
542 to the sub-buffer before this code gets executed, caution. */
543 /* The commit makes sure that this code is executed before the deliver
544 of this sub-buffer */
545 ltt_buffer_begin_callback(ltt_buf, *tsc, SUBBUF_INDEX(offset_begin, ltt_buf));
546 commit_count = atomic_add_return(ltt_subbuf_header_len(ltt_buf),
547 &ltt_buf->commit_count[SUBBUF_INDEX(offset_begin, ltt_buf)]);
548 /* Check if the written buffer has to be delivered */
549 if(commit_count
550 == atomic_read(&ltt_buf->reserve_count[SUBBUF_INDEX(offset_begin,
551 ltt_buf)])) {
552 ltt_deliver_callback(ltt_buf, SUBBUF_INDEX(offset_begin, ltt_buf), NULL);
553 }
554 }
555
556 if(end_switch_current) {
557 /* current subbuffer */
558 /* Concurrency safe because we are the last and only thread to alter this
559 sub-buffer. As long as it is not delivered and read, no other thread can
560 alter the offset, alter the reserve_count or call the
561 client_buffer_end_callback on this sub-buffer.
562 The only remaining threads could be the ones with pending commits. They
563 will have to do the deliver themself.
564 Not concurrency safe in overwrite mode. We detect corrupted subbuffers
565 with commit and reserve counts. We keep a corrupted sub-buffers count
566 and push the readers across these sub-buffers.
567 Not concurrency safe if a writer is stalled in a subbuffer and
568 another writer switches in, finding out it's corrupted. The result will
569 be than the old (uncommited) subbuffer will be declared corrupted, and
570 that the new subbuffer will be declared corrupted too because of the
571 commit count adjustment. */
572 ltt_buffer_end_callback(ltt_buf, *tsc, offset_end,
573 SUBBUF_INDEX((offset_end-1), ltt_buf));
574 /* Setting this reserve_count will allow the sub-buffer to be delivered by
575 the last committer. */
576 reserve_count =
577 atomic_add_return((SUBBUF_OFFSET((offset_end-1), ltt_buf)+1),
578 &ltt_buf->reserve_count[SUBBUF_INDEX((offset_end-1), ltt_buf)]);
579 if(reserve_count
580 == atomic_read(&ltt_buf->commit_count[SUBBUF_INDEX((offset_end-1),
581 ltt_buf)])) {
582 ltt_deliver_callback(ltt_buf, SUBBUF_INDEX((offset_end-1), ltt_buf), NULL);
583 }
584 }
585
586 *slot_size = size;
587
588 //BUG_ON(*slot_size != (data_size + *before_hdr_pad + *after_hdr_pad + *header_size));
589 //BUG_ON(*slot_size != (offset_end - offset_begin));
590
591 return ltt_buf->start + BUFFER_OFFSET(offset_begin, ltt_buf);
592 }
593
594
595 /* ltt_commit_slot
596 *
597 * Atomic unordered slot commit. Increments the commit count in the
598 * specified sub-buffer, and delivers it if necessary.
599 *
600 * Parameters:
601 *
602 * @buf : the buffer to commit to.
603 * @reserved : address of the beginnig of the reserved slot.
604 * @slot_size : size of the reserved slot.
605 *
606 */
607 static inline void __attribute__((no_instrument_function)) ltt_commit_slot(
608 struct ltt_buf *ltt_buf,
609 void *reserved,
610 unsigned int slot_size)
611 {
612 unsigned int offset_begin = reserved - ltt_buf->start;
613 int commit_count;
614
615 commit_count = atomic_add_return(slot_size,
616 &ltt_buf->commit_count[SUBBUF_INDEX(offset_begin,
617 ltt_buf)]);
618
619 /* Check if all commits have been done */
620 if(commit_count ==
621 atomic_read(&ltt_buf->reserve_count[SUBBUF_INDEX(offset_begin, ltt_buf)])) {
622 ltt_deliver_callback(ltt_buf, SUBBUF_INDEX(offset_begin, ltt_buf), NULL);
623 }
624 }
625
626
627 #endif //LTT_TRACE_FAST
628 #endif //LTT_TRACE
629 #endif //_LTT_USERTRACE_FAST_H
This page took 0.04222 seconds and 5 git commands to generate.