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