litl  0.1.1
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups
litl_read.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 #include <stdlib.h>
8 #include <sys/stat.h>
9 #include <math.h>
10 #include <string.h>
11 #include <fcntl.h>
12 #include <unistd.h>
13 
14 #include "litl_tools.h"
15 #include "litl_read.h"
16 
17 /*
18  * Initializes the trace header
19  */
20 static void __litl_read_init_trace_header(litl_read_trace_t* trace) {
21  int res;
22 
23  litl_size_t header_size, general_header_size;
24  general_header_size = sizeof(litl_general_header_t);
25 
26  // read the trace header
27  header_size = sizeof(litl_general_header_t);
28  trace->header_buffer_ptr = (litl_buffer_t) malloc(header_size);
29  if (!trace->header_buffer_ptr) {
30  perror("Could not allocate memory for the trace header!");
31  exit(EXIT_FAILURE);
32  }
33 
34  res = read(trace->f_handle, trace->header_buffer_ptr, header_size);
35  // If the end of file is reached, then all data are read; res = 0.
36  // Otherwise, res equals the number of elements (= 1) or the error
37  // occurred and res = -1.
38  if (res == -1) {
39  perror("Could not read the trace header!");
40  exit(EXIT_FAILURE);
41  }
42 
43  // init the trace header
45 
46  // get the number of processes
47  trace->nb_processes = trace->header->nb_processes;
48 
49  // relocate the header buffer
50  header_size += trace->nb_processes * sizeof(litl_process_header_t);
51  trace->header_buffer_ptr = (litl_buffer_t) realloc(trace->header_buffer_ptr,
52  header_size);
53 
54  // read the trace header
55  res = read(trace->f_handle, trace->header_buffer_ptr + general_header_size,
56  header_size - general_header_size);
57  if (res == -1) {
58  perror("Could not read the trace header!");
59  exit(EXIT_FAILURE);
60  }
62  trace->header_buffer = trace->header_buffer_ptr + general_header_size;
63 }
64 
65 /*
66  * Initializes the trace header, meaning it reads chunks with all pairs
67  */
68 static void __litl_read_init_process_header(litl_read_trace_t* trace,
69  litl_read_process_t* process) {
70 
71  // init the header structure
72  litl_trace_size_t header_size;
73  litl_med_size_t nb_threads =
74  (process->header->header_nb_threads > NBTHREADS) ?
76 
77  header_size = (nb_threads + 1) * sizeof(litl_thread_pair_t);
78  process->header_buffer_ptr = (litl_buffer_t) malloc(header_size);
79 
80  // read threads pairs (tid, offset)
81  lseek(trace->f_handle, process->header->offset, SEEK_SET);
82  header_size = (process->header->header_nb_threads + 1)
83  * sizeof(litl_thread_pair_t);
84  int res = read(trace->f_handle, process->header_buffer_ptr, header_size);
85  if (res == -1) {
86  perror("Could not read the trace header!");
87  exit(EXIT_FAILURE);
88  }
89  process->header_buffer = process->header_buffer_ptr;
90 }
91 
92 /*
93  * Reads another portion of pairs(tid, offset) from the trace file
94  */
95 static void __litl_read_next_pairs_buffer(litl_read_trace_t* trace,
96  litl_read_process_t* process,
98 
99  lseek(trace->f_handle, offset, SEEK_SET);
100 
101  litl_med_size_t nb_threads =
102  (process->nb_threads - process->header->header_nb_threads) > NBTHREADS ?
103  NBTHREADS : (process->nb_threads - process->header->header_nb_threads);
104 
105  int res = read(trace->f_handle, process->header_buffer_ptr,
106  (nb_threads + 1) * sizeof(litl_thread_pair_t));
107  process->header_buffer = process->header_buffer_ptr;
108 
109  if (res == -1) {
110  perror(
111  "Could not read the next part of pairs (tid, offset) from the trace file!");
112  exit(EXIT_FAILURE);
113  }
114 }
115 
116 /*
117  * Initializes buffers -- one buffer per thread.
118  */
119 static void __litl_read_init_threads(litl_read_trace_t* trace,
120  litl_read_process_t* process) {
121  litl_med_size_t thread_index, size;
122  litl_thread_pair_t *thread_pair;
123 
124  size = sizeof(litl_thread_pair_t);
125  // init nb_threads and allocate memory
126  process->nb_threads = process->header->nb_threads;
127  process->threads = (litl_read_thread_t **) malloc(
128  process->nb_threads * sizeof(litl_read_thread_t*));
129 
130  // increase a bit the buffer size 'cause of the event's tail and the offset
133 
134  for (thread_index = 0; thread_index < process->nb_threads; thread_index++) {
135  // allocate thread structure
136  process->threads[thread_index] = (litl_read_thread_t *) malloc(
137  sizeof(litl_read_thread_t));
138  process->threads[thread_index]->thread_pair = (litl_thread_pair_t *) malloc(
139  sizeof(litl_thread_pair_t));
140  process->threads[thread_index]->buffer_ptr = (litl_buffer_t) malloc(
141  process->header->buffer_size);
142 
143  // read pairs (tid, offset)
144  thread_pair = (litl_thread_pair_t *) process->header_buffer;
145 
146  // deal with slots of pairs
147  if ((thread_pair->tid == 0) && (thread_pair->offset != 0)) {
148  __litl_read_next_pairs_buffer(
149  trace, process, process->header->offset + thread_pair->offset);
150  thread_pair = (litl_thread_pair_t *) process->header_buffer;
151  }
152 
153  // end of reading pairs
154  if ((thread_pair->tid == 0) && (thread_pair->offset == 0))
155  break;
156 
157  process->threads[thread_index]->thread_pair->tid = thread_pair->tid;
158  // use two offsets: process and thread. Process offset for a position
159  // of thread pairs; thread offset for a position of events
160  process->threads[thread_index]->thread_pair->offset = thread_pair->offset
161  + process->header->offset;
162 
163  // read chunks of data
164  // use offsets in order to access a chuck of data that corresponds to
165  // each thread
166  lseek(trace->f_handle, process->threads[thread_index]->thread_pair->offset,
167  SEEK_SET);
168  int res = read(trace->f_handle, process->threads[thread_index]->buffer_ptr,
169  process->header->buffer_size);
170  if (res == -1) {
171  perror("Could not read the first partition of data from the trace file!");
172  exit(EXIT_FAILURE);
173  }
174 
175  process->threads[thread_index]->buffer =
176  process->threads[thread_index]->buffer_ptr;
177  process->threads[thread_index]->tracker = process->header->buffer_size;
178  process->threads[thread_index]->offset = 0;
179 
180  process->header_buffer += size;
181  }
182 }
183 
184 /*
185  * Opens a trace
186  */
187 litl_read_trace_t* litl_read_open_trace(const char* filename) {
188  litl_read_trace_t *trace = (litl_read_trace_t *) malloc(
189  sizeof(litl_read_trace_t));
190 
191  // open a trace file
192  if ((trace->f_handle = open(filename, O_RDONLY)) < 0) {
193  fprintf(stderr, "Cannot open %s\n", filename);
194  exit(EXIT_FAILURE);
195  }
196 
197  // init the trace header
198  __litl_read_init_trace_header(trace);
199 
200  return trace;
201 }
202 
203 /*
204  * Initializes processes as trace may store multiple processes
205  */
207 
208  trace->processes = (litl_read_process_t **) malloc(
209  trace->nb_processes * sizeof(litl_read_process_t*));
210 
211  litl_med_size_t process_index, size;
212  size = sizeof(litl_process_header_t);
213 
214  for (process_index = 0; process_index < trace->nb_processes;
215  process_index++) {
216  trace->processes[process_index] = (litl_read_process_t *) malloc(
217  sizeof(litl_read_process_t));
218 
219  // read the process header
220  trace->processes[process_index]->header =
222  trace->header_buffer += size;
223 
224  trace->processes[process_index]->cur_index = -1;
225  trace->processes[process_index]->is_initialized = 0;
226 
227  // init the process header
228  __litl_read_init_process_header(trace, trace->processes[process_index]);
229 
230  // init buffers of events: one buffer per thread
231  __litl_read_init_threads(trace, trace->processes[process_index]);
232  }
233 }
234 
235 /*
236  * Returns a pointer to the trace header
237  */
239  return trace->header;
240 }
241 
242 /*
243  * Returns a pointer to the process header
244  */
246  litl_read_process_t* process) {
247  return process->header;
248 }
249 
250 /*
251  * Sets the buffer size
252  */
254  const litl_size_t buf_size) {
255  litl_med_size_t i;
256 
257  for (i = 0; i < trace->nb_processes; i++)
258  trace->processes[i]->header->buffer_size = buf_size;
259 }
260 
261 /*
262  * Returns the buffer size
263  */
265  return trace->processes[0]->header->buffer_size;
266 }
267 
268 /*
269  * Reads a next portion of events from the trace file to the buffer
270  */
271 static void __litl_read_next_buffer(litl_read_trace_t* trace,
272  litl_read_process_t* process,
273  litl_med_size_t thread_index) {
274 
275  lseek(
276  trace->f_handle,
277  process->header->offset
278  + process->threads[thread_index]->thread_pair->offset,
279  SEEK_SET);
280 
281  process->threads[thread_index]->offset = 0;
282 
283  // read portion of next events
284  int res = read(trace->f_handle, process->threads[thread_index]->buffer_ptr,
285  process->header->buffer_size);
286  if (res == -1) {
287  perror("Could not read the next part of the trace file!");
288  exit(EXIT_FAILURE);
289  }
290 
291  process->threads[thread_index]->buffer =
292  process->threads[thread_index]->buffer_ptr;
293  process->threads[thread_index]->tracker =
294  process->threads[thread_index]->offset + process->header->buffer_size;
295 }
296 
297 /*
298  * Resets the thread buffers of a given process
299  */
301  litl_med_size_t thread_index;
302 
303  for (thread_index = 0; thread_index < process->nb_threads; thread_index++)
304  process->threads[thread_index]->buffer =
305  process->threads[thread_index]->buffer_ptr;
306 }
307 
308 /*
309  * Reads an event
310  */
311 static litl_read_event_t* __litl_read_next_thread_event(
312  litl_read_trace_t* trace, litl_read_process_t* process,
313  litl_med_size_t thread_index) {
314 
315  litl_data_t to_be_loaded;
316  litl_t* event;
317  litl_buffer_t buffer;
318 
319  buffer = process->threads[thread_index]->buffer;
320  to_be_loaded = 0;
321 
322  if (!buffer) {
323  process->threads[thread_index]->cur_event.event = NULL;
324  return NULL ;
325  }
326 
327  event = (litl_t *) buffer;
328 
329  // While reading events from the buffer, there can be two situations:
330  // 1. The situation when the buffer contains exact number of events;
331  // 2. The situation when only a part of the last event is loaded.
332  // Check whether the main four components (tid, time, code, nb_params) are
333  // loaded.
334  // Check whether all arguments are loaded.
335  // If any of these cases is not true, the next part of the trace plus
336  // the current event is loaded to the buffer
337  litl_size_t remaining_size = process->threads[thread_index]->tracker
338  - process->threads[thread_index]->offset;
339  if (remaining_size < __litl_get_reg_event_size(0)) {
340  // this event is truncated. We can't even read the nb_param field
341  to_be_loaded = 1;
342  } else {
343  // The nb_param (or size) field is available. Let's check whether
344  // the event is truncated
345  litl_med_size_t event_size = __litl_get_gen_event_size(event);
346  if (remaining_size < event_size)
347  to_be_loaded = 1;
348  }
349 
350  // event that stores tid and offset
351  if (event->code == LITL_OFFSET_CODE) {
352  if (event->parameters.offset.offset != 0) {
353  process->threads[thread_index]->thread_pair->offset =
354  event->parameters.offset.offset;
355  to_be_loaded = 1;
356  } else {
357  buffer = NULL;
358  process->threads[thread_index]->cur_event.event = NULL;
359  return NULL ;
360  }
361  }
362 
363  // fetch the next block of data from the trace
364  if (to_be_loaded) {
365  __litl_read_next_buffer(trace, process, thread_index);
366  buffer = process->threads[thread_index]->buffer;
367  event = (litl_t *) buffer;
368  }
369 
370  // move pointer to the next event and update __offset
371  litl_med_size_t evt_size = __litl_get_gen_event_size(event);
372  process->threads[thread_index]->buffer += evt_size;
373  process->threads[thread_index]->offset += evt_size;
374 
375  process->threads[thread_index]->cur_event.event = event;
376  process->threads[thread_index]->cur_event.tid =
377  process->threads[thread_index]->thread_pair->tid;
378 
379  return &process->threads[thread_index]->cur_event;
380 }
381 
382 /*
383  * Searches for the next event inside the trace
384  */
386  litl_read_process_t* process) {
387 
388  litl_med_size_t thread_index;
389  litl_time_t min_time = -1;
390 
391  if (!process->is_initialized) {
392  for (thread_index = 0; thread_index < process->nb_threads; thread_index++)
393  __litl_read_next_thread_event(trace, process, thread_index);
394 
395  process->cur_index = -1;
396  process->is_initialized = 1;
397  }
398 
399  // read the next event from the buffer
400  if (process->cur_index != -1)
401  __litl_read_next_thread_event(trace, process, process->cur_index);
402 
403  int found = 0;
404  for (thread_index = 0; thread_index < process->nb_threads; thread_index++) {
405  litl_read_event_t *evt =
406  LITL_READ_GET_CUR_EVENT_PER_THREAD(process, thread_index);
407  if ( evt && evt->event && (LITL_READ_GET_TIME(evt) < min_time))
408  {
409  found = 1;
410  min_time = LITL_READ_GET_TIME(evt);
411  process->cur_index = thread_index;
412  }
413  }
414 
415  if (found)
416  return LITL_READ_GET_CUR_EVENT(process);
417 
418  return NULL ;
419 }
420 
421 /*
422  * Reads the next event from a trace
423  */
425  litl_med_size_t process_index;
426  litl_read_event_t* event = NULL;
427 
428  for (process_index = 0; process_index < trace->nb_processes;
429  process_index++) {
430  event = litl_read_next_process_event(trace,
431  trace->processes[process_index]);
432 
433  if (event != NULL )
434  break;
435  }
436 
437  return event;
438 }
439 
440 /*
441  * Closes the trace and frees the buffer
442  */
444  litl_med_size_t process_index, thread_index;
445 
446  // close the file
447  close(trace->f_handle);
448  trace->f_handle = -1;
449 
450  // free traces
451  for (process_index = 0; process_index < trace->nb_processes;
452  process_index++) {
453 
454  for (thread_index = 0;
455  thread_index < trace->processes[process_index]->nb_threads;
456  thread_index++) {
457  free(trace->processes[process_index]->threads[thread_index]->thread_pair);
458  free(trace->processes[process_index]->threads[thread_index]->buffer_ptr);
459  free(trace->processes[process_index]->threads[thread_index]);
460  }
461 
462  free(trace->processes[process_index]->threads);
463  free(trace->processes[process_index]->header_buffer_ptr);
464  free(trace->processes[process_index]);
465  }
466 
467  // free a trace structure
468  free(trace->processes);
469  free(trace->header_buffer_ptr);
470  free(trace);
471 
472  // set the trace pointer to NULL
473  trace = NULL;
474 }
litl_med_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:27
#define LITL_READ_GET_CUR_EVENT_PER_THREAD(process, thread_index)
Returns a current event of a given thread.
Definition: litl_read.h:173
litl_med_size_t header_nb_threads
Definition: litl_types.h:261
litl_buffer_t header_buffer_ptr
Definition: litl_types.h:388
A data structure for reading events from both regular trace files and archives of traces...
Definition: litl_types.h:384
#define LITL_MAX_PARAMS
Defines the maximum number of parameters.
Definition: litl_types.h:167
litl_size_t buffer_size
Definition: litl_types.h:262
A data structure for reading thread-specific events.
Definition: litl_types.h:351
litl_read_trace_t * litl_read_open_trace(const char *filename)
Opens a trace and reads the first portion of data (trace header) to the buffer.
Definition: litl_read.c:187
void litl_read_reset_process(litl_read_process_t *process)
Resets the trace pointer.
Definition: litl_read.c:300
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
#define NBTHREADS
Defines the maximum number of threads (pairs of tid and offset) stored in one data slot...
Definition: litl_types.h:240
litl_general_header_t * header
Definition: litl_types.h:387
litl_process_header_t * litl_read_get_process_header(litl_read_process_t *process)
Returns a pointer to the process header.
Definition: litl_read.c:245
#define LITL_READ_GET_TIME(read_event)
Returns a time stamp of a given event.
Definition: litl_read.h:194
A data structure for reading one event.
Definition: litl_types.h:342
litl_read_event_t cur_event
Definition: litl_types.h:360
litl_read_thread_t ** threads
Definition: litl_types.h:373
litl_process_header_t * header
Definition: litl_types.h:368
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_size_t litl_read_get_buffer_size(litl_read_trace_t *trace)
Returns the buffer size.
Definition: litl_read.c:264
A general data structure that corresponds to the header of a trace file.
Definition: litl_types.h:258
litl_med_size_t nb_processes
Definition: litl_types.h:250
litl_tid_t tid
Definition: litl_types.h:272
litl_offset_t offset
Definition: litl_types.h:357
uint8_t * litl_buffer_t
A data type for storing sets of events.
Definition: litl_types.h:133
A data structure for reading process-specific events.
Definition: litl_types.h:367
litl_tid_t tid
Definition: litl_types.h:343
litl_read_event_t * litl_read_next_process_event(litl_read_trace_t *trace, litl_read_process_t *process)
Reads the next event from a trace.
Definition: litl_read.c:385
litl_buffer_t header_buffer
Definition: litl_types.h:370
litl_buffer_t header_buffer
Definition: litl_types.h:389
void litl_read_finalize_trace(litl_read_trace_t *trace)
Closes the trace and frees the allocated memory.
Definition: litl_read.c:443
litl_param_t offset
Definition: litl_types.h:229
void litl_read_set_buffer_size(litl_read_trace_t *trace, const litl_size_t buf_size)
Sets the buffer size.
Definition: litl_read.c:253
litl_buffer_t buffer
Definition: litl_types.h:355
litl_offset_t offset
Definition: litl_types.h:264
litl_thread_pair_t * thread_pair
Definition: litl_types.h:352
uint16_t litl_med_size_t
An auxiliary data type for the optimized storage of data.
Definition: litl_types.h:150
A data structure for pairs (tid, offset) stored in the trace header.
Definition: litl_types.h:271
litl_read_event_t * litl_read_next_event(litl_read_trace_t *trace)
Reads the next event from a trace file.
Definition: litl_read.c:424
An offset event.
#define LITL_OFFSET_CODE
Defines the code of an event of type offset.
Definition: litl_types.h:161
uint8_t litl_data_t
A data type for the optimized storage of parameters.
Definition: litl_types.h:155
litl_med_size_t nb_threads
Definition: litl_types.h:260
litl_read_process_t ** processes
Definition: litl_types.h:392
uint32_t litl_size_t
An auxiliary data type for storing data.
Definition: litl_types.h:145
litl_read Provides a set of functions for reading events from a regular trace file or an archive of t...
litl_buffer_t header_buffer_ptr
Definition: litl_types.h:369
#define LITL_READ_GET_CUR_EVENT(process)
Returns a current event of a given trace.
Definition: litl_read.h:180
uint64_t litl_time_t
A data type for storing time stamps.
Definition: litl_types.h:112
litl_offset_t tracker
Definition: litl_types.h:358
uint64_t litl_trace_size_t
A data type for storing traces sizes.
Definition: litl_types.h:117
litl_med_size_t nb_processes
Definition: litl_types.h:391
uint64_t litl_offset_t
A data type for storing offsets.
Definition: litl_types.h:127
litl_med_size_t nb_threads
Definition: litl_types.h:372
A general data structure that corresponds to the header of a trace file.
Definition: litl_types.h:247
void litl_read_init_processes(litl_read_trace_t *trace)
Initializes the event reading structure.
Definition: litl_read.c:206
litl_tools Provides a set of auxiliary functions
litl_general_header_t * litl_read_get_trace_header(litl_read_trace_t *trace)
Returns a pointer to the trace header.
Definition: litl_read.c:238
litl_code_t code
Definition: litl_types.h:192
litl_buffer_t buffer_ptr
Definition: litl_types.h:354