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