litl  0.1.9
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_read_thread_t* thread) {
274  lseek(trace->f_handle,
275  process->header->offset
276  + thread->thread_pair->offset,
277  SEEK_SET);
278 
279  thread->offset = 0;
280 
281  // read portion of next events
282  int res = read(trace->f_handle, thread->buffer_ptr,
283  process->header->buffer_size);
284  if (res == -1) {
285  perror("Could not read the next part of the trace file!");
286  exit(EXIT_FAILURE);
287  }
288 
289  thread->buffer = thread->buffer_ptr;
290  thread->tracker = thread ->offset + process->header->buffer_size;
291 }
292 
293 /*
294  * Resets the thread buffers of a given process
295  */
297  litl_med_size_t thread_index;
298 
299  for (thread_index = 0; thread_index < process->nb_threads; thread_index++)
300  process->threads[thread_index]->buffer =
301  process->threads[thread_index]->buffer_ptr;
302 }
303 
304 /*
305  * Reads an event
306  */
307 static litl_read_event_t* __litl_read_next_thread_event(
308  litl_read_trace_t* trace, litl_read_process_t* process,
309  litl_read_thread_t* thread) {
310 
311  litl_data_t to_be_loaded;
312  litl_t* event;
313  litl_buffer_t buffer;
314 
315  buffer = thread->buffer;
316  to_be_loaded = 0;
317 
318  if (!buffer) {
319  thread->cur_event.event = NULL;
320  return NULL ;
321  }
322 
323  event = (litl_t *) buffer;
324 
325  // While reading events from the buffer, there can be two situations:
326  // 1. The situation when the buffer contains exact number of events;
327  // 2. The situation when only a part of the last event is loaded.
328  // Check whether the main four components (tid, time, code, nb_params) are
329  // loaded.
330  // Check whether all arguments are loaded.
331  // If any of these cases is not true, the next part of the trace plus
332  // the current event is loaded to the buffer
333  litl_size_t remaining_size = thread->tracker - thread->offset;
334  if (remaining_size < __litl_get_reg_event_size(0)) {
335  // this event is truncated. We can't even read the nb_param field
336  to_be_loaded = 1;
337  } else {
338  // The nb_param (or size) field is available. Let's check whether
339  // the event is truncated
340  litl_med_size_t event_size = __litl_get_gen_event_size(event);
341  if (remaining_size < event_size)
342  to_be_loaded = 1;
343  }
344 
345  // fetch the next block of data from the trace
346  if (to_be_loaded) {
347  __litl_read_next_buffer(trace, process, thread);
348  buffer = thread->buffer;
349  event = (litl_t *) buffer;
350  }
351  to_be_loaded = 0;
352 
353  // event that stores tid and offset
354  if (event->code == LITL_OFFSET_CODE) {
355  if (event->parameters.offset.offset != 0) {
356  thread->thread_pair->offset = event->parameters.offset.offset;
357  to_be_loaded = 1;
358  } else {
359  buffer = NULL;
360  thread->cur_event.event = NULL;
361  return NULL ;
362  }
363  }
364 
365  // fetch the next block of data from the trace
366  if (to_be_loaded) {
367  __litl_read_next_buffer(trace, process, thread);
368  buffer = thread->buffer;
369  event = (litl_t *) buffer;
370  }
371 
372  // move pointer to the next event and update __offset
373  litl_med_size_t evt_size = __litl_get_gen_event_size(event);
374  thread->buffer += evt_size;
375  thread->offset += evt_size;
376 
377  thread->cur_event.event = event;
378  thread->cur_event.tid = thread->thread_pair->tid;
379 
380  return &thread->cur_event;
381 }
382 
384  litl_read_process_t* process,
385  litl_read_thread_t* thread) {
386  return __litl_read_next_thread_event(trace, process, thread);
387 }
388 
389 
390 /*
391  * Searches for the next event inside the trace
392  */
394  litl_read_process_t* process) {
395 
396  litl_med_size_t thread_index;
397  litl_time_t min_time = -1;
398 
399  if (!process->is_initialized) {
400  for (thread_index = 0; thread_index < process->nb_threads; thread_index++)
401  __litl_read_next_thread_event(trace, process, process->threads[thread_index]);
402 
403  process->cur_index = -1;
404  process->is_initialized = 1;
405  }
406 
407  // read the next event from the buffer
408  if (process->cur_index != -1)
409  __litl_read_next_thread_event(trace, process, process->threads[process->cur_index]);
410 
411  int found = 0;
412  for (thread_index = 0; thread_index < process->nb_threads; thread_index++) {
413  litl_read_event_t *evt =
414  LITL_READ_GET_CUR_EVENT_PER_THREAD(process, thread_index);
415  if ( evt && evt->event && (LITL_READ_GET_TIME(evt) < min_time))
416  {
417  found = 1;
418  min_time = LITL_READ_GET_TIME(evt);
419  process->cur_index = thread_index;
420  }
421  }
422 
423  if (found)
424  return LITL_READ_GET_CUR_EVENT(process);
425 
426  return NULL ;
427 }
428 
429 /*
430  * Reads the next event from a trace
431  */
433  litl_med_size_t process_index;
434  litl_read_event_t* event = NULL;
435 
436  for (process_index = 0; process_index < trace->nb_processes;
437  process_index++) {
438  event = litl_read_next_process_event(trace,
439  trace->processes[process_index]);
440 
441  if (event != NULL )
442  break;
443  }
444 
445  return event;
446 }
447 
448 /*
449  * Closes the trace and frees the buffer
450  */
452  litl_med_size_t process_index, thread_index;
453 
454  // close the file
455  close(trace->f_handle);
456  trace->f_handle = -1;
457 
458  // free traces
459  for (process_index = 0; process_index < trace->nb_processes;
460  process_index++) {
461 
462  for (thread_index = 0;
463  thread_index < trace->processes[process_index]->nb_threads;
464  thread_index++) {
465  free(trace->processes[process_index]->threads[thread_index]->thread_pair);
466  free(trace->processes[process_index]->threads[thread_index]->buffer_ptr);
467  free(trace->processes[process_index]->threads[thread_index]);
468  }
469 
470  free(trace->processes[process_index]->threads);
471  free(trace->processes[process_index]->header_buffer_ptr);
472  free(trace->processes[process_index]);
473  }
474 
475  // free a trace structure
476  free(trace->processes);
477  free(trace->header_buffer_ptr);
478  free(trace);
479 
480  // set the trace pointer to NULL
481  trace = NULL;
482 }
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
litl_size_t litl_read_get_buffer_size(litl_read_trace_t *trace)
Returns the buffer size.
Definition: litl_read.c:264
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_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
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
void litl_read_init_processes(litl_read_trace_t *trace)
Initializes the event reading structure.
Definition: litl_read.c:206
void litl_read_reset_process(litl_read_process_t *process)
Resets the trace pointer.
Definition: litl_read.c:296
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:393
litl_read_event_t * litl_read_next_thread_event(litl_read_trace_t *trace, litl_read_process_t *process, litl_read_thread_t *thread)
Reads the next event from a trace.
Definition: litl_read.c:383
void litl_read_finalize_trace(litl_read_trace_t *trace)
Closes the trace and frees the allocated memory.
Definition: litl_read.c:451
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:432
#define LITL_READ_GET_TIME(read_event)
Returns a time stamp of a given event.
Definition: litl_read.h:231
#define LITL_READ_GET_CUR_EVENT(process)
Returns a current event of a given trace.
Definition: litl_read.h:217
#define LITL_READ_GET_CUR_EVENT_PER_THREAD(process, thread_index)
Returns a current event of a given thread.
Definition: litl_read.h:210
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_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
#define LITL_OFFSET_CODE
Defines the code of an event of type offset.
Definition: litl_types.h:163
uint8_t litl_data_t
A data type for the optimized storage of parameters.
Definition: litl_types.h:157
uint32_t litl_size_t
An auxiliary data type for storing data.
Definition: litl_types.h:147
uint8_t * litl_buffer_t
A data type for storing sets of events.
Definition: litl_types.h:135
#define LITL_MAX_PARAMS
Defines the maximum number of parameters.
Definition: litl_types.h:169
uint16_t litl_med_size_t
An auxiliary data type for the optimized storage of data.
Definition: litl_types.h:152
#define NBTHREADS
Defines the maximum number of threads (pairs of tid and offset) stored in one data slot.
Definition: litl_types.h:242
uint64_t litl_trace_size_t
A data type for storing traces sizes.
Definition: litl_types.h:119
uint64_t litl_time_t
A data type for storing time stamps.
Definition: litl_types.h:114
uint64_t litl_offset_t
A data type for storing offsets.
Definition: litl_types.h:129
litl_read Provides a set of functions for reading events from a regular trace file or an archive of t...
litl_tools Provides a set of auxiliary functions
A general data structure that corresponds to the header of a trace file.
Definition: litl_types.h:249
litl_med_size_t nb_processes
Definition: litl_types.h:252
A general data structure that corresponds to the header of a trace file.
Definition: litl_types.h:260
litl_med_size_t header_nb_threads
Definition: litl_types.h:263
litl_med_size_t nb_threads
Definition: litl_types.h:262
litl_size_t buffer_size
Definition: litl_types.h:264
litl_offset_t offset
Definition: litl_types.h:266
A data structure for reading one event.
Definition: litl_types.h:345
litl_tid_t tid
Definition: litl_types.h:346
A data structure for reading process-specific events.
Definition: litl_types.h:370
litl_med_size_t nb_threads
Definition: litl_types.h:375
litl_read_thread_t ** threads
Definition: litl_types.h:376
litl_buffer_t header_buffer_ptr
Definition: litl_types.h:372
litl_buffer_t header_buffer
Definition: litl_types.h:373
litl_process_header_t * header
Definition: litl_types.h:371
A data structure for reading thread-specific events.
Definition: litl_types.h:354
litl_offset_t tracker
Definition: litl_types.h:361
litl_offset_t offset
Definition: litl_types.h:360
litl_thread_pair_t * thread_pair
Definition: litl_types.h:355
litl_buffer_t buffer
Definition: litl_types.h:358
litl_buffer_t buffer_ptr
Definition: litl_types.h:357
litl_read_event_t cur_event
Definition: litl_types.h:363
A data structure for reading events from both regular trace files and archives of traces.
Definition: litl_types.h:387
litl_general_header_t * header
Definition: litl_types.h:390
litl_buffer_t header_buffer
Definition: litl_types.h:392
litl_read_process_t ** processes
Definition: litl_types.h:395
litl_buffer_t header_buffer_ptr
Definition: litl_types.h:391
litl_med_size_t nb_processes
Definition: litl_types.h:394
A general structure of LiTL event type.
Definition: litl_types.h:192
union litl_t::@0 parameters
litl_param_t offset
Definition: litl_types.h:231
litl_code_t code
Definition: litl_types.h:194
A data structure for pairs (tid, offset) stored in the trace header.
Definition: litl_types.h:273
litl_offset_t offset
Definition: litl_types.h:275
litl_tid_t tid
Definition: litl_types.h:274
An offset event.