Commit | Line | Data |
---|---|---|
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 */ |
22660d97 | 788 | t->start_freq= 0; |
e45551ac | 789 | if(open_tracefiles(t, abs_path, "")) { |
790 | g_warning("Error opening tracefile %s", abs_path); | |
b56dcdf2 | 791 | goto find_error; |
e45551ac | 792 | } |
3aee1200 | 793 | |
750eb11a | 794 | /* Parse each trace metadata_N files : get runtime fac. info */ |
2fc874ab | 795 | group = g_datalist_id_get_data(&t->tracefiles, LTT_TRACEFILE_NAME_METADATA); |
3aee1200 | 796 | if(group == NULL) { |
8af0138e | 797 | g_warning("Trace %s has no metadata tracefile", abs_path); |
750eb11a | 798 | goto find_error; |
3aee1200 | 799 | } |
800 | ||
e0c7c400 | 801 | /* |
750eb11a | 802 | * Get the trace information for the metadata_0 tracefile. |
e0c7c400 | 803 | * Getting a correct trace start_time and start_tsc is insured by the fact |
804 | * that no subbuffers are supposed to be lost in the metadata channel. | |
805 | * Therefore, the first subbuffer contains the start_tsc timestamp in its | |
806 | * buffer header. | |
807 | */ | |
16fcbb80 | 808 | g_assert(group->len > 0); |
809 | tf = &g_array_index (group, LttTracefile, 0); | |
64dd41a5 | 810 | header = (ltt_subbuffer_header_t *)tf->buffer.head; |
ac3b1c7d | 811 | ret = parse_trace_header(header, tf, t); |
812 | g_assert(!ret); | |
b56dcdf2 | 813 | |
814 | t->num_cpu = group->len; | |
16fcbb80 | 815 | |
750eb11a | 816 | //ret = allocate_marker_data(t); |
817 | //if (ret) | |
818 | // g_error("Error in allocating marker data"); | |
d79909d1 | 819 | |
3aee1200 | 820 | for(i=0; i<group->len; i++) { |
821 | tf = &g_array_index (group, LttTracefile, i); | |
e85b0b1b | 822 | if (tf->cpu_online) |
2fc874ab | 823 | if(ltt_process_metadata_tracefile(tf)) |
750eb11a | 824 | goto find_error; |
825 | // goto metadata_error; | |
3aee1200 | 826 | } |
dd3a6d39 | 827 | |
3aee1200 | 828 | return t; |
829 | ||
830 | /* Error handling */ | |
750eb11a | 831 | //metadata_error: |
832 | // destroy_marker_data(t); | |
b56dcdf2 | 833 | find_error: |
3aee1200 | 834 | g_datalist_clear(&t->tracefiles); |
b56dcdf2 | 835 | open_error: |
3aee1200 | 836 | g_free(t); |
837 | alloc_error: | |
838 | return NULL; | |
839 | ||
840 | } | |
6cd62ccf | 841 | |
e95fe8f7 | 842 | /* Open another, completely independant, instance of a trace. |
843 | * | |
844 | * A read on this new instance will read the first event of the trace. | |
845 | * | |
3aee1200 | 846 | * When we copy a trace, we want all the opening actions to happen again : |
847 | * the trace will be reopened and totally independant from the original. | |
848 | * That's why we call ltt_trace_open. | |
e95fe8f7 | 849 | */ |
3aee1200 | 850 | LttTrace *ltt_trace_copy(LttTrace *self) |
963b5f2d | 851 | { |
3aee1200 | 852 | return ltt_trace_open(g_quark_to_string(self->pathname)); |
963b5f2d | 853 | } |
854 | ||
e95fe8f7 | 855 | /* |
856 | * Close a trace | |
857 | */ | |
858 | ||
3aee1200 | 859 | void ltt_trace_close(LttTrace *t) |
6cd62ccf | 860 | { |
3aee1200 | 861 | g_datalist_clear(&t->tracefiles); |
862 | g_free(t); | |
6cd62ccf | 863 | } |
864 | ||
3aee1200 | 865 | |
6cd62ccf | 866 | /***************************************************************************** |
3aee1200 | 867 | * Get the start time and end time of the trace |
6cd62ccf | 868 | ****************************************************************************/ |
869 | ||
3c165eaf | 870 | void ltt_tracefile_time_span_get(LttTracefile *tf, |
3aee1200 | 871 | LttTime *start, LttTime *end) |
6cd62ccf | 872 | { |
3aee1200 | 873 | int err; |
6cd62ccf | 874 | |
3aee1200 | 875 | err = map_block(tf, 0); |
876 | if(unlikely(err)) { | |
877 | g_error("Can not map block"); | |
878 | *start = ltt_time_infinite; | |
879 | } else | |
880 | *start = tf->buffer.begin.timestamp; | |
881 | ||
882 | err = map_block(tf, tf->num_blocks - 1); /* Last block */ | |
883 | if(unlikely(err)) { | |
884 | g_error("Can not map block"); | |
885 | *end = ltt_time_zero; | |
886 | } else | |
887 | *end = tf->buffer.end.timestamp; | |
6cd62ccf | 888 | } |
889 | ||
3aee1200 | 890 | struct tracefile_time_span_get_args { |
891 | LttTrace *t; | |
892 | LttTime *start; | |
893 | LttTime *end; | |
894 | }; | |
963b5f2d | 895 | |
8655430b | 896 | static void group_time_span_get(GQuark name, gpointer data, gpointer user_data) |
963b5f2d | 897 | { |
3aee1200 | 898 | struct tracefile_time_span_get_args *args = |
899 | (struct tracefile_time_span_get_args*)user_data; | |
900 | ||
901 | GArray *group = (GArray *)data; | |
43ed82b5 | 902 | unsigned int i; |
3aee1200 | 903 | LttTracefile *tf; |
904 | LttTime tmp_start; | |
905 | LttTime tmp_end; | |
906 | ||
907 | for(i=0; i<group->len; i++) { | |
908 | tf = &g_array_index (group, LttTracefile, i); | |
909 | if(tf->cpu_online) { | |
910 | ltt_tracefile_time_span_get(tf, &tmp_start, &tmp_end); | |
911 | if(ltt_time_compare(*args->start, tmp_start)>0) *args->start = tmp_start; | |
912 | if(ltt_time_compare(*args->end, tmp_end)<0) *args->end = tmp_end; | |
913 | } | |
914 | } | |
6cd62ccf | 915 | } |
916 | ||
8655430b | 917 | /* return the start and end time of a trace */ |
918 | ||
487ad181 | 919 | void ltt_trace_time_span_get(LttTrace *t, LttTime *start, LttTime *end) |
920 | { | |
3aee1200 | 921 | LttTime min_start = ltt_time_infinite; |
922 | LttTime max_end = ltt_time_zero; | |
923 | struct tracefile_time_span_get_args args = { t, &min_start, &max_end }; | |
487ad181 | 924 | |
3aee1200 | 925 | g_datalist_foreach(&t->tracefiles, &group_time_span_get, &args); |
926 | ||
927 | if(start != NULL) *start = min_start; | |
928 | if(end != NULL) *end = max_end; | |
929 | ||
487ad181 | 930 | } |
931 | ||
932 | ||
3aee1200 | 933 | /* Seek to the first event in a tracefile that has a time equal or greater than |
934 | * the time passed in parameter. | |
935 | * | |
936 | * If the time parameter is outside the tracefile time span, seek to the first | |
27304273 | 937 | * event or if after, return ERANGE. |
3aee1200 | 938 | * |
939 | * If the time parameter is before the first event, we have to seek specially to | |
940 | * there. | |
941 | * | |
27304273 | 942 | * If the time is after the end of the trace, return ERANGE. |
3aee1200 | 943 | * |
944 | * Do a binary search to find the right block, then a sequential search in the | |
945 | * block to find the event. | |
946 | * | |
947 | * In the special case where the time requested fits inside a block that has no | |
948 | * event corresponding to the requested time, the first event of the next block | |
949 | * will be seeked. | |
950 | * | |
951 | * IMPORTANT NOTE : // FIXME everywhere... | |
952 | * | |
953 | * You MUST NOT do a ltt_tracefile_read right after a ltt_tracefile_seek_time : | |
954 | * you will jump over an event if you do. | |
955 | * | |
956 | * Return value : 0 : no error, the tf->event can be used | |
27304273 | 957 | * ERANGE : time if after the last event of the trace |
3aee1200 | 958 | * otherwise : this is an error. |
959 | * | |
960 | * */ | |
961 | ||
962 | int ltt_tracefile_seek_time(LttTracefile *tf, LttTime time) | |
963 | { | |
964 | int ret = 0; | |
965 | int err; | |
966 | unsigned int block_num, high, low; | |
967 | ||
968 | /* seek at the beginning of trace */ | |
969 | err = map_block(tf, 0); /* First block */ | |
970 | if(unlikely(err)) { | |
971 | g_error("Can not map block"); | |
972 | goto fail; | |
caf7a67a | 973 | } |
974 | ||
3aee1200 | 975 | /* If the time is lower or equal the beginning of the trace, |
976 | * go to the first event. */ | |
977 | if(ltt_time_compare(time, tf->buffer.begin.timestamp) <= 0) { | |
978 | ret = ltt_tracefile_read(tf); | |
27304273 | 979 | if(ret == ERANGE) goto range; |
980 | else if (ret) goto fail; | |
3aee1200 | 981 | goto found; /* There is either no event in the trace or the event points |
982 | to the first event in the trace */ | |
983 | } | |
caf7a67a | 984 | |
3aee1200 | 985 | err = map_block(tf, tf->num_blocks - 1); /* Last block */ |
986 | if(unlikely(err)) { | |
987 | g_error("Can not map block"); | |
988 | goto fail; | |
caf7a67a | 989 | } |
6cd62ccf | 990 | |
27304273 | 991 | /* If the time is after the end of the trace, return ERANGE. */ |
992 | if(ltt_time_compare(time, tf->buffer.end.timestamp) > 0) { | |
993 | goto range; | |
3aee1200 | 994 | } |
62e55dd6 | 995 | |
3aee1200 | 996 | /* Binary search the block */ |
997 | high = tf->num_blocks - 1; | |
998 | low = 0; | |
999 | ||
1000 | while(1) { | |
1001 | block_num = ((high-low) / 2) + low; | |
1002 | ||
1003 | err = map_block(tf, block_num); | |
1004 | if(unlikely(err)) { | |
1005 | g_error("Can not map block"); | |
1006 | goto fail; | |
db55eaae | 1007 | } |
3aee1200 | 1008 | if(high == low) { |
1009 | /* We cannot divide anymore : this is what would happen if the time | |
1010 | * requested was exactly between two consecutive buffers'end and start | |
1011 | * timestamps. This is also what would happend if we didn't deal with out | |
1012 | * of span cases prior in this function. */ | |
1013 | /* The event is right in the buffer! | |
1014 | * (or in the next buffer first event) */ | |
1015 | while(1) { | |
1016 | ret = ltt_tracefile_read(tf); | |
27304273 | 1017 | if(ret == ERANGE) goto range; /* ERANGE or EPERM */ |
3aee1200 | 1018 | else if(ret) goto fail; |
1019 | ||
d9e13a0f | 1020 | if(ltt_time_compare(time, tf->event.event_time) <= 0) |
e45551ac | 1021 | goto found; |
3aee1200 | 1022 | } |
1023 | ||
27304273 | 1024 | } else if(ltt_time_compare(time, tf->buffer.begin.timestamp) < 0) { |
3aee1200 | 1025 | /* go to lower part */ |
b1369bef | 1026 | high = block_num - 1; |
3aee1200 | 1027 | } else if(ltt_time_compare(time, tf->buffer.end.timestamp) > 0) { |
1028 | /* go to higher part */ | |
b1369bef | 1029 | low = block_num + 1; |
3aee1200 | 1030 | } else {/* The event is right in the buffer! |
1031 | (or in the next buffer first event) */ | |
1032 | while(1) { | |
27304273 | 1033 | ret = ltt_tracefile_read(tf); |
1034 | if(ret == ERANGE) goto range; /* ERANGE or EPERM */ | |
3aee1200 | 1035 | else if(ret) goto fail; |
1036 | ||
d9e13a0f | 1037 | if(ltt_time_compare(time, tf->event.event_time) <= 0) |
3aee1200 | 1038 | break; |
6cd62ccf | 1039 | } |
3aee1200 | 1040 | goto found; |
6cd62ccf | 1041 | } |
6cd62ccf | 1042 | } |
3aee1200 | 1043 | |
1044 | found: | |
1045 | return 0; | |
27304273 | 1046 | range: |
1047 | return ERANGE; | |
3aee1200 | 1048 | |
1049 | /* Error handling */ | |
1050 | fail: | |
1051 | g_error("ltt_tracefile_seek_time failed on tracefile %s", | |
1052 | g_quark_to_string(tf->name)); | |
1053 | return EPERM; | |
6cd62ccf | 1054 | } |
1055 | ||
e95fe8f7 | 1056 | /* Seek to a position indicated by an LttEventPosition |
1057 | */ | |
80da81ad | 1058 | |
8655430b | 1059 | int ltt_tracefile_seek_position(LttTracefile *tf, const LttEventPosition *ep) |
1060 | { | |
3aee1200 | 1061 | int err; |
1062 | ||
1063 | if(ep->tracefile != tf) { | |
1064 | goto fail; | |
80da81ad | 1065 | } |
1066 | ||
3aee1200 | 1067 | err = map_block(tf, ep->block); |
1068 | if(unlikely(err)) { | |
1069 | g_error("Can not map block"); | |
1070 | goto fail; | |
1071 | } | |
1072 | ||
1073 | tf->event.offset = ep->offset; | |
18206708 | 1074 | |
62e4e7bf | 1075 | /* Put back the event real tsc */ |
1076 | tf->event.tsc = ep->tsc; | |
1077 | tf->buffer.tsc = ep->tsc; | |
78f79181 | 1078 | |
3aee1200 | 1079 | err = ltt_tracefile_read_update_event(tf); |
1080 | if(err) goto fail; | |
73faf25a | 1081 | |
1082 | /* deactivate this, as it does nothing for now | |
3aee1200 | 1083 | err = ltt_tracefile_read_op(tf); |
1084 | if(err) goto fail; | |
73faf25a | 1085 | */ |
80da81ad | 1086 | |
a0c1f622 | 1087 | return 0; |
3aee1200 | 1088 | |
1089 | fail: | |
1090 | g_error("ltt_tracefile_seek_time failed on tracefile %s", | |
1091 | g_quark_to_string(tf->name)); | |
a0c1f622 | 1092 | return 1; |
3aee1200 | 1093 | } |
1094 | ||
e95fe8f7 | 1095 | /* Given a TSC value, return the LttTime (seconds,nanoseconds) it |
1096 | * corresponds to. | |
1097 | */ | |
1098 | ||
ae3d0f50 | 1099 | LttTime ltt_interpolate_time_from_tsc(LttTracefile *tf, guint64 tsc) |
3aee1200 | 1100 | { |
1101 | LttTime time; | |
62e4e7bf | 1102 | |
1103 | if(tsc > tf->trace->start_tsc) { | |
1104 | time = ltt_time_from_uint64( | |
1105 | (double)(tsc - tf->trace->start_tsc) | |
d0e3122a | 1106 | * 1000000000.0 * tf->trace->freq_scale |
62e4e7bf | 1107 | / (double)tf->trace->start_freq); |
1108 | time = ltt_time_add(tf->trace->start_time_from_tsc, time); | |
1109 | } else { | |
1110 | time = ltt_time_from_uint64( | |
1111 | (double)(tf->trace->start_tsc - tsc) | |
d0e3122a | 1112 | * 1000000000.0 * tf->trace->freq_scale |
62e4e7bf | 1113 | / (double)tf->trace->start_freq); |
1114 | time = ltt_time_sub(tf->trace->start_time_from_tsc, time); | |
1115 | } | |
3aee1200 | 1116 | return time; |
80da81ad | 1117 | } |
1118 | ||
ae3d0f50 | 1119 | /* Calculate the real event time based on the buffer boundaries */ |
1120 | LttTime ltt_interpolate_time(LttTracefile *tf, LttEvent *event) | |
1121 | { | |
62e4e7bf | 1122 | return ltt_interpolate_time_from_tsc(tf, tf->buffer.tsc); |
ae3d0f50 | 1123 | } |
1124 | ||
eed2ef37 | 1125 | |
1126 | /* Get the current event of the tracefile : valid until the next read */ | |
1127 | LttEvent *ltt_tracefile_get_event(LttTracefile *tf) | |
1128 | { | |
1129 | return &tf->event; | |
1130 | } | |
1131 | ||
1132 | ||
1133 | ||
6cd62ccf | 1134 | /***************************************************************************** |
1135 | *Function name | |
3aee1200 | 1136 | * ltt_tracefile_read : Read the next event in the tracefile |
6cd62ccf | 1137 | *Input params |
1138 | * t : tracefile | |
1139 | *Return value | |
3aee1200 | 1140 | * |
1141 | * Returns 0 if an event can be used in tf->event. | |
d822520b | 1142 | * Returns ERANGE on end of trace. The event in tf->event still can be used |
1143 | * (if the last block was not empty). | |
3aee1200 | 1144 | * Returns EPERM on error. |
1145 | * | |
1146 | * This function does make the tracefile event structure point to the event | |
1147 | * currently pointed to by the tf->event. | |
1148 | * | |
1149 | * Note : you must call a ltt_tracefile_seek to the beginning of the trace to | |
1150 | * reinitialize it after an error if you want results to be coherent. | |
1151 | * It would be the case if a end of trace last buffer has no event : the end | |
1152 | * of trace wouldn't be returned, but an error. | |
1153 | * We make the assumption there is at least one event per buffer. | |
6cd62ccf | 1154 | ****************************************************************************/ |
1155 | ||
3aee1200 | 1156 | int ltt_tracefile_read(LttTracefile *tf) |
6cd62ccf | 1157 | { |
963b5f2d | 1158 | int err; |
6cd62ccf | 1159 | |
3aee1200 | 1160 | err = ltt_tracefile_read_seek(tf); |
1161 | if(err) return err; | |
1162 | err = ltt_tracefile_read_update_event(tf); | |
1163 | if(err) return err; | |
73faf25a | 1164 | |
1165 | /* deactivate this, as it does nothing for now | |
3aee1200 | 1166 | err = ltt_tracefile_read_op(tf); |
1167 | if(err) return err; | |
73faf25a | 1168 | */ |
3aee1200 | 1169 | |
1170 | return 0; | |
1171 | } | |
1172 | ||
1173 | int ltt_tracefile_read_seek(LttTracefile *tf) | |
1174 | { | |
1175 | int err; | |
1176 | ||
1177 | /* Get next buffer until we finally have an event, or end of trace */ | |
1178 | while(1) { | |
1179 | err = ltt_seek_next_event(tf); | |
1180 | if(unlikely(err == ENOPROTOOPT)) { | |
1181 | return EPERM; | |
bdc36259 | 1182 | } |
bdc36259 | 1183 | |
3aee1200 | 1184 | /* Are we at the end of the buffer ? */ |
1185 | if(err == ERANGE) { | |
1186 | if(unlikely(tf->buffer.index == tf->num_blocks-1)){ /* end of trace ? */ | |
1187 | return ERANGE; | |
1188 | } else { | |
1189 | /* get next block */ | |
1190 | err = map_block(tf, tf->buffer.index + 1); | |
1191 | if(unlikely(err)) { | |
1192 | g_error("Can not map block"); | |
1193 | return EPERM; | |
1194 | } | |
1195 | } | |
1196 | } else break; /* We found an event ! */ | |
1197 | } | |
2dee981d | 1198 | |
3aee1200 | 1199 | return 0; |
1200 | } | |
18206708 | 1201 | |
e95fe8f7 | 1202 | /* do an operation when reading a new event */ |
18206708 | 1203 | |
73faf25a | 1204 | /* This function does nothing for now */ |
1205 | #if 0 | |
3aee1200 | 1206 | int ltt_tracefile_read_op(LttTracefile *tf) |
1207 | { | |
3aee1200 | 1208 | LttEvent *event; |
1209 | ||
1210 | event = &tf->event; | |
18206708 | 1211 | |
73faf25a | 1212 | /* do event specific operation */ |
1213 | ||
1214 | /* nothing */ | |
40331ba8 | 1215 | |
3aee1200 | 1216 | return 0; |
6cd62ccf | 1217 | } |
73faf25a | 1218 | #endif |
6cd62ccf | 1219 | |
91f8d488 | 1220 | static void print_debug_event_header(LttEvent *ev, void *start_pos, void *end_pos) |
1221 | { | |
1222 | unsigned int offset = 0; | |
1223 | int i, j; | |
1224 | ||
43ed82b5 | 1225 | g_printf("Event header (tracefile %s offset %" PRIx64 "):\n", |
afd57a3c | 1226 | g_quark_to_string(ev->tracefile->long_name), |
43ed82b5 | 1227 | ((uint64_t)ev->tracefile->buffer.index * ev->tracefile->buf_size) |
1228 | + (long)start_pos - (long)ev->tracefile->buffer.head); | |
91f8d488 | 1229 | |
1230 | while (offset < (long)end_pos - (long)start_pos) { | |
1231 | g_printf("%8lx", (long)start_pos - (long)ev->tracefile->buffer.head + offset); | |
1232 | g_printf(" "); | |
1233 | ||
1234 | for (i = 0; i < 4 ; i++) { | |
1235 | for (j = 0; j < 4; j++) { | |
1236 | if (offset + ((i * 4) + j) < | |
1237 | (long)end_pos - (long)start_pos) | |
1238 | g_printf("%02hhX", | |
d3353231 | 1239 | ((char*)start_pos)[offset + ((i * 4) + j)]); |
91f8d488 | 1240 | else |
1241 | g_printf(" "); | |
1242 | g_printf(" "); | |
1243 | } | |
1244 | if (i < 4) | |
1245 | g_printf(" "); | |
1246 | } | |
1247 | offset+=16; | |
1248 | g_printf("\n"); | |
1249 | } | |
1250 | } | |
1251 | ||
6cd62ccf | 1252 | |
3aee1200 | 1253 | /* same as ltt_tracefile_read, but does not seek to the next event nor call |
1254 | * event specific operation. */ | |
1255 | int ltt_tracefile_read_update_event(LttTracefile *tf) | |
6cd62ccf | 1256 | { |
3aee1200 | 1257 | void * pos; |
1258 | LttEvent *event; | |
91f8d488 | 1259 | void *pos_aligned; |
551bf485 | 1260 | guint16 packed_evid; /* event id reader from the 5 bits in header */ |
3aee1200 | 1261 | |
1262 | event = &tf->event; | |
eed2ef37 | 1263 | pos = tf->buffer.head + event->offset; |
3aee1200 | 1264 | |
1265 | /* Read event header */ | |
1266 | ||
62e4e7bf | 1267 | /* Align the head */ |
2fc874ab | 1268 | pos += ltt_align((size_t)pos, sizeof(guint32), tf->alignment); |
91f8d488 | 1269 | pos_aligned = pos; |
3aee1200 | 1270 | |
2fc874ab | 1271 | event->timestamp = ltt_get_uint32(LTT_GET_BO(tf), pos); |
551bf485 | 1272 | event->event_id = packed_evid = event->timestamp >> tf->tscbits; |
a9048165 | 1273 | event->timestamp = event->timestamp & tf->tsc_mask; |
2fc874ab | 1274 | pos += sizeof(guint32); |
1275 | ||
551bf485 | 1276 | switch (packed_evid) { |
2fc874ab | 1277 | case 29: /* LTT_RFLAG_ID_SIZE_TSC */ |
1278 | event->event_id = ltt_get_uint16(LTT_GET_BO(tf), pos); | |
1279 | pos += sizeof(guint16); | |
1280 | event->event_size = ltt_get_uint16(LTT_GET_BO(tf), pos); | |
1281 | pos += sizeof(guint16); | |
1282 | if (event->event_size == 0xFFFF) { | |
1283 | event->event_size = ltt_get_uint32(LTT_GET_BO(tf), pos); | |
1284 | pos += sizeof(guint32); | |
d1bb700c | 1285 | } |
2fc874ab | 1286 | pos += ltt_align((size_t)pos, sizeof(guint64), tf->alignment); |
1287 | tf->buffer.tsc = ltt_get_uint64(LTT_GET_BO(tf), pos); | |
62e4e7bf | 1288 | pos += sizeof(guint64); |
2fc874ab | 1289 | break; |
1290 | case 30: /* LTT_RFLAG_ID_SIZE */ | |
f439de06 | 1291 | event->event_id = ltt_get_uint16(LTT_GET_BO(tf), pos); |
3c165eaf | 1292 | pos += sizeof(guint16); |
d1bb700c | 1293 | event->event_size = ltt_get_uint16(LTT_GET_BO(tf), pos); |
1294 | pos += sizeof(guint16); | |
2fc874ab | 1295 | if (event->event_size == 0xFFFF) { |
1296 | event->event_size = ltt_get_uint32(LTT_GET_BO(tf), pos); | |
1297 | pos += sizeof(guint32); | |
1298 | } | |
1299 | break; | |
1300 | case 31: /* LTT_RFLAG_ID */ | |
1301 | event->event_id = ltt_get_uint16(LTT_GET_BO(tf), pos); | |
1302 | pos += sizeof(guint16); | |
1303 | event->event_size = G_MAXUINT; | |
1304 | break; | |
1305 | default: | |
1306 | event->event_size = G_MAXUINT; | |
1307 | break; | |
1308 | } | |
1309 | ||
551bf485 | 1310 | if (likely(packed_evid != 29)) { |
2fc874ab | 1311 | /* No extended timestamp */ |
1312 | if (event->timestamp < (tf->buffer.tsc & tf->tsc_mask)) | |
1313 | tf->buffer.tsc = ((tf->buffer.tsc & ~tf->tsc_mask) /* overflow */ | |
1314 | + tf->tsc_mask_next_bit) | |
1315 | | (guint64)event->timestamp; | |
1316 | else | |
1317 | tf->buffer.tsc = (tf->buffer.tsc & ~tf->tsc_mask) /* no overflow */ | |
1318 | | (guint64)event->timestamp; | |
d1bb700c | 1319 | } |
2fc874ab | 1320 | event->tsc = tf->buffer.tsc; |
1321 | ||
1322 | event->event_time = ltt_interpolate_time(tf, event); | |
91f8d488 | 1323 | |
1324 | if (a_event_debug) | |
1325 | print_debug_event_header(event, pos_aligned, pos); | |
1326 | ||
3aee1200 | 1327 | event->data = pos; |
1328 | ||
2fc874ab | 1329 | /* |
1330 | * Let ltt_update_event_size update event->data according to the largest | |
1331 | * alignment within the payload. | |
1332 | * Get the data size and update the event fields with the current | |
1333 | * information. */ | |
eed2ef37 | 1334 | ltt_update_event_size(tf); |
77175651 | 1335 | |
3aee1200 | 1336 | return 0; |
6cd62ccf | 1337 | } |
1338 | ||
507915ee | 1339 | |
6cd62ccf | 1340 | /**************************************************************************** |
1341 | *Function name | |
3aee1200 | 1342 | * map_block : map a block from the file |
6cd62ccf | 1343 | *Input Params |
1344 | * lttdes : ltt trace file | |
1345 | * whichBlock : the block which will be read | |
1346 | *return value | |
1347 | * 0 : success | |
1348 | * EINVAL : lseek fail | |
1349 | * EIO : can not read from the file | |
1350 | ****************************************************************************/ | |
1351 | ||
8655430b | 1352 | static gint map_block(LttTracefile * tf, guint block_num) |
6cd62ccf | 1353 | { |
b77d1b57 | 1354 | int page_size = getpagesize(); |
64dd41a5 | 1355 | ltt_subbuffer_header_t *header; |
3aee1200 | 1356 | |
1357 | g_assert(block_num < tf->num_blocks); | |
6cd62ccf | 1358 | |
f628823c | 1359 | if(tf->buffer.head != NULL) { |
1360 | if(munmap(tf->buffer.head, PAGE_ALIGN(tf->buf_size))) { | |
1361 | g_warning("unmap size : %u\n", | |
1362 | PAGE_ALIGN(tf->buf_size)); | |
1363 | perror("munmap error"); | |
1364 | g_assert(0); | |
1365 | } | |
1366 | } | |
ac849774 | 1367 | |
3aee1200 | 1368 | /* Multiple of pages aligned head */ |
b77d1b57 | 1369 | tf->buffer.head = mmap(0, |
f628823c | 1370 | PAGE_ALIGN(tf->buf_size), |
b77d1b57 | 1371 | PROT_READ, MAP_PRIVATE, tf->fd, |
f628823c | 1372 | PAGE_ALIGN((off_t)tf->buf_size * (off_t)block_num)); |
3aee1200 | 1373 | |
3865ea09 | 1374 | if(tf->buffer.head == MAP_FAILED) { |
3aee1200 | 1375 | perror("Error in allocating memory for buffer of tracefile"); |
3865ea09 | 1376 | g_assert(0); |
3aee1200 | 1377 | goto map_error; |
6cd62ccf | 1378 | } |
f64fedd7 | 1379 | g_assert( ( (gulong)tf->buffer.head&(8-1) ) == 0); // make sure it's aligned. |
3aee1200 | 1380 | |
6cd62ccf | 1381 | |
3aee1200 | 1382 | tf->buffer.index = block_num; |
1383 | ||
64dd41a5 | 1384 | header = (ltt_subbuffer_header_t *)tf->buffer.head; |
3aee1200 | 1385 | |
3aee1200 | 1386 | tf->buffer.begin.cycle_count = ltt_get_uint64(LTT_GET_BO(tf), |
64dd41a5 | 1387 | &header->cycle_count_begin); |
3aee1200 | 1388 | tf->buffer.end.cycle_count = ltt_get_uint64(LTT_GET_BO(tf), |
64dd41a5 | 1389 | &header->cycle_count_end); |
3aee1200 | 1390 | tf->buffer.lost_size = ltt_get_uint32(LTT_GET_BO(tf), |
986e2a7c | 1391 | &header->lost_size); |
3aee1200 | 1392 | tf->buffer.tsc = tf->buffer.begin.cycle_count; |
1393 | tf->event.tsc = tf->buffer.tsc; | |
986e2a7c | 1394 | tf->buffer.freq = tf->buffer.begin.freq; |
3aee1200 | 1395 | |
22660d97 BP |
1396 | if (tf->trace->start_freq) |
1397 | { | |
1398 | tf->buffer.begin.freq = tf->trace->start_freq; | |
1399 | tf->buffer.begin.timestamp = ltt_interpolate_time_from_tsc(tf, | |
1400 | tf->buffer.begin.cycle_count); | |
1401 | tf->buffer.end.freq = tf->trace->start_freq; | |
1402 | tf->buffer.end.timestamp = ltt_interpolate_time_from_tsc(tf, | |
1403 | tf->buffer.end.cycle_count); | |
1404 | } | |
1405 | ||
3aee1200 | 1406 | /* FIXME |
1407 | * eventually support variable buffer size : will need a partial pre-read of | |
1408 | * the headers to create an index when we open the trace... eventually. */ | |
f628823c | 1409 | g_assert(tf->buf_size == ltt_get_uint32(LTT_GET_BO(tf), |
3aee1200 | 1410 | &header->buf_size)); |
507915ee | 1411 | |
3aee1200 | 1412 | /* Make the current event point to the beginning of the buffer : |
1413 | * it means that the event read must get the first event. */ | |
1414 | tf->event.tracefile = tf; | |
1415 | tf->event.block = block_num; | |
eed2ef37 | 1416 | tf->event.offset = 0; |
3aee1200 | 1417 | |
a2bbf2e5 | 1418 | if (header->events_lost) { |
1419 | g_warning("%d events lost so far in tracefile %s at block %u", | |
0c2f4984 | 1420 | (guint)header->events_lost, |
a2bbf2e5 | 1421 | g_quark_to_string(tf->long_name), |
1422 | block_num); | |
426f6149 | 1423 | tf->events_lost = header->events_lost; |
1424 | } | |
a2bbf2e5 | 1425 | if (header->subbuf_corrupt) { |
1426 | g_warning("%d subbuffer(s) corrupted so far in tracefile %s at block %u", | |
0c2f4984 | 1427 | (guint)header->subbuf_corrupt, |
a2bbf2e5 | 1428 | g_quark_to_string(tf->long_name), |
1429 | block_num); | |
426f6149 | 1430 | tf->subbuf_corrupt = header->subbuf_corrupt; |
1431 | } | |
1432 | ||
3aee1200 | 1433 | return 0; |
6cd62ccf | 1434 | |
3aee1200 | 1435 | map_error: |
1436 | return -errno; | |
6cd62ccf | 1437 | } |
1438 | ||
91f8d488 | 1439 | static void print_debug_event_data(LttEvent *ev) |
1440 | { | |
1441 | unsigned int offset = 0; | |
1442 | int i, j; | |
1443 | ||
1444 | if (!max(ev->event_size, ev->data_size)) | |
1445 | return; | |
1446 | ||
43ed82b5 | 1447 | g_printf("Event data (tracefile %s offset %" PRIx64 "):\n", |
1448 | g_quark_to_string(ev->tracefile->long_name), | |
1449 | ((uint64_t)ev->tracefile->buffer.index * ev->tracefile->buf_size) | |
1450 | + (long)ev->data - (long)ev->tracefile->buffer.head); | |
91f8d488 | 1451 | |
1452 | while (offset < max(ev->event_size, ev->data_size)) { | |
1453 | g_printf("%8lx", (long)ev->data + offset | |
1454 | - (long)ev->tracefile->buffer.head); | |
1455 | g_printf(" "); | |
1456 | ||
1457 | for (i = 0; i < 4 ; i++) { | |
1458 | for (j = 0; j < 4; j++) { | |
1459 | if (offset + ((i * 4) + j) < max(ev->event_size, ev->data_size)) | |
1460 | g_printf("%02hhX", ((char*)ev->data)[offset + ((i * 4) + j)]); | |
1461 | else | |
1462 | g_printf(" "); | |
1463 | g_printf(" "); | |
1464 | } | |
1465 | if (i < 4) | |
1466 | g_printf(" "); | |
1467 | } | |
1468 | ||
1469 | g_printf(" "); | |
1470 | ||
1471 | for (i = 0; i < 4; i++) { | |
1472 | for (j = 0; j < 4; j++) { | |
1473 | if (offset + ((i * 4) + j) < max(ev->event_size, ev->data_size)) { | |
1474 | if (isprint(((char*)ev->data)[offset + ((i * 4) + j)])) | |
1475 | g_printf("%c", ((char*)ev->data)[offset + ((i * 4) + j)]); | |
1476 | else | |
1477 | g_printf("."); | |
1478 | } else | |
1479 | g_printf(" "); | |
1480 | } | |
1481 | } | |
1482 | offset+=16; | |
1483 | g_printf("\n"); | |
1484 | } | |
1485 | } | |
1486 | ||
77175651 | 1487 | /* It will update the fields offsets too */ |
1488 | void ltt_update_event_size(LttTracefile *tf) | |
6cd62ccf | 1489 | { |
2312de30 | 1490 | off_t size = 0; |
d2007fbd | 1491 | struct marker_info *info; |
750eb11a | 1492 | |
1493 | if (tf->name == LTT_TRACEFILE_NAME_METADATA) { | |
1494 | switch((enum marker_id)tf->event.event_id) { | |
1495 | case MARKER_ID_SET_MARKER_ID: | |
1496 | size = strlen((char*)tf->event.data) + 1; | |
1497 | g_debug("marker %s id set", (char*)tf->event.data + size); | |
1498 | size += strlen((char*)tf->event.data + size) + 1; | |
1499 | size += ltt_align(size, sizeof(guint16), tf->alignment); | |
1500 | size += sizeof(guint16); | |
1501 | size += sizeof(guint8); | |
1502 | size += sizeof(guint8); | |
1503 | size += sizeof(guint8); | |
1504 | size += sizeof(guint8); | |
1505 | size += sizeof(guint8); | |
1506 | break; | |
1507 | case MARKER_ID_SET_MARKER_FORMAT: | |
1508 | size = strlen((char*)tf->event.data) + 1; | |
1509 | g_debug("marker %s format set", (char*)tf->event.data); | |
1510 | size += strlen((char*)tf->event.data + size) + 1; | |
1511 | size += strlen((char*)tf->event.data + size) + 1; | |
1512 | break; | |
1513 | } | |
256a5b3a | 1514 | } |
1515 | ||
750eb11a | 1516 | info = marker_get_info_from_id(tf->mdata, tf->event.event_id); |
dcf96842 | 1517 | |
256a5b3a | 1518 | if (tf->event.event_id >= MARKER_CORE_IDS) |
1519 | g_assert(info != NULL); | |
1520 | ||
1521 | /* Do not update field offsets of core markers when initially reading the | |
2fc874ab | 1522 | * metadata tracefile when the infos about these markers do not exist yet. |
256a5b3a | 1523 | */ |
1524 | if (likely(info && info->fields)) { | |
2fc874ab | 1525 | /* alignment */ |
196085f2 | 1526 | tf->event.data += ltt_align((off_t)(unsigned long)tf->event.data, |
1527 | info->largest_align, | |
2fc874ab | 1528 | info->alignment); |
1529 | /* size, dynamically computed */ | |
256a5b3a | 1530 | if (info->size != -1) |
1531 | size = info->size; | |
1532 | else | |
750eb11a | 1533 | size = marker_update_fields_offsets(marker_get_info_from_id(tf->mdata, |
256a5b3a | 1534 | tf->event.event_id), tf->event.data); |
44f317b7 | 1535 | } |
c4afd5d8 | 1536 | |
d2007fbd | 1537 | tf->event.data_size = size; |
1538 | ||
1539 | /* Check consistency between kernel and LTTV structure sizes */ | |
2fc874ab | 1540 | if(tf->event.event_size == G_MAXUINT) { |
d2007fbd | 1541 | /* Event size too big to fit in the event size field */ |
1542 | tf->event.event_size = tf->event.data_size; | |
1543 | } | |
91f8d488 | 1544 | |
1545 | if (a_event_debug) | |
1546 | print_debug_event_data(&tf->event); | |
1547 | ||
d2007fbd | 1548 | if (tf->event.data_size != tf->event.event_size) { |
750eb11a | 1549 | struct marker_info *info = marker_get_info_from_id(tf->mdata, |
3c165eaf | 1550 | tf->event.event_id); |
750eb11a | 1551 | if (!info) |
1552 | g_error("Undescribed event %hhu in channel %s", tf->event.event_id, | |
1553 | g_quark_to_string(tf->name)); | |
3c165eaf | 1554 | g_error("Kernel/LTTV event size differs for event %s: kernel %u, LTTV %u", |
1555 | g_quark_to_string(info->name), | |
1556 | tf->event.event_size, tf->event.data_size); | |
d2007fbd | 1557 | exit(-1); |
1558 | } | |
6cd62ccf | 1559 | } |
1560 | ||
6cd62ccf | 1561 | |
2fc874ab | 1562 | /* Take the tf current event offset and use the event id to figure out where is |
1563 | * the next event offset. | |
3aee1200 | 1564 | * |
1565 | * This is an internal function not aiming at being used elsewhere : it will | |
1566 | * not jump over the current block limits. Please consider using | |
1567 | * ltt_tracefile_read to do this. | |
1568 | * | |
1569 | * Returns 0 on success | |
1570 | * ERANGE if we are at the end of the buffer. | |
1571 | * ENOPROTOOPT if an error occured when getting the current event size. | |
1572 | */ | |
8655430b | 1573 | static int ltt_seek_next_event(LttTracefile *tf) |
6cd62ccf | 1574 | { |
3aee1200 | 1575 | int ret = 0; |
1576 | void *pos; | |
3aee1200 | 1577 | |
1578 | /* seek over the buffer header if we are at the buffer start */ | |
eed2ef37 | 1579 | if(tf->event.offset == 0) { |
51551c6f | 1580 | tf->event.offset += tf->buffer_header_size; |
b77d1b57 | 1581 | |
f628823c | 1582 | if(tf->event.offset == tf->buf_size - tf->buffer.lost_size) { |
b77d1b57 | 1583 | ret = ERANGE; |
1584 | } | |
3aee1200 | 1585 | goto found; |
1586 | } | |
2fc874ab | 1587 | |
3aee1200 | 1588 | pos = tf->event.data; |
1589 | ||
77175651 | 1590 | if(tf->event.data_size < 0) goto error; |
3aee1200 | 1591 | |
77175651 | 1592 | pos += (size_t)tf->event.data_size; |
3aee1200 | 1593 | |
eed2ef37 | 1594 | tf->event.offset = pos - tf->buffer.head; |
cb03932a | 1595 | |
f628823c | 1596 | if(tf->event.offset == tf->buf_size - tf->buffer.lost_size) { |
cb03932a | 1597 | ret = ERANGE; |
1598 | goto found; | |
1599 | } | |
36d36c9f | 1600 | g_assert(tf->event.offset < tf->buf_size - tf->buffer.lost_size); |
3aee1200 | 1601 | |
1602 | found: | |
1603 | return ret; | |
1604 | ||
1605 | error: | |
1606 | g_error("Error in ltt_seek_next_event for tracefile %s", | |
1607 | g_quark_to_string(tf->name)); | |
1608 | return ENOPROTOOPT; | |
6cd62ccf | 1609 | } |
1610 | ||
f104d082 | 1611 | |
6cd62ccf | 1612 | /***************************************************************************** |
1613 | *Function name | |
eed2ef37 | 1614 | * ltt_get_int : get an integer number |
6cd62ccf | 1615 | *Input params |
3aee1200 | 1616 | * reverse_byte_order: must we reverse the byte order ? |
6cd62ccf | 1617 | * size : the size of the integer |
3aee1200 | 1618 | * ptr : the data pointer |
6cd62ccf | 1619 | *Return value |
cf74a6f1 | 1620 | * gint64 : a 64 bits integer |
6cd62ccf | 1621 | ****************************************************************************/ |
1622 | ||
eed2ef37 | 1623 | gint64 ltt_get_int(gboolean reverse_byte_order, gint size, void *data) |
6cd62ccf | 1624 | { |
3aee1200 | 1625 | gint64 val; |
cf74a6f1 | 1626 | |
1627 | switch(size) { | |
3aee1200 | 1628 | case 1: val = *((gint8*)data); break; |
1629 | case 2: val = ltt_get_int16(reverse_byte_order, data); break; | |
1630 | case 4: val = ltt_get_int32(reverse_byte_order, data); break; | |
1631 | case 8: val = ltt_get_int64(reverse_byte_order, data); break; | |
1632 | default: val = ltt_get_int64(reverse_byte_order, data); | |
1633 | g_critical("get_int : integer size %d unknown", size); | |
cf74a6f1 | 1634 | break; |
1635 | } | |
1636 | ||
3aee1200 | 1637 | return val; |
6cd62ccf | 1638 | } |
3aee1200 | 1639 | |
6cd62ccf | 1640 | /***************************************************************************** |
1641 | *Function name | |
eed2ef37 | 1642 | * ltt_get_uint : get an unsigned integer number |
6cd62ccf | 1643 | *Input params |
3aee1200 | 1644 | * reverse_byte_order: must we reverse the byte order ? |
1645 | * size : the size of the integer | |
1646 | * ptr : the data pointer | |
1647 | *Return value | |
1648 | * guint64 : a 64 bits unsigned integer | |
6cd62ccf | 1649 | ****************************************************************************/ |
1650 | ||
eed2ef37 | 1651 | guint64 ltt_get_uint(gboolean reverse_byte_order, gint size, void *data) |
6cd62ccf | 1652 | { |
3aee1200 | 1653 | guint64 val; |
1654 | ||
1655 | switch(size) { | |
1656 | case 1: val = *((gint8*)data); break; | |
1657 | case 2: val = ltt_get_uint16(reverse_byte_order, data); break; | |
1658 | case 4: val = ltt_get_uint32(reverse_byte_order, data); break; | |
1659 | case 8: val = ltt_get_uint64(reverse_byte_order, data); break; | |
1660 | default: val = ltt_get_uint64(reverse_byte_order, data); | |
1661 | g_critical("get_uint : unsigned integer size %d unknown", | |
1662 | size); | |
1663 | break; | |
1664 | } | |
1665 | ||
1666 | return val; | |
6cd62ccf | 1667 | } |
3aee1200 | 1668 | |
1669 | ||
a5dcde2f | 1670 | /* get the node name of the system */ |
1671 | ||
1672 | char * ltt_trace_system_description_node_name (LttSystemDescription * s) | |
1673 | { | |
1674 | return s->node_name; | |
1675 | } | |
1676 | ||
1677 | ||
1678 | /* get the domain name of the system */ | |
1679 | ||
1680 | char * ltt_trace_system_description_domain_name (LttSystemDescription * s) | |
1681 | { | |
1682 | return s->domain_name; | |
1683 | } | |
1684 | ||
1685 | ||
1686 | /* get the description of the system */ | |
1687 | ||
1688 | char * ltt_trace_system_description_description (LttSystemDescription * s) | |
1689 | { | |
1690 | return s->description; | |
1691 | } | |
1692 | ||
1693 | ||
bf33dd50 | 1694 | /* get the NTP corrected start time of the trace */ |
7bd563ec | 1695 | LttTime ltt_trace_start_time(LttTrace *t) |
a5dcde2f | 1696 | { |
7bd563ec | 1697 | return t->start_time; |
a5dcde2f | 1698 | } |
1699 | ||
bf33dd50 | 1700 | /* get the monotonic start time of the trace */ |
1701 | LttTime ltt_trace_start_time_monotonic(LttTrace *t) | |
1702 | { | |
1703 | return t->start_time_from_tsc; | |
1704 | } | |
1705 | ||
43ed82b5 | 1706 | static __attribute__ ((__unused__)) LttTracefile *ltt_tracefile_new() |
18206708 | 1707 | { |
afd57a3c | 1708 | LttTracefile *tf; |
1709 | tf = g_new(LttTracefile, 1); | |
1710 | tf->event.tracefile = tf; | |
1711 | return tf; | |
18206708 | 1712 | } |
1713 | ||
43ed82b5 | 1714 | static __attribute__ ((__unused__)) void ltt_tracefile_destroy(LttTracefile *tf) |
18206708 | 1715 | { |
1716 | g_free(tf); | |
1717 | } | |
1718 | ||
43ed82b5 | 1719 | static __attribute__ ((__unused__)) void ltt_tracefile_copy(LttTracefile *dest, const LttTracefile *src) |
18206708 | 1720 | { |
1721 | *dest = *src; | |
1722 | } | |
1723 | ||
3aee1200 | 1724 | /* Before library loading... */ |
1725 | ||
8655430b | 1726 | static __attribute__((constructor)) void init(void) |
3aee1200 | 1727 | { |
750eb11a | 1728 | LTT_TRACEFILE_NAME_METADATA = g_quark_from_string("metadata"); |
3aee1200 | 1729 | } |