litl 0.1.9
Loading...
Searching...
No Matches
litl_write.c
Go to the documentation of this file.
1/* -*- c-file-style: "GNU" -*- */
2/*
3 * Copyright © Télécom SudParis.
4 * See COPYING in top-level directory.
5 */
6
7#define _GNU_SOURCE
8#include <stdio.h>
9#include <stdlib.h>
10#include <string.h>
11#include <math.h>
12#include <pthread.h>
13#include <sys/utsname.h>
14#include <fcntl.h>
15#include <unistd.h>
16#include <errno.h>
17#include <assert.h>
18#include <sys/mman.h>
19
20#include "litl_timer.h"
21#include "litl_tools.h"
22#include "litl_write.h"
23
24/*
25 * Adds a header to the trace file with the information regarding:
26 * - OS
27 * - Processor type
28 * - Version of LiTL
29 */
30static void __litl_write_add_trace_header(litl_write_trace_t* trace) {
31 struct utsname uts;
32
33 // allocate memory for the trace header
34 trace->header_ptr = (litl_buffer_t) malloc(trace->header_size);
35 if (!trace->header_ptr) {
36 perror("Could not allocate memory for the trace header!");
37 exit(EXIT_FAILURE);
38 }
39 trace->header = trace->header_ptr;
40 memset(trace->header_ptr, 0, trace->header_size);
41 if (uname(&uts) < 0)
42 perror("Could not use uname()!");
43
44 // add a general header
45 // version of LiTL
46 sprintf((char*) ((litl_general_header_t *) trace->header)->litl_ver, "%s",
47 VERSION);
48 // system information
49 sprintf((char*) ((litl_general_header_t *) trace->header)->sysinfo,
50 "%s %s %s %s %s", uts.sysname, uts.nodename, uts.release, uts.version,
51 uts.machine);
52 // a number of processes
53 ((litl_general_header_t *) trace->header)->nb_processes = 1;
54 // move pointer
55 trace->header += sizeof(litl_general_header_t);
56
57 // add a process-specific header
58 // by default one trace file contains events only of one process
59 char* filename = strrchr(trace->filename, '/');
60 filename++;
61 sprintf((char*) ((litl_process_header_t *) trace->header)->process_name, "%s",
62 filename);
63 ((litl_process_header_t *) trace->header)->nb_threads = trace->nb_threads;
64 ((litl_process_header_t *) trace->header)->header_nb_threads =
65 trace->nb_threads;
66 ((litl_process_header_t *) trace->header)->buffer_size = trace->buffer_size;
67 ((litl_process_header_t *) trace->header)->trace_size = 0;
68 ((litl_process_header_t *) trace->header)->offset =
70
71 // header_size stores the position of nb_threads in the trace file
72 trace->header_size = sizeof(litl_general_header_t)
73 + 256 * sizeof(litl_data_t);
74 // move pointer
75 trace->header += sizeof(litl_process_header_t);
76}
77
78/*
79 * Initializes the trace buffer
80 */
83 litl_write_trace_t* trace;
84
85 trace = (litl_write_trace_t*) malloc(sizeof(litl_write_trace_t));
86 if (!trace) {
87 perror("Could not allocate memory for the trace!");
88 exit(EXIT_FAILURE);
89 }
90
91 // set variables
92 trace->filename = NULL;
93 trace->general_offset = 0;
94 trace->is_header_flushed = 0;
95
96 // set the buffer size using the environment variable.
97 // If the variable is not specified, use the provided value
98 char* str = getenv("LITL_BUFFER_SIZE");
99 if (str != NULL )
100 trace->buffer_size = atoi(str);
101 else
102 trace->buffer_size = buf_size;
103
104 trace->is_buffer_full = 0;
105 trace->nb_allocated_buffers = 256;
106 trace->buffers = malloc(
107 sizeof(litl_write_buffer_t*) * trace->nb_allocated_buffers);
108 if (!trace->buffers) {
109 perror("Could not allocate memory for the threads!");
110 exit(EXIT_FAILURE);
111 }
112
113 for (i = 0; i < trace->nb_allocated_buffers; i++) {
114 // initialize the array already_flushed
115 trace->buffers[i] = malloc(sizeof(litl_write_buffer_t));
116 if (!trace->buffers[i]) {
117 perror("Could not allocate memory for a thread\n");
118 exit(EXIT_FAILURE);
119 }
120 trace->buffers[i]->already_flushed = 0;
121
122 // initialize tids by zeros; this is needed for __is_tid and __find_slot
123 trace->buffers[i]->tid = 0;
124 }
125 trace->nb_threads = 0;
126
127 // initialize the timing mechanism
129
130 assert(pthread_key_create(&trace->index, NULL ) == 0);
131
132 // set trace->allow_buffer_flush using the environment variable.
133 // By default the buffer flushing is disabled
135 str = getenv("LITL_BUFFER_FLUSH");
136 if (str) {
137 if(strcmp(str, "0") == 0)
139 else
141 }
142
143 // set trace->allow_thread_safety using the environment variable.
144 // By default thread safety is enabled
146 str = getenv("LITL_THREAD_SAFETY");
147 if (str && (strcmp(str, "0") == 0))
149
150 if (trace->allow_thread_safety)
151 pthread_mutex_init(&trace->lock_litl_flush, NULL );
152 pthread_mutex_init(&trace->lock_buffer_init, NULL );
153
154 // set trace->allow_tid_recording using the environment variable.
155 // By default tid recording is enabled
157 str = getenv("LITL_TID_RECORDING");
158 if (str && (strcmp(str, "0") == 0))
160
161 trace->is_recording_paused = 0;
162 trace->is_litl_initialized = 1;
163
164 return trace;
165}
166
167/*
168 * Computes the size of data in the trace header
169 */
170static litl_size_t __litl_write_get_header_size(litl_write_trace_t* trace) {
171 return (trace->header - trace->header_ptr);
172}
173
174/*
175 * Computes the size of data in buffer
176 */
177static litl_size_t __litl_write_get_buffer_size(litl_write_trace_t* trace,
178 litl_med_size_t pos) {
179 return (trace->buffers[pos]->buffer - trace->buffers[pos]->buffer_ptr);
180}
181
182/*
183 * Activates buffer flush
184 */
188
189/*
190 * Deactivates buffer flush. By default, it is activated
191 */
195
196/*
197 * Activate thread safety. By default it is deactivated
198 */
202
203/*
204 * Deactivates thread safety
205 */
209
210/*
211 * Activates recording tid. By default it is deactivated
212 */
216
217/*
218 * Deactivates recording tid
219 */
223
224/*
225 * Pauses the event recording
226 */
228 if (trace)
229 trace->is_recording_paused = 1;
230}
231
232/*
233 * Resumes the event recording
234 */
236 if (trace)
237 trace->is_recording_paused = 0;
238}
239
240/*
241 * Sets a new name for the trace file
242 */
243void litl_write_set_filename(litl_write_trace_t* trace, char* filename) {
244 if (trace->filename) {
245 if (trace->is_header_flushed)
246 fprintf(
247 stderr,
248 "Warning: changing the trace file name to %s after some events have been saved in file %s\n",
249 filename, trace->filename);
250 free(trace->filename);
251 }
252
253 // check whether the file name was set. If no, set it by default trace name.
254 if (filename == NULL )
255 sprintf(filename, "/tmp/%s_%s", getenv("USER"), "litl_log_1");
256
257 if (asprintf(&trace->filename, "%s", filename) == -1) {
258 perror("Error: Cannot set the filename for recording events!\n");
259 exit(EXIT_FAILURE);
260 }
261}
262
263/*
264 * Records an event with offset only
265 */
266static void __litl_write_probe_offset(litl_write_trace_t* trace,
267 litl_med_size_t index) {
268 if (!trace->is_litl_initialized || trace->is_recording_paused)
269 return;
270
271 litl_t* cur_ptr = (litl_t *) trace->buffers[index]->buffer;
272 cur_ptr->time = 0;
273 cur_ptr->code = LITL_OFFSET_CODE;
274 cur_ptr->type = LITL_TYPE_REGULAR;
275 cur_ptr->parameters.offset.nb_params = 1;
276 cur_ptr->parameters.offset.offset = 0;
277
278 trace->buffers[index]->buffer += __litl_get_gen_event_size(cur_ptr);
279}
280
281/* Open the trace file. If the file already exists, delete it first
282 */
283static void __litl_open_new_file(litl_write_trace_t* trace) {
284 /* if file exist. delete it first */
285 if ((trace->f_handle = open(trace->filename, O_WRONLY | O_CREAT | O_EXCL, 0644))
286 < 0) {
287
288 if(errno == EEXIST) {
289 /* file already exist. Delete it and open it */
290 if(unlink(trace->filename) < 0 ){
291 perror("Cannot delete trace file");
292 exit(EXIT_FAILURE);
293 }
294 if ((trace->f_handle = open(trace->filename, O_WRONLY | O_CREAT | O_EXCL, 0644))
295 < 0) {
296 perror("Cannot open trace file");
297 exit(EXIT_FAILURE);
298 }
299 } else {
300 fprintf(stderr, "Cannot open %s\n", trace->filename);
301 exit(EXIT_FAILURE);
302 }
303 }
304}
305
306/*
307 * Write the header on the disk
308 */
309static void __litl_write_update_header(litl_write_trace_t* trace) {
310 // write the trace header to the trace file
311 assert(trace->f_handle >= 0);
312 lseek(trace->f_handle, 0, SEEK_SET);
313
314 if (write(trace->f_handle, trace->header_ptr,
315 __litl_write_get_header_size(trace)) == -1) {
316 perror(
317 "Flushing the buffer. Could not write measured data to the trace file!");
318 exit(EXIT_FAILURE);
319 }
320}
321
322/*
323 * Update the header and flush it to disk
324 */
325static void __litl_write_flush_header(litl_write_trace_t* trace) {
326
327 if (!trace->is_header_flushed) {
328 // open the trace file
329 __litl_open_new_file(trace);
330
331 // add a header to the trace file
332 trace->header_size = sizeof(litl_general_header_t)
333 + sizeof(litl_process_header_t)
334 + (trace->nb_threads + 1) * sizeof(litl_thread_pair_t);
335 __litl_write_add_trace_header(trace);
336
337 // add information about each working thread: (tid, offset)
339 for (i = 0; i < trace->nb_threads; i++) {
340 ((litl_thread_pair_t *) trace->header)->tid = trace->buffers[i]->tid;
341 ((litl_thread_pair_t *) trace->header)->offset = 0;
342
343 trace->header += sizeof(litl_thread_pair_t);
344
345 // save the position of offset inside the trace file
346 trace->buffers[i]->offset = __litl_write_get_header_size(trace)
347 - sizeof(litl_offset_t);
348 trace->buffers[i]->already_flushed = 1;
349 }
350
351 // offset indicates the position of offset to the next slot of
352 // pairs (tid, offset) within the trace file
353 trace->header_offset = __litl_write_get_header_size(trace);
354
355 // specify the last slot of pairs (offset == 0)
356 litl_thread_pair_t *thread_pair = (litl_thread_pair_t *) trace->header;
357 trace->header += sizeof(litl_thread_pair_t);
358 thread_pair->tid = 0;
359 thread_pair->offset = 0;
360
361 // write the trace header to the trace file
362 __litl_write_update_header(trace);
363
364 trace->general_offset = __litl_write_get_header_size(trace);
365
366 trace->header_nb_threads = trace->nb_threads;
367 trace->threads_offset = 0;
368 trace->nb_slots = 0;
369
370 trace->is_header_flushed = 1;
371 }
372}
373
374
375/*
376 * Write the thread-specific header to disk
377 */
378static void __litl_write_flush_thread_header(litl_write_trace_t* trace,
379 litl_med_size_t index,
380 litl_offset_t header_size) {
382 int res;
383 // when more buffers to store threads information is required
384 if (trace->nb_threads
385 > (trace->header_nb_threads + NBTHREADS * trace->nb_slots)) {
386
387 // updated the offset from the previous slot
388 lseek(trace->f_handle, trace->header_offset + sizeof(litl_tid_t),
389 SEEK_SET);
390 offset = trace->general_offset - header_size;
391 res = write(trace->f_handle, &offset, sizeof(litl_offset_t));
392 assert(res>=0);
393
394 // reserve a new slot for pairs (tid, offset)
395 trace->header_offset = trace->general_offset;
396 trace->threads_offset = trace->header_offset;
397 trace->general_offset += (NBTHREADS + 1) * sizeof(litl_thread_pair_t);
398
399 trace->nb_slots++;
400 }
401
402 // add a new pair (tid, offset)
403 lseek(trace->f_handle, trace->header_offset, SEEK_SET);
404 res = write(trace->f_handle, &trace->buffers[index]->tid,
405 sizeof(litl_tid_t));
406 assert(res >= 0);
407 offset = trace->general_offset - header_size;
408 res = write(trace->f_handle, &offset, sizeof(litl_offset_t));
409 assert(res >= 0);
410
411 // add an indicator to specify the last slot of pairs (offset == 0)
412 // TODO: how to optimize this and write only once at the end of the slot
413 offset = 0;
414 res = write(trace->f_handle, &offset, sizeof(litl_tid_t));
415 assert(res >= 0);
416 res = write(trace->f_handle, &offset, sizeof(litl_offset_t));
417 assert(res >= 0);
418
419 trace->header_offset += sizeof(litl_thread_pair_t);
420 trace->buffers[index]->already_flushed = 1;
421
422 // updated the number of threads
423 // TODO: perform update only once 'cause there is duplication
424 lseek(trace->f_handle, trace->header_size, SEEK_SET);
425 res = write(trace->f_handle, &trace->nb_threads, sizeof(litl_med_size_t));
426 assert(res >= 0);
427}
428
429/*
430 * Update the thread-specific header and write it to disk
431 */
432static void __litl_write_update_thread_header(litl_write_trace_t* trace,
433 litl_med_size_t index,
434 litl_offset_t header_size) {
435 // update the previous offset of the current thread,
436 // updating the location in the file
437 lseek(trace->f_handle, trace->buffers[index]->offset, SEEK_SET);
438 litl_offset_t offset = trace->general_offset - header_size;
439 int res = write(trace->f_handle, &offset, sizeof(litl_offset_t));
440 assert(res >= 0);
441}
442
443/*
444 * Writes the recorded events from the buffer to the trace file
445 */
446static void __litl_write_flush_buffer(litl_write_trace_t* trace,
447 litl_med_size_t index) {
448 int res __attribute__ ((__unused__));
449 litl_offset_t header_size;
450 if (!trace->is_litl_initialized)
451 return;
452
453 if (trace->allow_thread_safety)
454 pthread_mutex_lock(&trace->lock_litl_flush);
455
456 if (!trace->is_header_flushed) {
457 /* flush the header to disk */
458 __litl_write_flush_header(trace);
459 }
460
461 header_size = sizeof(litl_general_header_t) + sizeof(litl_process_header_t);
462 // handle the situation when some threads start after the header was flushed
463 if (!trace->buffers[index]->already_flushed) {
464 __litl_write_flush_thread_header(trace, index, header_size);
465 } else {
466 __litl_write_update_thread_header(trace, index, header_size);
467 }
468
469 // add an event with offset
470 __litl_write_probe_offset(trace, index);
471 lseek(trace->f_handle, trace->general_offset, SEEK_SET);
472 if (write(trace->f_handle, trace->buffers[index]->buffer_ptr,
473 __litl_write_get_buffer_size(trace, index)) == -1) {
474 perror(
475 "Flushing the buffer. Could not write measured data to the trace file!");
476 exit(EXIT_FAILURE);
477 }
478
479 // update the general_offset
480 trace->general_offset += __litl_write_get_buffer_size(trace, index);
481 // update the current offset of the thread
482 trace->buffers[index]->offset = trace->general_offset - sizeof(litl_offset_t);
483
484 if (trace->allow_thread_safety)
485 pthread_mutex_unlock(&trace->lock_litl_flush);
486
487 trace->buffers[index]->buffer = trace->buffers[index]->buffer_ptr;
488}
489
490/*
491 * Checks whether the trace buffer was allocated. If no, then allocate
492 * the buffer and, for otherwise too, returns the position of
493 * the thread buffer in the array buffer_ptr/buffer.
494 */
495static void __litl_write_allocate_buffer(litl_write_trace_t* trace) {
496 litl_med_size_t* pos;
497
498 // thread safe region
499 pthread_mutex_lock(&trace->lock_buffer_init);
500
501 pos = malloc(sizeof(litl_med_size_t));
502 *pos = trace->nb_threads;
503 int thread_id = *pos;
504 pthread_setspecific(trace->index, pos);
505 trace->nb_threads++;
506
507 if (*pos >= trace->nb_allocated_buffers) {
508 // We need to allocate a bigger array of buffers
509 void* ptr = realloc(
510 trace->buffers,
511 trace->nb_allocated_buffers * 2 * sizeof(litl_write_buffer_t*));
512 if (!ptr) {
513 perror("LiTL failed to reallocate memory for threads!\n");
514 exit(EXIT_FAILURE);
515 }
516
517 trace->buffers = ptr;
518 unsigned i;
519 for (i = trace->nb_allocated_buffers; i < 2 * trace->nb_allocated_buffers;
520 i++) {
521 trace->buffers[i] = malloc(sizeof(litl_write_buffer_t));
522 if (!trace->buffers[i]) {
523 perror("Could not allocate memory for a thread\n!");
524 exit(EXIT_FAILURE);
525 }
526 trace->buffers[i]->already_flushed = 0;
527 trace->buffers[i]->initialized = 0;
528 }
529 trace->nb_allocated_buffers *= 2;
530 }
531
532 trace->buffers[thread_id]->tid = CUR_TID;
533 trace->buffers[thread_id]->already_flushed = 0;
534
535 pthread_mutex_unlock(&trace->lock_buffer_init);
536
537 /* use mmap instead of malloc so that we can use the MAP_POPULATE option
538 that makes sure the page table is populated. This way, the page faults
539 caused by litl are sensibly reduced.
540 */
541#define USE_MMAP
542
543#ifdef USE_MMAP
545
546 int mmap_flags = MAP_SHARED|MAP_ANONYMOUS;
547
548#ifdef MAP_POPULATE
549 /* make sure the pages are in the page table. This should reduce page faults when recording events */
550 mmap_flags |= MAP_POPULATE;
551#endif
552
553 trace->buffers[thread_id]->buffer_ptr = mmap(NULL,
554 length,
555 PROT_READ|PROT_WRITE,
556 mmap_flags,
557 -1,
558 0);
559 if(trace->buffers[thread_id]->buffer_ptr == MAP_FAILED) {
560 perror("mmap");
561 }
562
563#ifdef MAP_POPULATE
564 /* touch the first pages */
565 if(length> 1024*1024)
566 length=1024*1024;
567#endif /* if MAP_POPULATE is not available, touch the whole buffer to avoid future page faults */
568 memset(trace->buffers[thread_id]->buffer_ptr, 0, length);
569
570#else /* USE_MMAP */
572 trace->buffers[thread_id]->buffer_ptr = malloc(length);
573#endif /* USE_MMAP */
574
575 if (!trace->buffers[thread_id]->buffer_ptr) {
576 perror("Could not allocate memory buffer for the thread\n!");
577 exit(EXIT_FAILURE);
578 }
579
580 // touch the memory so that it is allocated for real (otherwise, this may
581 // cause performance issues on NUMA machines)
582 memset(trace->buffers[thread_id]->buffer_ptr, 1, 1);
583 trace->buffers[thread_id]->buffer = trace->buffers[thread_id]->buffer_ptr;
584
585 trace->buffers[thread_id]->initialized = 1;
586}
587
588/*
589 * For internal use only.
590 * Allocates an event
591 */
593 litl_code_t code, int param_size) {
594 litl_med_size_t index = 0;
595 litl_t*retval = NULL;
596 litl_size_t event_size = __litl_get_event_size(type, param_size);
597
598 if (trace && trace->is_litl_initialized && !trace->is_recording_paused
599 && !trace->is_buffer_full) {
600
601 // find the thread index
602 litl_med_size_t *p_index = pthread_getspecific(trace->index);
603 if (!p_index) {
604 __litl_write_allocate_buffer(trace);
605 p_index = pthread_getspecific(trace->index);
606 if(!p_index)
607 return NULL;
608 }
609 index = *(litl_med_size_t *) p_index;
610
611 if(trace->buffers[index]->initialized == 0)
612 return NULL;
613
614 litl_write_buffer_t *p_buffer = trace->buffers[index];
615
616 // is there enough space in the buffer?
617 litl_size_t used_memory= __litl_write_get_buffer_size(trace, index);
618
619 if (used_memory+event_size < trace->buffer_size) {
620 // there is enough space for this event
621 litl_t* cur_ptr = (litl_t*) p_buffer->buffer;
622
623 // fill the event
624 cur_ptr->time = litl_get_time();
625 cur_ptr->code = code;
626 cur_ptr->type = type;
627
628 switch (type) {
630 cur_ptr->parameters.regular.nb_params = (param_size) / sizeof(litl_param_t);
631 break;
632 case LITL_TYPE_RAW:
633 cur_ptr->parameters.raw.size = param_size;
634 break;
635 case LITL_TYPE_PACKED:
636 cur_ptr->parameters.packed.size = param_size;
637 break;
638 case LITL_TYPE_OFFSET:
639 cur_ptr->parameters.offset.nb_params = param_size;
640 break;
641 default:
642 fprintf(stderr, "Unknown event type %d\n", type);
643 abort();
644 }
645
646 p_buffer->buffer += __litl_get_gen_event_size(cur_ptr);
647
648 retval = cur_ptr;
649 goto out;
650 } else if (trace->allow_buffer_flush) {
651 // not enough space. flush the buffer and retry
652 __litl_write_flush_buffer(trace, index);
653 retval = __litl_write_get_event(trace, type, code, param_size);
654 goto out;
655 } else {
656 // not enough space, but flushing is disabled so just stop recording
657 trace->is_buffer_full = 1;
658 retval = NULL ;
659 goto out;
660 }
661 }
662
663 out:
664 return retval;
665}
666
667
668/* Common function for recording a regular event.
669 * This function fills all the fiels except for the parameters
670 */
671static litl_t* __litl_write_probe_reg_common(litl_write_trace_t* trace,
672 litl_code_t code,
673 unsigned nb_params) {
674 litl_t*retval = __litl_write_get_event(trace,
676 code,
677 nb_params);
678 return retval;
679}
680
681/*
682 * Records a regular event without any arguments
683 */
685 litl_t *cur_ptr = __litl_write_probe_reg_common(trace, code, 0);
686 return cur_ptr;
687}
688
689/*
690 * Records a regular event with one argument
691 */
693 litl_param_t param1) {
694 litl_t *cur_ptr = __litl_write_probe_reg_common(trace, code, 1);
695 if(cur_ptr) {
696 cur_ptr->parameters.regular.param[0] = param1;
697 }
698 return cur_ptr;
699}
700
701/*
702 * Records a regular event with two arguments
703 */
705 litl_param_t param1, litl_param_t param2) {
706 litl_t *cur_ptr = __litl_write_probe_reg_common(trace, code, 2);
707 if(cur_ptr) {
708 cur_ptr->parameters.regular.param[0] = param1;
709 cur_ptr->parameters.regular.param[1] = param2;
710 }
711 return cur_ptr;
712}
713
714/*
715 * Records a regular event with three arguments
716 */
718 litl_param_t param1, litl_param_t param2,
719 litl_param_t param3) {
720 litl_t *cur_ptr = __litl_write_probe_reg_common(trace, code, 3);
721 if(cur_ptr) {
722 cur_ptr->parameters.regular.param[0] = param1;
723 cur_ptr->parameters.regular.param[1] = param2;
724 cur_ptr->parameters.regular.param[2] = param3;
725 }
726 return cur_ptr;
727}
728
729/*
730 * Records a regular event with four arguments
731 */
733 litl_param_t param1, litl_param_t param2,
734 litl_param_t param3, litl_param_t param4) {
735 litl_t *cur_ptr = __litl_write_probe_reg_common(trace, code, 4);
736 if(cur_ptr) {
737 cur_ptr->parameters.regular.param[0] = param1;
738 cur_ptr->parameters.regular.param[1] = param2;
739 cur_ptr->parameters.regular.param[2] = param3;
740 cur_ptr->parameters.regular.param[3] = param4;
741 }
742 return cur_ptr;
743}
744
745/*
746 * Records a regular event with five arguments
747 */
749 litl_param_t param1, litl_param_t param2,
750 litl_param_t param3, litl_param_t param4,
751 litl_param_t param5) {
752 litl_t *cur_ptr = __litl_write_probe_reg_common(trace, code, 5);
753 if(cur_ptr) {
754 cur_ptr->parameters.regular.param[0] = param1;
755 cur_ptr->parameters.regular.param[1] = param2;
756 cur_ptr->parameters.regular.param[2] = param3;
757 cur_ptr->parameters.regular.param[3] = param4;
758 cur_ptr->parameters.regular.param[4] = param5;
759 }
760 return cur_ptr;
761}
762
763/*
764 * Records a regular event with six arguments
765 */
767 litl_param_t param1, litl_param_t param2,
768 litl_param_t param3, litl_param_t param4,
769 litl_param_t param5, litl_param_t param6) {
770 litl_t *cur_ptr = __litl_write_probe_reg_common(trace, code, 6);
771 if(cur_ptr) {
772 cur_ptr->parameters.regular.param[0] = param1;
773 cur_ptr->parameters.regular.param[1] = param2;
774 cur_ptr->parameters.regular.param[2] = param3;
775 cur_ptr->parameters.regular.param[3] = param4;
776 cur_ptr->parameters.regular.param[4] = param5;
777 cur_ptr->parameters.regular.param[5] = param6;
778 }
779 return cur_ptr;
780}
781
782/*
783 * Records a regular event with seven arguments
784 */
786 litl_param_t param1, litl_param_t param2,
787 litl_param_t param3, litl_param_t param4,
788 litl_param_t param5, litl_param_t param6,
789 litl_param_t param7) {
790 litl_t *cur_ptr = __litl_write_probe_reg_common(trace, code, 7);
791 if(cur_ptr) {
792 cur_ptr->parameters.regular.param[0] = param1;
793 cur_ptr->parameters.regular.param[1] = param2;
794 cur_ptr->parameters.regular.param[2] = param3;
795 cur_ptr->parameters.regular.param[3] = param4;
796 cur_ptr->parameters.regular.param[4] = param5;
797 cur_ptr->parameters.regular.param[5] = param6;
798 cur_ptr->parameters.regular.param[6] = param7;
799 }
800 return cur_ptr;
801}
802
803/*
804 * Records a regular event with eight arguments
805 */
807 litl_param_t param1, litl_param_t param2,
808 litl_param_t param3, litl_param_t param4,
809 litl_param_t param5, litl_param_t param6,
810 litl_param_t param7, litl_param_t param8) {
811 litl_t *cur_ptr = __litl_write_probe_reg_common(trace, code, 8);
812 if(cur_ptr) {
813 cur_ptr->parameters.regular.param[0] = param1;
814 cur_ptr->parameters.regular.param[1] = param2;
815 cur_ptr->parameters.regular.param[2] = param3;
816 cur_ptr->parameters.regular.param[3] = param4;
817 cur_ptr->parameters.regular.param[4] = param5;
818 cur_ptr->parameters.regular.param[5] = param6;
819 cur_ptr->parameters.regular.param[6] = param7;
820 cur_ptr->parameters.regular.param[7] = param8;
821 }
822 return cur_ptr;
823}
824
825/*
826 * Records a regular event with nine arguments
827 */
829 litl_param_t param1, litl_param_t param2,
830 litl_param_t param3, litl_param_t param4,
831 litl_param_t param5, litl_param_t param6,
832 litl_param_t param7, litl_param_t param8,
833 litl_param_t param9) {
834 litl_t *cur_ptr = __litl_write_probe_reg_common(trace, code, 9);
835 if(cur_ptr) {
836 cur_ptr->parameters.regular.param[0] = param1;
837 cur_ptr->parameters.regular.param[1] = param2;
838 cur_ptr->parameters.regular.param[2] = param3;
839 cur_ptr->parameters.regular.param[3] = param4;
840 cur_ptr->parameters.regular.param[4] = param5;
841 cur_ptr->parameters.regular.param[5] = param6;
842 cur_ptr->parameters.regular.param[6] = param7;
843 cur_ptr->parameters.regular.param[7] = param8;
844 cur_ptr->parameters.regular.param[8] = param9;
845 }
846 return cur_ptr;
847}
848
849/*
850 * Records a regular event with ten arguments
851 */
853 litl_param_t param1, litl_param_t param2,
854 litl_param_t param3, litl_param_t param4,
855 litl_param_t param5, litl_param_t param6,
856 litl_param_t param7, litl_param_t param8,
857 litl_param_t param9, litl_param_t param10) {
858 litl_t *cur_ptr = __litl_write_probe_reg_common(trace, code, 10);
859 if(cur_ptr) {
860 cur_ptr->parameters.regular.param[0] = param1;
861 cur_ptr->parameters.regular.param[1] = param2;
862 cur_ptr->parameters.regular.param[2] = param3;
863 cur_ptr->parameters.regular.param[3] = param4;
864 cur_ptr->parameters.regular.param[4] = param5;
865 cur_ptr->parameters.regular.param[5] = param6;
866 cur_ptr->parameters.regular.param[6] = param7;
867 cur_ptr->parameters.regular.param[7] = param8;
868 cur_ptr->parameters.regular.param[8] = param9;
869 cur_ptr->parameters.regular.param[9] = param10;
870 }
871 return cur_ptr;
872}
873
874/*
875 * Records an event in a raw state, where the size is #args in the void* array.
876 * That helps to discover places where the application has crashed
877 */
879 litl_size_t size, litl_data_t data[]) {
880 litl_t* retval = __litl_write_get_event(trace,
882 code,
883 size+1);
884 if(retval) {
885 litl_size_t i;
886 for (i = 0; i < size; i++) {
887 retval->parameters.raw.data[i] = data[i];
888 }
889 retval->parameters.raw.data[size]='\0';
890 }
891 return retval;
892}
893
894/*
895 * This function finalizes the trace
896 */
899 if(!trace)
900 return;
901
902 for (i = 0; i < trace->nb_threads; i++) {
903 __litl_write_flush_buffer(trace, i);
904 }
905
906 close(trace->f_handle);
907 trace->f_handle = -1;
908
909 for (i = 0; i < trace->nb_allocated_buffers; i++) {
910 if (trace->buffers[i]->tid != 0) {
912#ifdef USE_MMAP
913 int ret = munmap(trace->buffers[i]->buffer_ptr, length);
914 assert(ret==0);
915#else
916 free(trace->buffers[i]->buffer_ptr);
917#endif
918 trace->buffers[i]->buffer_ptr = NULL;
919 } else {
920 break;
921 }
922 }
923
924 if (trace->allow_thread_safety) {
925 pthread_mutex_destroy(&trace->lock_litl_flush);
926 }
927 pthread_mutex_destroy(&trace->lock_buffer_init);
928
929 free(trace->filename);
930 trace->filename = NULL;
931 trace->is_litl_initialized = 0;
932 trace->is_header_flushed = 0;
933 free(trace);
934}
void litl_time_initialize()
Initializes the timing mechanism.
Definition litl_timer.c:138
litl_timing_method_t litl_get_time
Calls the selected timing method and get the current time in ns.
Definition litl_timer.c:37
litl_size_t __litl_get_event_size(litl_type_t type, int param_size)
Returns the size of an event (in Bytes) depending on the number or size of its parameters.
Definition litl_tools.c:22
litl_size_t __litl_get_reg_event_size(litl_data_t nb_params)
Returns the size of a regular event (in Bytes) depending on the number of its parameters.
Definition litl_tools.c:18
litl_size_t __litl_get_gen_event_size(litl_t *p_evt)
Returns the size of a general event (in Bytes) depending on its type and the number of its parameters...
Definition litl_tools.c:42
#define LITL_OFFSET_CODE
Defines the code of an event of type offset.
Definition litl_types.h:163
uint64_t litl_param_t
A data type for the non-optimized storage of parameters.
Definition litl_types.h:124
litl_type_t
The enumeration of event types.
Definition litl_types.h:180
uint8_t litl_data_t
A data type for the optimized storage of parameters.
Definition litl_types.h:157
uint32_t litl_size_t
An auxiliary data type for storing data.
Definition litl_types.h:147
uint8_t * litl_buffer_t
A data type for storing sets of events.
Definition litl_types.h:135
#define LITL_MAX_PARAMS
Defines the maximum number of parameters.
Definition litl_types.h:169
uint16_t litl_med_size_t
An auxiliary data type for the optimized storage of data.
Definition litl_types.h:152
#define NBTHREADS
Defines the maximum number of threads (pairs of tid and offset) stored in one data slot.
Definition litl_types.h:242
uint64_t litl_tid_t
A data type for storing thread IDs.
Definition litl_types.h:109
uint32_t litl_code_t
A data type for storing events codes.
Definition litl_types.h:142
#define CUR_TID
A current thread ID.
Definition litl_types.h:68
uint64_t litl_offset_t
A data type for storing offsets.
Definition litl_types.h:129
@ LITL_TYPE_RAW
Definition litl_types.h:182
@ LITL_TYPE_PACKED
Definition litl_types.h:183
@ LITL_TYPE_REGULAR
Definition litl_types.h:181
@ LITL_TYPE_OFFSET
Definition litl_types.h:184
litl_write_trace_t * litl_write_init_trace(const litl_size_t buf_size)
Initializes the trace buffer.
Definition litl_write.c:81
void litl_write_tid_recording_on(litl_write_trace_t *trace)
Enable recording tid.
Definition litl_write.c:213
void litl_write_pause_recording(litl_write_trace_t *trace)
Pauses the event recording.
Definition litl_write.c:227
void litl_write_buffer_flush_on(litl_write_trace_t *trace)
Enable buffer flush. By default, it is disabled.
Definition litl_write.c:185
void litl_write_finalize_trace(litl_write_trace_t *trace)
Finalizes the trace.
Definition litl_write.c:897
void litl_write_tid_recording_off(litl_write_trace_t *trace)
Disable recording tid. By default, it is enabled.
Definition litl_write.c:220
void litl_write_resume_recording(litl_write_trace_t *trace)
Resumes the event recording.
Definition litl_write.c:235
void litl_write_buffer_flush_off(litl_write_trace_t *trace)
Disable buffer flush.
Definition litl_write.c:192
void litl_write_set_filename(litl_write_trace_t *trace, char *filename)
Sets a new name for the trace file.
Definition litl_write.c:243
void litl_write_thread_safety_on(litl_write_trace_t *trace)
Enable thread safety.
Definition litl_write.c:199
void litl_write_thread_safety_off(litl_write_trace_t *trace)
Disable thread safety. By default, it is enabled.
Definition litl_write.c:206
litl_t * __litl_write_get_event(litl_write_trace_t *trace, litl_type_t type, litl_code_t code, int param_size)
For internal use only. Allocates an event.
Definition litl_write.c:592
litl_t * litl_write_probe_raw(litl_write_trace_t *trace, litl_code_t code, litl_size_t size, litl_data_t data[])
Records an event with data in a string format.
Definition litl_write.c:878
litl_t * litl_write_probe_reg_7(litl_write_trace_t *trace, litl_code_t code, litl_param_t param1, litl_param_t param2, litl_param_t param3, litl_param_t param4, litl_param_t param5, litl_param_t param6, litl_param_t param7)
Records a regular event with 7 parameters.
Definition litl_write.c:785
litl_t * litl_write_probe_reg_3(litl_write_trace_t *trace, litl_code_t code, litl_param_t param1, litl_param_t param2, litl_param_t param3)
Records a regular event with 3 parameters.
Definition litl_write.c:717
litl_t * litl_write_probe_reg_0(litl_write_trace_t *trace, litl_code_t code)
Records a regular event without parameters.
Definition litl_write.c:684
litl_t * litl_write_probe_reg_2(litl_write_trace_t *trace, litl_code_t code, litl_param_t param1, litl_param_t param2)
Records a regular event with 2 parameters.
Definition litl_write.c:704
litl_t * litl_write_probe_reg_1(litl_write_trace_t *trace, litl_code_t code, litl_param_t param1)
Records a regular event with 1 parameter.
Definition litl_write.c:692
litl_t * litl_write_probe_reg_5(litl_write_trace_t *trace, litl_code_t code, litl_param_t param1, litl_param_t param2, litl_param_t param3, litl_param_t param4, litl_param_t param5)
Records a regular event with 5 parameters.
Definition litl_write.c:748
litl_t * litl_write_probe_reg_6(litl_write_trace_t *trace, litl_code_t code, litl_param_t param1, litl_param_t param2, litl_param_t param3, litl_param_t param4, litl_param_t param5, litl_param_t param6)
Records a regular event with 6 parameters.
Definition litl_write.c:766
litl_t * litl_write_probe_reg_4(litl_write_trace_t *trace, litl_code_t code, litl_param_t param1, litl_param_t param2, litl_param_t param3, litl_param_t param4)
Records a regular event with 4 parameters.
Definition litl_write.c:732
litl_t * litl_write_probe_reg_9(litl_write_trace_t *trace, litl_code_t code, litl_param_t param1, litl_param_t param2, litl_param_t param3, litl_param_t param4, litl_param_t param5, litl_param_t param6, litl_param_t param7, litl_param_t param8, litl_param_t param9)
Records a regular event with 9 parameters.
Definition litl_write.c:828
litl_t * litl_write_probe_reg_10(litl_write_trace_t *trace, litl_code_t code, litl_param_t param1, litl_param_t param2, litl_param_t param3, litl_param_t param4, litl_param_t param5, litl_param_t param6, litl_param_t param7, litl_param_t param8, litl_param_t param9, litl_param_t param10)
Records a regular event with 10 parameters.
Definition litl_write.c:852
litl_t * litl_write_probe_reg_8(litl_write_trace_t *trace, litl_code_t code, litl_param_t param1, litl_param_t param2, litl_param_t param3, litl_param_t param4, litl_param_t param5, litl_param_t param6, litl_param_t param7, litl_param_t param8)
Records a regular event with 8 parameters.
Definition litl_write.c:806
litl_timer Provides a set of functions for measuring time
litl_tools Provides a set of auxiliary functions
litl_write Provides a set of functions for recording events in a trace file
A general data structure that corresponds to the header of a trace file.
Definition litl_types.h:249
A general data structure that corresponds to the header of a trace file.
Definition litl_types.h:260
A general structure of LiTL event type.
Definition litl_types.h:192
union litl_t::@0 parameters
litl_data_t nb_params
Definition litl_types.h:206
litl_size_t size
Definition litl_types.h:214
litl_param_t offset
Definition litl_types.h:231
struct litl_t::@0::@1 regular
struct litl_t::@0::@2 raw
litl_time_t time
Definition litl_types.h:193
struct litl_t::@0::@3 packed
litl_code_t code
Definition litl_types.h:194
litl_param_t param[LITL_MAX_PARAMS]
Definition litl_types.h:207
litl_type_t type
Definition litl_types.h:195
litl_data_t data[LITL_MAX_DATA]
Definition litl_types.h:215
A data structure for pairs (tid, offset) stored in the trace header.
Definition litl_types.h:273
Thread-specific buffer.
Definition litl_types.h:292
litl_buffer_t buffer
Definition litl_types.h:294
litl_buffer_t buffer_ptr
Definition litl_types.h:293
litl_data_t already_flushed
Definition litl_types.h:299
litl_offset_t offset
Definition litl_types.h:297
A data structure for recording events.
Definition litl_types.h:307
litl_data_t allow_thread_safety
Definition litl_types.h:337
litl_buffer_t header
Definition litl_types.h:314
pthread_mutex_t lock_litl_flush
Definition litl_types.h:331
litl_buffer_t header_ptr
Definition litl_types.h:313
litl_offset_t general_offset
Definition litl_types.h:311
litl_size_t header_size
Definition litl_types.h:315
litl_size_t buffer_size
Definition litl_types.h:326
litl_data_t allow_buffer_flush
Definition litl_types.h:336
litl_write_buffer_t ** buffers
Definition litl_types.h:324
litl_data_t is_litl_initialized
Definition litl_types.h:334
litl_param_t threads_offset
Definition litl_types.h:322
litl_data_t is_header_flushed
Definition litl_types.h:318
volatile litl_data_t is_recording_paused
Definition litl_types.h:335
litl_data_t allow_tid_recording
Definition litl_types.h:338
litl_data_t is_buffer_full
Definition litl_types.h:327
litl_size_t nb_allocated_buffers
Definition litl_types.h:325
pthread_key_t index
Definition litl_types.h:330
litl_size_t header_offset
Definition litl_types.h:316
pthread_mutex_t lock_buffer_init
Definition litl_types.h:332
litl_med_size_t nb_slots
Definition litl_types.h:321
litl_med_size_t nb_threads
Definition litl_types.h:320
litl_med_size_t header_nb_threads
Definition litl_types.h:317
An offset event.