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