449cb9d7 |
1 | /* This file is part of the Linux Trace Toolkit viewer |
3aee1200 |
2 | * Copyright (C) 2005 Mathieu Desnoyers |
449cb9d7 |
3 | * |
3aee1200 |
4 | * Complete rewrite from the original version made by XangXiu Yang. |
5 | * |
1b44b0b5 |
6 | * This library is free software; you can redistribute it and/or |
7 | * modify it under the terms of the GNU Lesser General Public |
8 | * License Version 2.1 as published by the Free Software Foundation. |
449cb9d7 |
9 | * |
1b44b0b5 |
10 | * This library is distributed in the hope that it will be useful, |
449cb9d7 |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1b44b0b5 |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | * Lesser General Public License for more details. |
449cb9d7 |
14 | * |
1b44b0b5 |
15 | * You should have received a copy of the GNU Lesser General Public |
16 | * License along with this library; if not, write to the |
17 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
18 | * Boston, MA 02111-1307, USA. |
449cb9d7 |
19 | */ |
20 | |
4e4d11b3 |
21 | #ifdef HAVE_CONFIG_H |
22 | #include <config.h> |
23 | #endif |
24 | |
6cd62ccf |
25 | #include <stdio.h> |
26 | #include <fcntl.h> |
8d1e6362 |
27 | #include <string.h> |
28 | #include <dirent.h> |
6cd62ccf |
29 | #include <sys/stat.h> |
30 | #include <sys/types.h> |
8d1e6362 |
31 | #include <errno.h> |
32 | #include <unistd.h> |
42db9bf1 |
33 | #include <math.h> |
cdf90f40 |
34 | #include <glib.h> |
43ed82b5 |
35 | #include <glib/gprintf.h> |
3aee1200 |
36 | #include <malloc.h> |
37 | #include <sys/mman.h> |
dd3a6d39 |
38 | #include <string.h> |
43ed82b5 |
39 | #include <ctype.h> |
40 | #include <inttypes.h> |
6cd62ccf |
41 | |
ef35d837 |
42 | // For realpath |
43 | #include <limits.h> |
44 | #include <stdlib.h> |
45 | |
46 | |
a5dcde2f |
47 | #include <ltt/ltt.h> |
48 | #include "ltt-private.h" |
963b5f2d |
49 | #include <ltt/trace.h> |
c02ea99f |
50 | #include <ltt/event.h> |
1a2ceb63 |
51 | #include <ltt/ltt-types.h> |
bb38a290 |
52 | #include <ltt/marker.h> |
3aee1200 |
53 | |
43ed82b5 |
54 | /* from marker.c */ |
55 | extern long marker_update_fields_offsets(struct marker_info *info, const char *data); |
56 | |
2fc874ab |
57 | /* Tracefile names used in this file */ |
3aee1200 |
58 | |
2fc874ab |
59 | GQuark LTT_TRACEFILE_NAME_METADATA; |
3aee1200 |
60 | |
86005ded |
61 | #ifndef g_open |
62 | #define g_open open |
63 | #endif |
64 | |
65 | |
51b5991e |
66 | #define __UNUSED__ __attribute__((__unused__)) |
6cd62ccf |
67 | |
a1062ddd |
68 | #define g_info(format...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, format) |
3aee1200 |
69 | |
70 | #ifndef g_debug |
a1062ddd |
71 | #define g_debug(format...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, format) |
3aee1200 |
72 | #endif |
a1062ddd |
73 | |
45e14832 |
74 | #define g_close close |
8959a0c8 |
75 | |
b77d1b57 |
76 | /* Those macros must be called from within a function where page_size is a known |
77 | * variable */ |
78 | #define PAGE_MASK (~(page_size-1)) |
79 | #define PAGE_ALIGN(addr) (((addr)+page_size-1)&PAGE_MASK) |
80 | |
9c731a50 |
81 | LttTrace *father_trace = NULL; |
82 | |
6cd62ccf |
83 | /* set the offset of the fields belonging to the event, |
84 | need the information of the archecture */ |
f104d082 |
85 | //void set_fields_offsets(LttTracefile *tf, LttEventType *event_type); |
eed2ef37 |
86 | //size_t get_fields_offsets(LttTracefile *tf, LttEventType *event_type, void *data); |
6cd62ccf |
87 | |
3aee1200 |
88 | /* map a fixed size or a block information from the file (fd) */ |
89 | static gint map_block(LttTracefile * tf, guint block_num); |
90 | |
91 | /* calculate nsec per cycles for current block */ |
791dffa6 |
92 | #if 0 |
93 | static guint32 calc_nsecs_per_cycle(LttTracefile * t); |
94 | static guint64 cycles_2_ns(LttTracefile *tf, guint64 cycles); |
95 | #endif //0 |
6cd62ccf |
96 | |
3aee1200 |
97 | /* go to the next event */ |
98 | static int ltt_seek_next_event(LttTracefile *tf); |
6cd62ccf |
99 | |
3c165eaf |
100 | static int open_tracefiles(LttTrace *trace, gchar *root_path, |
101 | gchar *relative_path); |
2fc874ab |
102 | static int ltt_process_metadata_tracefile(LttTracefile *tf); |
3c165eaf |
103 | static void ltt_tracefile_time_span_get(LttTracefile *tf, |
104 | LttTime *start, LttTime *end); |
105 | static void group_time_span_get(GQuark name, gpointer data, gpointer user_data); |
106 | static gint map_block(LttTracefile * tf, guint block_num); |
3c165eaf |
107 | static void ltt_update_event_size(LttTracefile *tf); |
91f8d488 |
108 | |
109 | /* Enable event debugging */ |
110 | static int a_event_debug = 0; |
111 | |
112 | void ltt_event_debug(int state) |
113 | { |
114 | a_event_debug = state; |
115 | } |
116 | |
b7576a11 |
117 | /* trace can be NULL |
118 | * |
119 | * Return value : 0 success, 1 bad tracefile |
120 | */ |
64dd41a5 |
121 | static int parse_trace_header(ltt_subbuffer_header_t *header, |
122 | LttTracefile *tf, LttTrace *t) |
b7576a11 |
123 | { |
64dd41a5 |
124 | if (header->magic_number == LTT_MAGIC_NUMBER) |
b7576a11 |
125 | tf->reverse_bo = 0; |
64dd41a5 |
126 | else if(header->magic_number == LTT_REV_MAGIC_NUMBER) |
b7576a11 |
127 | tf->reverse_bo = 1; |
128 | else /* invalid magic number, bad tracefile ! */ |
129 | return 1; |
64dd41a5 |
130 | |
131 | if(t) { |
132 | t->ltt_major_version = header->major_version; |
133 | t->ltt_minor_version = header->minor_version; |
134 | t->arch_size = header->arch_size; |
135 | } |
136 | tf->alignment = header->alignment; |
137 | |
b7576a11 |
138 | /* Get float byte order : might be different from int byte order |
139 | * (or is set to 0 if the trace has no float (kernel trace)) */ |
64dd41a5 |
140 | tf->float_word_order = 0; |
b7576a11 |
141 | |
64dd41a5 |
142 | switch(header->major_version) { |
b7576a11 |
143 | case 0: |
2fc874ab |
144 | case 1: |
3c165eaf |
145 | g_warning("Unsupported trace version : %hhu.%hhu", |
64dd41a5 |
146 | header->major_version, header->minor_version); |
3c165eaf |
147 | return 1; |
148 | break; |
2fc874ab |
149 | case 2: |
64dd41a5 |
150 | switch(header->minor_version) { |
750eb11a |
151 | case 3: |
b7576a11 |
152 | { |
750eb11a |
153 | struct ltt_subbuffer_header_2_3 *vheader = header; |
1550fba6 |
154 | tf->buffer_header_size = ltt_subbuffer_header_size(); |
64dd41a5 |
155 | tf->tscbits = 27; |
156 | tf->eventbits = 5; |
2fc874ab |
157 | tf->tsc_mask = ((1ULL << tf->tscbits) - 1); |
158 | tf->tsc_mask_next_bit = (1ULL << tf->tscbits); |
159 | |
e939e5b2 |
160 | if(t) { |
161 | t->start_freq = ltt_get_uint64(LTT_GET_BO(tf), |
162 | &vheader->start_freq); |
a3999b49 |
163 | t->freq_scale = ltt_get_uint32(LTT_GET_BO(tf), |
164 | &vheader->freq_scale); |
9c731a50 |
165 | if(father_trace) { |
166 | t->start_freq = father_trace->start_freq; |
167 | t->freq_scale = father_trace->freq_scale; |
64dd41a5 |
168 | } else { |
9c731a50 |
169 | father_trace = t; |
170 | } |
e939e5b2 |
171 | t->start_tsc = ltt_get_uint64(LTT_GET_BO(tf), |
64dd41a5 |
172 | &vheader->cycle_count_begin); |
173 | t->start_monotonic = 0; |
e939e5b2 |
174 | t->start_time.tv_sec = ltt_get_uint64(LTT_GET_BO(tf), |
175 | &vheader->start_time_sec); |
176 | t->start_time.tv_nsec = ltt_get_uint64(LTT_GET_BO(tf), |
177 | &vheader->start_time_usec); |
178 | t->start_time.tv_nsec *= 1000; /* microsec to nanosec */ |
179 | |
180 | t->start_time_from_tsc = ltt_time_from_uint64( |
c7f86478 |
181 | (double)t->start_tsc |
d0e3122a |
182 | * 1000000000.0 * tf->trace->freq_scale |
62e4e7bf |
183 | / (double)t->start_freq); |
e939e5b2 |
184 | } |
185 | } |
186 | break; |
b7576a11 |
187 | default: |
986e2a7c |
188 | g_warning("Unsupported trace version : %hhu.%hhu", |
64dd41a5 |
189 | header->major_version, header->minor_version); |
b7576a11 |
190 | return 1; |
191 | } |
192 | break; |
b7576a11 |
193 | default: |
194 | g_warning("Unsupported trace version : %hhu.%hhu", |
64dd41a5 |
195 | header->major_version, header->minor_version); |
b7576a11 |
196 | return 1; |
197 | } |
b7576a11 |
198 | return 0; |
199 | } |
200 | |
201 | |
202 | |
6cd62ccf |
203 | /***************************************************************************** |
204 | *Function name |
963b5f2d |
205 | * ltt_tracefile_open : open a trace file, construct a LttTracefile |
6cd62ccf |
206 | *Input params |
963b5f2d |
207 | * t : the trace containing the tracefile |
208 | * fileName : path name of the trace file |
3aee1200 |
209 | * tf : the tracefile structure |
6cd62ccf |
210 | *Return value |
3aee1200 |
211 | * : 0 for success, -1 otherwise. |
6cd62ccf |
212 | ****************************************************************************/ |
213 | |
8655430b |
214 | static gint ltt_tracefile_open(LttTrace *t, gchar * fileName, LttTracefile *tf) |
6cd62ccf |
215 | { |
963b5f2d |
216 | struct stat lTDFStat; /* Trace data file status */ |
64dd41a5 |
217 | ltt_subbuffer_header_t *header; |
b77d1b57 |
218 | int page_size = getpagesize(); |
6cd62ccf |
219 | |
220 | //open the file |
d3d34f49 |
221 | tf->long_name = g_quark_from_string(fileName); |
963b5f2d |
222 | tf->trace = t; |
3865ea09 |
223 | tf->fd = open(fileName, O_RDONLY); |
6cd62ccf |
224 | if(tf->fd < 0){ |
2a74fbf4 |
225 | g_warning("Unable to open input data file %s\n", fileName); |
3aee1200 |
226 | goto end; |
6cd62ccf |
227 | } |
228 | |
229 | // Get the file's status |
230 | if(fstat(tf->fd, &lTDFStat) < 0){ |
2a74fbf4 |
231 | g_warning("Unable to get the status of the input data file %s\n", fileName); |
3aee1200 |
232 | goto close_file; |
6cd62ccf |
233 | } |
234 | |
235 | // Is the file large enough to contain a trace |
823820eb |
236 | if(lTDFStat.st_size < |
1550fba6 |
237 | (off_t)(ltt_subbuffer_header_size())){ |
8710c6c7 |
238 | g_print("The input data file %s does not contain a trace\n", fileName); |
3aee1200 |
239 | goto close_file; |
240 | } |
241 | |
242 | /* Temporarily map the buffer start header to get trace information */ |
243 | /* Multiple of pages aligned head */ |
b77d1b57 |
244 | tf->buffer.head = mmap(0, |
1550fba6 |
245 | PAGE_ALIGN(ltt_subbuffer_header_size()), PROT_READ, |
3aee1200 |
246 | MAP_PRIVATE, tf->fd, 0); |
3865ea09 |
247 | if(tf->buffer.head == MAP_FAILED) { |
3aee1200 |
248 | perror("Error in allocating memory for buffer of tracefile"); |
249 | goto close_file; |
6cd62ccf |
250 | } |
f64fedd7 |
251 | g_assert( ( (gulong)tf->buffer.head&(8-1) ) == 0); // make sure it's aligned. |
3aee1200 |
252 | |
64dd41a5 |
253 | header = (ltt_subbuffer_header_t *)tf->buffer.head; |
6cd62ccf |
254 | |
64dd41a5 |
255 | if(parse_trace_header(header, tf, NULL)) { |
51551c6f |
256 | g_warning("parse_trace_header error"); |
257 | goto unmap_file; |
258 | } |
3aee1200 |
259 | |
6cd62ccf |
260 | //store the size of the file |
261 | tf->file_size = lTDFStat.st_size; |
f628823c |
262 | tf->buf_size = ltt_get_uint32(LTT_GET_BO(tf), &header->buf_size); |
263 | tf->num_blocks = tf->file_size / tf->buf_size; |
426f6149 |
264 | tf->events_lost = 0; |
265 | tf->subbuf_corrupt = 0; |
f628823c |
266 | |
267 | if(munmap(tf->buffer.head, |
1550fba6 |
268 | PAGE_ALIGN(ltt_subbuffer_header_size()))) { |
43ed82b5 |
269 | g_warning("unmap size : %zu\n", |
1550fba6 |
270 | PAGE_ALIGN(ltt_subbuffer_header_size())); |
f628823c |
271 | perror("munmap error"); |
272 | g_assert(0); |
273 | } |
3aee1200 |
274 | tf->buffer.head = NULL; |
6cd62ccf |
275 | |
963b5f2d |
276 | //read the first block |
3aee1200 |
277 | if(map_block(tf,0)) { |
278 | perror("Cannot map block for tracefile"); |
279 | goto close_file; |
280 | } |
281 | |
282 | return 0; |
6cd62ccf |
283 | |
3aee1200 |
284 | /* Error */ |
285 | unmap_file: |
f628823c |
286 | if(munmap(tf->buffer.head, |
1550fba6 |
287 | PAGE_ALIGN(ltt_subbuffer_header_size()))) { |
43ed82b5 |
288 | g_warning("unmap size : %zu\n", |
1550fba6 |
289 | PAGE_ALIGN(ltt_subbuffer_header_size())); |
f628823c |
290 | perror("munmap error"); |
291 | g_assert(0); |
292 | } |
3aee1200 |
293 | close_file: |
3865ea09 |
294 | close(tf->fd); |
3aee1200 |
295 | end: |
296 | return -1; |
6cd62ccf |
297 | } |
298 | |
6cd62ccf |
299 | |
300 | /***************************************************************************** |
301 | *Function name |
963b5f2d |
302 | * ltt_tracefile_close: close a trace file, |
6cd62ccf |
303 | *Input params |
963b5f2d |
304 | * t : tracefile which will be closed |
6cd62ccf |
305 | ****************************************************************************/ |
306 | |
8655430b |
307 | static void ltt_tracefile_close(LttTracefile *t) |
6cd62ccf |
308 | { |
f628823c |
309 | int page_size = getpagesize(); |
310 | |
3aee1200 |
311 | if(t->buffer.head != NULL) |
f628823c |
312 | if(munmap(t->buffer.head, PAGE_ALIGN(t->buf_size))) { |
313 | g_warning("unmap size : %u\n", |
314 | PAGE_ALIGN(t->buf_size)); |
315 | perror("munmap error"); |
316 | g_assert(0); |
317 | } |
318 | |
3865ea09 |
319 | close(t->fd); |
963b5f2d |
320 | } |
6cd62ccf |
321 | |
8d1e6362 |
322 | /**************************************************************************** |
323 | * get_absolute_pathname |
803229fa |
324 | * |
8d1e6362 |
325 | * return the unique pathname in the system |
326 | * |
ef35d837 |
327 | * MD : Fixed this function so it uses realpath, dealing well with |
328 | * forgotten cases (.. were not used correctly before). |
803229fa |
329 | * |
963b5f2d |
330 | ****************************************************************************/ |
45e14832 |
331 | void get_absolute_pathname(const gchar *pathname, gchar * abs_pathname) |
9f797243 |
332 | { |
9f797243 |
333 | abs_pathname[0] = '\0'; |
803229fa |
334 | |
2fc874ab |
335 | if (realpath(pathname, abs_pathname) != NULL) |
ef35d837 |
336 | return; |
337 | else |
338 | { |
8d1e6362 |
339 | /* error, return the original path unmodified */ |
ef35d837 |
340 | strcpy(abs_pathname, pathname); |
9f797243 |
341 | return; |
342 | } |
ef35d837 |
343 | return; |
9f797243 |
344 | } |
345 | |
3aee1200 |
346 | /* Search for something like : .*_.* |
347 | * |
348 | * The left side is the name, the right side is the number. |
750eb11a |
349 | * Exclude leading /. |
4ad053df |
350 | * Exclude flight- prefix. |
3aee1200 |
351 | */ |
352 | |
8655430b |
353 | static int get_tracefile_name_number(gchar *raw_name, |
3aee1200 |
354 | GQuark *name, |
ae3d0f50 |
355 | guint *num, |
f64fedd7 |
356 | gulong *tid, |
357 | gulong *pgid, |
62e4e7bf |
358 | guint64 *creation) |
6cd62ccf |
359 | { |
3aee1200 |
360 | guint raw_name_len = strlen(raw_name); |
361 | gchar char_name[PATH_MAX]; |
8af0138e |
362 | int i; |
3aee1200 |
363 | int underscore_pos; |
364 | long int cpu_num; |
365 | gchar *endptr; |
62e4e7bf |
366 | gchar *tmpptr; |
3aee1200 |
367 | |
750eb11a |
368 | /* skip leading / */ |
369 | for(i = 0; i < raw_name_len-1;i++) { |
370 | if(raw_name[i] != '/') |
371 | break; |
372 | } |
373 | raw_name = &raw_name[i]; |
374 | raw_name_len = strlen(raw_name); |
375 | |
3aee1200 |
376 | for(i=raw_name_len-1;i>=0;i--) { |
377 | if(raw_name[i] == '_') break; |
378 | } |
ae3d0f50 |
379 | if(i==-1) { /* Either not found or name length is 0 */ |
62e4e7bf |
380 | /* This is a userspace tracefile */ |
381 | strncpy(char_name, raw_name, raw_name_len); |
382 | char_name[raw_name_len] = '\0'; |
383 | *name = g_quark_from_string(char_name); |
384 | *num = 0; /* unknown cpu */ |
385 | for(i=0;i<raw_name_len;i++) { |
386 | if(raw_name[i] == '/') { |
387 | break; |
388 | } |
389 | } |
390 | i++; |
391 | for(;i<raw_name_len;i++) { |
392 | if(raw_name[i] == '/') { |
393 | break; |
394 | } |
395 | } |
396 | i++; |
397 | for(;i<raw_name_len;i++) { |
398 | if(raw_name[i] == '-') { |
399 | break; |
400 | } |
401 | } |
402 | if(i == raw_name_len) return -1; |
403 | i++; |
404 | tmpptr = &raw_name[i]; |
405 | for(;i<raw_name_len;i++) { |
406 | if(raw_name[i] == '.') { |
407 | raw_name[i] = ' '; |
408 | break; |
409 | } |
410 | } |
411 | *tid = strtoul(tmpptr, &endptr, 10); |
412 | if(endptr == tmpptr) |
413 | return -1; /* No digit */ |
414 | if(*tid == ULONG_MAX) |
415 | return -1; /* underflow / overflow */ |
416 | i++; |
417 | tmpptr = &raw_name[i]; |
418 | for(;i<raw_name_len;i++) { |
419 | if(raw_name[i] == '.') { |
420 | raw_name[i] = ' '; |
421 | break; |
422 | } |
423 | } |
424 | *pgid = strtoul(tmpptr, &endptr, 10); |
425 | if(endptr == tmpptr) |
426 | return -1; /* No digit */ |
427 | if(*pgid == ULONG_MAX) |
428 | return -1; /* underflow / overflow */ |
429 | i++; |
430 | tmpptr = &raw_name[i]; |
431 | *creation = strtoull(tmpptr, &endptr, 10); |
432 | if(endptr == tmpptr) |
433 | return -1; /* No digit */ |
434 | if(*creation == G_MAXUINT64) |
435 | return -1; /* underflow / overflow */ |
436 | } else { |
437 | underscore_pos = i; |
438 | |
439 | cpu_num = strtol(raw_name+underscore_pos+1, &endptr, 10); |
440 | |
441 | if(endptr == raw_name+underscore_pos+1) |
442 | return -1; /* No digit */ |
443 | if(cpu_num == LONG_MIN || cpu_num == LONG_MAX) |
444 | return -1; /* underflow / overflow */ |
445 | |
4ad053df |
446 | if (!strncmp(raw_name, "flight-", sizeof("flight-") - 1)) { |
447 | raw_name += sizeof("flight-") - 1; |
448 | underscore_pos -= sizeof("flight-") - 1; |
449 | } |
62e4e7bf |
450 | strncpy(char_name, raw_name, underscore_pos); |
451 | char_name[underscore_pos] = '\0'; |
62e4e7bf |
452 | *name = g_quark_from_string(char_name); |
453 | *num = cpu_num; |
454 | } |
69bd59ed |
455 | |
b333a76b |
456 | |
3aee1200 |
457 | return 0; |
458 | } |
963b5f2d |
459 | |
3aee1200 |
460 | |
3865ea09 |
461 | GData **ltt_trace_get_tracefiles_groups(LttTrace *trace) |
77175651 |
462 | { |
3865ea09 |
463 | return &trace->tracefiles; |
77175651 |
464 | } |
465 | |
466 | |
3865ea09 |
467 | void compute_tracefile_group(GQuark key_id, |
468 | GArray *group, |
469 | struct compute_tracefile_group_args *args) |
77175651 |
470 | { |
43ed82b5 |
471 | unsigned int i; |
77175651 |
472 | LttTracefile *tf; |
473 | |
474 | for(i=0; i<group->len; i++) { |
475 | tf = &g_array_index (group, LttTracefile, i); |
476 | if(tf->cpu_online) |
3865ea09 |
477 | args->func(tf, args->func_args); |
77175651 |
478 | } |
479 | } |
480 | |
481 | |
8655430b |
482 | static void ltt_tracefile_group_destroy(gpointer data) |
3aee1200 |
483 | { |
484 | GArray *group = (GArray *)data; |
43ed82b5 |
485 | unsigned int i; |
3aee1200 |
486 | LttTracefile *tf; |
487 | |
750eb11a |
488 | if (group->len > 0) |
489 | destroy_marker_data(g_array_index (group, LttTracefile, 0).mdata); |
3aee1200 |
490 | for(i=0; i<group->len; i++) { |
491 | tf = &g_array_index (group, LttTracefile, i); |
492 | if(tf->cpu_online) |
493 | ltt_tracefile_close(tf); |
494 | } |
495 | g_array_free(group, TRUE); |
6cd62ccf |
496 | } |
497 | |
43ed82b5 |
498 | static __attribute__ ((__unused__)) gboolean ltt_tracefile_group_has_cpu_online(gpointer data) |
49bf71b5 |
499 | { |
3aee1200 |
500 | GArray *group = (GArray *)data; |
43ed82b5 |
501 | unsigned int i; |
3aee1200 |
502 | LttTracefile *tf; |
503 | |
504 | for(i=0; i<group->len; i++) { |
505 | tf = &g_array_index (group, LttTracefile, i); |
3c165eaf |
506 | if(tf->cpu_online) |
507 | return 1; |
3aee1200 |
508 | } |
509 | return 0; |
49bf71b5 |
510 | } |
511 | |
512 | |
3aee1200 |
513 | /* Open each tracefile under a specific directory. Put them in a |
514 | * GData : permits to access them using their tracefile group pathname. |
515 | * i.e. access control/modules tracefile group by index : |
516 | * "control/module". |
3865ea09 |
517 | * |
518 | * relative path is the path relative to the trace root |
519 | * root path is the full path |
3aee1200 |
520 | * |
4a55f63e |
521 | * A tracefile group is simply an array where all the per cpu tracefiles sit. |
3aee1200 |
522 | */ |
523 | |
8655430b |
524 | static int open_tracefiles(LttTrace *trace, gchar *root_path, gchar *relative_path) |
f7afe191 |
525 | { |
62e4e7bf |
526 | DIR *dir = opendir(root_path); |
527 | struct dirent *entry; |
528 | struct stat stat_buf; |
750eb11a |
529 | int ret, i; |
530 | struct marker_data *mdata; |
3865ea09 |
531 | |
62e4e7bf |
532 | gchar path[PATH_MAX]; |
533 | int path_len; |
534 | gchar *path_ptr; |
3aee1200 |
535 | |
3865ea09 |
536 | int rel_path_len; |
69bd59ed |
537 | gchar rel_path[PATH_MAX]; |
538 | gchar *rel_path_ptr; |
cb03932a |
539 | LttTracefile tmp_tf; |
3865ea09 |
540 | |
62e4e7bf |
541 | if(dir == NULL) { |
542 | perror(root_path); |
543 | return ENOENT; |
544 | } |
3aee1200 |
545 | |
62e4e7bf |
546 | strncpy(path, root_path, PATH_MAX-1); |
547 | path_len = strlen(path); |
548 | path[path_len] = '/'; |
549 | path_len++; |
550 | path_ptr = path + path_len; |
3aee1200 |
551 | |
3865ea09 |
552 | strncpy(rel_path, relative_path, PATH_MAX-1); |
553 | rel_path_len = strlen(rel_path); |
554 | rel_path[rel_path_len] = '/'; |
555 | rel_path_len++; |
556 | rel_path_ptr = rel_path + rel_path_len; |
557 | |
62e4e7bf |
558 | while((entry = readdir(dir)) != NULL) { |
559 | |
560 | if(entry->d_name[0] == '.') continue; |
561 | |
562 | strncpy(path_ptr, entry->d_name, PATH_MAX - path_len); |
563 | strncpy(rel_path_ptr, entry->d_name, PATH_MAX - rel_path_len); |
564 | |
565 | ret = stat(path, &stat_buf); |
566 | if(ret == -1) { |
567 | perror(path); |
568 | continue; |
569 | } |
570 | |
571 | g_debug("Tracefile file or directory : %s\n", path); |
572 | |
fe452434 |
573 | // if(strcmp(rel_path, "/eventdefs") == 0) continue; |
74a588bb |
574 | |
62e4e7bf |
575 | if(S_ISDIR(stat_buf.st_mode)) { |
3aee1200 |
576 | |
62e4e7bf |
577 | g_debug("Entering subdirectory...\n"); |
578 | ret = open_tracefiles(trace, path, rel_path); |
579 | if(ret < 0) continue; |
580 | } else if(S_ISREG(stat_buf.st_mode)) { |
581 | GQuark name; |
f64fedd7 |
582 | guint num; |
583 | gulong tid, pgid; |
62e4e7bf |
584 | guint64 creation; |
3aee1200 |
585 | GArray *group; |
f64fedd7 |
586 | num = 0; |
587 | tid = pgid = 0; |
62e4e7bf |
588 | creation = 0; |
ae3d0f50 |
589 | if(get_tracefile_name_number(rel_path, &name, &num, &tid, &pgid, &creation)) |
3aee1200 |
590 | continue; /* invalid name */ |
3865ea09 |
591 | |
62e4e7bf |
592 | g_debug("Opening file.\n"); |
cb03932a |
593 | if(ltt_tracefile_open(trace, path, &tmp_tf)) { |
594 | g_info("Error opening tracefile %s", path); |
595 | |
596 | continue; /* error opening the tracefile : bad magic number ? */ |
597 | } |
598 | |
3865ea09 |
599 | g_debug("Tracefile name is %s and number is %u", |
600 | g_quark_to_string(name), num); |
750eb11a |
601 | |
602 | mdata = NULL; |
cb03932a |
603 | tmp_tf.cpu_online = 1; |
604 | tmp_tf.cpu_num = num; |
d3d34f49 |
605 | tmp_tf.name = name; |
62e4e7bf |
606 | tmp_tf.tid = tid; |
607 | tmp_tf.pgid = pgid; |
608 | tmp_tf.creation = creation; |
3865ea09 |
609 | group = g_datalist_id_get_data(&trace->tracefiles, name); |
3aee1200 |
610 | if(group == NULL) { |
611 | /* Elements are automatically cleared when the array is allocated. |
612 | * It makes the cpu_online variable set to 0 : cpu offline, by default. |
613 | */ |
614 | group = g_array_sized_new (FALSE, TRUE, sizeof(LttTracefile), 10); |
3865ea09 |
615 | g_datalist_id_set_data_full(&trace->tracefiles, name, |
3aee1200 |
616 | group, ltt_tracefile_group_destroy); |
750eb11a |
617 | mdata = allocate_marker_data(); |
618 | if (!mdata) |
619 | g_error("Error in allocating marker data"); |
3aee1200 |
620 | } |
cb03932a |
621 | |
3aee1200 |
622 | /* Add the per cpu tracefile to the named group */ |
623 | unsigned int old_len = group->len; |
624 | if(num+1 > old_len) |
625 | group = g_array_set_size(group, num+1); |
750eb11a |
626 | |
627 | g_assert(group->len > 0); |
628 | if (!mdata) |
629 | mdata = g_array_index (group, LttTracefile, 0).mdata; |
630 | |
cb03932a |
631 | g_array_index (group, LttTracefile, num) = tmp_tf; |
afd57a3c |
632 | g_array_index (group, LttTracefile, num).event.tracefile = |
633 | &g_array_index (group, LttTracefile, num); |
750eb11a |
634 | for (i = 0; i < group->len; i++) |
635 | g_array_index (group, LttTracefile, i).mdata = mdata; |
62e4e7bf |
636 | } |
637 | } |
638 | |
639 | closedir(dir); |
3aee1200 |
640 | |
62e4e7bf |
641 | return 0; |
f7afe191 |
642 | } |
643 | |
3aee1200 |
644 | |
645 | /* Presumes the tracefile is already seeked at the beginning. It makes sense, |
646 | * because it must be done just after the opening */ |
2fc874ab |
647 | static int ltt_process_metadata_tracefile(LttTracefile *tf) |
3aee1200 |
648 | { |
649 | int err; |
3aee1200 |
650 | |
651 | while(1) { |
652 | err = ltt_tracefile_read_seek(tf); |
653 | if(err == EPERM) goto seek_error; |
654 | else if(err == ERANGE) break; /* End of tracefile */ |
655 | |
656 | err = ltt_tracefile_read_update_event(tf); |
657 | if(err) goto update_error; |
658 | |
3aee1200 |
659 | /* The rules are : |
2fc874ab |
660 | * It contains only core events : |
661 | * 0 : set_marker_id |
662 | * 1 : set_marker_format |
3aee1200 |
663 | */ |
3c165eaf |
664 | if(tf->event.event_id >= MARKER_CORE_IDS) { |
2fc874ab |
665 | /* Should only contain core events */ |
666 | g_warning("Error in processing metadata file %s, " |
3c165eaf |
667 | "should not contain event id %u.", g_quark_to_string(tf->name), |
668 | tf->event.event_id); |
3aee1200 |
669 | err = EPERM; |
3c165eaf |
670 | goto event_id_error; |
d2083cab |
671 | } else { |
2e13d6af |
672 | char *pos; |
750eb11a |
673 | const char *channel_name, *marker_name, *format; |
3c165eaf |
674 | uint16_t id; |
675 | guint8 int_size, long_size, pointer_size, size_t_size, alignment; |
3aee1200 |
676 | |
3c165eaf |
677 | switch((enum marker_id)tf->event.event_id) { |
678 | case MARKER_ID_SET_MARKER_ID: |
750eb11a |
679 | channel_name = pos = tf->event.data; |
680 | pos += strlen(channel_name) + 1; |
681 | marker_name = pos; |
682 | g_debug("Doing MARKER_ID_SET_MARKER_ID of marker %s.%s", |
683 | channel_name, marker_name); |
2e13d6af |
684 | pos += strlen(marker_name) + 1; |
2fc874ab |
685 | pos += ltt_align((size_t)pos, sizeof(guint16), tf->alignment); |
3c165eaf |
686 | id = ltt_get_uint16(LTT_GET_BO(tf), pos); |
750eb11a |
687 | g_debug("In MARKER_ID_SET_MARKER_ID of marker %s.%s id %hu", |
688 | channel_name, marker_name, id); |
3c165eaf |
689 | pos += sizeof(guint16); |
690 | int_size = *(guint8*)pos; |
691 | pos += sizeof(guint8); |
692 | long_size = *(guint8*)pos; |
693 | pos += sizeof(guint8); |
694 | pointer_size = *(guint8*)pos; |
695 | pos += sizeof(guint8); |
696 | size_t_size = *(guint8*)pos; |
697 | pos += sizeof(guint8); |
698 | alignment = *(guint8*)pos; |
699 | pos += sizeof(guint8); |
750eb11a |
700 | marker_id_event(tf->trace, |
701 | g_quark_from_string(channel_name), |
702 | g_quark_from_string(marker_name), |
3c165eaf |
703 | id, int_size, long_size, |
704 | pointer_size, size_t_size, alignment); |
3aee1200 |
705 | break; |
3c165eaf |
706 | case MARKER_ID_SET_MARKER_FORMAT: |
750eb11a |
707 | channel_name = pos = tf->event.data; |
708 | pos += strlen(channel_name) + 1; |
709 | marker_name = pos; |
710 | g_debug("Doing MARKER_ID_SET_MARKER_FORMAT of marker %s.%s", |
711 | channel_name, marker_name); |
2e13d6af |
712 | pos += strlen(marker_name) + 1; |
2e13d6af |
713 | format = pos; |
3c165eaf |
714 | pos += strlen(format) + 1; |
750eb11a |
715 | marker_format_event(tf->trace, |
716 | g_quark_from_string(channel_name), |
717 | g_quark_from_string(marker_name), |
3c165eaf |
718 | format); |
2fc874ab |
719 | /* get information from dictionary TODO */ |
d1bb700c |
720 | break; |
3aee1200 |
721 | default: |
2fc874ab |
722 | g_warning("Error in processing metadata file %s, " |
3c165eaf |
723 | "unknown event id %hhu.", |
3aee1200 |
724 | g_quark_to_string(tf->name), |
725 | tf->event.event_id); |
726 | err = EPERM; |
727 | goto event_id_error; |
728 | } |
729 | } |
963b5f2d |
730 | } |
3aee1200 |
731 | return 0; |
963b5f2d |
732 | |
3aee1200 |
733 | /* Error handling */ |
3aee1200 |
734 | event_id_error: |
3aee1200 |
735 | update_error: |
736 | seek_error: |
2fc874ab |
737 | g_warning("An error occured in metadata tracefile parsing"); |
3aee1200 |
738 | return err; |
6cd62ccf |
739 | } |
740 | |
e95fe8f7 |
741 | /* |
742 | * Open a trace and return its LttTrace handle. |
743 | * |
744 | * pathname must be the directory of the trace |
745 | */ |
963b5f2d |
746 | |
3aee1200 |
747 | LttTrace *ltt_trace_open(const gchar *pathname) |
748 | { |
749 | gchar abs_path[PATH_MAX]; |
750 | LttTrace * t; |
751 | LttTracefile *tf; |
752 | GArray *group; |
43ed82b5 |
753 | unsigned int i; |
754 | int ret; |
64dd41a5 |
755 | ltt_subbuffer_header_t *header; |
62e4e7bf |
756 | DIR *dir; |
757 | struct dirent *entry; |
62e4e7bf |
758 | struct stat stat_buf; |
b56dcdf2 |
759 | gchar path[PATH_MAX]; |
3aee1200 |
760 | |
761 | t = g_new(LttTrace, 1); |
762 | if(!t) goto alloc_error; |
763 | |
764 | get_absolute_pathname(pathname, abs_path); |
765 | t->pathname = g_quark_from_string(abs_path); |
766 | |
3aee1200 |
767 | g_datalist_init(&t->tracefiles); |
b56dcdf2 |
768 | |
769 | /* Test to see if it looks like a trace */ |
62e4e7bf |
770 | dir = opendir(abs_path); |
771 | if(dir == NULL) { |
772 | perror(abs_path); |
773 | goto open_error; |
774 | } |
775 | while((entry = readdir(dir)) != NULL) { |
b56dcdf2 |
776 | strcpy(path, abs_path); |
777 | strcat(path, "/"); |
778 | strcat(path, entry->d_name); |
62e4e7bf |
779 | ret = stat(path, &stat_buf); |
780 | if(ret == -1) { |
781 | perror(path); |
782 | continue; |
783 | } |
b56dcdf2 |
784 | } |
785 | closedir(dir); |
786 | |
b56dcdf2 |
787 | /* Open all the tracefiles */ |
e45551ac |
788 | if(open_tracefiles(t, abs_path, "")) { |
789 | g_warning("Error opening tracefile %s", abs_path); |
b56dcdf2 |
790 | goto find_error; |
e45551ac |
791 | } |
3aee1200 |
792 | |
750eb11a |
793 | /* Parse each trace metadata_N files : get runtime fac. info */ |
2fc874ab |
794 | group = g_datalist_id_get_data(&t->tracefiles, LTT_TRACEFILE_NAME_METADATA); |
3aee1200 |
795 | if(group == NULL) { |
8af0138e |
796 | g_warning("Trace %s has no metadata tracefile", abs_path); |
750eb11a |
797 | goto find_error; |
3aee1200 |
798 | } |
799 | |
e0c7c400 |
800 | /* |
750eb11a |
801 | * Get the trace information for the metadata_0 tracefile. |
e0c7c400 |
802 | * Getting a correct trace start_time and start_tsc is insured by the fact |
803 | * that no subbuffers are supposed to be lost in the metadata channel. |
804 | * Therefore, the first subbuffer contains the start_tsc timestamp in its |
805 | * buffer header. |
806 | */ |
16fcbb80 |
807 | g_assert(group->len > 0); |
808 | tf = &g_array_index (group, LttTracefile, 0); |
64dd41a5 |
809 | header = (ltt_subbuffer_header_t *)tf->buffer.head; |
ac3b1c7d |
810 | ret = parse_trace_header(header, tf, t); |
811 | g_assert(!ret); |
b56dcdf2 |
812 | |
813 | t->num_cpu = group->len; |
16fcbb80 |
814 | |
750eb11a |
815 | //ret = allocate_marker_data(t); |
816 | //if (ret) |
817 | // g_error("Error in allocating marker data"); |
d79909d1 |
818 | |
3aee1200 |
819 | for(i=0; i<group->len; i++) { |
820 | tf = &g_array_index (group, LttTracefile, i); |
e85b0b1b |
821 | if (tf->cpu_online) |
2fc874ab |
822 | if(ltt_process_metadata_tracefile(tf)) |
750eb11a |
823 | goto find_error; |
824 | // goto metadata_error; |
3aee1200 |
825 | } |
dd3a6d39 |
826 | |
3aee1200 |
827 | return t; |
828 | |
829 | /* Error handling */ |
750eb11a |
830 | //metadata_error: |
831 | // destroy_marker_data(t); |
b56dcdf2 |
832 | find_error: |
3aee1200 |
833 | g_datalist_clear(&t->tracefiles); |
b56dcdf2 |
834 | open_error: |
3aee1200 |
835 | g_free(t); |
836 | alloc_error: |
837 | return NULL; |
838 | |
839 | } |
6cd62ccf |
840 | |
e95fe8f7 |
841 | /* Open another, completely independant, instance of a trace. |
842 | * |
843 | * A read on this new instance will read the first event of the trace. |
844 | * |
3aee1200 |
845 | * When we copy a trace, we want all the opening actions to happen again : |
846 | * the trace will be reopened and totally independant from the original. |
847 | * That's why we call ltt_trace_open. |
e95fe8f7 |
848 | */ |
3aee1200 |
849 | LttTrace *ltt_trace_copy(LttTrace *self) |
963b5f2d |
850 | { |
3aee1200 |
851 | return ltt_trace_open(g_quark_to_string(self->pathname)); |
963b5f2d |
852 | } |
853 | |
e95fe8f7 |
854 | /* |
855 | * Close a trace |
856 | */ |
857 | |
3aee1200 |
858 | void ltt_trace_close(LttTrace *t) |
6cd62ccf |
859 | { |
3aee1200 |
860 | g_datalist_clear(&t->tracefiles); |
861 | g_free(t); |
6cd62ccf |
862 | } |
863 | |
3aee1200 |
864 | |
6cd62ccf |
865 | /***************************************************************************** |
3aee1200 |
866 | * Get the start time and end time of the trace |
6cd62ccf |
867 | ****************************************************************************/ |
868 | |
3c165eaf |
869 | void ltt_tracefile_time_span_get(LttTracefile *tf, |
3aee1200 |
870 | LttTime *start, LttTime *end) |
6cd62ccf |
871 | { |
3aee1200 |
872 | int err; |
6cd62ccf |
873 | |
3aee1200 |
874 | err = map_block(tf, 0); |
875 | if(unlikely(err)) { |
876 | g_error("Can not map block"); |
877 | *start = ltt_time_infinite; |
878 | } else |
879 | *start = tf->buffer.begin.timestamp; |
880 | |
881 | err = map_block(tf, tf->num_blocks - 1); /* Last block */ |
882 | if(unlikely(err)) { |
883 | g_error("Can not map block"); |
884 | *end = ltt_time_zero; |
885 | } else |
886 | *end = tf->buffer.end.timestamp; |
6cd62ccf |
887 | } |
888 | |
3aee1200 |
889 | struct tracefile_time_span_get_args { |
890 | LttTrace *t; |
891 | LttTime *start; |
892 | LttTime *end; |
893 | }; |
963b5f2d |
894 | |
8655430b |
895 | static void group_time_span_get(GQuark name, gpointer data, gpointer user_data) |
963b5f2d |
896 | { |
3aee1200 |
897 | struct tracefile_time_span_get_args *args = |
898 | (struct tracefile_time_span_get_args*)user_data; |
899 | |
900 | GArray *group = (GArray *)data; |
43ed82b5 |
901 | unsigned int i; |
3aee1200 |
902 | LttTracefile *tf; |
903 | LttTime tmp_start; |
904 | LttTime tmp_end; |
905 | |
906 | for(i=0; i<group->len; i++) { |
907 | tf = &g_array_index (group, LttTracefile, i); |
908 | if(tf->cpu_online) { |
909 | ltt_tracefile_time_span_get(tf, &tmp_start, &tmp_end); |
910 | if(ltt_time_compare(*args->start, tmp_start)>0) *args->start = tmp_start; |
911 | if(ltt_time_compare(*args->end, tmp_end)<0) *args->end = tmp_end; |
912 | } |
913 | } |
6cd62ccf |
914 | } |
915 | |
8655430b |
916 | /* return the start and end time of a trace */ |
917 | |
487ad181 |
918 | void ltt_trace_time_span_get(LttTrace *t, LttTime *start, LttTime *end) |
919 | { |
3aee1200 |
920 | LttTime min_start = ltt_time_infinite; |
921 | LttTime max_end = ltt_time_zero; |
922 | struct tracefile_time_span_get_args args = { t, &min_start, &max_end }; |
487ad181 |
923 | |
3aee1200 |
924 | g_datalist_foreach(&t->tracefiles, &group_time_span_get, &args); |
925 | |
926 | if(start != NULL) *start = min_start; |
927 | if(end != NULL) *end = max_end; |
928 | |
487ad181 |
929 | } |
930 | |
931 | |
3aee1200 |
932 | /* Seek to the first event in a tracefile that has a time equal or greater than |
933 | * the time passed in parameter. |
934 | * |
935 | * If the time parameter is outside the tracefile time span, seek to the first |
27304273 |
936 | * event or if after, return ERANGE. |
3aee1200 |
937 | * |
938 | * If the time parameter is before the first event, we have to seek specially to |
939 | * there. |
940 | * |
27304273 |
941 | * If the time is after the end of the trace, return ERANGE. |
3aee1200 |
942 | * |
943 | * Do a binary search to find the right block, then a sequential search in the |
944 | * block to find the event. |
945 | * |
946 | * In the special case where the time requested fits inside a block that has no |
947 | * event corresponding to the requested time, the first event of the next block |
948 | * will be seeked. |
949 | * |
950 | * IMPORTANT NOTE : // FIXME everywhere... |
951 | * |
952 | * You MUST NOT do a ltt_tracefile_read right after a ltt_tracefile_seek_time : |
953 | * you will jump over an event if you do. |
954 | * |
955 | * Return value : 0 : no error, the tf->event can be used |
27304273 |
956 | * ERANGE : time if after the last event of the trace |
3aee1200 |
957 | * otherwise : this is an error. |
958 | * |
959 | * */ |
960 | |
961 | int ltt_tracefile_seek_time(LttTracefile *tf, LttTime time) |
962 | { |
963 | int ret = 0; |
964 | int err; |
965 | unsigned int block_num, high, low; |
966 | |
967 | /* seek at the beginning of trace */ |
968 | err = map_block(tf, 0); /* First block */ |
969 | if(unlikely(err)) { |
970 | g_error("Can not map block"); |
971 | goto fail; |
caf7a67a |
972 | } |
973 | |
3aee1200 |
974 | /* If the time is lower or equal the beginning of the trace, |
975 | * go to the first event. */ |
976 | if(ltt_time_compare(time, tf->buffer.begin.timestamp) <= 0) { |
977 | ret = ltt_tracefile_read(tf); |
27304273 |
978 | if(ret == ERANGE) goto range; |
979 | else if (ret) goto fail; |
3aee1200 |
980 | goto found; /* There is either no event in the trace or the event points |
981 | to the first event in the trace */ |
982 | } |
caf7a67a |
983 | |
3aee1200 |
984 | err = map_block(tf, tf->num_blocks - 1); /* Last block */ |
985 | if(unlikely(err)) { |
986 | g_error("Can not map block"); |
987 | goto fail; |
caf7a67a |
988 | } |
6cd62ccf |
989 | |
27304273 |
990 | /* If the time is after the end of the trace, return ERANGE. */ |
991 | if(ltt_time_compare(time, tf->buffer.end.timestamp) > 0) { |
992 | goto range; |
3aee1200 |
993 | } |
62e55dd6 |
994 | |
3aee1200 |
995 | /* Binary search the block */ |
996 | high = tf->num_blocks - 1; |
997 | low = 0; |
998 | |
999 | while(1) { |
1000 | block_num = ((high-low) / 2) + low; |
1001 | |
1002 | err = map_block(tf, block_num); |
1003 | if(unlikely(err)) { |
1004 | g_error("Can not map block"); |
1005 | goto fail; |
db55eaae |
1006 | } |
3aee1200 |
1007 | if(high == low) { |
1008 | /* We cannot divide anymore : this is what would happen if the time |
1009 | * requested was exactly between two consecutive buffers'end and start |
1010 | * timestamps. This is also what would happend if we didn't deal with out |
1011 | * of span cases prior in this function. */ |
1012 | /* The event is right in the buffer! |
1013 | * (or in the next buffer first event) */ |
1014 | while(1) { |
1015 | ret = ltt_tracefile_read(tf); |
27304273 |
1016 | if(ret == ERANGE) goto range; /* ERANGE or EPERM */ |
3aee1200 |
1017 | else if(ret) goto fail; |
1018 | |
d9e13a0f |
1019 | if(ltt_time_compare(time, tf->event.event_time) <= 0) |
e45551ac |
1020 | goto found; |
3aee1200 |
1021 | } |
1022 | |
27304273 |
1023 | } else if(ltt_time_compare(time, tf->buffer.begin.timestamp) < 0) { |
3aee1200 |
1024 | /* go to lower part */ |
b1369bef |
1025 | high = block_num - 1; |
3aee1200 |
1026 | } else if(ltt_time_compare(time, tf->buffer.end.timestamp) > 0) { |
1027 | /* go to higher part */ |
b1369bef |
1028 | low = block_num + 1; |
3aee1200 |
1029 | } else {/* The event is right in the buffer! |
1030 | (or in the next buffer first event) */ |
1031 | while(1) { |
27304273 |
1032 | ret = ltt_tracefile_read(tf); |
1033 | if(ret == ERANGE) goto range; /* ERANGE or EPERM */ |
3aee1200 |
1034 | else if(ret) goto fail; |
1035 | |
d9e13a0f |
1036 | if(ltt_time_compare(time, tf->event.event_time) <= 0) |
3aee1200 |
1037 | break; |
6cd62ccf |
1038 | } |
3aee1200 |
1039 | goto found; |
6cd62ccf |
1040 | } |
6cd62ccf |
1041 | } |
3aee1200 |
1042 | |
1043 | found: |
1044 | return 0; |
27304273 |
1045 | range: |
1046 | return ERANGE; |
3aee1200 |
1047 | |
1048 | /* Error handling */ |
1049 | fail: |
1050 | g_error("ltt_tracefile_seek_time failed on tracefile %s", |
1051 | g_quark_to_string(tf->name)); |
1052 | return EPERM; |
6cd62ccf |
1053 | } |
1054 | |
e95fe8f7 |
1055 | /* Seek to a position indicated by an LttEventPosition |
1056 | */ |
80da81ad |
1057 | |
8655430b |
1058 | int ltt_tracefile_seek_position(LttTracefile *tf, const LttEventPosition *ep) |
1059 | { |
3aee1200 |
1060 | int err; |
1061 | |
1062 | if(ep->tracefile != tf) { |
1063 | goto fail; |
80da81ad |
1064 | } |
1065 | |
3aee1200 |
1066 | err = map_block(tf, ep->block); |
1067 | if(unlikely(err)) { |
1068 | g_error("Can not map block"); |
1069 | goto fail; |
1070 | } |
1071 | |
1072 | tf->event.offset = ep->offset; |
18206708 |
1073 | |
62e4e7bf |
1074 | /* Put back the event real tsc */ |
1075 | tf->event.tsc = ep->tsc; |
1076 | tf->buffer.tsc = ep->tsc; |
78f79181 |
1077 | |
3aee1200 |
1078 | err = ltt_tracefile_read_update_event(tf); |
1079 | if(err) goto fail; |
73faf25a |
1080 | |
1081 | /* deactivate this, as it does nothing for now |
3aee1200 |
1082 | err = ltt_tracefile_read_op(tf); |
1083 | if(err) goto fail; |
73faf25a |
1084 | */ |
80da81ad |
1085 | |
a0c1f622 |
1086 | return 0; |
3aee1200 |
1087 | |
1088 | fail: |
1089 | g_error("ltt_tracefile_seek_time failed on tracefile %s", |
1090 | g_quark_to_string(tf->name)); |
a0c1f622 |
1091 | return 1; |
3aee1200 |
1092 | } |
1093 | |
e95fe8f7 |
1094 | /* Given a TSC value, return the LttTime (seconds,nanoseconds) it |
1095 | * corresponds to. |
1096 | */ |
1097 | |
ae3d0f50 |
1098 | LttTime ltt_interpolate_time_from_tsc(LttTracefile *tf, guint64 tsc) |
3aee1200 |
1099 | { |
1100 | LttTime time; |
62e4e7bf |
1101 | |
1102 | if(tsc > tf->trace->start_tsc) { |
1103 | time = ltt_time_from_uint64( |
1104 | (double)(tsc - tf->trace->start_tsc) |
d0e3122a |
1105 | * 1000000000.0 * tf->trace->freq_scale |
62e4e7bf |
1106 | / (double)tf->trace->start_freq); |
1107 | time = ltt_time_add(tf->trace->start_time_from_tsc, time); |
1108 | } else { |
1109 | time = ltt_time_from_uint64( |
1110 | (double)(tf->trace->start_tsc - tsc) |
d0e3122a |
1111 | * 1000000000.0 * tf->trace->freq_scale |
62e4e7bf |
1112 | / (double)tf->trace->start_freq); |
1113 | time = ltt_time_sub(tf->trace->start_time_from_tsc, time); |
1114 | } |
3aee1200 |
1115 | return time; |
80da81ad |
1116 | } |
1117 | |
ae3d0f50 |
1118 | /* Calculate the real event time based on the buffer boundaries */ |
1119 | LttTime ltt_interpolate_time(LttTracefile *tf, LttEvent *event) |
1120 | { |
62e4e7bf |
1121 | return ltt_interpolate_time_from_tsc(tf, tf->buffer.tsc); |
ae3d0f50 |
1122 | } |
1123 | |
eed2ef37 |
1124 | |
1125 | /* Get the current event of the tracefile : valid until the next read */ |
1126 | LttEvent *ltt_tracefile_get_event(LttTracefile *tf) |
1127 | { |
1128 | return &tf->event; |
1129 | } |
1130 | |
1131 | |
1132 | |
6cd62ccf |
1133 | /***************************************************************************** |
1134 | *Function name |
3aee1200 |
1135 | * ltt_tracefile_read : Read the next event in the tracefile |
6cd62ccf |
1136 | *Input params |
1137 | * t : tracefile |
1138 | *Return value |
3aee1200 |
1139 | * |
1140 | * Returns 0 if an event can be used in tf->event. |
d822520b |
1141 | * Returns ERANGE on end of trace. The event in tf->event still can be used |
1142 | * (if the last block was not empty). |
3aee1200 |
1143 | * Returns EPERM on error. |
1144 | * |
1145 | * This function does make the tracefile event structure point to the event |
1146 | * currently pointed to by the tf->event. |
1147 | * |
1148 | * Note : you must call a ltt_tracefile_seek to the beginning of the trace to |
1149 | * reinitialize it after an error if you want results to be coherent. |
1150 | * It would be the case if a end of trace last buffer has no event : the end |
1151 | * of trace wouldn't be returned, but an error. |
1152 | * We make the assumption there is at least one event per buffer. |
6cd62ccf |
1153 | ****************************************************************************/ |
1154 | |
3aee1200 |
1155 | int ltt_tracefile_read(LttTracefile *tf) |
6cd62ccf |
1156 | { |
963b5f2d |
1157 | int err; |
6cd62ccf |
1158 | |
3aee1200 |
1159 | err = ltt_tracefile_read_seek(tf); |
1160 | if(err) return err; |
1161 | err = ltt_tracefile_read_update_event(tf); |
1162 | if(err) return err; |
73faf25a |
1163 | |
1164 | /* deactivate this, as it does nothing for now |
3aee1200 |
1165 | err = ltt_tracefile_read_op(tf); |
1166 | if(err) return err; |
73faf25a |
1167 | */ |
3aee1200 |
1168 | |
1169 | return 0; |
1170 | } |
1171 | |
1172 | int ltt_tracefile_read_seek(LttTracefile *tf) |
1173 | { |
1174 | int err; |
1175 | |
1176 | /* Get next buffer until we finally have an event, or end of trace */ |
1177 | while(1) { |
1178 | err = ltt_seek_next_event(tf); |
1179 | if(unlikely(err == ENOPROTOOPT)) { |
1180 | return EPERM; |
bdc36259 |
1181 | } |
bdc36259 |
1182 | |
3aee1200 |
1183 | /* Are we at the end of the buffer ? */ |
1184 | if(err == ERANGE) { |
1185 | if(unlikely(tf->buffer.index == tf->num_blocks-1)){ /* end of trace ? */ |
1186 | return ERANGE; |
1187 | } else { |
1188 | /* get next block */ |
1189 | err = map_block(tf, tf->buffer.index + 1); |
1190 | if(unlikely(err)) { |
1191 | g_error("Can not map block"); |
1192 | return EPERM; |
1193 | } |
1194 | } |
1195 | } else break; /* We found an event ! */ |
1196 | } |
2dee981d |
1197 | |
3aee1200 |
1198 | return 0; |
1199 | } |
18206708 |
1200 | |
e95fe8f7 |
1201 | /* do an operation when reading a new event */ |
18206708 |
1202 | |
73faf25a |
1203 | /* This function does nothing for now */ |
1204 | #if 0 |
3aee1200 |
1205 | int ltt_tracefile_read_op(LttTracefile *tf) |
1206 | { |
3aee1200 |
1207 | LttEvent *event; |
1208 | |
1209 | event = &tf->event; |
18206708 |
1210 | |
73faf25a |
1211 | /* do event specific operation */ |
1212 | |
1213 | /* nothing */ |
40331ba8 |
1214 | |
3aee1200 |
1215 | return 0; |
6cd62ccf |
1216 | } |
73faf25a |
1217 | #endif |
6cd62ccf |
1218 | |
91f8d488 |
1219 | static void print_debug_event_header(LttEvent *ev, void *start_pos, void *end_pos) |
1220 | { |
1221 | unsigned int offset = 0; |
1222 | int i, j; |
1223 | |
43ed82b5 |
1224 | g_printf("Event header (tracefile %s offset %" PRIx64 "):\n", |
afd57a3c |
1225 | g_quark_to_string(ev->tracefile->long_name), |
43ed82b5 |
1226 | ((uint64_t)ev->tracefile->buffer.index * ev->tracefile->buf_size) |
1227 | + (long)start_pos - (long)ev->tracefile->buffer.head); |
91f8d488 |
1228 | |
1229 | while (offset < (long)end_pos - (long)start_pos) { |
1230 | g_printf("%8lx", (long)start_pos - (long)ev->tracefile->buffer.head + offset); |
1231 | g_printf(" "); |
1232 | |
1233 | for (i = 0; i < 4 ; i++) { |
1234 | for (j = 0; j < 4; j++) { |
1235 | if (offset + ((i * 4) + j) < |
1236 | (long)end_pos - (long)start_pos) |
1237 | g_printf("%02hhX", |
d3353231 |
1238 | ((char*)start_pos)[offset + ((i * 4) + j)]); |
91f8d488 |
1239 | else |
1240 | g_printf(" "); |
1241 | g_printf(" "); |
1242 | } |
1243 | if (i < 4) |
1244 | g_printf(" "); |
1245 | } |
1246 | offset+=16; |
1247 | g_printf("\n"); |
1248 | } |
1249 | } |
1250 | |
6cd62ccf |
1251 | |
3aee1200 |
1252 | /* same as ltt_tracefile_read, but does not seek to the next event nor call |
1253 | * event specific operation. */ |
1254 | int ltt_tracefile_read_update_event(LttTracefile *tf) |
6cd62ccf |
1255 | { |
3aee1200 |
1256 | void * pos; |
1257 | LttEvent *event; |
91f8d488 |
1258 | void *pos_aligned; |
551bf485 |
1259 | guint16 packed_evid; /* event id reader from the 5 bits in header */ |
3aee1200 |
1260 | |
1261 | event = &tf->event; |
eed2ef37 |
1262 | pos = tf->buffer.head + event->offset; |
3aee1200 |
1263 | |
1264 | /* Read event header */ |
1265 | |
62e4e7bf |
1266 | /* Align the head */ |
2fc874ab |
1267 | pos += ltt_align((size_t)pos, sizeof(guint32), tf->alignment); |
91f8d488 |
1268 | pos_aligned = pos; |
3aee1200 |
1269 | |
2fc874ab |
1270 | event->timestamp = ltt_get_uint32(LTT_GET_BO(tf), pos); |
551bf485 |
1271 | event->event_id = packed_evid = event->timestamp >> tf->tscbits; |
a9048165 |
1272 | event->timestamp = event->timestamp & tf->tsc_mask; |
2fc874ab |
1273 | pos += sizeof(guint32); |
1274 | |
551bf485 |
1275 | switch (packed_evid) { |
2fc874ab |
1276 | case 29: /* LTT_RFLAG_ID_SIZE_TSC */ |
1277 | event->event_id = ltt_get_uint16(LTT_GET_BO(tf), pos); |
1278 | pos += sizeof(guint16); |
1279 | event->event_size = ltt_get_uint16(LTT_GET_BO(tf), pos); |
1280 | pos += sizeof(guint16); |
1281 | if (event->event_size == 0xFFFF) { |
1282 | event->event_size = ltt_get_uint32(LTT_GET_BO(tf), pos); |
1283 | pos += sizeof(guint32); |
d1bb700c |
1284 | } |
2fc874ab |
1285 | pos += ltt_align((size_t)pos, sizeof(guint64), tf->alignment); |
1286 | tf->buffer.tsc = ltt_get_uint64(LTT_GET_BO(tf), pos); |
62e4e7bf |
1287 | pos += sizeof(guint64); |
2fc874ab |
1288 | break; |
1289 | case 30: /* LTT_RFLAG_ID_SIZE */ |
f439de06 |
1290 | event->event_id = ltt_get_uint16(LTT_GET_BO(tf), pos); |
3c165eaf |
1291 | pos += sizeof(guint16); |
d1bb700c |
1292 | event->event_size = ltt_get_uint16(LTT_GET_BO(tf), pos); |
1293 | pos += sizeof(guint16); |
2fc874ab |
1294 | if (event->event_size == 0xFFFF) { |
1295 | event->event_size = ltt_get_uint32(LTT_GET_BO(tf), pos); |
1296 | pos += sizeof(guint32); |
1297 | } |
1298 | break; |
1299 | case 31: /* LTT_RFLAG_ID */ |
1300 | event->event_id = ltt_get_uint16(LTT_GET_BO(tf), pos); |
1301 | pos += sizeof(guint16); |
1302 | event->event_size = G_MAXUINT; |
1303 | break; |
1304 | default: |
1305 | event->event_size = G_MAXUINT; |
1306 | break; |
1307 | } |
1308 | |
551bf485 |
1309 | if (likely(packed_evid != 29)) { |
2fc874ab |
1310 | /* No extended timestamp */ |
1311 | if (event->timestamp < (tf->buffer.tsc & tf->tsc_mask)) |
1312 | tf->buffer.tsc = ((tf->buffer.tsc & ~tf->tsc_mask) /* overflow */ |
1313 | + tf->tsc_mask_next_bit) |
1314 | | (guint64)event->timestamp; |
1315 | else |
1316 | tf->buffer.tsc = (tf->buffer.tsc & ~tf->tsc_mask) /* no overflow */ |
1317 | | (guint64)event->timestamp; |
d1bb700c |
1318 | } |
2fc874ab |
1319 | event->tsc = tf->buffer.tsc; |
1320 | |
1321 | event->event_time = ltt_interpolate_time(tf, event); |
91f8d488 |
1322 | |
1323 | if (a_event_debug) |
1324 | print_debug_event_header(event, pos_aligned, pos); |
1325 | |
3aee1200 |
1326 | event->data = pos; |
1327 | |
2fc874ab |
1328 | /* |
1329 | * Let ltt_update_event_size update event->data according to the largest |
1330 | * alignment within the payload. |
1331 | * Get the data size and update the event fields with the current |
1332 | * information. */ |
eed2ef37 |
1333 | ltt_update_event_size(tf); |
77175651 |
1334 | |
3aee1200 |
1335 | return 0; |
6cd62ccf |
1336 | } |
1337 | |
507915ee |
1338 | |
6cd62ccf |
1339 | /**************************************************************************** |
1340 | *Function name |
3aee1200 |
1341 | * map_block : map a block from the file |
6cd62ccf |
1342 | *Input Params |
1343 | * lttdes : ltt trace file |
1344 | * whichBlock : the block which will be read |
1345 | *return value |
1346 | * 0 : success |
1347 | * EINVAL : lseek fail |
1348 | * EIO : can not read from the file |
1349 | ****************************************************************************/ |
1350 | |
8655430b |
1351 | static gint map_block(LttTracefile * tf, guint block_num) |
6cd62ccf |
1352 | { |
b77d1b57 |
1353 | int page_size = getpagesize(); |
64dd41a5 |
1354 | ltt_subbuffer_header_t *header; |
3aee1200 |
1355 | |
1356 | g_assert(block_num < tf->num_blocks); |
6cd62ccf |
1357 | |
f628823c |
1358 | if(tf->buffer.head != NULL) { |
1359 | if(munmap(tf->buffer.head, PAGE_ALIGN(tf->buf_size))) { |
1360 | g_warning("unmap size : %u\n", |
1361 | PAGE_ALIGN(tf->buf_size)); |
1362 | perror("munmap error"); |
1363 | g_assert(0); |
1364 | } |
1365 | } |
ac849774 |
1366 | |
3aee1200 |
1367 | /* Multiple of pages aligned head */ |
b77d1b57 |
1368 | tf->buffer.head = mmap(0, |
f628823c |
1369 | PAGE_ALIGN(tf->buf_size), |
b77d1b57 |
1370 | PROT_READ, MAP_PRIVATE, tf->fd, |
f628823c |
1371 | PAGE_ALIGN((off_t)tf->buf_size * (off_t)block_num)); |
3aee1200 |
1372 | |
3865ea09 |
1373 | if(tf->buffer.head == MAP_FAILED) { |
3aee1200 |
1374 | perror("Error in allocating memory for buffer of tracefile"); |
3865ea09 |
1375 | g_assert(0); |
3aee1200 |
1376 | goto map_error; |
6cd62ccf |
1377 | } |
f64fedd7 |
1378 | g_assert( ( (gulong)tf->buffer.head&(8-1) ) == 0); // make sure it's aligned. |
3aee1200 |
1379 | |
6cd62ccf |
1380 | |
3aee1200 |
1381 | tf->buffer.index = block_num; |
1382 | |
64dd41a5 |
1383 | header = (ltt_subbuffer_header_t *)tf->buffer.head; |
3aee1200 |
1384 | |
3aee1200 |
1385 | tf->buffer.begin.cycle_count = ltt_get_uint64(LTT_GET_BO(tf), |
64dd41a5 |
1386 | &header->cycle_count_begin); |
1387 | tf->buffer.begin.freq = tf->trace->start_freq; |
ae3d0f50 |
1388 | |
1389 | tf->buffer.begin.timestamp = ltt_interpolate_time_from_tsc(tf, |
62e4e7bf |
1390 | tf->buffer.begin.cycle_count); |
3aee1200 |
1391 | tf->buffer.end.cycle_count = ltt_get_uint64(LTT_GET_BO(tf), |
64dd41a5 |
1392 | &header->cycle_count_end); |
1393 | tf->buffer.end.freq = tf->trace->start_freq; |
62e4e7bf |
1394 | |
3aee1200 |
1395 | tf->buffer.lost_size = ltt_get_uint32(LTT_GET_BO(tf), |
986e2a7c |
1396 | &header->lost_size); |
ae3d0f50 |
1397 | tf->buffer.end.timestamp = ltt_interpolate_time_from_tsc(tf, |
62e4e7bf |
1398 | tf->buffer.end.cycle_count); |
3aee1200 |
1399 | tf->buffer.tsc = tf->buffer.begin.cycle_count; |
1400 | tf->event.tsc = tf->buffer.tsc; |
986e2a7c |
1401 | tf->buffer.freq = tf->buffer.begin.freq; |
3aee1200 |
1402 | |
1403 | /* FIXME |
1404 | * eventually support variable buffer size : will need a partial pre-read of |
1405 | * the headers to create an index when we open the trace... eventually. */ |
f628823c |
1406 | g_assert(tf->buf_size == ltt_get_uint32(LTT_GET_BO(tf), |
3aee1200 |
1407 | &header->buf_size)); |
507915ee |
1408 | |
3aee1200 |
1409 | /* Make the current event point to the beginning of the buffer : |
1410 | * it means that the event read must get the first event. */ |
1411 | tf->event.tracefile = tf; |
1412 | tf->event.block = block_num; |
eed2ef37 |
1413 | tf->event.offset = 0; |
3aee1200 |
1414 | |
a2bbf2e5 |
1415 | if (header->events_lost) { |
1416 | g_warning("%d events lost so far in tracefile %s at block %u", |
0c2f4984 |
1417 | (guint)header->events_lost, |
a2bbf2e5 |
1418 | g_quark_to_string(tf->long_name), |
1419 | block_num); |
426f6149 |
1420 | tf->events_lost = header->events_lost; |
1421 | } |
a2bbf2e5 |
1422 | if (header->subbuf_corrupt) { |
1423 | g_warning("%d subbuffer(s) corrupted so far in tracefile %s at block %u", |
0c2f4984 |
1424 | (guint)header->subbuf_corrupt, |
a2bbf2e5 |
1425 | g_quark_to_string(tf->long_name), |
1426 | block_num); |
426f6149 |
1427 | tf->subbuf_corrupt = header->subbuf_corrupt; |
1428 | } |
1429 | |
3aee1200 |
1430 | return 0; |
6cd62ccf |
1431 | |
3aee1200 |
1432 | map_error: |
1433 | return -errno; |
6cd62ccf |
1434 | } |
1435 | |
91f8d488 |
1436 | static void print_debug_event_data(LttEvent *ev) |
1437 | { |
1438 | unsigned int offset = 0; |
1439 | int i, j; |
1440 | |
1441 | if (!max(ev->event_size, ev->data_size)) |
1442 | return; |
1443 | |
43ed82b5 |
1444 | g_printf("Event data (tracefile %s offset %" PRIx64 "):\n", |
1445 | g_quark_to_string(ev->tracefile->long_name), |
1446 | ((uint64_t)ev->tracefile->buffer.index * ev->tracefile->buf_size) |
1447 | + (long)ev->data - (long)ev->tracefile->buffer.head); |
91f8d488 |
1448 | |
1449 | while (offset < max(ev->event_size, ev->data_size)) { |
1450 | g_printf("%8lx", (long)ev->data + offset |
1451 | - (long)ev->tracefile->buffer.head); |
1452 | g_printf(" "); |
1453 | |
1454 | for (i = 0; i < 4 ; i++) { |
1455 | for (j = 0; j < 4; j++) { |
1456 | if (offset + ((i * 4) + j) < max(ev->event_size, ev->data_size)) |
1457 | g_printf("%02hhX", ((char*)ev->data)[offset + ((i * 4) + j)]); |
1458 | else |
1459 | g_printf(" "); |
1460 | g_printf(" "); |
1461 | } |
1462 | if (i < 4) |
1463 | g_printf(" "); |
1464 | } |
1465 | |
1466 | g_printf(" "); |
1467 | |
1468 | for (i = 0; i < 4; i++) { |
1469 | for (j = 0; j < 4; j++) { |
1470 | if (offset + ((i * 4) + j) < max(ev->event_size, ev->data_size)) { |
1471 | if (isprint(((char*)ev->data)[offset + ((i * 4) + j)])) |
1472 | g_printf("%c", ((char*)ev->data)[offset + ((i * 4) + j)]); |
1473 | else |
1474 | g_printf("."); |
1475 | } else |
1476 | g_printf(" "); |
1477 | } |
1478 | } |
1479 | offset+=16; |
1480 | g_printf("\n"); |
1481 | } |
1482 | } |
1483 | |
77175651 |
1484 | /* It will update the fields offsets too */ |
1485 | void ltt_update_event_size(LttTracefile *tf) |
6cd62ccf |
1486 | { |
2312de30 |
1487 | off_t size = 0; |
d2007fbd |
1488 | struct marker_info *info; |
750eb11a |
1489 | |
1490 | if (tf->name == LTT_TRACEFILE_NAME_METADATA) { |
1491 | switch((enum marker_id)tf->event.event_id) { |
1492 | case MARKER_ID_SET_MARKER_ID: |
1493 | size = strlen((char*)tf->event.data) + 1; |
1494 | g_debug("marker %s id set", (char*)tf->event.data + size); |
1495 | size += strlen((char*)tf->event.data + size) + 1; |
1496 | size += ltt_align(size, sizeof(guint16), tf->alignment); |
1497 | size += sizeof(guint16); |
1498 | size += sizeof(guint8); |
1499 | size += sizeof(guint8); |
1500 | size += sizeof(guint8); |
1501 | size += sizeof(guint8); |
1502 | size += sizeof(guint8); |
1503 | break; |
1504 | case MARKER_ID_SET_MARKER_FORMAT: |
1505 | size = strlen((char*)tf->event.data) + 1; |
1506 | g_debug("marker %s format set", (char*)tf->event.data); |
1507 | size += strlen((char*)tf->event.data + size) + 1; |
1508 | size += strlen((char*)tf->event.data + size) + 1; |
1509 | break; |
1510 | } |
256a5b3a |
1511 | } |
1512 | |
750eb11a |
1513 | info = marker_get_info_from_id(tf->mdata, tf->event.event_id); |
dcf96842 |
1514 | |
256a5b3a |
1515 | if (tf->event.event_id >= MARKER_CORE_IDS) |
1516 | g_assert(info != NULL); |
1517 | |
1518 | /* Do not update field offsets of core markers when initially reading the |
2fc874ab |
1519 | * metadata tracefile when the infos about these markers do not exist yet. |
256a5b3a |
1520 | */ |
1521 | if (likely(info && info->fields)) { |
2fc874ab |
1522 | /* alignment */ |
196085f2 |
1523 | tf->event.data += ltt_align((off_t)(unsigned long)tf->event.data, |
1524 | info->largest_align, |
2fc874ab |
1525 | info->alignment); |
1526 | /* size, dynamically computed */ |
256a5b3a |
1527 | if (info->size != -1) |
1528 | size = info->size; |
1529 | else |
750eb11a |
1530 | size = marker_update_fields_offsets(marker_get_info_from_id(tf->mdata, |
256a5b3a |
1531 | tf->event.event_id), tf->event.data); |
44f317b7 |
1532 | } |
c4afd5d8 |
1533 | |
d2007fbd |
1534 | tf->event.data_size = size; |
1535 | |
1536 | /* Check consistency between kernel and LTTV structure sizes */ |
2fc874ab |
1537 | if(tf->event.event_size == G_MAXUINT) { |
d2007fbd |
1538 | /* Event size too big to fit in the event size field */ |
1539 | tf->event.event_size = tf->event.data_size; |
1540 | } |
91f8d488 |
1541 | |
1542 | if (a_event_debug) |
1543 | print_debug_event_data(&tf->event); |
1544 | |
d2007fbd |
1545 | if (tf->event.data_size != tf->event.event_size) { |
750eb11a |
1546 | struct marker_info *info = marker_get_info_from_id(tf->mdata, |
3c165eaf |
1547 | tf->event.event_id); |
750eb11a |
1548 | if (!info) |
1549 | g_error("Undescribed event %hhu in channel %s", tf->event.event_id, |
1550 | g_quark_to_string(tf->name)); |
3c165eaf |
1551 | g_error("Kernel/LTTV event size differs for event %s: kernel %u, LTTV %u", |
1552 | g_quark_to_string(info->name), |
1553 | tf->event.event_size, tf->event.data_size); |
d2007fbd |
1554 | exit(-1); |
1555 | } |
6cd62ccf |
1556 | } |
1557 | |
6cd62ccf |
1558 | |
2fc874ab |
1559 | /* Take the tf current event offset and use the event id to figure out where is |
1560 | * the next event offset. |
3aee1200 |
1561 | * |
1562 | * This is an internal function not aiming at being used elsewhere : it will |
1563 | * not jump over the current block limits. Please consider using |
1564 | * ltt_tracefile_read to do this. |
1565 | * |
1566 | * Returns 0 on success |
1567 | * ERANGE if we are at the end of the buffer. |
1568 | * ENOPROTOOPT if an error occured when getting the current event size. |
1569 | */ |
8655430b |
1570 | static int ltt_seek_next_event(LttTracefile *tf) |
6cd62ccf |
1571 | { |
3aee1200 |
1572 | int ret = 0; |
1573 | void *pos; |
3aee1200 |
1574 | |
1575 | /* seek over the buffer header if we are at the buffer start */ |
eed2ef37 |
1576 | if(tf->event.offset == 0) { |
51551c6f |
1577 | tf->event.offset += tf->buffer_header_size; |
b77d1b57 |
1578 | |
f628823c |
1579 | if(tf->event.offset == tf->buf_size - tf->buffer.lost_size) { |
b77d1b57 |
1580 | ret = ERANGE; |
1581 | } |
3aee1200 |
1582 | goto found; |
1583 | } |
2fc874ab |
1584 | |
3aee1200 |
1585 | pos = tf->event.data; |
1586 | |
77175651 |
1587 | if(tf->event.data_size < 0) goto error; |
3aee1200 |
1588 | |
77175651 |
1589 | pos += (size_t)tf->event.data_size; |
3aee1200 |
1590 | |
eed2ef37 |
1591 | tf->event.offset = pos - tf->buffer.head; |
cb03932a |
1592 | |
f628823c |
1593 | if(tf->event.offset == tf->buf_size - tf->buffer.lost_size) { |
cb03932a |
1594 | ret = ERANGE; |
1595 | goto found; |
1596 | } |
36d36c9f |
1597 | g_assert(tf->event.offset < tf->buf_size - tf->buffer.lost_size); |
3aee1200 |
1598 | |
1599 | found: |
1600 | return ret; |
1601 | |
1602 | error: |
1603 | g_error("Error in ltt_seek_next_event for tracefile %s", |
1604 | g_quark_to_string(tf->name)); |
1605 | return ENOPROTOOPT; |
6cd62ccf |
1606 | } |
1607 | |
f104d082 |
1608 | |
6cd62ccf |
1609 | /***************************************************************************** |
1610 | *Function name |
eed2ef37 |
1611 | * ltt_get_int : get an integer number |
6cd62ccf |
1612 | *Input params |
3aee1200 |
1613 | * reverse_byte_order: must we reverse the byte order ? |
6cd62ccf |
1614 | * size : the size of the integer |
3aee1200 |
1615 | * ptr : the data pointer |
6cd62ccf |
1616 | *Return value |
cf74a6f1 |
1617 | * gint64 : a 64 bits integer |
6cd62ccf |
1618 | ****************************************************************************/ |
1619 | |
eed2ef37 |
1620 | gint64 ltt_get_int(gboolean reverse_byte_order, gint size, void *data) |
6cd62ccf |
1621 | { |
3aee1200 |
1622 | gint64 val; |
cf74a6f1 |
1623 | |
1624 | switch(size) { |
3aee1200 |
1625 | case 1: val = *((gint8*)data); break; |
1626 | case 2: val = ltt_get_int16(reverse_byte_order, data); break; |
1627 | case 4: val = ltt_get_int32(reverse_byte_order, data); break; |
1628 | case 8: val = ltt_get_int64(reverse_byte_order, data); break; |
1629 | default: val = ltt_get_int64(reverse_byte_order, data); |
1630 | g_critical("get_int : integer size %d unknown", size); |
cf74a6f1 |
1631 | break; |
1632 | } |
1633 | |
3aee1200 |
1634 | return val; |
6cd62ccf |
1635 | } |
3aee1200 |
1636 | |
6cd62ccf |
1637 | /***************************************************************************** |
1638 | *Function name |
eed2ef37 |
1639 | * ltt_get_uint : get an unsigned integer number |
6cd62ccf |
1640 | *Input params |
3aee1200 |
1641 | * reverse_byte_order: must we reverse the byte order ? |
1642 | * size : the size of the integer |
1643 | * ptr : the data pointer |
1644 | *Return value |
1645 | * guint64 : a 64 bits unsigned integer |
6cd62ccf |
1646 | ****************************************************************************/ |
1647 | |
eed2ef37 |
1648 | guint64 ltt_get_uint(gboolean reverse_byte_order, gint size, void *data) |
6cd62ccf |
1649 | { |
3aee1200 |
1650 | guint64 val; |
1651 | |
1652 | switch(size) { |
1653 | case 1: val = *((gint8*)data); break; |
1654 | case 2: val = ltt_get_uint16(reverse_byte_order, data); break; |
1655 | case 4: val = ltt_get_uint32(reverse_byte_order, data); break; |
1656 | case 8: val = ltt_get_uint64(reverse_byte_order, data); break; |
1657 | default: val = ltt_get_uint64(reverse_byte_order, data); |
1658 | g_critical("get_uint : unsigned integer size %d unknown", |
1659 | size); |
1660 | break; |
1661 | } |
1662 | |
1663 | return val; |
6cd62ccf |
1664 | } |
3aee1200 |
1665 | |
1666 | |
a5dcde2f |
1667 | /* get the node name of the system */ |
1668 | |
1669 | char * ltt_trace_system_description_node_name (LttSystemDescription * s) |
1670 | { |
1671 | return s->node_name; |
1672 | } |
1673 | |
1674 | |
1675 | /* get the domain name of the system */ |
1676 | |
1677 | char * ltt_trace_system_description_domain_name (LttSystemDescription * s) |
1678 | { |
1679 | return s->domain_name; |
1680 | } |
1681 | |
1682 | |
1683 | /* get the description of the system */ |
1684 | |
1685 | char * ltt_trace_system_description_description (LttSystemDescription * s) |
1686 | { |
1687 | return s->description; |
1688 | } |
1689 | |
1690 | |
bf33dd50 |
1691 | /* get the NTP corrected start time of the trace */ |
7bd563ec |
1692 | LttTime ltt_trace_start_time(LttTrace *t) |
a5dcde2f |
1693 | { |
7bd563ec |
1694 | return t->start_time; |
a5dcde2f |
1695 | } |
1696 | |
bf33dd50 |
1697 | /* get the monotonic start time of the trace */ |
1698 | LttTime ltt_trace_start_time_monotonic(LttTrace *t) |
1699 | { |
1700 | return t->start_time_from_tsc; |
1701 | } |
1702 | |
43ed82b5 |
1703 | static __attribute__ ((__unused__)) LttTracefile *ltt_tracefile_new() |
18206708 |
1704 | { |
afd57a3c |
1705 | LttTracefile *tf; |
1706 | tf = g_new(LttTracefile, 1); |
1707 | tf->event.tracefile = tf; |
1708 | return tf; |
18206708 |
1709 | } |
1710 | |
43ed82b5 |
1711 | static __attribute__ ((__unused__)) void ltt_tracefile_destroy(LttTracefile *tf) |
18206708 |
1712 | { |
1713 | g_free(tf); |
1714 | } |
1715 | |
43ed82b5 |
1716 | static __attribute__ ((__unused__)) void ltt_tracefile_copy(LttTracefile *dest, const LttTracefile *src) |
18206708 |
1717 | { |
1718 | *dest = *src; |
1719 | } |
1720 | |
3aee1200 |
1721 | /* Before library loading... */ |
1722 | |
8655430b |
1723 | static __attribute__((constructor)) void init(void) |
3aee1200 |
1724 | { |
750eb11a |
1725 | LTT_TRACEFILE_NAME_METADATA = g_quark_from_string("metadata"); |
3aee1200 |
1726 | } |