litl  0.1.3
 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 disabled
145  str = getenv("LITL_BUFFER_FLUSH");
146  if (str) {
147  if(strcmp(str, "0") == 0)
149  else
151  }
152 
153  // set trace->allow_thread_safety using the environment variable.
154  // By default thread safety is enabled
156  str = getenv("LITL_THREAD_SAFETY");
157  if (str && (strcmp(str, "0") == 0))
159 
160  if (trace->allow_thread_safety)
161  pthread_mutex_init(&trace->lock_litl_flush, NULL );
162  pthread_mutex_init(&trace->lock_buffer_init, NULL );
163 
164  // set trace->allow_tid_recording using the environment variable.
165  // By default tid recording is enabled
167  str = getenv("LITL_TID_RECORDING");
168  if (str && (strcmp(str, "0") == 0))
170 
171  trace->is_recording_paused = 0;
172  trace->is_litl_initialized = 1;
173 
174  return trace;
175 }
176 
177 /*
178  * Computes the size of data in the trace header
179  */
180 static litl_size_t __litl_write_get_header_size(litl_write_trace_t* trace) {
181  return (trace->header - trace->header_ptr);
182 }
183 
184 /*
185  * Computes the size of data in buffer
186  */
187 static litl_size_t __litl_write_get_buffer_size(litl_write_trace_t* trace,
188  litl_med_size_t pos) {
189  return (trace->buffers[pos]->buffer - trace->buffers[pos]->buffer_ptr);
190 }
191 
192 /*
193  * Activates buffer flush
194  */
196  trace->allow_buffer_flush = 1;
197 }
198 
199 /*
200  * Deactivates buffer flush. By default, it is activated
201  */
203  trace->allow_buffer_flush = 0;
204 }
205 
206 /*
207  * Activate thread safety. By default it is deactivated
208  */
210  trace->allow_thread_safety = 1;
211 }
212 
213 /*
214  * Deactivates thread safety
215  */
217  trace->allow_thread_safety = 0;
218 }
219 
220 /*
221  * Activates recording tid. By default it is deactivated
222  */
224  trace->allow_tid_recording = 1;
225 }
226 
227 /*
228  * Deactivates recording tid
229  */
231  trace->allow_tid_recording = 0;
232 }
233 
234 /*
235  * Pauses the event recording
236  */
238  if (trace)
239  trace->is_recording_paused = 1;
240 }
241 
242 /*
243  * Resumes the event recording
244  */
246  if (trace)
247  trace->is_recording_paused = 0;
248 }
249 
250 /*
251  * Sets a new name for the trace file
252  */
253 void litl_write_set_filename(litl_write_trace_t* trace, char* filename) {
254  if (trace->filename) {
255  if (trace->is_header_flushed)
256  fprintf(
257  stderr,
258  "Warning: changing the trace file name to %s after some events have been saved in file %s\n",
259  filename, trace->filename);
260  free(trace->filename);
261  }
262 
263  // check whether the file name was set. If no, set it by default trace name.
264  if (filename == NULL )
265  sprintf(filename, "/tmp/%s_%s", getenv("USER"), "litl_log_1");
266 
267  if (asprintf(&trace->filename, "%s", filename) == -1) {
268  perror("Error: Cannot set the filename for recording events!\n");
269  exit(EXIT_FAILURE);
270  }
271 }
272 
273 /*
274  * Records an event with offset only
275  */
276 static void __litl_write_probe_offset(litl_write_trace_t* trace,
277  litl_med_size_t index) {
278  if (!trace->is_litl_initialized || trace->is_recording_paused
279  || trace->is_buffer_full)
280  return;
281  // litl_t* cur_ptr = litl_cmpxchg((uint8_t**) &trace->buffer[index],
282  // LITL_BASE_SIZE + sizeof(litl_param_t));
283  litl_t* cur_ptr = (litl_t *) trace->buffers[index]->buffer;
284 
285  cur_ptr->time = 0;
286  cur_ptr->code = LITL_OFFSET_CODE;
287  cur_ptr->type = LITL_TYPE_REGULAR;
288  cur_ptr->parameters.offset.nb_params = 1;
289  cur_ptr->parameters.offset.offset = 0;
290  trace->buffers[index]->buffer += LITL_BASE_SIZE + sizeof(litl_param_t);
291 }
292 
293 /*
294  * Writes the recorded events from the buffer to the trace file
295  */
296 static void __litl_write_flush_buffer(litl_write_trace_t* trace,
297  litl_med_size_t index) {
298  int res __attribute__ ((__unused__));
299  litl_offset_t offset, header_size;
300 
301  if (!trace->is_litl_initialized)
302  return;
303 
304  if (trace->allow_thread_safety)
305  pthread_mutex_lock(&trace->lock_litl_flush);
306 
307  if (!trace->is_header_flushed) {
308  // check whether the trace file can be opened
309  if ((trace->f_handle = open(trace->filename, O_WRONLY | O_CREAT, 0644))
310  < 0) {
311  fprintf(stderr, "Cannot open %s\n", trace->filename);
312  exit(EXIT_FAILURE);
313  }
314 
315  // add a header to the trace file
316  trace->header_size = sizeof(litl_general_header_t)
317  + sizeof(litl_process_header_t)
318  + (trace->nb_threads + 1) * sizeof(litl_thread_pair_t);
319  __litl_write_add_trace_header(trace);
320 
321  // add information about each working thread: (tid, offset)
322  litl_med_size_t i;
323  for (i = 0; i < trace->nb_threads; i++) {
324  ((litl_thread_pair_t *) trace->header)->tid = trace->buffers[i]->tid;
325  ((litl_thread_pair_t *) trace->header)->offset = 0;
326 
327  trace->header += sizeof(litl_thread_pair_t);
328 
329  // save the position of offset inside the trace file
330  trace->buffers[i]->offset = __litl_write_get_header_size(trace)
331  - sizeof(litl_offset_t);
332  trace->buffers[i]->already_flushed = 1;
333  }
334 
335  // offset indicates the position of offset to the next slot of
336  // pairs (tid, offset) within the trace file
337  trace->header_offset = __litl_write_get_header_size(trace);
338 
339  // specify the last slot of pairs (offset == 0)
340  ((litl_thread_pair_t *) trace->header)->tid = 0;
341  ((litl_thread_pair_t *) trace->header)->offset = 0;
342  trace->header += sizeof(litl_thread_pair_t);
343 
344  // write the trace header to the trace file
345  if (write(trace->f_handle, trace->header_ptr,
346  __litl_write_get_header_size(trace)) == -1) {
347  perror(
348  "Flushing the buffer. Could not write measured data to the trace file!");
349  exit(EXIT_FAILURE);
350  }
351 
352  trace->general_offset = __litl_write_get_header_size(trace);
353 
354  trace->header_nb_threads = trace->nb_threads;
355  trace->threads_offset = 0;
356  trace->nb_slots = 0;
357 
358  trace->is_header_flushed = 1;
359  }
360 
361  header_size = sizeof(litl_general_header_t) + sizeof(litl_process_header_t);
362  // handle the situation when some threads start after the header was flushed
363  if (!trace->buffers[index]->already_flushed) {
364 
365  // when more buffers to store threads information is required
366  if (trace->nb_threads
367  > (trace->header_nb_threads + NBTHREADS * trace->nb_slots)) {
368 
369  // updated the offset from the previous slot
370  lseek(trace->f_handle, trace->header_offset + sizeof(litl_tid_t),
371  SEEK_SET);
372  offset = trace->general_offset - header_size;
373  res = write(trace->f_handle, &offset, sizeof(litl_offset_t));
374 
375  // reserve a new slot for pairs (tid, offset)
376  trace->header_offset = trace->general_offset;
377  trace->threads_offset = trace->header_offset;
378  trace->general_offset += (NBTHREADS + 1) * sizeof(litl_thread_pair_t);
379 
380  trace->nb_slots++;
381  }
382 
383  // add a new pair (tid, offset)
384  lseek(trace->f_handle, trace->header_offset, SEEK_SET);
385  res = write(trace->f_handle, &trace->buffers[index]->tid,
386  sizeof(litl_tid_t));
387  offset = trace->general_offset - header_size;
388  res = write(trace->f_handle, &offset, sizeof(litl_offset_t));
389 
390  // add an indicator to specify the last slot of pairs (offset == 0)
391  // TODO: how to optimize this and write only once at the end of the slot
392  offset = 0;
393  res = write(trace->f_handle, &offset, sizeof(litl_tid_t));
394  res = write(trace->f_handle, &offset, sizeof(litl_offset_t));
395 
396  trace->header_offset += sizeof(litl_thread_pair_t);
397  trace->buffers[index]->already_flushed = 1;
398 
399  // updated the number of threads
400  // TODO: perform update only once 'cause there is duplication
401  lseek(trace->f_handle, trace->header_size, SEEK_SET);
402  res = write(trace->f_handle, &trace->nb_threads, sizeof(litl_med_size_t));
403  lseek(trace->f_handle, trace->general_offset, SEEK_SET);
404  } else {
405  // update the previous offset of the current thread,
406  // updating the location in the file
407  lseek(trace->f_handle, trace->buffers[index]->offset, SEEK_SET);
408  offset = trace->general_offset - header_size;
409  res = write(trace->f_handle, &offset, sizeof(litl_offset_t));
410  lseek(trace->f_handle, trace->general_offset, SEEK_SET);
411  }
412 
413  // add an event with offset
414  __litl_write_probe_offset(trace, index);
415  if (write(trace->f_handle, trace->buffers[index]->buffer_ptr,
416  __litl_write_get_buffer_size(trace, index)) == -1) {
417  perror(
418  "Flushing the buffer. Could not write measured data to the trace file!");
419  exit(EXIT_FAILURE);
420  }
421 
422  // update the general_offset
423  trace->general_offset += __litl_write_get_buffer_size(trace, index);
424  // update the current offset of the thread
425  trace->buffers[index]->offset = trace->general_offset - sizeof(litl_offset_t);
426 
427  if (trace->allow_thread_safety)
428  pthread_mutex_unlock(&trace->lock_litl_flush);
429 
430  trace->buffers[index]->buffer = trace->buffers[index]->buffer_ptr;
431 }
432 
433 /*
434  * Checks whether the trace buffer was allocated. If no, then allocate
435  * the buffer and, for otherwise too, returns the position of
436  * the thread buffer in the array buffer_ptr/buffer.
437  */
438 static void __litl_write_allocate_buffer(litl_write_trace_t* trace) {
439  litl_med_size_t* pos;
440 
441  // thread safe region
442  pthread_mutex_lock(&trace->lock_buffer_init);
443 
444  pos = malloc(sizeof(litl_med_size_t));
445  *pos = trace->nb_threads;
446  pthread_setspecific(trace->index, pos);
447  trace->nb_threads++;
448 
449  if (*pos >= trace->nb_allocated_buffers) {
450  // We need to allocate a bigger array of buffers
451  void* ptr = realloc(
452  trace->buffers,
453  trace->nb_allocated_buffers * 2 * sizeof(litl_write_buffer_t*));
454  if (!ptr) {
455  perror("LiTL failed to reallocate memory for threads!\n");
456  exit(EXIT_FAILURE);
457  }
458 
459  trace->buffers = ptr;
460  unsigned i;
461  for (i = trace->nb_allocated_buffers; i < 2 * trace->nb_allocated_buffers;
462  i++) {
463  trace->buffers[i] = malloc(sizeof(litl_write_buffer_t));
464  if (!trace->buffers[i]) {
465  perror("Could not allocate memory for a thread\n!");
466  exit(EXIT_FAILURE);
467  }
468  trace->buffers[i]->already_flushed = 0;
469  }
470  trace->nb_allocated_buffers *= 2;
471  }
472 
473  trace->buffers[*pos]->tid = CUR_TID;
474  trace->buffers[*pos]->already_flushed = 0;
475 
476  pthread_mutex_unlock(&trace->lock_buffer_init);
477 
478  trace->buffers[*pos]->buffer_ptr = malloc(
481  if (!trace->buffers[*pos]->buffer_ptr) {
482  perror("Could not allocate memory buffer for the thread\n!");
483  exit(EXIT_FAILURE);
484  }
485 
486  // touch the memory so that it is allocated for real (otherwise, this may
487  // cause performance issues on NUMA machines)
488  memset(trace->buffers[*pos]->buffer_ptr, 1, 1);
489  trace->buffers[*pos]->buffer = trace->buffers[*pos]->buffer_ptr;
490 }
491 
492 /*
493  * For internal use only.
494  * Allocates an event
495  */
497  litl_code_t code, int size) {
498 
499  if (trace && trace->is_litl_initialized && !trace->is_recording_paused
500  && !trace->is_buffer_full) {
501 
502  // find the thread index
503  litl_med_size_t *p_index = pthread_getspecific(trace->index);
504  if (!p_index) {
505  __litl_write_allocate_buffer(trace);
506  p_index = pthread_getspecific(trace->index);
507  }
508  litl_med_size_t index = *(litl_med_size_t *) p_index;
509 
510  litl_write_buffer_t *p_buffer = trace->buffers[index];
511 
512  // is there enough space in the buffer?
513  if (__litl_write_get_buffer_size(trace, index) < trace->buffer_size) {
514  // there is enough space for this event
515  litl_t* cur_ptr = (litl_t*) p_buffer->buffer;
516  p_buffer->buffer += size;
517 
518  // fill the event
519  cur_ptr->time = litl_get_time();
520  cur_ptr->code = code;
521  cur_ptr->type = type;
522 
523  switch (type) {
524  case LITL_TYPE_REGULAR:
525  cur_ptr->parameters.regular.nb_params = size;
526  break;
527  case LITL_TYPE_RAW:
528  cur_ptr->parameters.raw.size = size;
529  break;
530  case LITL_TYPE_PACKED:
531  cur_ptr->parameters.packed.size = size;
532  break;
533  default:
534  fprintf(stderr, "Unknown event type %d\n", type);
535  abort();
536  }
537  return cur_ptr;
538  } else if (trace->allow_buffer_flush) {
539 
540  // not enough space. flush the buffer and retry
541  __litl_write_flush_buffer(trace, index);
542  return __litl_write_get_event(trace, type, code, size);
543  } else {
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 /* Common function for recording a regular event.
554  * This function fills all the fiels except for the parameters
555  */
556 static litl_t* __litl_write_probe_reg_common(litl_write_trace_t* trace,
557  litl_code_t code,
558  unsigned nb_params) {
559  if (!trace->is_litl_initialized || trace->is_recording_paused
560  || trace->is_buffer_full)
561  return NULL;
562 
563  if (pthread_getspecific(trace->index) == NULL )
564  __litl_write_allocate_buffer(trace);
565 
566  litl_med_size_t index = *(litl_med_size_t *) pthread_getspecific(
567  trace->index);
568  if (__litl_write_get_buffer_size(trace, index) < trace->buffer_size) {
569  litl_t* cur_ptr = (litl_t *) trace->buffers[index]->buffer;
570 
571  cur_ptr->time = litl_get_time();
572  cur_ptr->code = code;
573  cur_ptr->type = LITL_TYPE_REGULAR;
574 
575  cur_ptr->parameters.regular.nb_params = nb_params;
576  trace->buffers[index]->buffer += LITL_BASE_SIZE + (nb_params * sizeof(litl_param_t));
577 
578  return cur_ptr;
579  } else {
580  /* buffer is full */
581  if (trace->allow_buffer_flush) {
582 
583  /* flush the buffer to disk */
584  __litl_write_flush_buffer(trace, index);
585  return __litl_write_probe_reg_common(trace, code, nb_params);
586  } else
587  /* stop recording events */
588  trace->is_buffer_full = 1;
589  return NULL;
590  }
591 
592 }
593 
594 /*
595  * Records a regular event without any arguments
596  */
598  litl_t *cur_ptr = __litl_write_probe_reg_common(trace, code, 0);
599  return cur_ptr;
600 }
601 
602 /*
603  * Records a regular event with one argument
604  */
606  litl_param_t param1) {
607  litl_t *cur_ptr = __litl_write_probe_reg_common(trace, code, 1);
608  if(cur_ptr) {
609  cur_ptr->parameters.regular.param[0] = param1;
610  }
611  return cur_ptr;
612 }
613 
614 /*
615  * Records a regular event with two arguments
616  */
618  litl_param_t param1, litl_param_t param2) {
619  litl_t *cur_ptr = __litl_write_probe_reg_common(trace, code, 2);
620  if(cur_ptr) {
621  cur_ptr->parameters.regular.param[0] = param1;
622  cur_ptr->parameters.regular.param[1] = param2;
623  }
624  return cur_ptr;
625 }
626 
627 /*
628  * Records a regular event with three arguments
629  */
631  litl_param_t param1, litl_param_t param2,
632  litl_param_t param3) {
633  litl_t *cur_ptr = __litl_write_probe_reg_common(trace, code, 3);
634  if(cur_ptr) {
635  cur_ptr->parameters.regular.param[0] = param1;
636  cur_ptr->parameters.regular.param[1] = param2;
637  cur_ptr->parameters.regular.param[2] = param3;
638  }
639  return cur_ptr;
640 }
641 
642 /*
643  * Records a regular event with four arguments
644  */
646  litl_param_t param1, litl_param_t param2,
647  litl_param_t param3, litl_param_t param4) {
648  litl_t *cur_ptr = __litl_write_probe_reg_common(trace, code, 4);
649  if(cur_ptr) {
650  cur_ptr->parameters.regular.param[0] = param1;
651  cur_ptr->parameters.regular.param[1] = param2;
652  cur_ptr->parameters.regular.param[2] = param3;
653  cur_ptr->parameters.regular.param[3] = param4;
654  }
655  return cur_ptr;
656 }
657 
658 /*
659  * Records a regular event with five arguments
660  */
662  litl_param_t param1, litl_param_t param2,
663  litl_param_t param3, litl_param_t param4,
664  litl_param_t param5) {
665  litl_t *cur_ptr = __litl_write_probe_reg_common(trace, code, 5);
666  if(cur_ptr) {
667  cur_ptr->parameters.regular.param[0] = param1;
668  cur_ptr->parameters.regular.param[1] = param2;
669  cur_ptr->parameters.regular.param[2] = param3;
670  cur_ptr->parameters.regular.param[3] = param4;
671  cur_ptr->parameters.regular.param[4] = param5;
672  }
673  return cur_ptr;
674 }
675 
676 /*
677  * Records a regular event with six arguments
678  */
680  litl_param_t param1, litl_param_t param2,
681  litl_param_t param3, litl_param_t param4,
682  litl_param_t param5, litl_param_t param6) {
683  litl_t *cur_ptr = __litl_write_probe_reg_common(trace, code, 6);
684  if(cur_ptr) {
685  cur_ptr->parameters.regular.param[0] = param1;
686  cur_ptr->parameters.regular.param[1] = param2;
687  cur_ptr->parameters.regular.param[2] = param3;
688  cur_ptr->parameters.regular.param[3] = param4;
689  cur_ptr->parameters.regular.param[4] = param5;
690  cur_ptr->parameters.regular.param[5] = param6;
691  }
692  return cur_ptr;
693 }
694 
695 /*
696  * Records a regular event with seven arguments
697  */
699  litl_param_t param1, litl_param_t param2,
700  litl_param_t param3, litl_param_t param4,
701  litl_param_t param5, litl_param_t param6,
702  litl_param_t param7) {
703  litl_t *cur_ptr = __litl_write_probe_reg_common(trace, code, 7);
704  if(cur_ptr) {
705  cur_ptr->parameters.regular.param[0] = param1;
706  cur_ptr->parameters.regular.param[1] = param2;
707  cur_ptr->parameters.regular.param[2] = param3;
708  cur_ptr->parameters.regular.param[3] = param4;
709  cur_ptr->parameters.regular.param[4] = param5;
710  cur_ptr->parameters.regular.param[5] = param6;
711  cur_ptr->parameters.regular.param[6] = param7;
712  }
713  return cur_ptr;
714 }
715 
716 /*
717  * Records a regular event with eight arguments
718  */
720  litl_param_t param1, litl_param_t param2,
721  litl_param_t param3, litl_param_t param4,
722  litl_param_t param5, litl_param_t param6,
723  litl_param_t param7, litl_param_t param8) {
724  litl_t *cur_ptr = __litl_write_probe_reg_common(trace, code, 8);
725  if(cur_ptr) {
726  cur_ptr->parameters.regular.param[0] = param1;
727  cur_ptr->parameters.regular.param[1] = param2;
728  cur_ptr->parameters.regular.param[2] = param3;
729  cur_ptr->parameters.regular.param[3] = param4;
730  cur_ptr->parameters.regular.param[4] = param5;
731  cur_ptr->parameters.regular.param[5] = param6;
732  cur_ptr->parameters.regular.param[6] = param7;
733  cur_ptr->parameters.regular.param[7] = param8;
734  }
735  return cur_ptr;
736 }
737 
738 /*
739  * Records a regular event with nine arguments
740  */
742  litl_param_t param1, litl_param_t param2,
743  litl_param_t param3, litl_param_t param4,
744  litl_param_t param5, litl_param_t param6,
745  litl_param_t param7, litl_param_t param8,
746  litl_param_t param9) {
747  litl_t *cur_ptr = __litl_write_probe_reg_common(trace, code, 9);
748  if(cur_ptr) {
749  cur_ptr->parameters.regular.param[0] = param1;
750  cur_ptr->parameters.regular.param[1] = param2;
751  cur_ptr->parameters.regular.param[2] = param3;
752  cur_ptr->parameters.regular.param[3] = param4;
753  cur_ptr->parameters.regular.param[4] = param5;
754  cur_ptr->parameters.regular.param[5] = param6;
755  cur_ptr->parameters.regular.param[6] = param7;
756  cur_ptr->parameters.regular.param[7] = param8;
757  cur_ptr->parameters.regular.param[8] = param9;
758  }
759  return cur_ptr;
760 }
761 
762 /*
763  * Records a regular event with ten arguments
764  */
766  litl_param_t param1, litl_param_t param2,
767  litl_param_t param3, litl_param_t param4,
768  litl_param_t param5, litl_param_t param6,
769  litl_param_t param7, litl_param_t param8,
770  litl_param_t param9, litl_param_t param10) {
771  litl_t *cur_ptr = __litl_write_probe_reg_common(trace, code, 10);
772  if(cur_ptr) {
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  cur_ptr->parameters.regular.param[6] = param7;
780  cur_ptr->parameters.regular.param[7] = param8;
781  cur_ptr->parameters.regular.param[8] = param9;
782  cur_ptr->parameters.regular.param[9] = param10;
783  }
784  return cur_ptr;
785 }
786 
787 /*
788  * Records an event in a raw state, where the size is #args in the void* array.
789  * That helps to discover places where the application has crashed
790  */
792  litl_size_t size, litl_data_t data[]) {
793  if (!trace->is_litl_initialized || trace->is_recording_paused
794  || trace->is_buffer_full)
795  return NULL;
796 
797  // specify explicitly the end of the string
798  data[size] = '\0';
799  size++;
800 
801  if (pthread_getspecific(trace->index) == NULL )
802  __litl_write_allocate_buffer(trace);
803 
804  litl_med_size_t i, index;
805  index = *(litl_med_size_t *) pthread_getspecific(trace->index);
806 
807  litl_t* cur_ptr = (litl_t *) trace->buffers[index]->buffer;
808  // needs to be done outside of the if statement 'cause of undefined size of
809  // the string that may cause segfault
810  trace->buffers[index]->buffer += LITL_BASE_SIZE + 7 + size;
811 
812  if (__litl_write_get_buffer_size(trace, index) < trace->buffer_size) {
813  cur_ptr->time = litl_get_time();
814  cur_ptr->code = code;
815  cur_ptr->type = LITL_TYPE_RAW;
816  cur_ptr->parameters.raw.size = size;
817  if (size > 0)
818  for (i = 0; i < size; i++)
819  cur_ptr->parameters.raw.data[i] = data[i];
820 
821  return cur_ptr;
822 
823  } else {
824  /* the buffer is full */
825  if (trace->allow_buffer_flush) {
826  // if there is not enough size we reset back the buffer pointer
827  trace->buffers[index]->buffer -= LITL_BASE_SIZE + 7 + size;
828 
829  __litl_write_flush_buffer(trace, index);
830  return litl_write_probe_raw(trace, code, size, data);
831  } else {
832  // this applies only when the flushing is off
833  trace->is_buffer_full = 1;
834  return NULL;
835  }
836  }
837 }
838 
839 /*
840  * This function finalizes the trace
841  */
843  litl_med_size_t i;
844  if(!trace)
845  return;
846 
847  for (i = 0; i < trace->nb_threads; i++)
848  __litl_write_flush_buffer(trace, i);
849 
850  close(trace->f_handle);
851  trace->f_handle = -1;
852 
853  for (i = 0; i < trace->nb_allocated_buffers; i++)
854  if (trace->buffers[i]->tid != 0) {
855  free(trace->buffers[i]->buffer_ptr);
856  } else {
857  break;
858  }
859 
860  if (trace->allow_thread_safety) {
861  pthread_mutex_destroy(&trace->lock_litl_flush);
862  }
863  pthread_mutex_destroy(&trace->lock_buffer_init);
864 
865  free(trace->filename);
866  trace->filename = NULL;
867  trace->is_litl_initialized = 0;
868  trace->is_header_flushed = 0;
869  free(trace);
870 }
struct litl_t::@0::@1 regular
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:617
litl_buffer_t buffer_ptr
Definition: litl_types.h:291
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
#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)
Enable buffer flush. By default, it is disabled.
Definition: litl_write.c:195
Thread-specific buffer.
Definition: litl_types.h:290
litl_write_buffer_t ** buffers
Definition: litl_types.h:321
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)
Enable thread safety.
Definition: litl_write.c:209
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:605
litl_med_size_t nb_slots
Definition: litl_types.h:318
volatile litl_data_t is_recording_paused
Definition: litl_types.h:332
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:679
void litl_write_thread_safety_off(litl_write_trace_t *trace)
Disable thread safety. By default, it is enabled.
Definition: litl_write.c:216
#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
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:645
litl_buffer_t buffer
Definition: litl_types.h:292
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:741
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_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:791
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
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:698
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)
Disable recording tid. By default, it is enabled.
Definition: litl_write.c:230
pthread_key_t index
Definition: litl_types.h:327
litl_buffer_t header
Definition: litl_types.h:311
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:842
#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:496
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:630
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.
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:719
#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_resume_recording(litl_write_trace_t *trace)
Resumes the event recording.
Definition: litl_write.c:245
struct litl_t::@0::@3 packed
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:253
pthread_once_t index_once
Definition: litl_types.h:326
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:765
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:661
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)
Enable recording tid.
Definition: litl_write.c:223
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)
Disable buffer flush.
Definition: litl_write.c:202
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:597
void litl_write_pause_recording(litl_write_trace_t *trace)
Pauses the event recording.
Definition: litl_write.c:237
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