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 */
20static 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 */
68static 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 */
95static 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 */
119static 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 */
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) {
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 */
271static 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 */
307static 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
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_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_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_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_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
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
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
#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.