update quickstart
[lttv.git] / trunk / lttv / ltt / tracefile.c
CommitLineData
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 */
55extern long marker_update_fields_offsets(struct marker_info *info, const char *data);
56
2fc874ab 57/* Tracefile names used in this file */
3aee1200 58
2fc874ab 59GQuark 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 81LttTrace *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
2fc874ab 88#if 0
3aee1200 89/* get the size of the field type according to
90 * The facility size information. */
91static inline void preset_field_type_size(LttTracefile *tf,
92 LttEventType *event_type,
93 off_t offset_root, off_t offset_parent,
94 enum field_status *fixed_root, enum field_status *fixed_parent,
95 LttField *field);
f104d082 96#endif //0
6cd62ccf 97
3aee1200 98/* map a fixed size or a block information from the file (fd) */
99static gint map_block(LttTracefile * tf, guint block_num);
100
101/* calculate nsec per cycles for current block */
791dffa6 102#if 0
103static guint32 calc_nsecs_per_cycle(LttTracefile * t);
104static guint64 cycles_2_ns(LttTracefile *tf, guint64 cycles);
105#endif //0
6cd62ccf 106
3aee1200 107/* go to the next event */
108static int ltt_seek_next_event(LttTracefile *tf);
6cd62ccf 109
3c165eaf 110static int open_tracefiles(LttTrace *trace, gchar *root_path,
111 gchar *relative_path);
2fc874ab 112static int ltt_process_metadata_tracefile(LttTracefile *tf);
3c165eaf 113static void ltt_tracefile_time_span_get(LttTracefile *tf,
114 LttTime *start, LttTime *end);
115static void group_time_span_get(GQuark name, gpointer data, gpointer user_data);
116static gint map_block(LttTracefile * tf, guint block_num);
3c165eaf 117static void ltt_update_event_size(LttTracefile *tf);
91f8d488 118
119/* Enable event debugging */
120static int a_event_debug = 0;
121
122void ltt_event_debug(int state)
123{
124 a_event_debug = state;
125}
126
b7576a11 127/* trace can be NULL
128 *
129 * Return value : 0 success, 1 bad tracefile
130 */
64dd41a5 131static int parse_trace_header(ltt_subbuffer_header_t *header,
132 LttTracefile *tf, LttTrace *t)
b7576a11 133{
64dd41a5 134 if (header->magic_number == LTT_MAGIC_NUMBER)
b7576a11 135 tf->reverse_bo = 0;
64dd41a5 136 else if(header->magic_number == LTT_REV_MAGIC_NUMBER)
b7576a11 137 tf->reverse_bo = 1;
138 else /* invalid magic number, bad tracefile ! */
139 return 1;
64dd41a5 140
141 if(t) {
142 t->ltt_major_version = header->major_version;
143 t->ltt_minor_version = header->minor_version;
144 t->arch_size = header->arch_size;
145 }
146 tf->alignment = header->alignment;
147
b7576a11 148 /* Get float byte order : might be different from int byte order
149 * (or is set to 0 if the trace has no float (kernel trace)) */
64dd41a5 150 tf->float_word_order = 0;
b7576a11 151
64dd41a5 152 switch(header->major_version) {
b7576a11 153 case 0:
2fc874ab 154 case 1:
3c165eaf 155 g_warning("Unsupported trace version : %hhu.%hhu",
64dd41a5 156 header->major_version, header->minor_version);
3c165eaf 157 return 1;
158 break;
2fc874ab 159 case 2:
64dd41a5 160 switch(header->minor_version) {
750eb11a 161 case 3:
b7576a11 162 {
750eb11a 163 struct ltt_subbuffer_header_2_3 *vheader = header;
1550fba6 164 tf->buffer_header_size = ltt_subbuffer_header_size();
64dd41a5 165 tf->tscbits = 27;
166 tf->eventbits = 5;
2fc874ab 167 tf->tsc_mask = ((1ULL << tf->tscbits) - 1);
168 tf->tsc_mask_next_bit = (1ULL << tf->tscbits);
169
e939e5b2 170 if(t) {
171 t->start_freq = ltt_get_uint64(LTT_GET_BO(tf),
172 &vheader->start_freq);
a3999b49 173 t->freq_scale = ltt_get_uint32(LTT_GET_BO(tf),
174 &vheader->freq_scale);
9c731a50 175 if(father_trace) {
176 t->start_freq = father_trace->start_freq;
177 t->freq_scale = father_trace->freq_scale;
64dd41a5 178 } else {
9c731a50 179 father_trace = t;
180 }
e939e5b2 181 t->start_tsc = ltt_get_uint64(LTT_GET_BO(tf),
64dd41a5 182 &vheader->cycle_count_begin);
183 t->start_monotonic = 0;
e939e5b2 184 t->start_time.tv_sec = ltt_get_uint64(LTT_GET_BO(tf),
185 &vheader->start_time_sec);
186 t->start_time.tv_nsec = ltt_get_uint64(LTT_GET_BO(tf),
187 &vheader->start_time_usec);
188 t->start_time.tv_nsec *= 1000; /* microsec to nanosec */
189
190 t->start_time_from_tsc = ltt_time_from_uint64(
c7f86478 191 (double)t->start_tsc
d0e3122a 192 * 1000000000.0 * tf->trace->freq_scale
62e4e7bf 193 / (double)t->start_freq);
e939e5b2 194 }
195 }
196 break;
b7576a11 197 default:
986e2a7c 198 g_warning("Unsupported trace version : %hhu.%hhu",
64dd41a5 199 header->major_version, header->minor_version);
b7576a11 200 return 1;
201 }
202 break;
b7576a11 203 default:
204 g_warning("Unsupported trace version : %hhu.%hhu",
64dd41a5 205 header->major_version, header->minor_version);
b7576a11 206 return 1;
207 }
b7576a11 208 return 0;
209}
210
211
212
6cd62ccf 213/*****************************************************************************
214 *Function name
963b5f2d 215 * ltt_tracefile_open : open a trace file, construct a LttTracefile
6cd62ccf 216 *Input params
963b5f2d 217 * t : the trace containing the tracefile
218 * fileName : path name of the trace file
3aee1200 219 * tf : the tracefile structure
6cd62ccf 220 *Return value
3aee1200 221 * : 0 for success, -1 otherwise.
6cd62ccf 222 ****************************************************************************/
223
8655430b 224static gint ltt_tracefile_open(LttTrace *t, gchar * fileName, LttTracefile *tf)
6cd62ccf 225{
963b5f2d 226 struct stat lTDFStat; /* Trace data file status */
64dd41a5 227 ltt_subbuffer_header_t *header;
b77d1b57 228 int page_size = getpagesize();
6cd62ccf 229
230 //open the file
d3d34f49 231 tf->long_name = g_quark_from_string(fileName);
963b5f2d 232 tf->trace = t;
3865ea09 233 tf->fd = open(fileName, O_RDONLY);
6cd62ccf 234 if(tf->fd < 0){
2a74fbf4 235 g_warning("Unable to open input data file %s\n", fileName);
3aee1200 236 goto end;
6cd62ccf 237 }
238
239 // Get the file's status
240 if(fstat(tf->fd, &lTDFStat) < 0){
2a74fbf4 241 g_warning("Unable to get the status of the input data file %s\n", fileName);
3aee1200 242 goto close_file;
6cd62ccf 243 }
244
245 // Is the file large enough to contain a trace
823820eb 246 if(lTDFStat.st_size <
1550fba6 247 (off_t)(ltt_subbuffer_header_size())){
8710c6c7 248 g_print("The input data file %s does not contain a trace\n", fileName);
3aee1200 249 goto close_file;
250 }
251
252 /* Temporarily map the buffer start header to get trace information */
253 /* Multiple of pages aligned head */
b77d1b57 254 tf->buffer.head = mmap(0,
1550fba6 255 PAGE_ALIGN(ltt_subbuffer_header_size()), PROT_READ,
3aee1200 256 MAP_PRIVATE, tf->fd, 0);
3865ea09 257 if(tf->buffer.head == MAP_FAILED) {
3aee1200 258 perror("Error in allocating memory for buffer of tracefile");
259 goto close_file;
6cd62ccf 260 }
f64fedd7 261 g_assert( ( (gulong)tf->buffer.head&(8-1) ) == 0); // make sure it's aligned.
3aee1200 262
64dd41a5 263 header = (ltt_subbuffer_header_t *)tf->buffer.head;
6cd62ccf 264
64dd41a5 265 if(parse_trace_header(header, tf, NULL)) {
51551c6f 266 g_warning("parse_trace_header error");
267 goto unmap_file;
268 }
3aee1200 269
6cd62ccf 270 //store the size of the file
271 tf->file_size = lTDFStat.st_size;
f628823c 272 tf->buf_size = ltt_get_uint32(LTT_GET_BO(tf), &header->buf_size);
273 tf->num_blocks = tf->file_size / tf->buf_size;
426f6149 274 tf->events_lost = 0;
275 tf->subbuf_corrupt = 0;
f628823c 276
277 if(munmap(tf->buffer.head,
1550fba6 278 PAGE_ALIGN(ltt_subbuffer_header_size()))) {
43ed82b5 279 g_warning("unmap size : %zu\n",
1550fba6 280 PAGE_ALIGN(ltt_subbuffer_header_size()));
f628823c 281 perror("munmap error");
282 g_assert(0);
283 }
3aee1200 284 tf->buffer.head = NULL;
6cd62ccf 285
963b5f2d 286 //read the first block
3aee1200 287 if(map_block(tf,0)) {
288 perror("Cannot map block for tracefile");
289 goto close_file;
290 }
291
292 return 0;
6cd62ccf 293
3aee1200 294 /* Error */
295unmap_file:
f628823c 296 if(munmap(tf->buffer.head,
1550fba6 297 PAGE_ALIGN(ltt_subbuffer_header_size()))) {
43ed82b5 298 g_warning("unmap size : %zu\n",
1550fba6 299 PAGE_ALIGN(ltt_subbuffer_header_size()));
f628823c 300 perror("munmap error");
301 g_assert(0);
302 }
3aee1200 303close_file:
3865ea09 304 close(tf->fd);
3aee1200 305end:
306 return -1;
6cd62ccf 307}
308
6cd62ccf 309
310/*****************************************************************************
311 *Function name
963b5f2d 312 * ltt_tracefile_close: close a trace file,
6cd62ccf 313 *Input params
963b5f2d 314 * t : tracefile which will be closed
6cd62ccf 315 ****************************************************************************/
316
8655430b 317static void ltt_tracefile_close(LttTracefile *t)
6cd62ccf 318{
f628823c 319 int page_size = getpagesize();
320
3aee1200 321 if(t->buffer.head != NULL)
f628823c 322 if(munmap(t->buffer.head, PAGE_ALIGN(t->buf_size))) {
323 g_warning("unmap size : %u\n",
324 PAGE_ALIGN(t->buf_size));
325 perror("munmap error");
326 g_assert(0);
327 }
328
3865ea09 329 close(t->fd);
963b5f2d 330}
6cd62ccf 331
8d1e6362 332/****************************************************************************
333 * get_absolute_pathname
803229fa 334 *
8d1e6362 335 * return the unique pathname in the system
336 *
ef35d837 337 * MD : Fixed this function so it uses realpath, dealing well with
338 * forgotten cases (.. were not used correctly before).
803229fa 339 *
963b5f2d 340 ****************************************************************************/
45e14832 341void get_absolute_pathname(const gchar *pathname, gchar * abs_pathname)
9f797243 342{
9f797243 343 abs_pathname[0] = '\0';
803229fa 344
2fc874ab 345 if (realpath(pathname, abs_pathname) != NULL)
ef35d837 346 return;
347 else
348 {
8d1e6362 349 /* error, return the original path unmodified */
ef35d837 350 strcpy(abs_pathname, pathname);
9f797243 351 return;
352 }
ef35d837 353 return;
9f797243 354}
355
3aee1200 356/* Search for something like : .*_.*
357 *
358 * The left side is the name, the right side is the number.
750eb11a 359 * Exclude leading /.
4ad053df 360 * Exclude flight- prefix.
3aee1200 361 */
362
8655430b 363static int get_tracefile_name_number(gchar *raw_name,
3aee1200 364 GQuark *name,
ae3d0f50 365 guint *num,
f64fedd7 366 gulong *tid,
367 gulong *pgid,
62e4e7bf 368 guint64 *creation)
6cd62ccf 369{
3aee1200 370 guint raw_name_len = strlen(raw_name);
371 gchar char_name[PATH_MAX];
43ed82b5 372 unsigned int i;
3aee1200 373 int underscore_pos;
374 long int cpu_num;
375 gchar *endptr;
62e4e7bf 376 gchar *tmpptr;
3aee1200 377
750eb11a 378 /* skip leading / */
379 for(i = 0; i < raw_name_len-1;i++) {
380 if(raw_name[i] != '/')
381 break;
382 }
383 raw_name = &raw_name[i];
384 raw_name_len = strlen(raw_name);
385
3aee1200 386 for(i=raw_name_len-1;i>=0;i--) {
387 if(raw_name[i] == '_') break;
388 }
ae3d0f50 389 if(i==-1) { /* Either not found or name length is 0 */
62e4e7bf 390 /* This is a userspace tracefile */
391 strncpy(char_name, raw_name, raw_name_len);
392 char_name[raw_name_len] = '\0';
393 *name = g_quark_from_string(char_name);
394 *num = 0; /* unknown cpu */
395 for(i=0;i<raw_name_len;i++) {
396 if(raw_name[i] == '/') {
397 break;
398 }
399 }
400 i++;
401 for(;i<raw_name_len;i++) {
402 if(raw_name[i] == '/') {
403 break;
404 }
405 }
406 i++;
407 for(;i<raw_name_len;i++) {
408 if(raw_name[i] == '-') {
409 break;
410 }
411 }
412 if(i == raw_name_len) return -1;
413 i++;
414 tmpptr = &raw_name[i];
415 for(;i<raw_name_len;i++) {
416 if(raw_name[i] == '.') {
417 raw_name[i] = ' ';
418 break;
419 }
420 }
421 *tid = strtoul(tmpptr, &endptr, 10);
422 if(endptr == tmpptr)
423 return -1; /* No digit */
424 if(*tid == ULONG_MAX)
425 return -1; /* underflow / overflow */
426 i++;
427 tmpptr = &raw_name[i];
428 for(;i<raw_name_len;i++) {
429 if(raw_name[i] == '.') {
430 raw_name[i] = ' ';
431 break;
432 }
433 }
434 *pgid = strtoul(tmpptr, &endptr, 10);
435 if(endptr == tmpptr)
436 return -1; /* No digit */
437 if(*pgid == ULONG_MAX)
438 return -1; /* underflow / overflow */
439 i++;
440 tmpptr = &raw_name[i];
441 *creation = strtoull(tmpptr, &endptr, 10);
442 if(endptr == tmpptr)
443 return -1; /* No digit */
444 if(*creation == G_MAXUINT64)
445 return -1; /* underflow / overflow */
446 } else {
447 underscore_pos = i;
448
449 cpu_num = strtol(raw_name+underscore_pos+1, &endptr, 10);
450
451 if(endptr == raw_name+underscore_pos+1)
452 return -1; /* No digit */
453 if(cpu_num == LONG_MIN || cpu_num == LONG_MAX)
454 return -1; /* underflow / overflow */
455
4ad053df 456 if (!strncmp(raw_name, "flight-", sizeof("flight-") - 1)) {
457 raw_name += sizeof("flight-") - 1;
458 underscore_pos -= sizeof("flight-") - 1;
459 }
62e4e7bf 460 strncpy(char_name, raw_name, underscore_pos);
461 char_name[underscore_pos] = '\0';
62e4e7bf 462 *name = g_quark_from_string(char_name);
463 *num = cpu_num;
464 }
69bd59ed 465
b333a76b 466
3aee1200 467 return 0;
468}
963b5f2d 469
3aee1200 470
3865ea09 471GData **ltt_trace_get_tracefiles_groups(LttTrace *trace)
77175651 472{
3865ea09 473 return &trace->tracefiles;
77175651 474}
475
476
3865ea09 477void compute_tracefile_group(GQuark key_id,
478 GArray *group,
479 struct compute_tracefile_group_args *args)
77175651 480{
43ed82b5 481 unsigned int i;
77175651 482 LttTracefile *tf;
483
484 for(i=0; i<group->len; i++) {
485 tf = &g_array_index (group, LttTracefile, i);
486 if(tf->cpu_online)
3865ea09 487 args->func(tf, args->func_args);
77175651 488 }
489}
490
491
8655430b 492static void ltt_tracefile_group_destroy(gpointer data)
3aee1200 493{
494 GArray *group = (GArray *)data;
43ed82b5 495 unsigned int i;
3aee1200 496 LttTracefile *tf;
497
750eb11a 498 if (group->len > 0)
499 destroy_marker_data(g_array_index (group, LttTracefile, 0).mdata);
3aee1200 500 for(i=0; i<group->len; i++) {
501 tf = &g_array_index (group, LttTracefile, i);
502 if(tf->cpu_online)
503 ltt_tracefile_close(tf);
504 }
505 g_array_free(group, TRUE);
6cd62ccf 506}
507
43ed82b5 508static __attribute__ ((__unused__)) gboolean ltt_tracefile_group_has_cpu_online(gpointer data)
49bf71b5 509{
3aee1200 510 GArray *group = (GArray *)data;
43ed82b5 511 unsigned int i;
3aee1200 512 LttTracefile *tf;
513
514 for(i=0; i<group->len; i++) {
515 tf = &g_array_index (group, LttTracefile, i);
3c165eaf 516 if(tf->cpu_online)
517 return 1;
3aee1200 518 }
519 return 0;
49bf71b5 520}
521
522
3aee1200 523/* Open each tracefile under a specific directory. Put them in a
524 * GData : permits to access them using their tracefile group pathname.
525 * i.e. access control/modules tracefile group by index :
526 * "control/module".
3865ea09 527 *
528 * relative path is the path relative to the trace root
529 * root path is the full path
3aee1200 530 *
4a55f63e 531 * A tracefile group is simply an array where all the per cpu tracefiles sit.
3aee1200 532 */
533
8655430b 534static int open_tracefiles(LttTrace *trace, gchar *root_path, gchar *relative_path)
f7afe191 535{
62e4e7bf 536 DIR *dir = opendir(root_path);
537 struct dirent *entry;
538 struct stat stat_buf;
750eb11a 539 int ret, i;
540 struct marker_data *mdata;
3865ea09 541
62e4e7bf 542 gchar path[PATH_MAX];
543 int path_len;
544 gchar *path_ptr;
3aee1200 545
3865ea09 546 int rel_path_len;
69bd59ed 547 gchar rel_path[PATH_MAX];
548 gchar *rel_path_ptr;
cb03932a 549 LttTracefile tmp_tf;
3865ea09 550
62e4e7bf 551 if(dir == NULL) {
552 perror(root_path);
553 return ENOENT;
554 }
3aee1200 555
62e4e7bf 556 strncpy(path, root_path, PATH_MAX-1);
557 path_len = strlen(path);
558 path[path_len] = '/';
559 path_len++;
560 path_ptr = path + path_len;
3aee1200 561
3865ea09 562 strncpy(rel_path, relative_path, PATH_MAX-1);
563 rel_path_len = strlen(rel_path);
564 rel_path[rel_path_len] = '/';
565 rel_path_len++;
566 rel_path_ptr = rel_path + rel_path_len;
567
62e4e7bf 568 while((entry = readdir(dir)) != NULL) {
569
570 if(entry->d_name[0] == '.') continue;
571
572 strncpy(path_ptr, entry->d_name, PATH_MAX - path_len);
573 strncpy(rel_path_ptr, entry->d_name, PATH_MAX - rel_path_len);
574
575 ret = stat(path, &stat_buf);
576 if(ret == -1) {
577 perror(path);
578 continue;
579 }
580
581 g_debug("Tracefile file or directory : %s\n", path);
582
fe452434 583 // if(strcmp(rel_path, "/eventdefs") == 0) continue;
74a588bb 584
62e4e7bf 585 if(S_ISDIR(stat_buf.st_mode)) {
3aee1200 586
62e4e7bf 587 g_debug("Entering subdirectory...\n");
588 ret = open_tracefiles(trace, path, rel_path);
589 if(ret < 0) continue;
590 } else if(S_ISREG(stat_buf.st_mode)) {
591 GQuark name;
f64fedd7 592 guint num;
593 gulong tid, pgid;
62e4e7bf 594 guint64 creation;
3aee1200 595 GArray *group;
f64fedd7 596 num = 0;
597 tid = pgid = 0;
62e4e7bf 598 creation = 0;
ae3d0f50 599 if(get_tracefile_name_number(rel_path, &name, &num, &tid, &pgid, &creation))
3aee1200 600 continue; /* invalid name */
3865ea09 601
62e4e7bf 602 g_debug("Opening file.\n");
cb03932a 603 if(ltt_tracefile_open(trace, path, &tmp_tf)) {
604 g_info("Error opening tracefile %s", path);
605
606 continue; /* error opening the tracefile : bad magic number ? */
607 }
608
3865ea09 609 g_debug("Tracefile name is %s and number is %u",
610 g_quark_to_string(name), num);
750eb11a 611
612 mdata = NULL;
cb03932a 613 tmp_tf.cpu_online = 1;
614 tmp_tf.cpu_num = num;
d3d34f49 615 tmp_tf.name = name;
62e4e7bf 616 tmp_tf.tid = tid;
617 tmp_tf.pgid = pgid;
618 tmp_tf.creation = creation;
3865ea09 619 group = g_datalist_id_get_data(&trace->tracefiles, name);
3aee1200 620 if(group == NULL) {
621 /* Elements are automatically cleared when the array is allocated.
622 * It makes the cpu_online variable set to 0 : cpu offline, by default.
623 */
624 group = g_array_sized_new (FALSE, TRUE, sizeof(LttTracefile), 10);
3865ea09 625 g_datalist_id_set_data_full(&trace->tracefiles, name,
3aee1200 626 group, ltt_tracefile_group_destroy);
750eb11a 627 mdata = allocate_marker_data();
628 if (!mdata)
629 g_error("Error in allocating marker data");
3aee1200 630 }
cb03932a 631
3aee1200 632 /* Add the per cpu tracefile to the named group */
633 unsigned int old_len = group->len;
634 if(num+1 > old_len)
635 group = g_array_set_size(group, num+1);
750eb11a 636
637 g_assert(group->len > 0);
638 if (!mdata)
639 mdata = g_array_index (group, LttTracefile, 0).mdata;
640
cb03932a 641 g_array_index (group, LttTracefile, num) = tmp_tf;
afd57a3c 642 g_array_index (group, LttTracefile, num).event.tracefile =
643 &g_array_index (group, LttTracefile, num);
750eb11a 644 for (i = 0; i < group->len; i++)
645 g_array_index (group, LttTracefile, i).mdata = mdata;
62e4e7bf 646 }
647 }
648
649 closedir(dir);
3aee1200 650
62e4e7bf 651 return 0;
f7afe191 652}
653
3aee1200 654
655/* Presumes the tracefile is already seeked at the beginning. It makes sense,
656 * because it must be done just after the opening */
2fc874ab 657static int ltt_process_metadata_tracefile(LttTracefile *tf)
3aee1200 658{
659 int err;
3aee1200 660
661 while(1) {
662 err = ltt_tracefile_read_seek(tf);
663 if(err == EPERM) goto seek_error;
664 else if(err == ERANGE) break; /* End of tracefile */
665
666 err = ltt_tracefile_read_update_event(tf);
667 if(err) goto update_error;
668
3aee1200 669 /* The rules are :
2fc874ab 670 * It contains only core events :
671 * 0 : set_marker_id
672 * 1 : set_marker_format
3aee1200 673 */
3c165eaf 674 if(tf->event.event_id >= MARKER_CORE_IDS) {
2fc874ab 675 /* Should only contain core events */
676 g_warning("Error in processing metadata file %s, "
3c165eaf 677 "should not contain event id %u.", g_quark_to_string(tf->name),
678 tf->event.event_id);
3aee1200 679 err = EPERM;
3c165eaf 680 goto event_id_error;
d2083cab 681 } else {
2e13d6af 682 char *pos;
750eb11a 683 const char *channel_name, *marker_name, *format;
3c165eaf 684 uint16_t id;
685 guint8 int_size, long_size, pointer_size, size_t_size, alignment;
3aee1200 686
3c165eaf 687 switch((enum marker_id)tf->event.event_id) {
688 case MARKER_ID_SET_MARKER_ID:
750eb11a 689 channel_name = pos = tf->event.data;
690 pos += strlen(channel_name) + 1;
691 marker_name = pos;
692 g_debug("Doing MARKER_ID_SET_MARKER_ID of marker %s.%s",
693 channel_name, marker_name);
2e13d6af 694 pos += strlen(marker_name) + 1;
2fc874ab 695 pos += ltt_align((size_t)pos, sizeof(guint16), tf->alignment);
3c165eaf 696 id = ltt_get_uint16(LTT_GET_BO(tf), pos);
750eb11a 697 g_debug("In MARKER_ID_SET_MARKER_ID of marker %s.%s id %hu",
698 channel_name, marker_name, id);
3c165eaf 699 pos += sizeof(guint16);
700 int_size = *(guint8*)pos;
701 pos += sizeof(guint8);
702 long_size = *(guint8*)pos;
703 pos += sizeof(guint8);
704 pointer_size = *(guint8*)pos;
705 pos += sizeof(guint8);
706 size_t_size = *(guint8*)pos;
707 pos += sizeof(guint8);
708 alignment = *(guint8*)pos;
709 pos += sizeof(guint8);
750eb11a 710 marker_id_event(tf->trace,
711 g_quark_from_string(channel_name),
712 g_quark_from_string(marker_name),
3c165eaf 713 id, int_size, long_size,
714 pointer_size, size_t_size, alignment);
3aee1200 715 break;
3c165eaf 716 case MARKER_ID_SET_MARKER_FORMAT:
750eb11a 717 channel_name = pos = tf->event.data;
718 pos += strlen(channel_name) + 1;
719 marker_name = pos;
720 g_debug("Doing MARKER_ID_SET_MARKER_FORMAT of marker %s.%s",
721 channel_name, marker_name);
2e13d6af 722 pos += strlen(marker_name) + 1;
2e13d6af 723 format = pos;
3c165eaf 724 pos += strlen(format) + 1;
750eb11a 725 marker_format_event(tf->trace,
726 g_quark_from_string(channel_name),
727 g_quark_from_string(marker_name),
3c165eaf 728 format);
2fc874ab 729 /* get information from dictionary TODO */
d1bb700c 730 break;
3aee1200 731 default:
2fc874ab 732 g_warning("Error in processing metadata file %s, "
3c165eaf 733 "unknown event id %hhu.",
3aee1200 734 g_quark_to_string(tf->name),
735 tf->event.event_id);
736 err = EPERM;
737 goto event_id_error;
738 }
739 }
963b5f2d 740 }
3aee1200 741 return 0;
963b5f2d 742
3aee1200 743 /* Error handling */
3aee1200 744event_id_error:
3aee1200 745update_error:
746seek_error:
2fc874ab 747 g_warning("An error occured in metadata tracefile parsing");
3aee1200 748 return err;
6cd62ccf 749}
750
e95fe8f7 751/*
752 * Open a trace and return its LttTrace handle.
753 *
754 * pathname must be the directory of the trace
755 */
963b5f2d 756
3aee1200 757LttTrace *ltt_trace_open(const gchar *pathname)
758{
759 gchar abs_path[PATH_MAX];
760 LttTrace * t;
761 LttTracefile *tf;
762 GArray *group;
43ed82b5 763 unsigned int i;
764 int ret;
64dd41a5 765 ltt_subbuffer_header_t *header;
62e4e7bf 766 DIR *dir;
767 struct dirent *entry;
62e4e7bf 768 struct stat stat_buf;
b56dcdf2 769 gchar path[PATH_MAX];
3aee1200 770
771 t = g_new(LttTrace, 1);
772 if(!t) goto alloc_error;
773
774 get_absolute_pathname(pathname, abs_path);
775 t->pathname = g_quark_from_string(abs_path);
776
3aee1200 777 g_datalist_init(&t->tracefiles);
b56dcdf2 778
779 /* Test to see if it looks like a trace */
62e4e7bf 780 dir = opendir(abs_path);
781 if(dir == NULL) {
782 perror(abs_path);
783 goto open_error;
784 }
785 while((entry = readdir(dir)) != NULL) {
b56dcdf2 786 strcpy(path, abs_path);
787 strcat(path, "/");
788 strcat(path, entry->d_name);
62e4e7bf 789 ret = stat(path, &stat_buf);
790 if(ret == -1) {
791 perror(path);
792 continue;
793 }
b56dcdf2 794 }
795 closedir(dir);
796
b56dcdf2 797 /* Open all the tracefiles */
e45551ac 798 if(open_tracefiles(t, abs_path, "")) {
799 g_warning("Error opening tracefile %s", abs_path);
b56dcdf2 800 goto find_error;
e45551ac 801 }
3aee1200 802
750eb11a 803 /* Parse each trace metadata_N files : get runtime fac. info */
2fc874ab 804 group = g_datalist_id_get_data(&t->tracefiles, LTT_TRACEFILE_NAME_METADATA);
3aee1200 805 if(group == NULL) {
2fc874ab 806 g_error("Trace %s has no metadata tracefile", abs_path);
3865ea09 807 g_assert(0);
750eb11a 808 goto find_error;
3aee1200 809 }
810
e0c7c400 811 /*
750eb11a 812 * Get the trace information for the metadata_0 tracefile.
e0c7c400 813 * Getting a correct trace start_time and start_tsc is insured by the fact
814 * that no subbuffers are supposed to be lost in the metadata channel.
815 * Therefore, the first subbuffer contains the start_tsc timestamp in its
816 * buffer header.
817 */
16fcbb80 818 g_assert(group->len > 0);
819 tf = &g_array_index (group, LttTracefile, 0);
64dd41a5 820 header = (ltt_subbuffer_header_t *)tf->buffer.head;
ac3b1c7d 821 ret = parse_trace_header(header, tf, t);
822 g_assert(!ret);
b56dcdf2 823
824 t->num_cpu = group->len;
16fcbb80 825
750eb11a 826 //ret = allocate_marker_data(t);
827 //if (ret)
828 // g_error("Error in allocating marker data");
d79909d1 829
3aee1200 830 for(i=0; i<group->len; i++) {
831 tf = &g_array_index (group, LttTracefile, i);
e85b0b1b 832 if (tf->cpu_online)
2fc874ab 833 if(ltt_process_metadata_tracefile(tf))
750eb11a 834 goto find_error;
835 // goto metadata_error;
3aee1200 836 }
dd3a6d39 837
3aee1200 838 return t;
839
840 /* Error handling */
750eb11a 841//metadata_error:
842// destroy_marker_data(t);
b56dcdf2 843find_error:
3aee1200 844 g_datalist_clear(&t->tracefiles);
b56dcdf2 845open_error:
3aee1200 846 g_free(t);
847alloc_error:
848 return NULL;
849
850}
6cd62ccf 851
e95fe8f7 852/* Open another, completely independant, instance of a trace.
853 *
854 * A read on this new instance will read the first event of the trace.
855 *
3aee1200 856 * When we copy a trace, we want all the opening actions to happen again :
857 * the trace will be reopened and totally independant from the original.
858 * That's why we call ltt_trace_open.
e95fe8f7 859 */
3aee1200 860LttTrace *ltt_trace_copy(LttTrace *self)
963b5f2d 861{
3aee1200 862 return ltt_trace_open(g_quark_to_string(self->pathname));
963b5f2d 863}
864
e95fe8f7 865/*
866 * Close a trace
867 */
868
3aee1200 869void ltt_trace_close(LttTrace *t)
6cd62ccf 870{
3aee1200 871 g_datalist_clear(&t->tracefiles);
872 g_free(t);
6cd62ccf 873}
874
3aee1200 875
6cd62ccf 876/*****************************************************************************
3aee1200 877 * Get the start time and end time of the trace
6cd62ccf 878 ****************************************************************************/
879
3c165eaf 880void ltt_tracefile_time_span_get(LttTracefile *tf,
3aee1200 881 LttTime *start, LttTime *end)
6cd62ccf 882{
3aee1200 883 int err;
6cd62ccf 884
3aee1200 885 err = map_block(tf, 0);
886 if(unlikely(err)) {
887 g_error("Can not map block");
888 *start = ltt_time_infinite;
889 } else
890 *start = tf->buffer.begin.timestamp;
891
892 err = map_block(tf, tf->num_blocks - 1); /* Last block */
893 if(unlikely(err)) {
894 g_error("Can not map block");
895 *end = ltt_time_zero;
896 } else
897 *end = tf->buffer.end.timestamp;
6cd62ccf 898}
899
3aee1200 900struct tracefile_time_span_get_args {
901 LttTrace *t;
902 LttTime *start;
903 LttTime *end;
904};
963b5f2d 905
8655430b 906static void group_time_span_get(GQuark name, gpointer data, gpointer user_data)
963b5f2d 907{
3aee1200 908 struct tracefile_time_span_get_args *args =
909 (struct tracefile_time_span_get_args*)user_data;
910
911 GArray *group = (GArray *)data;
43ed82b5 912 unsigned int i;
3aee1200 913 LttTracefile *tf;
914 LttTime tmp_start;
915 LttTime tmp_end;
916
917 for(i=0; i<group->len; i++) {
918 tf = &g_array_index (group, LttTracefile, i);
919 if(tf->cpu_online) {
920 ltt_tracefile_time_span_get(tf, &tmp_start, &tmp_end);
921 if(ltt_time_compare(*args->start, tmp_start)>0) *args->start = tmp_start;
922 if(ltt_time_compare(*args->end, tmp_end)<0) *args->end = tmp_end;
923 }
924 }
6cd62ccf 925}
926
8655430b 927/* return the start and end time of a trace */
928
487ad181 929void ltt_trace_time_span_get(LttTrace *t, LttTime *start, LttTime *end)
930{
3aee1200 931 LttTime min_start = ltt_time_infinite;
932 LttTime max_end = ltt_time_zero;
933 struct tracefile_time_span_get_args args = { t, &min_start, &max_end };
487ad181 934
3aee1200 935 g_datalist_foreach(&t->tracefiles, &group_time_span_get, &args);
936
937 if(start != NULL) *start = min_start;
938 if(end != NULL) *end = max_end;
939
487ad181 940}
941
942
3aee1200 943/* Seek to the first event in a tracefile that has a time equal or greater than
944 * the time passed in parameter.
945 *
946 * If the time parameter is outside the tracefile time span, seek to the first
27304273 947 * event or if after, return ERANGE.
3aee1200 948 *
949 * If the time parameter is before the first event, we have to seek specially to
950 * there.
951 *
27304273 952 * If the time is after the end of the trace, return ERANGE.
3aee1200 953 *
954 * Do a binary search to find the right block, then a sequential search in the
955 * block to find the event.
956 *
957 * In the special case where the time requested fits inside a block that has no
958 * event corresponding to the requested time, the first event of the next block
959 * will be seeked.
960 *
961 * IMPORTANT NOTE : // FIXME everywhere...
962 *
963 * You MUST NOT do a ltt_tracefile_read right after a ltt_tracefile_seek_time :
964 * you will jump over an event if you do.
965 *
966 * Return value : 0 : no error, the tf->event can be used
27304273 967 * ERANGE : time if after the last event of the trace
3aee1200 968 * otherwise : this is an error.
969 *
970 * */
971
972int ltt_tracefile_seek_time(LttTracefile *tf, LttTime time)
973{
974 int ret = 0;
975 int err;
976 unsigned int block_num, high, low;
977
978 /* seek at the beginning of trace */
979 err = map_block(tf, 0); /* First block */
980 if(unlikely(err)) {
981 g_error("Can not map block");
982 goto fail;
caf7a67a 983 }
984
3aee1200 985 /* If the time is lower or equal the beginning of the trace,
986 * go to the first event. */
987 if(ltt_time_compare(time, tf->buffer.begin.timestamp) <= 0) {
988 ret = ltt_tracefile_read(tf);
27304273 989 if(ret == ERANGE) goto range;
990 else if (ret) goto fail;
3aee1200 991 goto found; /* There is either no event in the trace or the event points
992 to the first event in the trace */
993 }
caf7a67a 994
3aee1200 995 err = map_block(tf, tf->num_blocks - 1); /* Last block */
996 if(unlikely(err)) {
997 g_error("Can not map block");
998 goto fail;
caf7a67a 999 }
6cd62ccf 1000
27304273 1001 /* If the time is after the end of the trace, return ERANGE. */
1002 if(ltt_time_compare(time, tf->buffer.end.timestamp) > 0) {
1003 goto range;
3aee1200 1004 }
62e55dd6 1005
3aee1200 1006 /* Binary search the block */
1007 high = tf->num_blocks - 1;
1008 low = 0;
1009
1010 while(1) {
1011 block_num = ((high-low) / 2) + low;
1012
1013 err = map_block(tf, block_num);
1014 if(unlikely(err)) {
1015 g_error("Can not map block");
1016 goto fail;
db55eaae 1017 }
3aee1200 1018 if(high == low) {
1019 /* We cannot divide anymore : this is what would happen if the time
1020 * requested was exactly between two consecutive buffers'end and start
1021 * timestamps. This is also what would happend if we didn't deal with out
1022 * of span cases prior in this function. */
1023 /* The event is right in the buffer!
1024 * (or in the next buffer first event) */
1025 while(1) {
1026 ret = ltt_tracefile_read(tf);
27304273 1027 if(ret == ERANGE) goto range; /* ERANGE or EPERM */
3aee1200 1028 else if(ret) goto fail;
1029
d9e13a0f 1030 if(ltt_time_compare(time, tf->event.event_time) <= 0)
e45551ac 1031 goto found;
3aee1200 1032 }
1033
27304273 1034 } else if(ltt_time_compare(time, tf->buffer.begin.timestamp) < 0) {
3aee1200 1035 /* go to lower part */
b1369bef 1036 high = block_num - 1;
3aee1200 1037 } else if(ltt_time_compare(time, tf->buffer.end.timestamp) > 0) {
1038 /* go to higher part */
b1369bef 1039 low = block_num + 1;
3aee1200 1040 } else {/* The event is right in the buffer!
1041 (or in the next buffer first event) */
1042 while(1) {
27304273 1043 ret = ltt_tracefile_read(tf);
1044 if(ret == ERANGE) goto range; /* ERANGE or EPERM */
3aee1200 1045 else if(ret) goto fail;
1046
d9e13a0f 1047 if(ltt_time_compare(time, tf->event.event_time) <= 0)
3aee1200 1048 break;
6cd62ccf 1049 }
3aee1200 1050 goto found;
6cd62ccf 1051 }
6cd62ccf 1052 }
3aee1200 1053
1054found:
1055 return 0;
27304273 1056range:
1057 return ERANGE;
3aee1200 1058
1059 /* Error handling */
1060fail:
1061 g_error("ltt_tracefile_seek_time failed on tracefile %s",
1062 g_quark_to_string(tf->name));
1063 return EPERM;
6cd62ccf 1064}
1065
e95fe8f7 1066/* Seek to a position indicated by an LttEventPosition
1067 */
80da81ad 1068
8655430b 1069int ltt_tracefile_seek_position(LttTracefile *tf, const LttEventPosition *ep)
1070{
3aee1200 1071 int err;
1072
1073 if(ep->tracefile != tf) {
1074 goto fail;
80da81ad 1075 }
1076
3aee1200 1077 err = map_block(tf, ep->block);
1078 if(unlikely(err)) {
1079 g_error("Can not map block");
1080 goto fail;
1081 }
1082
1083 tf->event.offset = ep->offset;
18206708 1084
62e4e7bf 1085 /* Put back the event real tsc */
1086 tf->event.tsc = ep->tsc;
1087 tf->buffer.tsc = ep->tsc;
78f79181 1088
3aee1200 1089 err = ltt_tracefile_read_update_event(tf);
1090 if(err) goto fail;
73faf25a 1091
1092 /* deactivate this, as it does nothing for now
3aee1200 1093 err = ltt_tracefile_read_op(tf);
1094 if(err) goto fail;
73faf25a 1095 */
80da81ad 1096
a0c1f622 1097 return 0;
3aee1200 1098
1099fail:
1100 g_error("ltt_tracefile_seek_time failed on tracefile %s",
1101 g_quark_to_string(tf->name));
a0c1f622 1102 return 1;
3aee1200 1103}
1104
e95fe8f7 1105/* Given a TSC value, return the LttTime (seconds,nanoseconds) it
1106 * corresponds to.
1107 */
1108
ae3d0f50 1109LttTime ltt_interpolate_time_from_tsc(LttTracefile *tf, guint64 tsc)
3aee1200 1110{
1111 LttTime time;
62e4e7bf 1112
1113 if(tsc > tf->trace->start_tsc) {
1114 time = ltt_time_from_uint64(
1115 (double)(tsc - tf->trace->start_tsc)
d0e3122a 1116 * 1000000000.0 * tf->trace->freq_scale
62e4e7bf 1117 / (double)tf->trace->start_freq);
1118 time = ltt_time_add(tf->trace->start_time_from_tsc, time);
1119 } else {
1120 time = ltt_time_from_uint64(
1121 (double)(tf->trace->start_tsc - tsc)
d0e3122a 1122 * 1000000000.0 * tf->trace->freq_scale
62e4e7bf 1123 / (double)tf->trace->start_freq);
1124 time = ltt_time_sub(tf->trace->start_time_from_tsc, time);
1125 }
3aee1200 1126 return time;
80da81ad 1127}
1128
ae3d0f50 1129/* Calculate the real event time based on the buffer boundaries */
1130LttTime ltt_interpolate_time(LttTracefile *tf, LttEvent *event)
1131{
62e4e7bf 1132 return ltt_interpolate_time_from_tsc(tf, tf->buffer.tsc);
ae3d0f50 1133}
1134
eed2ef37 1135
1136/* Get the current event of the tracefile : valid until the next read */
1137LttEvent *ltt_tracefile_get_event(LttTracefile *tf)
1138{
1139 return &tf->event;
1140}
1141
1142
1143
6cd62ccf 1144/*****************************************************************************
1145 *Function name
3aee1200 1146 * ltt_tracefile_read : Read the next event in the tracefile
6cd62ccf 1147 *Input params
1148 * t : tracefile
1149 *Return value
3aee1200 1150 *
1151 * Returns 0 if an event can be used in tf->event.
d822520b 1152 * Returns ERANGE on end of trace. The event in tf->event still can be used
1153 * (if the last block was not empty).
3aee1200 1154 * Returns EPERM on error.
1155 *
1156 * This function does make the tracefile event structure point to the event
1157 * currently pointed to by the tf->event.
1158 *
1159 * Note : you must call a ltt_tracefile_seek to the beginning of the trace to
1160 * reinitialize it after an error if you want results to be coherent.
1161 * It would be the case if a end of trace last buffer has no event : the end
1162 * of trace wouldn't be returned, but an error.
1163 * We make the assumption there is at least one event per buffer.
6cd62ccf 1164 ****************************************************************************/
1165
3aee1200 1166int ltt_tracefile_read(LttTracefile *tf)
6cd62ccf 1167{
963b5f2d 1168 int err;
6cd62ccf 1169
3aee1200 1170 err = ltt_tracefile_read_seek(tf);
1171 if(err) return err;
1172 err = ltt_tracefile_read_update_event(tf);
1173 if(err) return err;
73faf25a 1174
1175 /* deactivate this, as it does nothing for now
3aee1200 1176 err = ltt_tracefile_read_op(tf);
1177 if(err) return err;
73faf25a 1178 */
3aee1200 1179
1180 return 0;
1181}
1182
1183int ltt_tracefile_read_seek(LttTracefile *tf)
1184{
1185 int err;
1186
1187 /* Get next buffer until we finally have an event, or end of trace */
1188 while(1) {
1189 err = ltt_seek_next_event(tf);
1190 if(unlikely(err == ENOPROTOOPT)) {
1191 return EPERM;
bdc36259 1192 }
bdc36259 1193
3aee1200 1194 /* Are we at the end of the buffer ? */
1195 if(err == ERANGE) {
1196 if(unlikely(tf->buffer.index == tf->num_blocks-1)){ /* end of trace ? */
1197 return ERANGE;
1198 } else {
1199 /* get next block */
1200 err = map_block(tf, tf->buffer.index + 1);
1201 if(unlikely(err)) {
1202 g_error("Can not map block");
1203 return EPERM;
1204 }
1205 }
1206 } else break; /* We found an event ! */
1207 }
2dee981d 1208
3aee1200 1209 return 0;
1210}
18206708 1211
e95fe8f7 1212/* do an operation when reading a new event */
18206708 1213
73faf25a 1214/* This function does nothing for now */
1215#if 0
3aee1200 1216int ltt_tracefile_read_op(LttTracefile *tf)
1217{
3aee1200 1218 LttEvent *event;
1219
1220 event = &tf->event;
18206708 1221
73faf25a 1222 /* do event specific operation */
1223
1224 /* nothing */
40331ba8 1225
3aee1200 1226 return 0;
6cd62ccf 1227}
73faf25a 1228#endif
6cd62ccf 1229
91f8d488 1230static void print_debug_event_header(LttEvent *ev, void *start_pos, void *end_pos)
1231{
1232 unsigned int offset = 0;
1233 int i, j;
1234
43ed82b5 1235 g_printf("Event header (tracefile %s offset %" PRIx64 "):\n",
afd57a3c 1236 g_quark_to_string(ev->tracefile->long_name),
43ed82b5 1237 ((uint64_t)ev->tracefile->buffer.index * ev->tracefile->buf_size)
1238 + (long)start_pos - (long)ev->tracefile->buffer.head);
91f8d488 1239
1240 while (offset < (long)end_pos - (long)start_pos) {
1241 g_printf("%8lx", (long)start_pos - (long)ev->tracefile->buffer.head + offset);
1242 g_printf(" ");
1243
1244 for (i = 0; i < 4 ; i++) {
1245 for (j = 0; j < 4; j++) {
1246 if (offset + ((i * 4) + j) <
1247 (long)end_pos - (long)start_pos)
1248 g_printf("%02hhX",
d3353231 1249 ((char*)start_pos)[offset + ((i * 4) + j)]);
91f8d488 1250 else
1251 g_printf(" ");
1252 g_printf(" ");
1253 }
1254 if (i < 4)
1255 g_printf(" ");
1256 }
1257 offset+=16;
1258 g_printf("\n");
1259 }
1260}
1261
6cd62ccf 1262
3aee1200 1263/* same as ltt_tracefile_read, but does not seek to the next event nor call
1264 * event specific operation. */
1265int ltt_tracefile_read_update_event(LttTracefile *tf)
6cd62ccf 1266{
3aee1200 1267 void * pos;
1268 LttEvent *event;
91f8d488 1269 void *pos_aligned;
3aee1200 1270
1271 event = &tf->event;
eed2ef37 1272 pos = tf->buffer.head + event->offset;
3aee1200 1273
1274 /* Read event header */
1275
62e4e7bf 1276 /* Align the head */
2fc874ab 1277 pos += ltt_align((size_t)pos, sizeof(guint32), tf->alignment);
91f8d488 1278 pos_aligned = pos;
3aee1200 1279
2fc874ab 1280 event->timestamp = ltt_get_uint32(LTT_GET_BO(tf), pos);
1281 event->event_id = event->timestamp >> tf->tscbits;
a9048165 1282 event->timestamp = event->timestamp & tf->tsc_mask;
2fc874ab 1283 pos += sizeof(guint32);
1284
1285 switch (event->event_id) {
1286 case 29: /* LTT_RFLAG_ID_SIZE_TSC */
1287 event->event_id = ltt_get_uint16(LTT_GET_BO(tf), pos);
1288 pos += sizeof(guint16);
1289 event->event_size = ltt_get_uint16(LTT_GET_BO(tf), pos);
1290 pos += sizeof(guint16);
1291 if (event->event_size == 0xFFFF) {
1292 event->event_size = ltt_get_uint32(LTT_GET_BO(tf), pos);
1293 pos += sizeof(guint32);
d1bb700c 1294 }
2fc874ab 1295 pos += ltt_align((size_t)pos, sizeof(guint64), tf->alignment);
1296 tf->buffer.tsc = ltt_get_uint64(LTT_GET_BO(tf), pos);
62e4e7bf 1297 pos += sizeof(guint64);
2fc874ab 1298 break;
1299 case 30: /* LTT_RFLAG_ID_SIZE */
f439de06 1300 event->event_id = ltt_get_uint16(LTT_GET_BO(tf), pos);
3c165eaf 1301 pos += sizeof(guint16);
d1bb700c 1302 event->event_size = ltt_get_uint16(LTT_GET_BO(tf), pos);
1303 pos += sizeof(guint16);
2fc874ab 1304 if (event->event_size == 0xFFFF) {
1305 event->event_size = ltt_get_uint32(LTT_GET_BO(tf), pos);
1306 pos += sizeof(guint32);
1307 }
1308 break;
1309 case 31: /* LTT_RFLAG_ID */
1310 event->event_id = ltt_get_uint16(LTT_GET_BO(tf), pos);
1311 pos += sizeof(guint16);
1312 event->event_size = G_MAXUINT;
1313 break;
1314 default:
1315 event->event_size = G_MAXUINT;
1316 break;
1317 }
1318
1319 if (likely(event->event_id != 29)) {
1320 /* No extended timestamp */
1321 if (event->timestamp < (tf->buffer.tsc & tf->tsc_mask))
1322 tf->buffer.tsc = ((tf->buffer.tsc & ~tf->tsc_mask) /* overflow */
1323 + tf->tsc_mask_next_bit)
1324 | (guint64)event->timestamp;
1325 else
1326 tf->buffer.tsc = (tf->buffer.tsc & ~tf->tsc_mask) /* no overflow */
1327 | (guint64)event->timestamp;
d1bb700c 1328 }
2fc874ab 1329 event->tsc = tf->buffer.tsc;
1330
1331 event->event_time = ltt_interpolate_time(tf, event);
91f8d488 1332
1333 if (a_event_debug)
1334 print_debug_event_header(event, pos_aligned, pos);
1335
3aee1200 1336 event->data = pos;
1337
2fc874ab 1338 /*
1339 * Let ltt_update_event_size update event->data according to the largest
1340 * alignment within the payload.
1341 * Get the data size and update the event fields with the current
1342 * information. */
eed2ef37 1343 ltt_update_event_size(tf);
77175651 1344
3aee1200 1345 return 0;
6cd62ccf 1346}
1347
507915ee 1348
6cd62ccf 1349/****************************************************************************
1350 *Function name
3aee1200 1351 * map_block : map a block from the file
6cd62ccf 1352 *Input Params
1353 * lttdes : ltt trace file
1354 * whichBlock : the block which will be read
1355 *return value
1356 * 0 : success
1357 * EINVAL : lseek fail
1358 * EIO : can not read from the file
1359 ****************************************************************************/
1360
8655430b 1361static gint map_block(LttTracefile * tf, guint block_num)
6cd62ccf 1362{
b77d1b57 1363 int page_size = getpagesize();
64dd41a5 1364 ltt_subbuffer_header_t *header;
3aee1200 1365
1366 g_assert(block_num < tf->num_blocks);
6cd62ccf 1367
f628823c 1368 if(tf->buffer.head != NULL) {
1369 if(munmap(tf->buffer.head, PAGE_ALIGN(tf->buf_size))) {
1370 g_warning("unmap size : %u\n",
1371 PAGE_ALIGN(tf->buf_size));
1372 perror("munmap error");
1373 g_assert(0);
1374 }
1375 }
ac849774 1376
3aee1200 1377 /* Multiple of pages aligned head */
b77d1b57 1378 tf->buffer.head = mmap(0,
f628823c 1379 PAGE_ALIGN(tf->buf_size),
b77d1b57 1380 PROT_READ, MAP_PRIVATE, tf->fd,
f628823c 1381 PAGE_ALIGN((off_t)tf->buf_size * (off_t)block_num));
3aee1200 1382
3865ea09 1383 if(tf->buffer.head == MAP_FAILED) {
3aee1200 1384 perror("Error in allocating memory for buffer of tracefile");
3865ea09 1385 g_assert(0);
3aee1200 1386 goto map_error;
6cd62ccf 1387 }
f64fedd7 1388 g_assert( ( (gulong)tf->buffer.head&(8-1) ) == 0); // make sure it's aligned.
3aee1200 1389
6cd62ccf 1390
3aee1200 1391 tf->buffer.index = block_num;
1392
64dd41a5 1393 header = (ltt_subbuffer_header_t *)tf->buffer.head;
3aee1200 1394
3aee1200 1395 tf->buffer.begin.cycle_count = ltt_get_uint64(LTT_GET_BO(tf),
64dd41a5 1396 &header->cycle_count_begin);
1397 tf->buffer.begin.freq = tf->trace->start_freq;
ae3d0f50 1398
1399 tf->buffer.begin.timestamp = ltt_interpolate_time_from_tsc(tf,
62e4e7bf 1400 tf->buffer.begin.cycle_count);
3aee1200 1401 tf->buffer.end.cycle_count = ltt_get_uint64(LTT_GET_BO(tf),
64dd41a5 1402 &header->cycle_count_end);
1403 tf->buffer.end.freq = tf->trace->start_freq;
62e4e7bf 1404
3aee1200 1405 tf->buffer.lost_size = ltt_get_uint32(LTT_GET_BO(tf),
986e2a7c 1406 &header->lost_size);
ae3d0f50 1407 tf->buffer.end.timestamp = ltt_interpolate_time_from_tsc(tf,
62e4e7bf 1408 tf->buffer.end.cycle_count);
3aee1200 1409 tf->buffer.tsc = tf->buffer.begin.cycle_count;
1410 tf->event.tsc = tf->buffer.tsc;
986e2a7c 1411 tf->buffer.freq = tf->buffer.begin.freq;
3aee1200 1412
1413 /* FIXME
1414 * eventually support variable buffer size : will need a partial pre-read of
1415 * the headers to create an index when we open the trace... eventually. */
f628823c 1416 g_assert(tf->buf_size == ltt_get_uint32(LTT_GET_BO(tf),
3aee1200 1417 &header->buf_size));
507915ee 1418
3aee1200 1419 /* Make the current event point to the beginning of the buffer :
1420 * it means that the event read must get the first event. */
1421 tf->event.tracefile = tf;
1422 tf->event.block = block_num;
eed2ef37 1423 tf->event.offset = 0;
3aee1200 1424
a2bbf2e5 1425 if (header->events_lost) {
1426 g_warning("%d events lost so far in tracefile %s at block %u",
0c2f4984 1427 (guint)header->events_lost,
a2bbf2e5 1428 g_quark_to_string(tf->long_name),
1429 block_num);
426f6149 1430 tf->events_lost = header->events_lost;
1431 }
a2bbf2e5 1432 if (header->subbuf_corrupt) {
1433 g_warning("%d subbuffer(s) corrupted so far in tracefile %s at block %u",
0c2f4984 1434 (guint)header->subbuf_corrupt,
a2bbf2e5 1435 g_quark_to_string(tf->long_name),
1436 block_num);
426f6149 1437 tf->subbuf_corrupt = header->subbuf_corrupt;
1438 }
1439
3aee1200 1440 return 0;
6cd62ccf 1441
3aee1200 1442map_error:
1443 return -errno;
6cd62ccf 1444}
1445
91f8d488 1446static void print_debug_event_data(LttEvent *ev)
1447{
1448 unsigned int offset = 0;
1449 int i, j;
1450
1451 if (!max(ev->event_size, ev->data_size))
1452 return;
1453
43ed82b5 1454 g_printf("Event data (tracefile %s offset %" PRIx64 "):\n",
1455 g_quark_to_string(ev->tracefile->long_name),
1456 ((uint64_t)ev->tracefile->buffer.index * ev->tracefile->buf_size)
1457 + (long)ev->data - (long)ev->tracefile->buffer.head);
91f8d488 1458
1459 while (offset < max(ev->event_size, ev->data_size)) {
1460 g_printf("%8lx", (long)ev->data + offset
1461 - (long)ev->tracefile->buffer.head);
1462 g_printf(" ");
1463
1464 for (i = 0; i < 4 ; i++) {
1465 for (j = 0; j < 4; j++) {
1466 if (offset + ((i * 4) + j) < max(ev->event_size, ev->data_size))
1467 g_printf("%02hhX", ((char*)ev->data)[offset + ((i * 4) + j)]);
1468 else
1469 g_printf(" ");
1470 g_printf(" ");
1471 }
1472 if (i < 4)
1473 g_printf(" ");
1474 }
1475
1476 g_printf(" ");
1477
1478 for (i = 0; i < 4; i++) {
1479 for (j = 0; j < 4; j++) {
1480 if (offset + ((i * 4) + j) < max(ev->event_size, ev->data_size)) {
1481 if (isprint(((char*)ev->data)[offset + ((i * 4) + j)]))
1482 g_printf("%c", ((char*)ev->data)[offset + ((i * 4) + j)]);
1483 else
1484 g_printf(".");
1485 } else
1486 g_printf(" ");
1487 }
1488 }
1489 offset+=16;
1490 g_printf("\n");
1491 }
1492}
1493
77175651 1494/* It will update the fields offsets too */
1495void ltt_update_event_size(LttTracefile *tf)
6cd62ccf 1496{
2312de30 1497 off_t size = 0;
d2007fbd 1498 struct marker_info *info;
750eb11a 1499
1500 if (tf->name == LTT_TRACEFILE_NAME_METADATA) {
1501 switch((enum marker_id)tf->event.event_id) {
1502 case MARKER_ID_SET_MARKER_ID:
1503 size = strlen((char*)tf->event.data) + 1;
1504 g_debug("marker %s id set", (char*)tf->event.data + size);
1505 size += strlen((char*)tf->event.data + size) + 1;
1506 size += ltt_align(size, sizeof(guint16), tf->alignment);
1507 size += sizeof(guint16);
1508 size += sizeof(guint8);
1509 size += sizeof(guint8);
1510 size += sizeof(guint8);
1511 size += sizeof(guint8);
1512 size += sizeof(guint8);
1513 break;
1514 case MARKER_ID_SET_MARKER_FORMAT:
1515 size = strlen((char*)tf->event.data) + 1;
1516 g_debug("marker %s format set", (char*)tf->event.data);
1517 size += strlen((char*)tf->event.data + size) + 1;
1518 size += strlen((char*)tf->event.data + size) + 1;
1519 break;
1520 }
256a5b3a 1521 }
1522
750eb11a 1523 info = marker_get_info_from_id(tf->mdata, tf->event.event_id);
dcf96842 1524
256a5b3a 1525 if (tf->event.event_id >= MARKER_CORE_IDS)
1526 g_assert(info != NULL);
1527
1528 /* Do not update field offsets of core markers when initially reading the
2fc874ab 1529 * metadata tracefile when the infos about these markers do not exist yet.
256a5b3a 1530 */
1531 if (likely(info && info->fields)) {
2fc874ab 1532 /* alignment */
196085f2 1533 tf->event.data += ltt_align((off_t)(unsigned long)tf->event.data,
1534 info->largest_align,
2fc874ab 1535 info->alignment);
1536 /* size, dynamically computed */
256a5b3a 1537 if (info->size != -1)
1538 size = info->size;
1539 else
750eb11a 1540 size = marker_update_fields_offsets(marker_get_info_from_id(tf->mdata,
256a5b3a 1541 tf->event.event_id), tf->event.data);
44f317b7 1542 }
c4afd5d8 1543
d2007fbd 1544 tf->event.data_size = size;
1545
1546 /* Check consistency between kernel and LTTV structure sizes */
2fc874ab 1547 if(tf->event.event_size == G_MAXUINT) {
d2007fbd 1548 /* Event size too big to fit in the event size field */
1549 tf->event.event_size = tf->event.data_size;
1550 }
91f8d488 1551
1552 if (a_event_debug)
1553 print_debug_event_data(&tf->event);
1554
d2007fbd 1555 if (tf->event.data_size != tf->event.event_size) {
750eb11a 1556 struct marker_info *info = marker_get_info_from_id(tf->mdata,
3c165eaf 1557 tf->event.event_id);
750eb11a 1558 if (!info)
1559 g_error("Undescribed event %hhu in channel %s", tf->event.event_id,
1560 g_quark_to_string(tf->name));
3c165eaf 1561 g_error("Kernel/LTTV event size differs for event %s: kernel %u, LTTV %u",
1562 g_quark_to_string(info->name),
1563 tf->event.event_size, tf->event.data_size);
d2007fbd 1564 exit(-1);
1565 }
6cd62ccf 1566}
1567
6cd62ccf 1568
2fc874ab 1569/* Take the tf current event offset and use the event id to figure out where is
1570 * the next event offset.
3aee1200 1571 *
1572 * This is an internal function not aiming at being used elsewhere : it will
1573 * not jump over the current block limits. Please consider using
1574 * ltt_tracefile_read to do this.
1575 *
1576 * Returns 0 on success
1577 * ERANGE if we are at the end of the buffer.
1578 * ENOPROTOOPT if an error occured when getting the current event size.
1579 */
8655430b 1580static int ltt_seek_next_event(LttTracefile *tf)
6cd62ccf 1581{
3aee1200 1582 int ret = 0;
1583 void *pos;
3aee1200 1584
1585 /* seek over the buffer header if we are at the buffer start */
eed2ef37 1586 if(tf->event.offset == 0) {
51551c6f 1587 tf->event.offset += tf->buffer_header_size;
b77d1b57 1588
f628823c 1589 if(tf->event.offset == tf->buf_size - tf->buffer.lost_size) {
b77d1b57 1590 ret = ERANGE;
1591 }
3aee1200 1592 goto found;
1593 }
2fc874ab 1594
3aee1200 1595 pos = tf->event.data;
1596
77175651 1597 if(tf->event.data_size < 0) goto error;
3aee1200 1598
77175651 1599 pos += (size_t)tf->event.data_size;
3aee1200 1600
eed2ef37 1601 tf->event.offset = pos - tf->buffer.head;
cb03932a 1602
f628823c 1603 if(tf->event.offset == tf->buf_size - tf->buffer.lost_size) {
cb03932a 1604 ret = ERANGE;
1605 goto found;
1606 }
36d36c9f 1607 g_assert(tf->event.offset < tf->buf_size - tf->buffer.lost_size);
3aee1200 1608
1609found:
1610 return ret;
1611
1612error:
1613 g_error("Error in ltt_seek_next_event for tracefile %s",
1614 g_quark_to_string(tf->name));
1615 return ENOPROTOOPT;
6cd62ccf 1616}
1617
f104d082 1618#if 0
3aee1200 1619/*****************************************************************************
6cd62ccf 1620 *Function name
3aee1200 1621 * set_fields_offsets : set the precomputable offset of the fields
6cd62ccf 1622 *Input params
3aee1200 1623 * tracefile : opened trace file
1624 * event_type : the event type
6cd62ccf 1625 ****************************************************************************/
1626
3aee1200 1627void set_fields_offsets(LttTracefile *tf, LttEventType *event_type)
6cd62ccf 1628{
3aee1200 1629 LttField *field = event_type->root_field;
1630 enum field_status fixed_root = FIELD_FIXED, fixed_parent = FIELD_FIXED;
1631
1632 if(likely(field))
1633 preset_field_type_size(tf, event_type, 0, 0,
1634 &fixed_root, &fixed_parent,
1635 field);
1636
1637}
f104d082 1638#endif //0
1639
1640
1641/*****************************************************************************
1642 *Function name
1643 * get_alignment : Get the alignment needed for a field.
1644 *Input params
f104d082 1645 * field : field
1646 *
1647 * returns : The size on which it must be aligned.
1648 *
1649 ****************************************************************************/
3c165eaf 1650#if 0
743e50fd 1651off_t get_alignment(LttField *field)
f104d082 1652{
2312de30 1653 LttType *type = &field->field_type;
f104d082 1654
1655 switch(type->type_class) {
1656 case LTT_INT_FIXED:
1657 case LTT_UINT_FIXED:
1658 case LTT_POINTER:
1659 case LTT_CHAR:
1660 case LTT_UCHAR:
1661 case LTT_SHORT:
1662 case LTT_USHORT:
1663 case LTT_INT:
1664 case LTT_UINT:
1665 case LTT_LONG:
1666 case LTT_ULONG:
1667 case LTT_SIZE_T:
1668 case LTT_SSIZE_T:
1669 case LTT_OFF_T:
1670 case LTT_FLOAT:
1671 case LTT_ENUM:
1672 /* Align offset on type size */
83e160f2 1673 g_assert(field->field_size != 0);
f104d082 1674 return field->field_size;
1675 break;
1676 case LTT_STRING:
83e160f2 1677 return 1;
f104d082 1678 break;
1679 case LTT_ARRAY:
1680 g_assert(type->fields->len == 1);
1681 {
1682 LttField *child = &g_array_index(type->fields, LttField, 0);
743e50fd 1683 return get_alignment(child);
f104d082 1684 }
1685 break;
1686 case LTT_SEQUENCE:
1687 g_assert(type->fields->len == 2);
1688 {
83e160f2 1689 off_t localign = 1;
f104d082 1690 LttField *child = &g_array_index(type->fields, LttField, 0);
1691
743e50fd 1692 localign = max(localign, get_alignment(child));
f104d082 1693
1694 child = &g_array_index(type->fields, LttField, 1);
743e50fd 1695 localign = max(localign, get_alignment(child));
f104d082 1696
1697 return localign;
1698 }
1699 break;
1700 case LTT_STRUCT:
1701 case LTT_UNION:
1702 {
1703 guint i;
83e160f2 1704 off_t localign = 1;
f104d082 1705
1706 for(i=0; i<type->fields->len; i++) {
1707 LttField *child = &g_array_index(type->fields, LttField, i);
743e50fd 1708 localign = max(localign, get_alignment(child));
f104d082 1709 }
1710 return localign;
1711 }
1712 break;
1713 case LTT_NONE:
1714 default:
1715 g_error("get_alignment : unknown type");
83e160f2 1716 return -1;
f104d082 1717 }
f104d082 1718}
1719
3c165eaf 1720#endif //0
1721
f104d082 1722/*****************************************************************************
1723 *Function name
1724 * field_compute_static_size : Determine the size of fields known by their
1725 * sole definition. Unions, arrays and struct sizes might be known, but
1726 * the parser does not give that information.
1727 *Input params
1728 * tf : tracefile
1729 * field : field
1730 *
1731 ****************************************************************************/
3c165eaf 1732#if 0
743e50fd 1733void field_compute_static_size(LttFacility *fac, LttField *field)
f104d082 1734{
2312de30 1735 LttType *type = &field->field_type;
f104d082 1736
1737 switch(type->type_class) {
1738 case LTT_INT_FIXED:
1739 case LTT_UINT_FIXED:
1740 case LTT_POINTER:
1741 case LTT_CHAR:
1742 case LTT_UCHAR:
1743 case LTT_SHORT:
1744 case LTT_USHORT:
1745 case LTT_INT:
1746 case LTT_UINT:
1747 case LTT_LONG:
1748 case LTT_ULONG:
1749 case LTT_SIZE_T:
1750 case LTT_SSIZE_T:
1751 case LTT_OFF_T:
1752 case LTT_FLOAT:
1753 case LTT_ENUM:
1754 case LTT_STRING:
1755 /* nothing to do */
1756 break;
1757 case LTT_ARRAY:
1758 /* note this : array type size is the number of elements in the array,
1759 * while array field size of the length of the array in bytes */
1760 g_assert(type->fields->len == 1);
1761 {
1762 LttField *child = &g_array_index(type->fields, LttField, 0);
743e50fd 1763 field_compute_static_size(fac, child);
f104d082 1764
1765 if(child->field_size != 0) {
1766 field->field_size = type->size * child->field_size;
1767 field->dynamic_offsets = g_array_sized_new(FALSE, TRUE,
1768 sizeof(off_t), type->size);
1769 } else {
1770 field->field_size = 0;
1771 }
1772 }
1773 break;
1774 case LTT_SEQUENCE:
1775 g_assert(type->fields->len == 2);
1776 {
2312de30 1777 off_t local_offset = 0;
f104d082 1778 LttField *child = &g_array_index(type->fields, LttField, 1);
743e50fd 1779 field_compute_static_size(fac, child);
f104d082 1780 field->field_size = 0;
1781 type->size = 0;
1782 if(child->field_size != 0) {
1783 field->dynamic_offsets = g_array_sized_new(FALSE, TRUE,
1784 sizeof(off_t), SEQUENCE_AVG_ELEMENTS);
1785 }
1786 }
1787 break;
1788 case LTT_STRUCT:
1789 case LTT_UNION:
1790 {
1791 guint i;
1792 for(i=0;i<type->fields->len;i++) {
1793 LttField *child = &g_array_index(type->fields, LttField, i);
743e50fd 1794 field_compute_static_size(fac, child);
f104d082 1795 if(child->field_size != 0) {
743e50fd 1796 type->size += ltt_align(type->size, get_alignment(child),
1797 fac->alignment);
f104d082 1798 type->size += child->field_size;
1799 } else {
1800 /* As soon as we find a child with variable size, we have
1801 * a variable size */
1802 type->size = 0;
1803 break;
1804 }
1805 }
1806 field->field_size = type->size;
1807 }
1808 break;
1809 default:
1810 g_error("field_static_size : unknown type");
2312de30 1811 }
f104d082 1812
1813}
3c165eaf 1814#endif //0
f104d082 1815
1816
1817/*****************************************************************************
1818 *Function name
1819 * precompute_fields_offsets : set the precomputable offset of the fields
1820 *Input params
743e50fd 1821 * fac : facility
f104d082 1822 * field : the field
1823 * offset : pointer to the current offset, must be incremented
1824 *
1825 * return : 1 : found a variable length field, stop the processing.
1826 * 0 otherwise.
1827 ****************************************************************************/
1828
3c165eaf 1829#if 0
dd3a6d39 1830gint precompute_fields_offsets(LttFacility *fac, LttField *field, off_t *offset, gint is_compact)
f104d082 1831{
2312de30 1832 LttType *type = &field->field_type;
dd3a6d39 1833
1834 if(unlikely(is_compact)) {
1835 g_assert(field->field_size != 0);
1836 /* FIXME THIS IS A HUUUUUGE hack :
1837 * offset is between the compact_data field in struct LttEvent
1838 * and the address of the field root in the memory map.
1839 * ark. Both will stay at the same addresses while the event
1840 * is readable, so it's ok.
1841 */
1842 field->offset_root = 0;
1843 field->fixed_root = FIELD_FIXED;
1844 return 0;
1845 }
f104d082 1846
1847 switch(type->type_class) {
1848 case LTT_INT_FIXED:
1849 case LTT_UINT_FIXED:
1850 case LTT_POINTER:
1851 case LTT_CHAR:
1852 case LTT_UCHAR:
1853 case LTT_SHORT:
1854 case LTT_USHORT:
1855 case LTT_INT:
1856 case LTT_UINT:
1857 case LTT_LONG:
1858 case LTT_ULONG:
1859 case LTT_SIZE_T:
1860 case LTT_SSIZE_T:
1861 case LTT_OFF_T:
1862 case LTT_FLOAT:
1863 case LTT_ENUM:
743e50fd 1864 g_assert(field->field_size != 0);
f104d082 1865 /* Align offset on type size */
743e50fd 1866 *offset += ltt_align(*offset, get_alignment(field),
1867 fac->alignment);
f104d082 1868 /* remember offset */
1869 field->offset_root = *offset;
1870 field->fixed_root = FIELD_FIXED;
1871 /* Increment offset */
1872 *offset += field->field_size;
1873 return 0;
1874 break;
1875 case LTT_STRING:
1876 field->offset_root = *offset;
1877 field->fixed_root = FIELD_FIXED;
1878 return 1;
1879 break;
1880 case LTT_ARRAY:
1881 g_assert(type->fields->len == 1);
1882 {
1883 LttField *child = &g_array_index(type->fields, LttField, 0);
1884
743e50fd 1885 *offset += ltt_align(*offset, get_alignment(field),
1886 fac->alignment);
f104d082 1887
1888 /* remember offset */
1889 field->offset_root = *offset;
1890 field->array_offset = *offset;
1891 field->fixed_root = FIELD_FIXED;
1892
1893 /* Let the child be variable */
1894 //precompute_fields_offsets(tf, child, offset);
1895
1896 if(field->field_size != 0) {
1897 /* Increment offset */
1898 /* field_size is the array size in bytes */
1899 *offset += field->field_size;
1900 return 0;
1901 } else {
1902 return 1;
1903 }
1904 }
1905 break;
1906 case LTT_SEQUENCE:
1907 g_assert(type->fields->len == 2);
1908 {
1909 LttField *child;
1910 guint ret;
1911
743e50fd 1912 *offset += ltt_align(*offset, get_alignment(field),
1913 fac->alignment);
f104d082 1914
1915 /* remember offset */
1916 field->offset_root = *offset;
1917 field->fixed_root = FIELD_FIXED;
1918
1919 child = &g_array_index(type->fields, LttField, 0);
dd3a6d39 1920 ret = precompute_fields_offsets(fac, child, offset, is_compact);
f104d082 1921 g_assert(ret == 0); /* Seq len cannot have variable len */
1922
1923 child = &g_array_index(type->fields, LttField, 1);
743e50fd 1924 *offset += ltt_align(*offset, get_alignment(child),
1925 fac->alignment);
f104d082 1926 field->array_offset = *offset;
743e50fd 1927 /* Let the child be variable. */
1928 //ret = precompute_fields_offsets(fac, child, offset);
f104d082 1929
1930 /* Cannot precompute fields offsets of sequence members, and has
1931 * variable length. */
1932 return 1;
1933 }
1934 break;
1935 case LTT_STRUCT:
1936 {
1937 LttField *child;
1938 guint i;
1939 gint ret=0;
1940
743e50fd 1941 *offset += ltt_align(*offset, get_alignment(field),
1942 fac->alignment);
f104d082 1943 /* remember offset */
1944 field->offset_root = *offset;
1945 field->fixed_root = FIELD_FIXED;
1946
1947 for(i=0; i< type->fields->len; i++) {
1948 child = &g_array_index(type->fields, LttField, i);
dd3a6d39 1949 ret = precompute_fields_offsets(fac, child, offset, is_compact);
f104d082 1950
1951 if(ret) break;
1952 }
1953 return ret;
1954 }
1955 break;
1956 case LTT_UNION:
1957 {
1958 LttField *child;
1959 guint i;
1960 gint ret=0;
1961
743e50fd 1962 *offset += ltt_align(*offset, get_alignment(field),
1963 fac->alignment);
f104d082 1964 /* remember offset */
1965 field->offset_root = *offset;
1966 field->fixed_root = FIELD_FIXED;
1967
1968 for(i=0; i< type->fields->len; i++) {
1969 *offset = field->offset_root;
1970 child = &g_array_index(type->fields, LttField, i);
dd3a6d39 1971 ret = precompute_fields_offsets(fac, child, offset, is_compact);
f104d082 1972
1973 if(ret) break;
1974 }
1975 *offset = field->offset_root + field->field_size;
1976 return ret;
1977 }
1978
1979 break;
1980 case LTT_NONE:
1981 default:
1982 g_error("precompute_fields_offsets : unknown type");
1983 return 1;
1984 }
1985
1986}
1987
3c165eaf 1988#endif //0
f104d082 1989
3c165eaf 1990#if 0
f104d082 1991/*****************************************************************************
1992 *Function name
1993 * precompute_offsets : set the precomputable offset of an event type
1994 *Input params
1995 * tf : tracefile
1996 * event : event type
1997 *
1998 ****************************************************************************/
743e50fd 1999void precompute_offsets(LttFacility *fac, LttEventType *event)
f104d082 2000{
2001 guint i;
2002 off_t offset = 0;
2003 gint ret;
2004
2005 /* First, compute the size of fixed size fields. Will determine size for
2006 * arrays, struct and unions, which is not done by the parser */
2007 for(i=0; i<event->fields->len; i++) {
2008 LttField *field = &g_array_index(event->fields, LttField, i);
743e50fd 2009 field_compute_static_size(fac, field);
f104d082 2010 }
2011
2012 /* Precompute all known offsets */
2013 for(i=0; i<event->fields->len; i++) {
2014 LttField *field = &g_array_index(event->fields, LttField, i);
dd3a6d39 2015 if(event->has_compact_data && i == 0)
2016 ret = precompute_fields_offsets(fac, field, &offset, 1);
2017 else
2018 ret = precompute_fields_offsets(fac, field, &offset, 0);
f104d082 2019 if(ret) break;
2020 }
2021}
3c165eaf 2022#endif //0
f104d082 2023
e4eced0f 2024
bbf28e50 2025
3aee1200 2026/*****************************************************************************
2027 *Function name
2028 * preset_field_type_size : set the fixed sizes of the field type
2029 *Input params
2030 * tf : tracefile
2031 * event_type : event type
2032 * offset_root : offset from the root
2033 * offset_parent : offset from the parent
2034 * fixed_root : Do we know a fixed offset to the root ?
2035 * fixed_parent : Do we know a fixed offset to the parent ?
2036 * field : field
2037 ****************************************************************************/
f104d082 2038
2039
2040
2041// preset the fixed size offsets. Calculate them just like genevent-new : an
2042// increment of a *to value that represents the offset from the start of the
2043// event data.
2044// The preset information is : offsets up to (and including) the first element
2045// of variable size. All subsequent fields must be flagged "VARIABLE OFFSET".
2046#if 0
3aee1200 2047void preset_field_type_size(LttTracefile *tf, LttEventType *event_type,
2048 off_t offset_root, off_t offset_parent,
2049 enum field_status *fixed_root, enum field_status *fixed_parent,
2050 LttField *field)
2051{
2052 enum field_status local_fixed_root, local_fixed_parent;
2053 guint i;
2054 LttType *type;
dfb73233 2055
3aee1200 2056 g_assert(field->fixed_root == FIELD_UNKNOWN);
2057 g_assert(field->fixed_parent == FIELD_UNKNOWN);
2058 g_assert(field->fixed_size == FIELD_UNKNOWN);
dfb73233 2059
3aee1200 2060 type = field->field_type;
2061
2062 field->fixed_root = *fixed_root;
2063 if(field->fixed_root == FIELD_FIXED)
2064 field->offset_root = offset_root;
2065 else
2066 field->offset_root = 0;
2067
2068 field->fixed_parent = *fixed_parent;
2069 if(field->fixed_parent == FIELD_FIXED)
2070 field->offset_parent = offset_parent;
2071 else
2072 field->offset_parent = 0;
2073
2074 size_t current_root_offset;
2075 size_t current_offset;
2076 enum field_status current_child_status, final_child_status;
2077 size_t max_size;
2078
2079 switch(type->type_class) {
83e160f2 2080 case LTT_INT_FIXED:
2081 case LTT_UINT_FIXED:
2082 case LTT_CHAR:
2083 case LTT_UCHAR:
2084 case LTT_SHORT:
2085 case LTT_USHORT:
3aee1200 2086 case LTT_INT:
2087 case LTT_UINT:
2088 case LTT_FLOAT:
2089 case LTT_ENUM:
2090 field->field_size = ltt_type_size(tf->trace, type);
2091 field->fixed_size = FIELD_FIXED;
2092 break;
2093 case LTT_POINTER:
2094 field->field_size = (off_t)event_type->facility->pointer_size;
2095 field->fixed_size = FIELD_FIXED;
2096 break;
2097 case LTT_LONG:
2098 case LTT_ULONG:
cb03932a 2099 field->field_size = (off_t)event_type->facility->long_size;
3aee1200 2100 field->fixed_size = FIELD_FIXED;
2101 break;
2102 case LTT_SIZE_T:
2103 case LTT_SSIZE_T:
2104 case LTT_OFF_T:
2105 field->field_size = (off_t)event_type->facility->size_t_size;
2106 field->fixed_size = FIELD_FIXED;
2107 break;
2108 case LTT_SEQUENCE:
2109 local_fixed_root = FIELD_VARIABLE;
2110 local_fixed_parent = FIELD_VARIABLE;
2111 preset_field_type_size(tf, event_type,
2112 0, 0,
2113 &local_fixed_root, &local_fixed_parent,
2114 field->child[0]);
2115 field->fixed_size = FIELD_VARIABLE;
2116 field->field_size = 0;
27304273 2117 *fixed_root = FIELD_VARIABLE;
2118 *fixed_parent = FIELD_VARIABLE;
3aee1200 2119 break;
2120 case LTT_STRING:
2121 field->fixed_size = FIELD_VARIABLE;
2122 field->field_size = 0;
27304273 2123 *fixed_root = FIELD_VARIABLE;
2124 *fixed_parent = FIELD_VARIABLE;
3aee1200 2125 break;
2126 case LTT_ARRAY:
2127 local_fixed_root = FIELD_VARIABLE;
2128 local_fixed_parent = FIELD_VARIABLE;
2129 preset_field_type_size(tf, event_type,
2130 0, 0,
2131 &local_fixed_root, &local_fixed_parent,
2132 field->child[0]);
2133 field->fixed_size = field->child[0]->fixed_size;
27304273 2134 if(field->fixed_size == FIELD_FIXED) {
3aee1200 2135 field->field_size = type->element_number * field->child[0]->field_size;
27304273 2136 } else {
3aee1200 2137 field->field_size = 0;
27304273 2138 *fixed_root = FIELD_VARIABLE;
2139 *fixed_parent = FIELD_VARIABLE;
2140 }
3aee1200 2141 break;
2142 case LTT_STRUCT:
2143 current_root_offset = field->offset_root;
2144 current_offset = 0;
2145 current_child_status = FIELD_FIXED;
2146 for(i=0;i<type->element_number;i++) {
2147 preset_field_type_size(tf, event_type,
2148 current_root_offset, current_offset,
2149 fixed_root, &current_child_status,
2150 field->child[i]);
2151 if(current_child_status == FIELD_FIXED) {
2152 current_root_offset += field->child[i]->field_size;
2153 current_offset += field->child[i]->field_size;
2154 } else {
2155 current_root_offset = 0;
2156 current_offset = 0;
2157 }
2158 }
2159 if(current_child_status != FIELD_FIXED) {
2160 *fixed_parent = current_child_status;
2161 field->field_size = 0;
2162 field->fixed_size = current_child_status;
2163 } else {
2164 field->field_size = current_offset;
2165 field->fixed_size = FIELD_FIXED;
2166 }
2167 break;
2168 case LTT_UNION:
2169 current_root_offset = field->offset_root;
2170 current_offset = 0;
2171 max_size = 0;
2172 final_child_status = FIELD_FIXED;
2173 for(i=0;i<type->element_number;i++) {
2174 enum field_status current_root_child_status = FIELD_FIXED;
2175 enum field_status current_child_status = FIELD_FIXED;
2176 preset_field_type_size(tf, event_type,
2177 current_root_offset, current_offset,
2178 &current_root_child_status, &current_child_status,
2179 field->child[i]);
2180 if(current_child_status != FIELD_FIXED)
2181 final_child_status = current_child_status;
2182 else
2183 max_size = max(max_size, field->child[i]->field_size);
2184 }
2185 if(final_child_status != FIELD_FIXED) {
62e4e7bf 2186 g_error("LTTV does not support variable size fields in unions.");
2187 /* This will stop the application. */
3aee1200 2188 *fixed_root = final_child_status;
2189 *fixed_parent = final_child_status;
2190 field->field_size = 0;
2191 field->fixed_size = current_child_status;
2192 } else {
2193 field->field_size = max_size;
2194 field->fixed_size = FIELD_FIXED;
2195 }
2196 break;
83e160f2 2197 case LTT_NONE:
2198 g_error("unexpected type NONE");
2199 break;
dfb73233 2200 }
2201
6cd62ccf 2202}
f104d082 2203#endif //0
3aee1200 2204
77175651 2205/*****************************************************************************
2206 *Function name
2207 * check_fields_compatibility : Check for compatibility between two fields :
2208 * do they use the same inner structure ?
2209 *Input params
2210 * event_type1 : event type
2211 * event_type2 : event type
2212 * field1 : field
2213 * field2 : field
2214 *Returns : 0 if identical
2215 * 1 if not.
2216 ****************************************************************************/
f104d082 2217// this function checks for equality of field types. Therefore, it does not use
2218// per se offsets. For instance, an aligned version of a structure is
2219// compatible with an unaligned version of the same structure.
3c165eaf 2220#if 0
f104d082 2221gint check_fields_compatibility(LttEventType *event_type1,
2222 LttEventType *event_type2,
2223 LttField *field1, LttField *field2)
2224{
2225 guint different = 0;
2312de30 2226 LttType *type1;
2227 LttType *type2;
f104d082 2228
2229 if(field1 == NULL) {
2230 if(field2 == NULL) goto end;
2231 else {
2232 different = 1;
2233 goto end;
2234 }
2235 } else if(field2 == NULL) {
2236 different = 1;
2237 goto end;
2238 }
2239
2312de30 2240 type1 = &field1->field_type;
2241 type2 = &field2->field_type;
f104d082 2242
2243 if(type1->type_class != type2->type_class) {
2244 different = 1;
2245 goto end;
2246 }
62e4e7bf 2247 if(type1->network != type2->network) {
2248 different = 1;
2249 goto end;
2250 }
f104d082 2251
2252 switch(type1->type_class) {
2253 case LTT_INT_FIXED:
2254 case LTT_UINT_FIXED:
2255 case LTT_POINTER:
2256 case LTT_CHAR:
2257 case LTT_UCHAR:
2258 case LTT_SHORT:
2259 case LTT_USHORT:
2260 case LTT_INT:
2261 case LTT_UINT:
2262 case LTT_LONG:
2263 case LTT_ULONG:
2264 case LTT_SIZE_T:
2265 case LTT_SSIZE_T:
2266 case LTT_OFF_T:
2267 case LTT_FLOAT:
2268 case LTT_ENUM:
2269 if(field1->field_size != field2->field_size)
2270 different = 1;
2271 break;
2272 case LTT_STRING:
2273 break;
2274 case LTT_ARRAY:
2275 {
2276 LttField *child1 = &g_array_index(type1->fields, LttField, 0);
2277 LttField *child2 = &g_array_index(type2->fields, LttField, 0);
2278
2279 if(type1->size != type2->size)
2280 different = 1;
2281 if(check_fields_compatibility(event_type1, event_type2, child1, child2))
2282 different = 1;
2283 }
2284 break;
2285 case LTT_SEQUENCE:
2286 {
2287 LttField *child1 = &g_array_index(type1->fields, LttField, 1);
2288 LttField *child2 = &g_array_index(type2->fields, LttField, 1);
2289
2290 if(check_fields_compatibility(event_type1, event_type2, child1, child2))
2291 different = 1;
2292 }
2293 break;
2294 case LTT_STRUCT:
2295 case LTT_UNION:
2296 {
2297 LttField *child;
2298 guint i;
2299
2300 if(type1->fields->len != type2->fields->len) {
2301 different = 1;
2302 goto end;
2303 }
2304
2305 for(i=0; i< type1->fields->len; i++) {
2312de30 2306 LttField *child1;
2307 LttField *child2;
f104d082 2308 child1 = &g_array_index(type1->fields, LttField, i);
2309 child2 = &g_array_index(type2->fields, LttField, i);
2310 different = check_fields_compatibility(event_type1,
2311 event_type2, child1, child2);
2312
2313 if(different) break;
2314 }
2315 }
2316 break;
2317 case LTT_NONE:
2318 default:
dd3a6d39 2319 g_error("check_fields_compatibility : unknown type");
f104d082 2320 }
2321
2322end:
2323 return different;
2324}
3c165eaf 2325#endif //0
f104d082 2326
2327#if 0
77175651 2328gint check_fields_compatibility(LttEventType *event_type1,
2329 LttEventType *event_type2,
2330 LttField *field1, LttField *field2)
2331{
2332 guint different = 0;
77175651 2333 guint i;
2334 LttType *type1;
2335 LttType *type2;
2336
2337 if(field1 == NULL) {
2338 if(field2 == NULL) goto end;
2339 else {
2340 different = 1;
2341 goto end;
2342 }
2343 } else if(field2 == NULL) {
2344 different = 1;
2345 goto end;
2346 }
2347
2348 g_assert(field1->fixed_root != FIELD_UNKNOWN);
2349 g_assert(field2->fixed_root != FIELD_UNKNOWN);
2350 g_assert(field1->fixed_parent != FIELD_UNKNOWN);
2351 g_assert(field2->fixed_parent != FIELD_UNKNOWN);
2352 g_assert(field1->fixed_size != FIELD_UNKNOWN);
2353 g_assert(field2->fixed_size != FIELD_UNKNOWN);
2354
2355 type1 = field1->field_type;
2356 type2 = field2->field_type;
2357
77175651 2358 if(type1->type_class != type2->type_class) {
2359 different = 1;
2360 goto end;
2361 }
2362 if(type1->element_name != type2->element_name) {
2363 different = 1;
2364 goto end;
2365 }
2366
2367 switch(type1->type_class) {
83e160f2 2368 case LTT_INT_FIXED:
2369 case LTT_UINT_FIXED:
2370 case LTT_POINTER:
2371 case LTT_CHAR:
2372 case LTT_UCHAR:
2373 case LTT_SHORT:
2374 case LTT_USHORT:
77175651 2375 case LTT_INT:
2376 case LTT_UINT:
2377 case LTT_FLOAT:
2378 case LTT_POINTER:
2379 case LTT_LONG:
2380 case LTT_ULONG:
2381 case LTT_SIZE_T:
2382 case LTT_SSIZE_T:
2383 case LTT_OFF_T:
2384 if(field1->field_size != field2->field_size) {
2385 different = 1;
2386 goto end;
2387 }
2388 break;
2389 case LTT_ENUM:
2390 if(type1->element_number != type2->element_number) {
2391 different = 1;
2392 goto end;
2393 }
2394 for(i=0;i<type1->element_number;i++) {
2395 if(type1->enum_strings[i] != type2->enum_strings[i]) {
2396 different = 1;
2397 goto end;
2398 }
2399 }
2400 break;
2401 case LTT_SEQUENCE:
2402 /* Two elements : size and child */
2403 g_assert(type1->element_number != type2->element_number);
2404 for(i=0;i<type1->element_number;i++) {
2405 if(check_fields_compatibility(event_type1, event_type2,
2406 field1->child[0], field2->child[0])) {
2407 different = 1;
2408 goto end;
2409 }
2410 }
2411 break;
2412 case LTT_STRING:
2413 break;
2414 case LTT_ARRAY:
2415 if(field1->field_size != field2->field_size) {
2416 different = 1;
2417 goto end;
2418 }
2419 /* Two elements : size and child */
2420 g_assert(type1->element_number != type2->element_number);
2421 for(i=0;i<type1->element_number;i++) {
2422 if(check_fields_compatibility(event_type1, event_type2,
2423 field1->child[0], field2->child[0])) {
2424 different = 1;
2425 goto end;
2426 }
2427 }
2428 break;
2429 case LTT_STRUCT:
2430 case LTT_UNION:
2431 if(type1->element_number != type2->element_number) {
2432 different = 1;
2433 break;
2434 }
2435 for(i=0;i<type1->element_number;i++) {
2436 if(check_fields_compatibility(event_type1, event_type2,
2437 field1->child[0], field2->child[0])) {
2438 different = 1;
2439 goto end;
2440 }
2441 }
2442 break;
2443 }
2444end:
2445 return different;
2446}
3aee1200 2447#endif //0
6cd62ccf 2448
f104d082 2449
6cd62ccf 2450/*****************************************************************************
2451 *Function name
eed2ef37 2452 * ltt_get_int : get an integer number
6cd62ccf 2453 *Input params
3aee1200 2454 * reverse_byte_order: must we reverse the byte order ?
6cd62ccf 2455 * size : the size of the integer
3aee1200 2456 * ptr : the data pointer
6cd62ccf 2457 *Return value
cf74a6f1 2458 * gint64 : a 64 bits integer
6cd62ccf 2459 ****************************************************************************/
2460
eed2ef37 2461gint64 ltt_get_int(gboolean reverse_byte_order, gint size, void *data)
6cd62ccf 2462{
3aee1200 2463 gint64 val;
cf74a6f1 2464
2465 switch(size) {
3aee1200 2466 case 1: val = *((gint8*)data); break;
2467 case 2: val = ltt_get_int16(reverse_byte_order, data); break;
2468 case 4: val = ltt_get_int32(reverse_byte_order, data); break;
2469 case 8: val = ltt_get_int64(reverse_byte_order, data); break;
2470 default: val = ltt_get_int64(reverse_byte_order, data);
2471 g_critical("get_int : integer size %d unknown", size);
cf74a6f1 2472 break;
2473 }
2474
3aee1200 2475 return val;
6cd62ccf 2476}
3aee1200 2477
6cd62ccf 2478/*****************************************************************************
2479 *Function name
eed2ef37 2480 * ltt_get_uint : get an unsigned integer number
6cd62ccf 2481 *Input params
3aee1200 2482 * reverse_byte_order: must we reverse the byte order ?
2483 * size : the size of the integer
2484 * ptr : the data pointer
2485 *Return value
2486 * guint64 : a 64 bits unsigned integer
6cd62ccf 2487 ****************************************************************************/
2488
eed2ef37 2489guint64 ltt_get_uint(gboolean reverse_byte_order, gint size, void *data)
6cd62ccf 2490{
3aee1200 2491 guint64 val;
2492
2493 switch(size) {
2494 case 1: val = *((gint8*)data); break;
2495 case 2: val = ltt_get_uint16(reverse_byte_order, data); break;
2496 case 4: val = ltt_get_uint32(reverse_byte_order, data); break;
2497 case 8: val = ltt_get_uint64(reverse_byte_order, data); break;
2498 default: val = ltt_get_uint64(reverse_byte_order, data);
2499 g_critical("get_uint : unsigned integer size %d unknown",
2500 size);
2501 break;
2502 }
2503
2504 return val;
6cd62ccf 2505}
3aee1200 2506
2507
a5dcde2f 2508/* get the node name of the system */
2509
2510char * ltt_trace_system_description_node_name (LttSystemDescription * s)
2511{
2512 return s->node_name;
2513}
2514
2515
2516/* get the domain name of the system */
2517
2518char * ltt_trace_system_description_domain_name (LttSystemDescription * s)
2519{
2520 return s->domain_name;
2521}
2522
2523
2524/* get the description of the system */
2525
2526char * ltt_trace_system_description_description (LttSystemDescription * s)
2527{
2528 return s->description;
2529}
2530
2531
bf33dd50 2532/* get the NTP corrected start time of the trace */
7bd563ec 2533LttTime ltt_trace_start_time(LttTrace *t)
a5dcde2f 2534{
7bd563ec 2535 return t->start_time;
a5dcde2f 2536}
2537
bf33dd50 2538/* get the monotonic start time of the trace */
2539LttTime ltt_trace_start_time_monotonic(LttTrace *t)
2540{
2541 return t->start_time_from_tsc;
2542}
2543
43ed82b5 2544static __attribute__ ((__unused__)) LttTracefile *ltt_tracefile_new()
18206708 2545{
afd57a3c 2546 LttTracefile *tf;
2547 tf = g_new(LttTracefile, 1);
2548 tf->event.tracefile = tf;
2549 return tf;
18206708 2550}
2551
43ed82b5 2552static __attribute__ ((__unused__)) void ltt_tracefile_destroy(LttTracefile *tf)
18206708 2553{
2554 g_free(tf);
2555}
2556
43ed82b5 2557static __attribute__ ((__unused__)) void ltt_tracefile_copy(LttTracefile *dest, const LttTracefile *src)
18206708 2558{
2559 *dest = *src;
2560}
2561
3aee1200 2562/* Before library loading... */
2563
8655430b 2564static __attribute__((constructor)) void init(void)
3aee1200 2565{
750eb11a 2566 LTT_TRACEFILE_NAME_METADATA = g_quark_from_string("metadata");
3aee1200 2567}
This page took 0.207444 seconds and 4 git commands to generate.