litl  0.1.9
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  */
30 static 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  */
170 static 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  */
177 static 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  */
186  trace->allow_buffer_flush = 1;
187 }
188 
189 /*
190  * Deactivates buffer flush. By default, it is activated
191  */
193  trace->allow_buffer_flush = 0;
194 }
195 
196 /*
197  * Activate thread safety. By default it is deactivated
198  */
200  trace->allow_thread_safety = 1;
201 }
202 
203 /*
204  * Deactivates thread safety
205  */
207  trace->allow_thread_safety = 0;
208 }
209 
210 /*
211  * Activates recording tid. By default it is deactivated
212  */
214  trace->allow_tid_recording = 1;
215 }
216 
217 /*
218  * Deactivates recording tid
219  */
221  trace->allow_tid_recording = 0;
222 }
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  */
243 void 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  */
266 static 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  */
283 static 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  */
309 static 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  */
325 static 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)
338  litl_med_size_t i;
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  */
378 static 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  */
432 static 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  */
446 static 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  */
495 static 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) {
629  case LITL_TYPE_REGULAR:
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  */
671 static 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  */
898  litl_med_size_t i;
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
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
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_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_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_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_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_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_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_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_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_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_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_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_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_type_t type
Definition: litl_types.h:195
A data structure for pairs (tid, offset) stored in the trace header.
Definition: litl_types.h:273
litl_offset_t offset
Definition: litl_types.h:275
litl_tid_t tid
Definition: litl_types.h:274
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.