litl  0.1.8
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  memset(trace->header_ptr, 0, trace->header_size);
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_t *) trace->buffers[index]->buffer;
271  cur_ptr->time = 0;
272  cur_ptr->code = LITL_OFFSET_CODE;
273  cur_ptr->type = LITL_TYPE_REGULAR;
274  cur_ptr->parameters.offset.nb_params = 1;
275  cur_ptr->parameters.offset.offset = 0;
276 
277  trace->buffers[index]->buffer += __litl_get_gen_event_size(cur_ptr);
278 }
279 
280 /* Open the trace file. If the file already exists, delete it first
281  */
282 static void __litl_open_new_file(litl_write_trace_t* trace) {
283  /* if file exist. delete it first */
284  if ((trace->f_handle = open(trace->filename, O_WRONLY | O_CREAT | O_EXCL, 0644))
285  < 0) {
286 
287  if(errno == EEXIST) {
288  /* file already exist. Delete it and open it */
289  if(unlink(trace->filename) < 0 ){
290  perror("Cannot delete trace file");
291  exit(EXIT_FAILURE);
292  }
293  if ((trace->f_handle = open(trace->filename, O_WRONLY | O_CREAT | O_EXCL, 0644))
294  < 0) {
295  perror("Cannot open trace file");
296  exit(EXIT_FAILURE);
297  }
298  } else {
299  fprintf(stderr, "Cannot open %s\n", trace->filename);
300  exit(EXIT_FAILURE);
301  }
302  }
303 }
304 
305 /*
306  * Write the header on the disk
307  */
308 static void __litl_write_update_header(litl_write_trace_t* trace) {
309  // write the trace header to the trace file
310  assert(trace->f_handle >= 0);
311  lseek(trace->f_handle, 0, SEEK_SET);
312 
313  if (write(trace->f_handle, trace->header_ptr,
314  __litl_write_get_header_size(trace)) == -1) {
315  perror(
316  "Flushing the buffer. Could not write measured data to the trace file!");
317  exit(EXIT_FAILURE);
318  }
319 }
320 
321 /*
322  * Update the header and flush it to disk
323  */
324 static void __litl_write_flush_header(litl_write_trace_t* trace) {
325 
326  if (!trace->is_header_flushed) {
327  // open the trace file
328  __litl_open_new_file(trace);
329 
330  // add a header to the trace file
331  trace->header_size = sizeof(litl_general_header_t)
332  + sizeof(litl_process_header_t)
333  + (trace->nb_threads + 1) * sizeof(litl_thread_pair_t);
334  __litl_write_add_trace_header(trace);
335 
336  // add information about each working thread: (tid, offset)
337  litl_med_size_t i;
338  for (i = 0; i < trace->nb_threads; i++) {
339  ((litl_thread_pair_t *) trace->header)->tid = trace->buffers[i]->tid;
340  ((litl_thread_pair_t *) trace->header)->offset = 0;
341 
342  trace->header += sizeof(litl_thread_pair_t);
343 
344  // save the position of offset inside the trace file
345  trace->buffers[i]->offset = __litl_write_get_header_size(trace)
346  - sizeof(litl_offset_t);
347  trace->buffers[i]->already_flushed = 1;
348  }
349 
350  // offset indicates the position of offset to the next slot of
351  // pairs (tid, offset) within the trace file
352  trace->header_offset = __litl_write_get_header_size(trace);
353 
354  // specify the last slot of pairs (offset == 0)
355  litl_thread_pair_t *thread_pair = (litl_thread_pair_t *) trace->header;
356  trace->header += sizeof(litl_thread_pair_t);
357  thread_pair->tid = 0;
358  thread_pair->offset = 0;
359 
360  // write the trace header to the trace file
361  __litl_write_update_header(trace);
362 
363  trace->general_offset = __litl_write_get_header_size(trace);
364 
365  trace->header_nb_threads = trace->nb_threads;
366  trace->threads_offset = 0;
367  trace->nb_slots = 0;
368 
369  trace->is_header_flushed = 1;
370  }
371 }
372 
373 
374 /*
375  * Write the thread-specific header to disk
376  */
377 static void __litl_write_flush_thread_header(litl_write_trace_t* trace,
378  litl_med_size_t index,
379  litl_offset_t header_size) {
381  int res;
382  // when more buffers to store threads information is required
383  if (trace->nb_threads
384  > (trace->header_nb_threads + NBTHREADS * trace->nb_slots)) {
385 
386  // updated the offset from the previous slot
387  lseek(trace->f_handle, trace->header_offset + sizeof(litl_tid_t),
388  SEEK_SET);
389  offset = trace->general_offset - header_size;
390  res = write(trace->f_handle, &offset, sizeof(litl_offset_t));
391  assert(res>=0);
392 
393  // reserve a new slot for pairs (tid, offset)
394  trace->header_offset = trace->general_offset;
395  trace->threads_offset = trace->header_offset;
396  trace->general_offset += (NBTHREADS + 1) * sizeof(litl_thread_pair_t);
397 
398  trace->nb_slots++;
399  }
400 
401  // add a new pair (tid, offset)
402  lseek(trace->f_handle, trace->header_offset, SEEK_SET);
403  res = write(trace->f_handle, &trace->buffers[index]->tid,
404  sizeof(litl_tid_t));
405  assert(res >= 0);
406  offset = trace->general_offset - header_size;
407  res = write(trace->f_handle, &offset, sizeof(litl_offset_t));
408  assert(res >= 0);
409 
410  // add an indicator to specify the last slot of pairs (offset == 0)
411  // TODO: how to optimize this and write only once at the end of the slot
412  offset = 0;
413  res = write(trace->f_handle, &offset, sizeof(litl_tid_t));
414  assert(res >= 0);
415  res = write(trace->f_handle, &offset, sizeof(litl_offset_t));
416  assert(res >= 0);
417 
418  trace->header_offset += sizeof(litl_thread_pair_t);
419  trace->buffers[index]->already_flushed = 1;
420 
421  // updated the number of threads
422  // TODO: perform update only once 'cause there is duplication
423  lseek(trace->f_handle, trace->header_size, SEEK_SET);
424  res = write(trace->f_handle, &trace->nb_threads, sizeof(litl_med_size_t));
425  assert(res >= 0);
426 }
427 
428 /*
429  * Update the thread-specific header and write it to disk
430  */
431 static void __litl_write_update_thread_header(litl_write_trace_t* trace,
432  litl_med_size_t index,
433  litl_offset_t header_size) {
434  // update the previous offset of the current thread,
435  // updating the location in the file
436  lseek(trace->f_handle, trace->buffers[index]->offset, SEEK_SET);
437  litl_offset_t offset = trace->general_offset - header_size;
438  int res = write(trace->f_handle, &offset, sizeof(litl_offset_t));
439  assert(res >= 0);
440 }
441 
442 /*
443  * Writes the recorded events from the buffer to the trace file
444  */
445 static void __litl_write_flush_buffer(litl_write_trace_t* trace,
446  litl_med_size_t index) {
447  int res __attribute__ ((__unused__));
448  litl_offset_t header_size;
449  if (!trace->is_litl_initialized)
450  return;
451 
452  if (trace->allow_thread_safety)
453  pthread_mutex_lock(&trace->lock_litl_flush);
454 
455  if (!trace->is_header_flushed) {
456  /* flush the header to disk */
457  __litl_write_flush_header(trace);
458  }
459 
460  header_size = sizeof(litl_general_header_t) + sizeof(litl_process_header_t);
461  // handle the situation when some threads start after the header was flushed
462  if (!trace->buffers[index]->already_flushed) {
463  __litl_write_flush_thread_header(trace, index, header_size);
464  } else {
465  __litl_write_update_thread_header(trace, index, header_size);
466  }
467 
468  // add an event with offset
469  __litl_write_probe_offset(trace, index);
470  lseek(trace->f_handle, trace->general_offset, SEEK_SET);
471  if (write(trace->f_handle, trace->buffers[index]->buffer_ptr,
472  __litl_write_get_buffer_size(trace, index)) == -1) {
473  perror(
474  "Flushing the buffer. Could not write measured data to the trace file!");
475  exit(EXIT_FAILURE);
476  }
477 
478  // update the general_offset
479  trace->general_offset += __litl_write_get_buffer_size(trace, index);
480  // update the current offset of the thread
481  trace->buffers[index]->offset = trace->general_offset - sizeof(litl_offset_t);
482 
483  if (trace->allow_thread_safety)
484  pthread_mutex_unlock(&trace->lock_litl_flush);
485 
486  trace->buffers[index]->buffer = trace->buffers[index]->buffer_ptr;
487 }
488 
489 /*
490  * Checks whether the trace buffer was allocated. If no, then allocate
491  * the buffer and, for otherwise too, returns the position of
492  * the thread buffer in the array buffer_ptr/buffer.
493  */
494 static void __litl_write_allocate_buffer(litl_write_trace_t* trace) {
495  litl_med_size_t* pos;
496 
497  // thread safe region
498  pthread_mutex_lock(&trace->lock_buffer_init);
499 
500  pos = malloc(sizeof(litl_med_size_t));
501  *pos = trace->nb_threads;
502  pthread_setspecific(trace->index, pos);
503  trace->nb_threads++;
504 
505  if (*pos >= trace->nb_allocated_buffers) {
506  // We need to allocate a bigger array of buffers
507  void* ptr = realloc(
508  trace->buffers,
509  trace->nb_allocated_buffers * 2 * sizeof(litl_write_buffer_t*));
510  if (!ptr) {
511  perror("LiTL failed to reallocate memory for threads!\n");
512  exit(EXIT_FAILURE);
513  }
514 
515  trace->buffers = ptr;
516  unsigned i;
517  for (i = trace->nb_allocated_buffers; i < 2 * trace->nb_allocated_buffers;
518  i++) {
519  trace->buffers[i] = malloc(sizeof(litl_write_buffer_t));
520  if (!trace->buffers[i]) {
521  perror("Could not allocate memory for a thread\n!");
522  exit(EXIT_FAILURE);
523  }
524  trace->buffers[i]->already_flushed = 0;
525  }
526  trace->nb_allocated_buffers *= 2;
527  }
528 
529  trace->buffers[*pos]->tid = CUR_TID;
530  trace->buffers[*pos]->already_flushed = 0;
531 
532  pthread_mutex_unlock(&trace->lock_buffer_init);
533 
534  trace->buffers[*pos]->buffer_ptr = malloc(
537 
538  if (!trace->buffers[*pos]->buffer_ptr) {
539  perror("Could not allocate memory buffer for the thread\n!");
540  exit(EXIT_FAILURE);
541  }
542 
543  // touch the memory so that it is allocated for real (otherwise, this may
544  // cause performance issues on NUMA machines)
545  memset(trace->buffers[*pos]->buffer_ptr, 1, 1);
546  trace->buffers[*pos]->buffer = trace->buffers[*pos]->buffer_ptr;
547 }
548 
549 /*
550  * For internal use only.
551  * Allocates an event
552  */
554  litl_code_t code, int param_size) {
555  litl_med_size_t index = 0;
556  litl_t*retval = NULL;
557  litl_size_t event_size = __litl_get_event_size(type, param_size);
558 
559  if (trace && trace->is_litl_initialized && !trace->is_recording_paused
560  && !trace->is_buffer_full) {
561 
562  // find the thread index
563  litl_med_size_t *p_index = pthread_getspecific(trace->index);
564  if (!p_index) {
565  __litl_write_allocate_buffer(trace);
566  p_index = pthread_getspecific(trace->index);
567  }
568  index = *(litl_med_size_t *) p_index;
569 
570  litl_write_buffer_t *p_buffer = trace->buffers[index];
571 
572  // is there enough space in the buffer?
573  litl_size_t used_memory= __litl_write_get_buffer_size(trace, index);
574 
575  if (used_memory+event_size < trace->buffer_size) {
576  // there is enough space for this event
577  litl_t* cur_ptr = (litl_t*) p_buffer->buffer;
578 
579  // fill the event
580  cur_ptr->time = litl_get_time();
581  cur_ptr->code = code;
582  cur_ptr->type = type;
583 
584  switch (type) {
585  case LITL_TYPE_REGULAR:
586  cur_ptr->parameters.regular.nb_params = (param_size) / sizeof(litl_param_t);
587  break;
588  case LITL_TYPE_RAW:
589  cur_ptr->parameters.raw.size = param_size;
590  break;
591  case LITL_TYPE_PACKED:
592  cur_ptr->parameters.packed.size = param_size;
593  break;
594  case LITL_TYPE_OFFSET:
595  cur_ptr->parameters.offset.nb_params = param_size;
596  break;
597  default:
598  fprintf(stderr, "Unknown event type %d\n", type);
599  abort();
600  }
601 
602  p_buffer->buffer += __litl_get_gen_event_size(cur_ptr);
603 
604  retval = cur_ptr;
605  goto out;
606  } else if (trace->allow_buffer_flush) {
607  // not enough space. flush the buffer and retry
608  __litl_write_flush_buffer(trace, index);
609  retval = __litl_write_get_event(trace, type, code, param_size);
610  goto out;
611  } else {
612  // not enough space, but flushing is disabled so just stop recording
613  trace->is_buffer_full = 1;
614  retval = NULL ;
615  goto out;
616  }
617  }
618 
619  out:
620  return retval;
621 }
622 
623 
624 /* Common function for recording a regular event.
625  * This function fills all the fiels except for the parameters
626  */
627 static litl_t* __litl_write_probe_reg_common(litl_write_trace_t* trace,
628  litl_code_t code,
629  unsigned nb_params) {
630  litl_t*retval = __litl_write_get_event(trace,
632  code,
633  nb_params);
634  return retval;
635 }
636 
637 /*
638  * Records a regular event without any arguments
639  */
641  litl_t *cur_ptr = __litl_write_probe_reg_common(trace, code, 0);
642  return cur_ptr;
643 }
644 
645 /*
646  * Records a regular event with one argument
647  */
649  litl_param_t param1) {
650  litl_t *cur_ptr = __litl_write_probe_reg_common(trace, code, 1);
651  if(cur_ptr) {
652  cur_ptr->parameters.regular.param[0] = param1;
653  }
654  return cur_ptr;
655 }
656 
657 /*
658  * Records a regular event with two arguments
659  */
661  litl_param_t param1, litl_param_t param2) {
662  litl_t *cur_ptr = __litl_write_probe_reg_common(trace, code, 2);
663  if(cur_ptr) {
664  cur_ptr->parameters.regular.param[0] = param1;
665  cur_ptr->parameters.regular.param[1] = param2;
666  }
667  return cur_ptr;
668 }
669 
670 /*
671  * Records a regular event with three arguments
672  */
674  litl_param_t param1, litl_param_t param2,
675  litl_param_t param3) {
676  litl_t *cur_ptr = __litl_write_probe_reg_common(trace, code, 3);
677  if(cur_ptr) {
678  cur_ptr->parameters.regular.param[0] = param1;
679  cur_ptr->parameters.regular.param[1] = param2;
680  cur_ptr->parameters.regular.param[2] = param3;
681  }
682  return cur_ptr;
683 }
684 
685 /*
686  * Records a regular event with four arguments
687  */
689  litl_param_t param1, litl_param_t param2,
690  litl_param_t param3, litl_param_t param4) {
691  litl_t *cur_ptr = __litl_write_probe_reg_common(trace, code, 4);
692  if(cur_ptr) {
693  cur_ptr->parameters.regular.param[0] = param1;
694  cur_ptr->parameters.regular.param[1] = param2;
695  cur_ptr->parameters.regular.param[2] = param3;
696  cur_ptr->parameters.regular.param[3] = param4;
697  }
698  return cur_ptr;
699 }
700 
701 /*
702  * Records a regular event with five arguments
703  */
705  litl_param_t param1, litl_param_t param2,
706  litl_param_t param3, litl_param_t param4,
707  litl_param_t param5) {
708  litl_t *cur_ptr = __litl_write_probe_reg_common(trace, code, 5);
709  if(cur_ptr) {
710  cur_ptr->parameters.regular.param[0] = param1;
711  cur_ptr->parameters.regular.param[1] = param2;
712  cur_ptr->parameters.regular.param[2] = param3;
713  cur_ptr->parameters.regular.param[3] = param4;
714  cur_ptr->parameters.regular.param[4] = param5;
715  }
716  return cur_ptr;
717 }
718 
719 /*
720  * Records a regular event with six arguments
721  */
723  litl_param_t param1, litl_param_t param2,
724  litl_param_t param3, litl_param_t param4,
725  litl_param_t param5, litl_param_t param6) {
726  litl_t *cur_ptr = __litl_write_probe_reg_common(trace, code, 6);
727  if(cur_ptr) {
728  cur_ptr->parameters.regular.param[0] = param1;
729  cur_ptr->parameters.regular.param[1] = param2;
730  cur_ptr->parameters.regular.param[2] = param3;
731  cur_ptr->parameters.regular.param[3] = param4;
732  cur_ptr->parameters.regular.param[4] = param5;
733  cur_ptr->parameters.regular.param[5] = param6;
734  }
735  return cur_ptr;
736 }
737 
738 /*
739  * Records a regular event with seven 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) {
746  litl_t *cur_ptr = __litl_write_probe_reg_common(trace, code, 7);
747  if(cur_ptr) {
748  cur_ptr->parameters.regular.param[0] = param1;
749  cur_ptr->parameters.regular.param[1] = param2;
750  cur_ptr->parameters.regular.param[2] = param3;
751  cur_ptr->parameters.regular.param[3] = param4;
752  cur_ptr->parameters.regular.param[4] = param5;
753  cur_ptr->parameters.regular.param[5] = param6;
754  cur_ptr->parameters.regular.param[6] = param7;
755  }
756  return cur_ptr;
757 }
758 
759 /*
760  * Records a regular event with eight arguments
761  */
763  litl_param_t param1, litl_param_t param2,
764  litl_param_t param3, litl_param_t param4,
765  litl_param_t param5, litl_param_t param6,
766  litl_param_t param7, litl_param_t param8) {
767  litl_t *cur_ptr = __litl_write_probe_reg_common(trace, code, 8);
768  if(cur_ptr) {
769  cur_ptr->parameters.regular.param[0] = param1;
770  cur_ptr->parameters.regular.param[1] = param2;
771  cur_ptr->parameters.regular.param[2] = param3;
772  cur_ptr->parameters.regular.param[3] = param4;
773  cur_ptr->parameters.regular.param[4] = param5;
774  cur_ptr->parameters.regular.param[5] = param6;
775  cur_ptr->parameters.regular.param[6] = param7;
776  cur_ptr->parameters.regular.param[7] = param8;
777  }
778  return cur_ptr;
779 }
780 
781 /*
782  * Records a regular event with nine arguments
783  */
785  litl_param_t param1, litl_param_t param2,
786  litl_param_t param3, litl_param_t param4,
787  litl_param_t param5, litl_param_t param6,
788  litl_param_t param7, litl_param_t param8,
789  litl_param_t param9) {
790  litl_t *cur_ptr = __litl_write_probe_reg_common(trace, code, 9);
791  if(cur_ptr) {
792  cur_ptr->parameters.regular.param[0] = param1;
793  cur_ptr->parameters.regular.param[1] = param2;
794  cur_ptr->parameters.regular.param[2] = param3;
795  cur_ptr->parameters.regular.param[3] = param4;
796  cur_ptr->parameters.regular.param[4] = param5;
797  cur_ptr->parameters.regular.param[5] = param6;
798  cur_ptr->parameters.regular.param[6] = param7;
799  cur_ptr->parameters.regular.param[7] = param8;
800  cur_ptr->parameters.regular.param[8] = param9;
801  }
802  return cur_ptr;
803 }
804 
805 /*
806  * Records a regular event with ten arguments
807  */
809  litl_param_t param1, litl_param_t param2,
810  litl_param_t param3, litl_param_t param4,
811  litl_param_t param5, litl_param_t param6,
812  litl_param_t param7, litl_param_t param8,
813  litl_param_t param9, litl_param_t param10) {
814  litl_t *cur_ptr = __litl_write_probe_reg_common(trace, code, 10);
815  if(cur_ptr) {
816  cur_ptr->parameters.regular.param[0] = param1;
817  cur_ptr->parameters.regular.param[1] = param2;
818  cur_ptr->parameters.regular.param[2] = param3;
819  cur_ptr->parameters.regular.param[3] = param4;
820  cur_ptr->parameters.regular.param[4] = param5;
821  cur_ptr->parameters.regular.param[5] = param6;
822  cur_ptr->parameters.regular.param[6] = param7;
823  cur_ptr->parameters.regular.param[7] = param8;
824  cur_ptr->parameters.regular.param[8] = param9;
825  cur_ptr->parameters.regular.param[9] = param10;
826  }
827  return cur_ptr;
828 }
829 
830 /*
831  * Records an event in a raw state, where the size is #args in the void* array.
832  * That helps to discover places where the application has crashed
833  */
835  litl_size_t size, litl_data_t data[]) {
836  litl_t* retval = __litl_write_get_event(trace,
838  code,
839  size+1);
840  if(retval) {
841  litl_size_t i;
842  for (i = 0; i < size; i++) {
843  retval->parameters.raw.data[i] = data[i];
844  }
845  retval->parameters.raw.data[size]='\0';
846  }
847  return retval;
848 }
849 
850 /*
851  * This function finalizes the trace
852  */
854  litl_med_size_t i;
855  if(!trace)
856  return;
857 
858  for (i = 0; i < trace->nb_threads; i++) {
859  __litl_write_flush_buffer(trace, i);
860  }
861 
862  close(trace->f_handle);
863  trace->f_handle = -1;
864 
865  for (i = 0; i < trace->nb_allocated_buffers; i++) {
866  if (trace->buffers[i]->tid != 0) {
867  free(trace->buffers[i]->buffer_ptr);
868  trace->buffers[i]->buffer_ptr = NULL;
869  } else {
870  break;
871  }
872  }
873 
874  if (trace->allow_thread_safety) {
875  pthread_mutex_destroy(&trace->lock_litl_flush);
876  }
877  pthread_mutex_destroy(&trace->lock_buffer_init);
878 
879  free(trace->filename);
880  trace->filename = NULL;
881  trace->is_litl_initialized = 0;
882  trace->is_header_flushed = 0;
883  free(trace);
884 }
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:660
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_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
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:648
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:722
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:688
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:784
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:834
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_offset_t offset
Definition: litl_types.h:273
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:741
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
litl_size_t __litl_get_reg_event_size(litl_data_t nb_params)
Returns the size of a regular event (in Bytes) depending on the number of its parameters.
Definition: litl_tools.c:18
litl_tid_t tid
Definition: litl_types.h:272
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:853
#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 param_size)
For internal use only. Allocates an event.
Definition: litl_write.c:553
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:673
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
litl_size_t __litl_get_event_size(litl_type_t type, int param_size)
Returns the size of an event (in Bytes) depending on the number or size of its parameters.
Definition: litl_tools.c:22
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:762
#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
litl_size_t __litl_get_gen_event_size(litl_t *p_evt)
Returns the size of a general event (in Bytes) depending on its type and the number of its parameters...
Definition: litl_tools.c:42
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:133
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:808
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:704
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:640
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