Richard Purdie patches : add ARM arch and fix automake for dynamic symbols
[lttv.git] / ltt / branches / poly / ltt / tracefile.c
1 /* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2005 Mathieu Desnoyers
3 *
4 * Complete rewrite from the original version made by XangXiu Yang.
5 *
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.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
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.
19 */
20
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24
25 #include <stdio.h>
26 #include <fcntl.h>
27 #include <string.h>
28 #include <dirent.h>
29 #include <sys/stat.h>
30 #include <sys/types.h>
31 #include <errno.h>
32 #include <unistd.h>
33 #include <math.h>
34 #include <glib.h>
35 #include <malloc.h>
36 #include <sys/mman.h>
37
38 // For realpath
39 #include <limits.h>
40 #include <stdlib.h>
41
42
43 #include "parser.h"
44 #include <ltt/ltt.h>
45 #include "ltt-private.h"
46 #include <ltt/trace.h>
47 #include <ltt/facility.h>
48 #include <ltt/event.h>
49 #include <ltt/type.h>
50 #include <ltt/ltt-types.h>
51
52
53 /* Facility names used in this file */
54
55 GQuark LTT_FACILITY_NAME_HEARTBEAT,
56 LTT_EVENT_NAME_HEARTBEAT;
57 GQuark LTT_TRACEFILE_NAME_FACILITIES;
58
59 #ifndef g_open
60 #define g_open open
61 #endif
62
63
64 #define __UNUSED__ __attribute__((__unused__))
65
66 #define g_info(format...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, format)
67
68 #ifndef g_debug
69 #define g_debug(format...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, format)
70 #endif
71
72 #define g_close close
73
74 /* Those macros must be called from within a function where page_size is a known
75 * variable */
76 #define PAGE_MASK (~(page_size-1))
77 #define PAGE_ALIGN(addr) (((addr)+page_size-1)&PAGE_MASK)
78
79 /* set the offset of the fields belonging to the event,
80 need the information of the archecture */
81 //void set_fields_offsets(LttTracefile *tf, LttEventType *event_type);
82 //size_t get_fields_offsets(LttTracefile *tf, LttEventType *event_type, void *data);
83
84 /* get the size of the field type according to
85 * The facility size information. */
86 #if 0
87 static inline void preset_field_type_size(LttTracefile *tf,
88 LttEventType *event_type,
89 off_t offset_root, off_t offset_parent,
90 enum field_status *fixed_root, enum field_status *fixed_parent,
91 LttField *field);
92 #endif //0
93
94 /* map a fixed size or a block information from the file (fd) */
95 static gint map_block(LttTracefile * tf, guint block_num);
96
97 /* calculate nsec per cycles for current block */
98 #if 0
99 static guint32 calc_nsecs_per_cycle(LttTracefile * t);
100 static guint64 cycles_2_ns(LttTracefile *tf, guint64 cycles);
101 #endif //0
102
103 /* go to the next event */
104 static int ltt_seek_next_event(LttTracefile *tf);
105
106 void ltt_update_event_size(LttTracefile *tf);
107
108
109 void precompute_offsets(LttFacility *fac, LttEventType *event);
110
111 #if 0
112 /* Functions to parse system.xml file (using glib xml parser) */
113 static void parser_start_element (GMarkupParseContext __UNUSED__ *context,
114 const gchar *element_name,
115 const gchar **attribute_names,
116 const gchar **attribute_values,
117 gpointer user_data,
118 GError **error)
119 {
120 int i=0;
121 LttSystemDescription* des = (LttSystemDescription* )user_data;
122 if(strcmp("system", element_name)){
123 *error = g_error_new(G_MARKUP_ERROR,
124 G_LOG_LEVEL_WARNING,
125 "This is not system.xml file");
126 return;
127 }
128
129 while(attribute_names[i]){
130 if(strcmp("node_name", attribute_names[i])==0){
131 des->node_name = g_strdup(attribute_values[i]);
132 }else if(strcmp("domainname", attribute_names[i])==0){
133 des->domain_name = g_strdup(attribute_values[i]);
134 }else if(strcmp("cpu", attribute_names[i])==0){
135 des->nb_cpu = atoi(attribute_values[i]);
136 }else if(strcmp("arch_size", attribute_names[i])==0){
137 if(strcmp(attribute_values[i],"LP32") == 0) des->size = LTT_LP32;
138 else if(strcmp(attribute_values[i],"ILP32") == 0) des->size = LTT_ILP32;
139 else if(strcmp(attribute_values[i],"LP64") == 0) des->size = LTT_LP64;
140 else if(strcmp(attribute_values[i],"ILP64") == 0) des->size = LTT_ILP64;
141 else if(strcmp(attribute_values[i],"UNKNOWN") == 0) des->size = LTT_UNKNOWN;
142 }else if(strcmp("endian", attribute_names[i])==0){
143 if(strcmp(attribute_values[i],"LITTLE_ENDIAN") == 0)
144 des->endian = LTT_LITTLE_ENDIAN;
145 else if(strcmp(attribute_values[i],"BIG_ENDIAN") == 0)
146 des->endian = LTT_BIG_ENDIAN;
147 }else if(strcmp("kernel_name", attribute_names[i])==0){
148 des->kernel_name = g_strdup(attribute_values[i]);
149 }else if(strcmp("kernel_release", attribute_names[i])==0){
150 des->kernel_release = g_strdup(attribute_values[i]);
151 }else if(strcmp("kernel_version", attribute_names[i])==0){
152 des->kernel_version = g_strdup(attribute_values[i]);
153 }else if(strcmp("machine", attribute_names[i])==0){
154 des->machine = g_strdup(attribute_values[i]);
155 }else if(strcmp("processor", attribute_names[i])==0){
156 des->processor = g_strdup(attribute_values[i]);
157 }else if(strcmp("hardware_platform", attribute_names[i])==0){
158 des->hardware_platform = g_strdup(attribute_values[i]);
159 }else if(strcmp("operating_system", attribute_names[i])==0){
160 des->operating_system = g_strdup(attribute_values[i]);
161 }else if(strcmp("ltt_major_version", attribute_names[i])==0){
162 des->ltt_major_version = atoi(attribute_values[i]);
163 }else if(strcmp("ltt_minor_version", attribute_names[i])==0){
164 des->ltt_minor_version = atoi(attribute_values[i]);
165 }else if(strcmp("ltt_block_size", attribute_names[i])==0){
166 des->ltt_block_size = atoi(attribute_values[i]);
167 }else{
168 *error = g_error_new(G_MARKUP_ERROR,
169 G_LOG_LEVEL_WARNING,
170 "Not a valid attribute");
171 return;
172 }
173 i++;
174 }
175 }
176
177 static void parser_characters (GMarkupParseContext __UNUSED__ *context,
178 const gchar *text,
179 gsize __UNUSED__ text_len,
180 gpointer user_data,
181 GError __UNUSED__ **error)
182 {
183 LttSystemDescription* des = (LttSystemDescription* )user_data;
184 des->description = g_strdup(text);
185 }
186 #endif //0
187
188
189 LttFacility *ltt_trace_get_facility_by_num(LttTrace *t,
190 guint num)
191 {
192 g_assert(num < t->facilities_by_num->len);
193
194 return &g_array_index(t->facilities_by_num, LttFacility, num);
195
196 }
197
198 guint ltt_trace_get_num_cpu(LttTrace *t)
199 {
200 return t->num_cpu;
201 }
202
203
204 /* trace can be NULL
205 *
206 * Return value : 0 success, 1 bad tracefile
207 */
208 int parse_trace_header(void *header, LttTracefile *tf, LttTrace *t)
209 {
210 guint32 *magic_number = (guint32*)header;
211 struct ltt_trace_header_any *any = (struct ltt_trace_header_any *)header;
212
213 if(*magic_number == LTT_MAGIC_NUMBER)
214 tf->reverse_bo = 0;
215 else if(*magic_number == LTT_REV_MAGIC_NUMBER)
216 tf->reverse_bo = 1;
217 else /* invalid magic number, bad tracefile ! */
218 return 1;
219
220 /* Get float byte order : might be different from int byte order
221 * (or is set to 0 if the trace has no float (kernel trace)) */
222 tf->float_word_order = any->float_word_order;
223 tf->has_alignment = any->has_alignment;
224
225 if(t) {
226 t->arch_type = ltt_get_uint32(LTT_GET_BO(tf),
227 &any->arch_type);
228 t->arch_variant = ltt_get_uint32(LTT_GET_BO(tf),
229 &any->arch_variant);
230 t->arch_size = any->arch_size;
231 t->ltt_major_version = any->major_version;
232 t->ltt_minor_version = any->minor_version;
233 t->flight_recorder = any->flight_recorder;
234 t->has_heartbeat = any->has_heartbeat;
235 t->freq_scale = any->freq_scale;
236 }
237
238
239 switch(any->major_version) {
240
241 case 0:
242 switch(any->minor_version) {
243 case 3:
244 {
245 tf->buffer_header_size =
246 sizeof(struct ltt_block_start_header)
247 + sizeof(struct ltt_trace_header_0_3);
248 g_warning("Unsupported trace version : %hhu.%hhu",
249 any->major_version, any->minor_version);
250 return 1;
251 }
252 break;
253 case 7:
254 {
255 struct ltt_trace_header_0_7 *vheader =
256 (struct ltt_trace_header_0_7 *)header;
257 tf->buffer_header_size =
258 sizeof(struct ltt_block_start_header)
259 + sizeof(struct ltt_trace_header_0_7);
260 if(t) {
261 t->start_freq = ltt_get_uint64(LTT_GET_BO(tf),
262 &vheader->start_freq);
263 t->start_tsc = ltt_get_uint64(LTT_GET_BO(tf),
264 &vheader->start_tsc);
265 t->start_monotonic = ltt_get_uint64(LTT_GET_BO(tf),
266 &vheader->start_monotonic);
267 t->start_time.tv_sec = ltt_get_uint64(LTT_GET_BO(tf),
268 &vheader->start_time_sec);
269 t->start_time.tv_nsec = ltt_get_uint64(LTT_GET_BO(tf),
270 &vheader->start_time_usec);
271 t->start_time.tv_nsec *= 1000; /* microsec to nanosec */
272
273 t->start_time_from_tsc = ltt_time_from_uint64(
274 (double)t->start_tsc * 1000000.0 / (double)t->start_freq);
275 }
276 }
277 break;
278 default:
279 g_warning("Unsupported trace version : %hhu.%hhu",
280 any->major_version, any->minor_version);
281 return 1;
282 }
283 break;
284
285 default:
286 g_warning("Unsupported trace version : %hhu.%hhu",
287 any->major_version, any->minor_version);
288 return 1;
289 }
290
291
292 return 0;
293 }
294
295
296
297 /*****************************************************************************
298 *Function name
299 * ltt_tracefile_open : open a trace file, construct a LttTracefile
300 *Input params
301 * t : the trace containing the tracefile
302 * fileName : path name of the trace file
303 * tf : the tracefile structure
304 *Return value
305 * : 0 for success, -1 otherwise.
306 ****************************************************************************/
307
308 gint ltt_tracefile_open(LttTrace *t, gchar * fileName, LttTracefile *tf)
309 {
310 struct stat lTDFStat; /* Trace data file status */
311 struct ltt_block_start_header *header;
312 int page_size = getpagesize();
313
314 //open the file
315 tf->long_name = g_quark_from_string(fileName);
316 tf->trace = t;
317 tf->fd = open(fileName, O_RDONLY);
318 if(tf->fd < 0){
319 g_warning("Unable to open input data file %s\n", fileName);
320 goto end;
321 }
322
323 // Get the file's status
324 if(fstat(tf->fd, &lTDFStat) < 0){
325 g_warning("Unable to get the status of the input data file %s\n", fileName);
326 goto close_file;
327 }
328
329 // Is the file large enough to contain a trace
330 if(lTDFStat.st_size <
331 (off_t)(sizeof(struct ltt_block_start_header)
332 + sizeof(struct ltt_trace_header_any))){
333 g_print("The input data file %s does not contain a trace\n", fileName);
334 goto close_file;
335 }
336
337 /* Temporarily map the buffer start header to get trace information */
338 /* Multiple of pages aligned head */
339 tf->buffer.head = mmap(0,
340 PAGE_ALIGN(sizeof(struct ltt_block_start_header)
341 + sizeof(struct ltt_trace_header_any)), PROT_READ,
342 MAP_PRIVATE, tf->fd, 0);
343 if(tf->buffer.head == MAP_FAILED) {
344 perror("Error in allocating memory for buffer of tracefile");
345 goto close_file;
346 }
347 g_assert( ( (guint)tf->buffer.head&(8-1) ) == 0); // make sure it's aligned.
348
349 header = (struct ltt_block_start_header*)tf->buffer.head;
350
351 if(parse_trace_header(header->trace, tf, NULL)) {
352 g_warning("parse_trace_header error");
353 goto unmap_file;
354 }
355
356 //store the size of the file
357 tf->file_size = lTDFStat.st_size;
358 tf->buf_size = ltt_get_uint32(LTT_GET_BO(tf), &header->buf_size);
359 tf->num_blocks = tf->file_size / tf->buf_size;
360
361 if(munmap(tf->buffer.head,
362 PAGE_ALIGN(sizeof(struct ltt_block_start_header)
363 + sizeof(struct ltt_trace_header_any)))) {
364 g_warning("unmap size : %u\n",
365 PAGE_ALIGN(sizeof(struct ltt_block_start_header)
366 + sizeof(struct ltt_trace_header_any)));
367 perror("munmap error");
368 g_assert(0);
369 }
370 tf->buffer.head = NULL;
371
372 //read the first block
373 if(map_block(tf,0)) {
374 perror("Cannot map block for tracefile");
375 goto close_file;
376 }
377
378 return 0;
379
380 /* Error */
381 unmap_file:
382 if(munmap(tf->buffer.head,
383 PAGE_ALIGN(sizeof(struct ltt_block_start_header)
384 + sizeof(struct ltt_trace_header_any)))) {
385 g_warning("unmap size : %u\n",
386 PAGE_ALIGN(sizeof(struct ltt_block_start_header)
387 + sizeof(struct ltt_trace_header_any)));
388 perror("munmap error");
389 g_assert(0);
390 }
391 close_file:
392 close(tf->fd);
393 end:
394 return -1;
395 }
396
397 LttTrace *ltt_tracefile_get_trace(LttTracefile *tf)
398 {
399 return tf->trace;
400 }
401
402 #if 0
403 /*****************************************************************************
404 *Open control and per cpu tracefiles
405 ****************************************************************************/
406
407 void ltt_tracefile_open_cpu(LttTrace *t, gchar * tracefile_name)
408 {
409 LttTracefile * tf;
410 tf = ltt_tracefile_open(t,tracefile_name);
411 if(!tf) return;
412 t->per_cpu_tracefile_number++;
413 g_ptr_array_add(t->per_cpu_tracefiles, tf);
414 }
415
416 gint ltt_tracefile_open_control(LttTrace *t, gchar * control_name)
417 {
418 LttTracefile * tf;
419 LttEvent ev;
420 LttFacility * f;
421 void * pos;
422 FacilityLoad fLoad;
423 unsigned int i;
424
425 tf = ltt_tracefile_open(t,control_name);
426 if(!tf) {
427 g_warning("ltt_tracefile_open_control : bad file descriptor");
428 return -1;
429 }
430 t->control_tracefile_number++;
431 g_ptr_array_add(t->control_tracefiles,tf);
432
433 //parse facilities tracefile to get base_id
434 if(strcmp(&control_name[strlen(control_name)-10],"facilities") ==0){
435 while(1){
436 if(!ltt_tracefile_read(tf,&ev)) return 0; // end of file
437
438 if(ev.event_id == TRACE_FACILITY_LOAD){
439 pos = ev.data;
440 fLoad.name = (gchar*)pos;
441 fLoad.checksum = *(LttChecksum*)(pos + strlen(fLoad.name));
442 fLoad.base_code = *(guint32 *)(pos + strlen(fLoad.name) + sizeof(LttChecksum));
443
444 for(i=0;i<t->facility_number;i++){
445 f = (LttFacility*)g_ptr_array_index(t->facilities,i);
446 if(strcmp(f->name,fLoad.name)==0 && fLoad.checksum==f->checksum){
447 f->base_id = fLoad.base_code;
448 break;
449 }
450 }
451 if(i==t->facility_number) {
452 g_warning("Facility: %s, checksum: %u is not found",
453 fLoad.name,(unsigned int)fLoad.checksum);
454 return -1;
455 }
456 }else if(ev.event_id == TRACE_BLOCK_START){
457 continue;
458 }else if(ev.event_id == TRACE_BLOCK_END){
459 break;
460 }else {
461 g_warning("Not valid facilities trace file");
462 return -1;
463 }
464 }
465 }
466 return 0;
467 }
468 #endif //0
469
470 /*****************************************************************************
471 *Function name
472 * ltt_tracefile_close: close a trace file,
473 *Input params
474 * t : tracefile which will be closed
475 ****************************************************************************/
476
477 void ltt_tracefile_close(LttTracefile *t)
478 {
479 int page_size = getpagesize();
480
481 if(t->buffer.head != NULL)
482 if(munmap(t->buffer.head, PAGE_ALIGN(t->buf_size))) {
483 g_warning("unmap size : %u\n",
484 PAGE_ALIGN(t->buf_size));
485 perror("munmap error");
486 g_assert(0);
487 }
488
489 close(t->fd);
490 }
491
492
493 /*****************************************************************************
494 *Get system information
495 ****************************************************************************/
496 #if 0
497 gint getSystemInfo(LttSystemDescription* des, gchar * pathname)
498 {
499 int fd;
500 GIOChannel *iochan;
501 gchar *buf = NULL;
502 gsize length;
503
504 GMarkupParseContext * context;
505 GError * error = NULL;
506 GMarkupParser markup_parser =
507 {
508 parser_start_element,
509 NULL,
510 parser_characters,
511 NULL, /* passthrough */
512 NULL /* error */
513 };
514
515 fd = g_open(pathname, O_RDONLY, 0);
516 if(fd == -1){
517 g_warning("Can not open file : %s\n", pathname);
518 return -1;
519 }
520
521 iochan = g_io_channel_unix_new(fd);
522
523 context = g_markup_parse_context_new(&markup_parser, 0, des,NULL);
524
525 //while(fgets(buf,DIR_NAME_SIZE, fp) != NULL){
526 while(g_io_channel_read_line(iochan, &buf, &length, NULL, &error)
527 != G_IO_STATUS_EOF) {
528
529 if(error != NULL) {
530 g_warning("Can not read xml file: \n%s\n", error->message);
531 g_error_free(error);
532 }
533 if(!g_markup_parse_context_parse(context, buf, length, &error)){
534 if(error != NULL) {
535 g_warning("Can not parse xml file: \n%s\n", error->message);
536 g_error_free(error);
537 }
538 g_markup_parse_context_free(context);
539
540 g_io_channel_shutdown(iochan, FALSE, &error); /* No flush */
541 if(error != NULL) {
542 g_warning("Can not close file: \n%s\n", error->message);
543 g_error_free(error);
544 }
545
546 close(fd);
547 return -1;
548 }
549 }
550 g_markup_parse_context_free(context);
551
552 g_io_channel_shutdown(iochan, FALSE, &error); /* No flush */
553 if(error != NULL) {
554 g_warning("Can not close file: \n%s\n", error->message);
555 g_error_free(error);
556 }
557
558 g_close(fd);
559
560 g_free(buf);
561 return 0;
562 }
563 #endif //0
564
565 /*****************************************************************************
566 *The following functions get facility/tracefile information
567 ****************************************************************************/
568 #if 0
569 gint getFacilityInfo(LttTrace *t, gchar* eventdefs)
570 {
571 GDir * dir;
572 const gchar * name;
573 unsigned int i,j;
574 LttFacility * f;
575 LttEventType * et;
576 gchar fullname[DIR_NAME_SIZE];
577 GError * error = NULL;
578
579 dir = g_dir_open(eventdefs, 0, &error);
580
581 if(error != NULL) {
582 g_warning("Can not open directory: %s, %s\n", eventdefs, error->message);
583 g_error_free(error);
584 return -1;
585 }
586
587 while((name = g_dir_read_name(dir)) != NULL){
588 if(!g_pattern_match_simple("*.xml", name)) continue;
589 strcpy(fullname,eventdefs);
590 strcat(fullname,name);
591 ltt_facility_open(t,fullname);
592 }
593 g_dir_close(dir);
594
595 for(j=0;j<t->facility_number;j++){
596 f = (LttFacility*)g_ptr_array_index(t->facilities, j);
597 for(i=0; i<f->event_number; i++){
598 et = f->events[i];
599 setFieldsOffset(NULL, et, NULL, t);
600 }
601 }
602 return 0;
603 }
604 #endif //0
605
606 /*****************************************************************************
607 *A trace is specified as a pathname to the directory containing all the
608 *associated data (control tracefiles, per cpu tracefiles, event
609 *descriptions...).
610 *
611 *When a trace is closed, all the associated facilities, types and fields
612 *are released as well.
613 */
614
615
616 /****************************************************************************
617 * get_absolute_pathname
618 *
619 * return the unique pathname in the system
620 *
621 * MD : Fixed this function so it uses realpath, dealing well with
622 * forgotten cases (.. were not used correctly before).
623 *
624 ****************************************************************************/
625 void get_absolute_pathname(const gchar *pathname, gchar * abs_pathname)
626 {
627 abs_pathname[0] = '\0';
628
629 if ( realpath (pathname, abs_pathname) != NULL)
630 return;
631 else
632 {
633 /* error, return the original path unmodified */
634 strcpy(abs_pathname, pathname);
635 return;
636 }
637 return;
638 }
639
640 /* Search for something like : .*_.*
641 *
642 * The left side is the name, the right side is the number.
643 */
644
645 int get_tracefile_name_number(const gchar *raw_name,
646 GQuark *name,
647 guint *num)
648 {
649 guint raw_name_len = strlen(raw_name);
650 gchar char_name[PATH_MAX];
651 int i;
652 int underscore_pos;
653 long int cpu_num;
654 gchar *endptr;
655
656 for(i=raw_name_len-1;i>=0;i--) {
657 if(raw_name[i] == '_') break;
658 }
659 if(i==0) /* Either not found or name length is 0 */
660 return -1;
661 underscore_pos = i;
662
663 cpu_num = strtol(raw_name+underscore_pos+1, &endptr, 10);
664
665 if(endptr == raw_name+underscore_pos+1)
666 return -1; /* No digit */
667 if(cpu_num == LONG_MIN || cpu_num == LONG_MAX)
668 return -1; /* underflow / overflow */
669
670 strncpy(char_name, raw_name, underscore_pos);
671
672 char_name[underscore_pos] = '\0';
673
674 *name = g_quark_from_string(char_name);
675 *num = cpu_num;
676
677 return 0;
678 }
679
680
681 GData **ltt_trace_get_tracefiles_groups(LttTrace *trace)
682 {
683 return &trace->tracefiles;
684 }
685
686
687 void compute_tracefile_group(GQuark key_id,
688 GArray *group,
689 struct compute_tracefile_group_args *args)
690 {
691 int i;
692 LttTracefile *tf;
693
694 for(i=0; i<group->len; i++) {
695 tf = &g_array_index (group, LttTracefile, i);
696 if(tf->cpu_online)
697 args->func(tf, args->func_args);
698 }
699 }
700
701
702 void ltt_tracefile_group_destroy(gpointer data)
703 {
704 GArray *group = (GArray *)data;
705 int i;
706 LttTracefile *tf;
707
708 for(i=0; i<group->len; i++) {
709 tf = &g_array_index (group, LttTracefile, i);
710 if(tf->cpu_online)
711 ltt_tracefile_close(tf);
712 }
713 g_array_free(group, TRUE);
714 }
715
716 gboolean ltt_tracefile_group_has_cpu_online(gpointer data)
717 {
718 GArray *group = (GArray *)data;
719 int i;
720 LttTracefile *tf;
721
722 for(i=0; i<group->len; i++) {
723 tf = &g_array_index (group, LttTracefile, i);
724 if(tf->cpu_online) return 1;
725 }
726 return 0;
727 }
728
729
730 /* Open each tracefile under a specific directory. Put them in a
731 * GData : permits to access them using their tracefile group pathname.
732 * i.e. access control/modules tracefile group by index :
733 * "control/module".
734 *
735 * relative path is the path relative to the trace root
736 * root path is the full path
737 *
738 * A tracefile group is simply an array where all the per cpu tracefiles sits.
739 */
740
741 static int open_tracefiles(LttTrace *trace, gchar *root_path,
742 gchar *relative_path)
743 {
744 DIR *dir = opendir(root_path);
745 struct dirent *entry;
746 struct stat stat_buf;
747 int ret;
748
749 gchar path[PATH_MAX];
750 int path_len;
751 gchar *path_ptr;
752
753 int rel_path_len;
754 gchar rel_path[PATH_MAX];
755 gchar *rel_path_ptr;
756 LttTracefile tmp_tf;
757
758 if(dir == NULL) {
759 perror(root_path);
760 return ENOENT;
761 }
762
763 strncpy(path, root_path, PATH_MAX-1);
764 path_len = strlen(path);
765 path[path_len] = '/';
766 path_len++;
767 path_ptr = path + path_len;
768
769 strncpy(rel_path, relative_path, PATH_MAX-1);
770 rel_path_len = strlen(rel_path);
771 rel_path[rel_path_len] = '/';
772 rel_path_len++;
773 rel_path_ptr = rel_path + rel_path_len;
774
775 while((entry = readdir(dir)) != NULL) {
776
777 if(entry->d_name[0] == '.') continue;
778
779 strncpy(path_ptr, entry->d_name, PATH_MAX - path_len);
780 strncpy(rel_path_ptr, entry->d_name, PATH_MAX - rel_path_len);
781
782 ret = stat(path, &stat_buf);
783 if(ret == -1) {
784 perror(path);
785 continue;
786 }
787
788 g_debug("Tracefile file or directory : %s\n", path);
789
790 if(strcmp(rel_path, "/eventdefs") == 0) continue;
791
792 if(S_ISDIR(stat_buf.st_mode)) {
793
794 g_debug("Entering subdirectory...\n");
795 ret = open_tracefiles(trace, path, rel_path);
796 if(ret < 0) continue;
797 } else if(S_ISREG(stat_buf.st_mode)) {
798 GQuark name;
799 guint num;
800 GArray *group;
801
802 if(get_tracefile_name_number(rel_path, &name, &num))
803 continue; /* invalid name */
804
805 g_debug("Opening file.\n");
806 if(ltt_tracefile_open(trace, path, &tmp_tf)) {
807 g_info("Error opening tracefile %s", path);
808
809 continue; /* error opening the tracefile : bad magic number ? */
810 }
811
812 g_debug("Tracefile name is %s and number is %u",
813 g_quark_to_string(name), num);
814
815 tmp_tf.cpu_online = 1;
816 tmp_tf.cpu_num = num;
817 tmp_tf.name = name;
818
819 group = g_datalist_id_get_data(&trace->tracefiles, name);
820 if(group == NULL) {
821 /* Elements are automatically cleared when the array is allocated.
822 * It makes the cpu_online variable set to 0 : cpu offline, by default.
823 */
824 group = g_array_sized_new (FALSE, TRUE, sizeof(LttTracefile), 10);
825 g_datalist_id_set_data_full(&trace->tracefiles, name,
826 group, ltt_tracefile_group_destroy);
827 }
828
829 /* Add the per cpu tracefile to the named group */
830 unsigned int old_len = group->len;
831 if(num+1 > old_len)
832 group = g_array_set_size(group, num+1);
833 g_array_index (group, LttTracefile, num) = tmp_tf;
834
835 }
836 }
837
838 closedir(dir);
839
840 return 0;
841 }
842
843 /* ltt_get_facility_description
844 *
845 * Opens the file corresponding to the requested facility (identified by fac_id
846 * and checksum).
847 *
848 * The name searched is : %trace root%/eventdefs/facname_checksum.xml
849 *
850 * Returns 0 on success, or 1 on failure.
851 */
852
853 static int ltt_get_facility_description(LttFacility *f,
854 LttTrace *t,
855 LttTracefile *fac_tf)
856 {
857 char desc_file_name[PATH_MAX];
858 const gchar *text;
859 guint textlen;
860 gint err;
861 gint arch_spec;
862 gint fac_name_len;
863
864 text = g_quark_to_string(t->pathname);
865 textlen = strlen(text);
866
867 if(textlen >= PATH_MAX) goto name_error;
868 strcpy(desc_file_name, text);
869
870 text = "/eventdefs/";
871 textlen+=strlen(text);
872 if(textlen >= PATH_MAX) goto name_error;
873 strcat(desc_file_name, text);
874
875 text = g_quark_to_string(f->name);
876 fac_name_len = strlen(text);
877 textlen+=fac_name_len;
878 if(textlen >= PATH_MAX) goto name_error;
879 strcat(desc_file_name, text);
880
881 /* arch specific facilities are named like this : name_arch */
882 if(fac_name_len+1 < sizeof("_arch"))
883 arch_spec = 0;
884 else {
885 if(!strcmp(&text[fac_name_len+1-sizeof("_arch")], "_arch"))
886 arch_spec = 1;
887 else
888 arch_spec = 0;
889 }
890
891 #if 0
892 text = "_";
893 textlen+=strlen(text);
894 if(textlen >= PATH_MAX) goto name_error;
895 strcat(desc_file_name, text);
896
897 err = snprintf(desc_file_name+textlen, PATH_MAX-textlen-1,
898 "%u", f->checksum);
899 if(err < 0) goto name_error;
900
901 textlen=strlen(desc_file_name);
902
903 #endif //0
904
905 if(arch_spec) {
906 switch(t->arch_type) {
907 case LTT_ARCH_TYPE_I386:
908 text = "_i386";
909 break;
910 case LTT_ARCH_TYPE_PPC:
911 text = "_ppc";
912 break;
913 case LTT_ARCH_TYPE_SH:
914 text = "_sh";
915 break;
916 case LTT_ARCH_TYPE_S390:
917 text = "_s390";
918 break;
919 case LTT_ARCH_TYPE_MIPS:
920 text = "_mips";
921 break;
922 case LTT_ARCH_TYPE_ARM:
923 text = "_arm";
924 break;
925 case LTT_ARCH_TYPE_PPC64:
926 text = "_ppc64";
927 break;
928 case LTT_ARCH_TYPE_X86_64:
929 text = "_x86_64";
930 break;
931 default:
932 g_error("Trace from unsupported architecture.");
933 }
934 textlen+=strlen(text);
935 if(textlen >= PATH_MAX) goto name_error;
936 strcat(desc_file_name, text);
937 }
938
939 text = ".xml";
940 textlen+=strlen(text);
941 if(textlen >= PATH_MAX) goto name_error;
942 strcat(desc_file_name, text);
943
944 err = ltt_facility_open(f, t, desc_file_name);
945 if(err) goto facility_error;
946
947 return 0;
948
949 facility_error:
950 name_error:
951 return 1;
952 }
953
954 static void ltt_fac_ids_destroy(gpointer data)
955 {
956 GArray *fac_ids = (GArray *)data;
957
958 g_array_free(fac_ids, TRUE);
959 }
960
961
962 /* Presumes the tracefile is already seeked at the beginning. It makes sense,
963 * because it must be done just after the opening */
964 static int ltt_process_facility_tracefile(LttTracefile *tf)
965 {
966 int err;
967 LttFacility *fac;
968 GArray *fac_ids;
969 guint i;
970 LttEventType *et;
971
972 while(1) {
973 err = ltt_tracefile_read_seek(tf);
974 if(err == EPERM) goto seek_error;
975 else if(err == ERANGE) break; /* End of tracefile */
976
977 err = ltt_tracefile_read_update_event(tf);
978 if(err) goto update_error;
979
980 /* We are on a facility load/or facility unload/ or heartbeat event */
981 /* The rules are :
982 * * facility 0 is hardcoded : this is the core facility. It will be shown
983 * in the facility array though, and is shown as "loaded builtin" in the
984 * trace.
985 * It contains event :
986 * 0 : facility load
987 * 1 : facility unload
988 * 2 : state dump facility load
989 * 3 : heartbeat
990 */
991 if(tf->event.facility_id != LTT_FACILITY_CORE) {
992 /* Should only contain core facility */
993 g_warning("Error in processing facility file %s, "
994 "should not contain facility id %u.", g_quark_to_string(tf->name),
995 tf->event.facility_id);
996 err = EPERM;
997 goto fac_id_error;
998 } else {
999
1000 struct LttFacilityLoad *fac_load_data;
1001 struct LttStateDumpFacilityLoad *fac_state_dump_load_data;
1002 char *fac_name;
1003 void *pos;
1004
1005 // FIXME align
1006 switch((enum ltt_core_events)tf->event.event_id) {
1007 case LTT_EVENT_FACILITY_LOAD:
1008 fac_name = (char*)(tf->event.data);
1009 g_debug("Doing LTT_EVENT_FACILITY_LOAD of facility %s",
1010 fac_name);
1011 pos = (tf->event.data + strlen(fac_name) + 1);
1012 pos += ltt_align((size_t)pos, sizeof(guint32), tf->has_alignment);
1013 fac_load_data = (struct LttFacilityLoad *)pos;
1014
1015 fac = &g_array_index (tf->trace->facilities_by_num, LttFacility,
1016 ltt_get_uint32(LTT_GET_BO(tf), &fac_load_data->id));
1017 /* facility may already exist if trace is paused/unpaused */
1018 if(fac->exists) continue;
1019 fac->name = g_quark_from_string(fac_name);
1020 fac->checksum = ltt_get_uint32(LTT_GET_BO(tf),
1021 &fac_load_data->checksum);
1022 fac->id = ltt_get_uint32(LTT_GET_BO(tf), &fac_load_data->id);
1023 fac->pointer_size = ltt_get_uint32(LTT_GET_BO(tf),
1024 &fac_load_data->pointer_size);
1025 fac->int_size = ltt_get_uint32(LTT_GET_BO(tf),
1026 &fac_load_data->int_size);
1027 fac->long_size = ltt_get_uint32(LTT_GET_BO(tf),
1028 &fac_load_data->long_size);
1029 fac->size_t_size = ltt_get_uint32(LTT_GET_BO(tf),
1030 &fac_load_data->size_t_size);
1031 fac->alignment = ltt_get_uint32(LTT_GET_BO(tf),
1032 &fac_load_data->has_alignment);
1033
1034 if(ltt_get_facility_description(fac, tf->trace, tf))
1035 continue; /* error opening description */
1036
1037 fac->trace = tf->trace;
1038
1039 /* Preset the field offsets */
1040 for(i=0; i<fac->events->len; i++){
1041 et = &g_array_index(fac->events, LttEventType, i);
1042 precompute_offsets(fac, et);
1043 }
1044
1045 fac->exists = 1;
1046
1047 fac_ids = g_datalist_id_get_data(&tf->trace->facilities_by_name,
1048 fac->name);
1049 if(fac_ids == NULL) {
1050 fac_ids = g_array_sized_new (FALSE, TRUE, sizeof(guint), 1);
1051 g_datalist_id_set_data_full(&tf->trace->facilities_by_name,
1052 fac->name,
1053 fac_ids, ltt_fac_ids_destroy);
1054 }
1055 g_array_append_val(fac_ids, fac->id);
1056
1057 break;
1058 case LTT_EVENT_FACILITY_UNLOAD:
1059 g_debug("Doing LTT_EVENT_FACILITY_UNLOAD");
1060 /* We don't care about unload : facilities ID are valid for the whole
1061 * trace. They simply won't be used after the unload. */
1062 break;
1063 case LTT_EVENT_STATE_DUMP_FACILITY_LOAD:
1064 fac_name = (char*)(tf->event.data);
1065 g_debug("Doing LTT_EVENT_STATE_DUMP_FACILITY_LOAD of facility %s",
1066 fac_name);
1067 pos = (tf->event.data + strlen(fac_name) + 1);
1068 pos += ltt_align((size_t)pos, sizeof(guint32), tf->has_alignment);
1069 fac_state_dump_load_data = (struct LttStateDumpFacilityLoad *)pos;
1070
1071 fac = &g_array_index (tf->trace->facilities_by_num, LttFacility,
1072 ltt_get_uint32(LTT_GET_BO(tf), &fac_state_dump_load_data->id));
1073 /* facility may already exist if trace is paused/unpaused */
1074 if(fac->exists) continue;
1075 fac->name = g_quark_from_string(fac_name);
1076 fac->checksum = ltt_get_uint32(LTT_GET_BO(tf),
1077 &fac_state_dump_load_data->checksum);
1078 fac->id = ltt_get_uint32(LTT_GET_BO(tf),
1079 &fac_state_dump_load_data->id);
1080 fac->pointer_size = ltt_get_uint32(LTT_GET_BO(tf),
1081 &fac_state_dump_load_data->pointer_size);
1082 fac->int_size = ltt_get_uint32(LTT_GET_BO(tf),
1083 &fac_state_dump_load_data->int_size);
1084 fac->long_size = ltt_get_uint32(LTT_GET_BO(tf),
1085 &fac_state_dump_load_data->long_size);
1086 fac->size_t_size = ltt_get_uint32(LTT_GET_BO(tf),
1087 &fac_state_dump_load_data->size_t_size);
1088 fac->alignment = ltt_get_uint32(LTT_GET_BO(tf),
1089 &fac_state_dump_load_data->has_alignment);
1090 if(ltt_get_facility_description(fac, tf->trace, tf))
1091 continue; /* error opening description */
1092
1093 fac->trace = tf->trace;
1094
1095 /* Preset the field offsets */
1096 for(i=0; i<fac->events->len; i++){
1097 et = &g_array_index(fac->events, LttEventType, i);
1098 precompute_offsets(fac, et);
1099 }
1100
1101 fac->exists = 1;
1102
1103 fac_ids = g_datalist_id_get_data(&tf->trace->facilities_by_name,
1104 fac->name);
1105 if(fac_ids == NULL) {
1106 fac_ids = g_array_sized_new (FALSE, TRUE, sizeof(guint), 1);
1107 g_datalist_id_set_data_full(&tf->trace->facilities_by_name,
1108 fac->name,
1109 fac_ids, ltt_fac_ids_destroy);
1110 }
1111 g_array_append_val(fac_ids, fac->id);
1112
1113 break;
1114 case LTT_EVENT_HEARTBEAT:
1115 break;
1116 default:
1117 g_warning("Error in processing facility file %s, "
1118 "unknown event id %hhu in core facility.",
1119 g_quark_to_string(tf->name),
1120 tf->event.event_id);
1121 err = EPERM;
1122 goto event_id_error;
1123 }
1124 }
1125 }
1126 return 0;
1127
1128 /* Error handling */
1129 event_id_error:
1130 fac_id_error:
1131 update_error:
1132 seek_error:
1133 g_warning("An error occured in facility tracefile parsing");
1134 return err;
1135 }
1136
1137
1138 LttTrace *ltt_trace_open(const gchar *pathname)
1139 {
1140 gchar abs_path[PATH_MAX];
1141 LttTrace * t;
1142 LttTracefile *tf;
1143 GArray *group;
1144 int i, ret;
1145 struct ltt_block_start_header *header;
1146 DIR *dir;
1147 struct dirent *entry;
1148 guint control_found = 0;
1149 guint eventdefs_found = 0;
1150 struct stat stat_buf;
1151 gchar path[PATH_MAX];
1152
1153 t = g_new(LttTrace, 1);
1154 if(!t) goto alloc_error;
1155
1156 get_absolute_pathname(pathname, abs_path);
1157 t->pathname = g_quark_from_string(abs_path);
1158
1159 g_datalist_init(&t->tracefiles);
1160
1161 /* Test to see if it looks like a trace */
1162 dir = opendir(abs_path);
1163 if(dir == NULL) {
1164 perror(abs_path);
1165 goto open_error;
1166 }
1167 while((entry = readdir(dir)) != NULL) {
1168 strcpy(path, abs_path);
1169 strcat(path, "/");
1170 strcat(path, entry->d_name);
1171 ret = stat(path, &stat_buf);
1172 if(ret == -1) {
1173 perror(path);
1174 continue;
1175 }
1176 if(S_ISDIR(stat_buf.st_mode)) {
1177 if(strcmp(entry->d_name, "control") == 0) {
1178 control_found = 1;
1179 }
1180 if(strcmp(entry->d_name, "eventdefs") == 0) {
1181 eventdefs_found = 1;
1182 }
1183 }
1184 }
1185 closedir(dir);
1186
1187 if(!control_found || !eventdefs_found) goto find_error;
1188
1189 /* Open all the tracefiles */
1190 if(open_tracefiles(t, abs_path, "")) {
1191 g_warning("Error opening tracefile %s", abs_path);
1192 goto find_error;
1193 }
1194
1195 /* Prepare the facilities containers : array and mapping */
1196 /* Array is zeroed : the "exists" field is set to false by default */
1197 t->facilities_by_num = g_array_sized_new (FALSE,
1198 TRUE, sizeof(LttFacility),
1199 NUM_FACILITIES);
1200 t->facilities_by_num = g_array_set_size(t->facilities_by_num, NUM_FACILITIES);
1201
1202 g_datalist_init(&t->facilities_by_name);
1203
1204 /* Parse each trace control/facilitiesN files : get runtime fac. info */
1205 group = g_datalist_id_get_data(&t->tracefiles, LTT_TRACEFILE_NAME_FACILITIES);
1206 if(group == NULL) {
1207 g_error("Trace %s has no facility tracefile", abs_path);
1208 g_assert(0);
1209 goto facilities_error;
1210 }
1211
1212 /* Get the trace information for the control/facility 0 tracefile */
1213 g_assert(group->len > 0);
1214 tf = &g_array_index (group, LttTracefile, 0);
1215 header = (struct ltt_block_start_header*)tf->buffer.head;
1216 g_assert(parse_trace_header(header->trace,
1217 tf, t) == 0);
1218
1219 t->num_cpu = group->len;
1220
1221 for(i=0; i<group->len; i++) {
1222 tf = &g_array_index (group, LttTracefile, i);
1223 if(ltt_process_facility_tracefile(tf))
1224 goto facilities_error;
1225 }
1226
1227 return t;
1228
1229 /* Error handling */
1230 facilities_error:
1231 g_datalist_clear(&t->facilities_by_name);
1232 g_array_free(t->facilities_by_num, TRUE);
1233 find_error:
1234 g_datalist_clear(&t->tracefiles);
1235 open_error:
1236 g_free(t);
1237 alloc_error:
1238 return NULL;
1239
1240 }
1241
1242 GQuark ltt_trace_name(const LttTrace *t)
1243 {
1244 return t->pathname;
1245 }
1246
1247
1248 /******************************************************************************
1249 * When we copy a trace, we want all the opening actions to happen again :
1250 * the trace will be reopened and totally independant from the original.
1251 * That's why we call ltt_trace_open.
1252 *****************************************************************************/
1253 LttTrace *ltt_trace_copy(LttTrace *self)
1254 {
1255 return ltt_trace_open(g_quark_to_string(self->pathname));
1256 }
1257
1258 void ltt_trace_close(LttTrace *t)
1259 {
1260 guint i;
1261 LttFacility *fac;
1262
1263 for(i=0; i<t->facilities_by_num->len; i++) {
1264 fac = &g_array_index (t->facilities_by_num, LttFacility, i);
1265 if(fac->exists)
1266 ltt_facility_close(fac);
1267 }
1268
1269 g_datalist_clear(&t->facilities_by_name);
1270 g_array_free(t->facilities_by_num, TRUE);
1271 g_datalist_clear(&t->tracefiles);
1272 g_free(t);
1273 }
1274
1275
1276 /*****************************************************************************
1277 *Get the system description of the trace
1278 ****************************************************************************/
1279
1280 LttFacility *ltt_trace_facility_by_id(LttTrace *t, guint8 id)
1281 {
1282 g_assert(id < t->facilities_by_num->len);
1283 return &g_array_index(t->facilities_by_num, LttFacility, id);
1284 }
1285
1286 /* ltt_trace_facility_get_by_name
1287 *
1288 * Returns the GArray of facility indexes. All the fac_ids that matches the
1289 * requested facility name.
1290 *
1291 * If name is not found, returns NULL.
1292 */
1293 GArray *ltt_trace_facility_get_by_name(LttTrace *t, GQuark name)
1294 {
1295 return g_datalist_id_get_data(&t->facilities_by_name, name);
1296 }
1297
1298 /*****************************************************************************
1299 * Functions to discover all the event types in the trace
1300 ****************************************************************************/
1301
1302 #if 0
1303 unsigned ltt_trace_eventtype_number(LttTrace *t)
1304 {
1305 unsigned int i;
1306 unsigned count = 0;
1307 unsigned int num = t->facility_number;
1308 LttFacility * f;
1309
1310 for(i=0;i<num;i++){
1311 f = (LttFacility*)g_ptr_array_index(t->facilities, i);
1312 count += f->event_number;
1313 }
1314 return count;
1315 }
1316 #endif //0
1317
1318 #if 0
1319 //use an iteration on all the trace facilities, and inside iteration on all the
1320 //event types in each facilities instead.
1321 LttEventType *ltt_trace_eventtype_get(LttTrace *t, unsigned evId)
1322 {
1323 LttEventType *event_type;
1324
1325 LttFacility * f;
1326 f = ltt_trace_facility_by_id(t,evId);
1327
1328 if(unlikely(!f)) event_type = NULL;
1329 else event_type = f->events[evId - f->base_id];
1330
1331 return event_type;
1332 }
1333 #endif //0
1334
1335 #if 0
1336 /*****************************************************************************
1337 * ltt_trace_find_tracefile
1338 *
1339 * Find a tracefile by name and index in the group.
1340 *
1341 * Returns a pointer to the tracefiles, else NULL.
1342 ****************************************************************************/
1343
1344 LttTracefile *ltt_trace_find_tracefile(LttTrace *t, const gchar *name)
1345 {
1346 }
1347 #endif //0
1348
1349 /*****************************************************************************
1350 * Get the start time and end time of the trace
1351 ****************************************************************************/
1352
1353 static void ltt_tracefile_time_span_get(LttTracefile *tf,
1354 LttTime *start, LttTime *end)
1355 {
1356 int err;
1357
1358 err = map_block(tf, 0);
1359 if(unlikely(err)) {
1360 g_error("Can not map block");
1361 *start = ltt_time_infinite;
1362 } else
1363 *start = tf->buffer.begin.timestamp;
1364
1365 err = map_block(tf, tf->num_blocks - 1); /* Last block */
1366 if(unlikely(err)) {
1367 g_error("Can not map block");
1368 *end = ltt_time_zero;
1369 } else
1370 *end = tf->buffer.end.timestamp;
1371 }
1372
1373 struct tracefile_time_span_get_args {
1374 LttTrace *t;
1375 LttTime *start;
1376 LttTime *end;
1377 };
1378
1379 static void group_time_span_get(GQuark name, gpointer data, gpointer user_data)
1380 {
1381 struct tracefile_time_span_get_args *args =
1382 (struct tracefile_time_span_get_args*)user_data;
1383
1384 GArray *group = (GArray *)data;
1385 int i;
1386 LttTracefile *tf;
1387 LttTime tmp_start;
1388 LttTime tmp_end;
1389
1390 for(i=0; i<group->len; i++) {
1391 tf = &g_array_index (group, LttTracefile, i);
1392 if(tf->cpu_online) {
1393 ltt_tracefile_time_span_get(tf, &tmp_start, &tmp_end);
1394 if(ltt_time_compare(*args->start, tmp_start)>0) *args->start = tmp_start;
1395 if(ltt_time_compare(*args->end, tmp_end)<0) *args->end = tmp_end;
1396 }
1397 }
1398 }
1399
1400 void ltt_trace_time_span_get(LttTrace *t, LttTime *start, LttTime *end)
1401 {
1402 LttTime min_start = ltt_time_infinite;
1403 LttTime max_end = ltt_time_zero;
1404 struct tracefile_time_span_get_args args = { t, &min_start, &max_end };
1405
1406 g_datalist_foreach(&t->tracefiles, &group_time_span_get, &args);
1407
1408 if(start != NULL) *start = min_start;
1409 if(end != NULL) *end = max_end;
1410
1411 }
1412
1413
1414 /*****************************************************************************
1415 *Get the name of a tracefile
1416 ****************************************************************************/
1417
1418 GQuark ltt_tracefile_name(const LttTracefile *tf)
1419 {
1420 return tf->name;
1421 }
1422
1423 GQuark ltt_tracefile_long_name(const LttTracefile *tf)
1424 {
1425 return tf->long_name;
1426 }
1427
1428
1429
1430 guint ltt_tracefile_num(LttTracefile *tf)
1431 {
1432 return tf->cpu_num;
1433 }
1434
1435 /*****************************************************************************
1436 * Get the number of blocks in the tracefile
1437 ****************************************************************************/
1438
1439 guint ltt_tracefile_block_number(LttTracefile *tf)
1440 {
1441 return tf->num_blocks;
1442 }
1443
1444
1445 /* Seek to the first event in a tracefile that has a time equal or greater than
1446 * the time passed in parameter.
1447 *
1448 * If the time parameter is outside the tracefile time span, seek to the first
1449 * event or if after, return ERANGE.
1450 *
1451 * If the time parameter is before the first event, we have to seek specially to
1452 * there.
1453 *
1454 * If the time is after the end of the trace, return ERANGE.
1455 *
1456 * Do a binary search to find the right block, then a sequential search in the
1457 * block to find the event.
1458 *
1459 * In the special case where the time requested fits inside a block that has no
1460 * event corresponding to the requested time, the first event of the next block
1461 * will be seeked.
1462 *
1463 * IMPORTANT NOTE : // FIXME everywhere...
1464 *
1465 * You MUST NOT do a ltt_tracefile_read right after a ltt_tracefile_seek_time :
1466 * you will jump over an event if you do.
1467 *
1468 * Return value : 0 : no error, the tf->event can be used
1469 * ERANGE : time if after the last event of the trace
1470 * otherwise : this is an error.
1471 *
1472 * */
1473
1474 int ltt_tracefile_seek_time(LttTracefile *tf, LttTime time)
1475 {
1476 int ret = 0;
1477 int err;
1478 unsigned int block_num, high, low;
1479
1480 /* seek at the beginning of trace */
1481 err = map_block(tf, 0); /* First block */
1482 if(unlikely(err)) {
1483 g_error("Can not map block");
1484 goto fail;
1485 }
1486
1487 /* If the time is lower or equal the beginning of the trace,
1488 * go to the first event. */
1489 if(ltt_time_compare(time, tf->buffer.begin.timestamp) <= 0) {
1490 ret = ltt_tracefile_read(tf);
1491 if(ret == ERANGE) goto range;
1492 else if (ret) goto fail;
1493 goto found; /* There is either no event in the trace or the event points
1494 to the first event in the trace */
1495 }
1496
1497 err = map_block(tf, tf->num_blocks - 1); /* Last block */
1498 if(unlikely(err)) {
1499 g_error("Can not map block");
1500 goto fail;
1501 }
1502
1503 /* If the time is after the end of the trace, return ERANGE. */
1504 if(ltt_time_compare(time, tf->buffer.end.timestamp) > 0) {
1505 goto range;
1506 }
1507
1508 /* Binary search the block */
1509 high = tf->num_blocks - 1;
1510 low = 0;
1511
1512 while(1) {
1513 block_num = ((high-low) / 2) + low;
1514
1515 err = map_block(tf, block_num);
1516 if(unlikely(err)) {
1517 g_error("Can not map block");
1518 goto fail;
1519 }
1520 if(high == low) {
1521 /* We cannot divide anymore : this is what would happen if the time
1522 * requested was exactly between two consecutive buffers'end and start
1523 * timestamps. This is also what would happend if we didn't deal with out
1524 * of span cases prior in this function. */
1525 /* The event is right in the buffer!
1526 * (or in the next buffer first event) */
1527 while(1) {
1528 ret = ltt_tracefile_read(tf);
1529 if(ret == ERANGE) goto range; /* ERANGE or EPERM */
1530 else if(ret) goto fail;
1531
1532 if(ltt_time_compare(time, tf->event.event_time) <= 0)
1533 goto found;
1534 }
1535
1536 } else if(ltt_time_compare(time, tf->buffer.begin.timestamp) < 0) {
1537 /* go to lower part */
1538 high = block_num - 1;
1539 } else if(ltt_time_compare(time, tf->buffer.end.timestamp) > 0) {
1540 /* go to higher part */
1541 low = block_num + 1;
1542 } else {/* The event is right in the buffer!
1543 (or in the next buffer first event) */
1544 while(1) {
1545 ret = ltt_tracefile_read(tf);
1546 if(ret == ERANGE) goto range; /* ERANGE or EPERM */
1547 else if(ret) goto fail;
1548
1549 if(ltt_time_compare(time, tf->event.event_time) <= 0)
1550 break;
1551 }
1552 goto found;
1553 }
1554 }
1555
1556 found:
1557 return 0;
1558 range:
1559 return ERANGE;
1560
1561 /* Error handling */
1562 fail:
1563 g_error("ltt_tracefile_seek_time failed on tracefile %s",
1564 g_quark_to_string(tf->name));
1565 return EPERM;
1566 }
1567
1568
1569 int ltt_tracefile_seek_position(LttTracefile *tf, const LttEventPosition *ep) {
1570
1571 int err;
1572
1573 if(ep->tracefile != tf) {
1574 goto fail;
1575 }
1576
1577 err = map_block(tf, ep->block);
1578 if(unlikely(err)) {
1579 g_error("Can not map block");
1580 goto fail;
1581 }
1582
1583 tf->event.offset = ep->offset;
1584
1585 err = ltt_tracefile_read_update_event(tf);
1586 if(err) goto fail;
1587 err = ltt_tracefile_read_op(tf);
1588 if(err) goto fail;
1589
1590 return 0;
1591
1592 fail:
1593 g_error("ltt_tracefile_seek_time failed on tracefile %s",
1594 g_quark_to_string(tf->name));
1595 return 1;
1596 }
1597
1598 /* Calculate the real event time based on the buffer boundaries */
1599 LttTime ltt_interpolate_time(LttTracefile *tf, LttEvent *event)
1600 {
1601 LttTime time;
1602
1603 // time = ltt_time_from_uint64(
1604 // cycles_2_ns(tf, (guint64)(tf->buffer.tsc - tf->buffer.begin.cycle_count)));
1605 time = ltt_time_from_uint64(
1606 (double)(tf->buffer.tsc - tf->trace->start_tsc)
1607 * (1000000000.0 / tf->trace->freq_scale)
1608 / (double)tf->trace->start_freq);
1609 //time = ltt_time_add(tf->buffer.begin.timestamp, time);
1610 time = ltt_time_add(tf->trace->start_time_from_tsc, time);
1611
1612 return time;
1613 }
1614
1615
1616 /* Get the current event of the tracefile : valid until the next read */
1617 LttEvent *ltt_tracefile_get_event(LttTracefile *tf)
1618 {
1619 return &tf->event;
1620 }
1621
1622
1623
1624 /*****************************************************************************
1625 *Function name
1626 * ltt_tracefile_read : Read the next event in the tracefile
1627 *Input params
1628 * t : tracefile
1629 *Return value
1630 *
1631 * Returns 0 if an event can be used in tf->event.
1632 * Returns ERANGE on end of trace. The event in tf->event still can be used
1633 * (if the last block was not empty).
1634 * Returns EPERM on error.
1635 *
1636 * This function does make the tracefile event structure point to the event
1637 * currently pointed to by the tf->event.
1638 *
1639 * Note : you must call a ltt_tracefile_seek to the beginning of the trace to
1640 * reinitialize it after an error if you want results to be coherent.
1641 * It would be the case if a end of trace last buffer has no event : the end
1642 * of trace wouldn't be returned, but an error.
1643 * We make the assumption there is at least one event per buffer.
1644 ****************************************************************************/
1645
1646 int ltt_tracefile_read(LttTracefile *tf)
1647 {
1648 int err;
1649
1650 err = ltt_tracefile_read_seek(tf);
1651 if(err) return err;
1652 err = ltt_tracefile_read_update_event(tf);
1653 if(err) return err;
1654 err = ltt_tracefile_read_op(tf);
1655 if(err) return err;
1656
1657 return 0;
1658 }
1659
1660 int ltt_tracefile_read_seek(LttTracefile *tf)
1661 {
1662 int err;
1663
1664 /* Get next buffer until we finally have an event, or end of trace */
1665 while(1) {
1666 err = ltt_seek_next_event(tf);
1667 if(unlikely(err == ENOPROTOOPT)) {
1668 return EPERM;
1669 }
1670
1671 /* Are we at the end of the buffer ? */
1672 if(err == ERANGE) {
1673 if(unlikely(tf->buffer.index == tf->num_blocks-1)){ /* end of trace ? */
1674 return ERANGE;
1675 } else {
1676 /* get next block */
1677 err = map_block(tf, tf->buffer.index + 1);
1678 if(unlikely(err)) {
1679 g_error("Can not map block");
1680 return EPERM;
1681 }
1682 }
1683 } else break; /* We found an event ! */
1684 }
1685
1686 return 0;
1687 }
1688
1689
1690 /* do specific operation on events */
1691 int ltt_tracefile_read_op(LttTracefile *tf)
1692 {
1693 LttEvent *event;
1694
1695 event = &tf->event;
1696
1697 /* do event specific operation */
1698
1699 /* do something if its an heartbeat event : increment the heartbeat count */
1700 //if(event->facility_id == LTT_FACILITY_CORE)
1701 // if(event->event_id == LTT_EVENT_HEARTBEAT)
1702 // tf->cur_heart_beat_number++;
1703
1704 return 0;
1705 }
1706
1707
1708 /* same as ltt_tracefile_read, but does not seek to the next event nor call
1709 * event specific operation. */
1710 int ltt_tracefile_read_update_event(LttTracefile *tf)
1711 {
1712 void * pos;
1713 LttEvent *event;
1714
1715 event = &tf->event;
1716 pos = tf->buffer.head + event->offset;
1717
1718 /* Read event header */
1719
1720 /* Align the head */
1721 pos += ltt_align((size_t)pos, tf->trace->arch_size, tf->has_alignment);
1722
1723 if(tf->trace->has_heartbeat) {
1724 event->timestamp = ltt_get_uint32(LTT_GET_BO(tf),
1725 pos);
1726 /* 32 bits -> 64 bits tsc */
1727 /* note : still works for seek and non seek cases. */
1728 if(event->timestamp < (0xFFFFFFFFULL&tf->buffer.tsc)) {
1729 tf->buffer.tsc = ((tf->buffer.tsc&0xFFFFFFFF00000000ULL)
1730 + 0x100000000ULL)
1731 | (guint64)event->timestamp;
1732 event->tsc = tf->buffer.tsc;
1733 } else {
1734 /* no overflow */
1735 tf->buffer.tsc = (tf->buffer.tsc&0xFFFFFFFF00000000ULL)
1736 | (guint64)event->timestamp;
1737 event->tsc = tf->buffer.tsc;
1738 }
1739 pos += sizeof(guint32);
1740 } else {
1741 event->tsc = ltt_get_uint64(LTT_GET_BO(tf), pos);
1742 tf->buffer.tsc = event->tsc;
1743 pos += sizeof(guint64);
1744 }
1745
1746 event->event_time = ltt_interpolate_time(tf, event);
1747 event->facility_id = *(guint8*)pos;
1748 pos += sizeof(guint8);
1749
1750 event->event_id = *(guint8*)pos;
1751 pos += sizeof(guint8);
1752
1753 event->event_size = ltt_get_uint16(LTT_GET_BO(tf), pos);
1754 pos += sizeof(guint16);
1755
1756 /* Align the head */
1757 pos += ltt_align((size_t)pos, tf->trace->arch_size, tf->has_alignment);
1758
1759 event->data = pos;
1760
1761 /* get the data size and update the event fields with the current
1762 * information */
1763 ltt_update_event_size(tf);
1764
1765 return 0;
1766 }
1767
1768
1769 /****************************************************************************
1770 *Function name
1771 * map_block : map a block from the file
1772 *Input Params
1773 * lttdes : ltt trace file
1774 * whichBlock : the block which will be read
1775 *return value
1776 * 0 : success
1777 * EINVAL : lseek fail
1778 * EIO : can not read from the file
1779 ****************************************************************************/
1780
1781 static gint map_block(LttTracefile * tf, guint block_num)
1782 {
1783 int page_size = getpagesize();
1784 struct ltt_block_start_header *header;
1785
1786 g_assert(block_num < tf->num_blocks);
1787
1788 if(tf->buffer.head != NULL) {
1789 if(munmap(tf->buffer.head, PAGE_ALIGN(tf->buf_size))) {
1790 g_warning("unmap size : %u\n",
1791 PAGE_ALIGN(tf->buf_size));
1792 perror("munmap error");
1793 g_assert(0);
1794 }
1795 }
1796
1797
1798 /* Multiple of pages aligned head */
1799 tf->buffer.head = mmap(0,
1800 PAGE_ALIGN(tf->buf_size),
1801 PROT_READ, MAP_PRIVATE, tf->fd,
1802 PAGE_ALIGN((off_t)tf->buf_size * (off_t)block_num));
1803
1804 if(tf->buffer.head == MAP_FAILED) {
1805 perror("Error in allocating memory for buffer of tracefile");
1806 g_assert(0);
1807 goto map_error;
1808 }
1809 g_assert( ( (guint)tf->buffer.head&(8-1) ) == 0); // make sure it's aligned.
1810
1811
1812 tf->buffer.index = block_num;
1813
1814 header = (struct ltt_block_start_header*)tf->buffer.head;
1815
1816 #if 0
1817 tf->buffer.begin.timestamp = ltt_time_add(
1818 ltt_time_from_uint64(
1819 ltt_get_uint64(LTT_GET_BO(tf),
1820 &header->begin.timestamp)
1821 - tf->trace->start_monotonic),
1822 tf->trace->start_time);
1823 #endif //0
1824 //g_debug("block %u begin : %lu.%lu", block_num,
1825 // tf->buffer.begin.timestamp.tv_sec, tf->buffer.begin.timestamp.tv_nsec);
1826 tf->buffer.begin.cycle_count = ltt_get_uint64(LTT_GET_BO(tf),
1827 &header->begin.cycle_count);
1828 tf->buffer.begin.freq = ltt_get_uint64(LTT_GET_BO(tf),
1829 &header->begin.freq);
1830 tf->buffer.begin.timestamp = ltt_time_add(
1831 ltt_time_from_uint64(
1832 (double)(tf->buffer.begin.cycle_count
1833 - tf->trace->start_tsc) * 1000000.0
1834 / (double)tf->trace->start_freq),
1835 tf->trace->start_time_from_tsc);
1836 #if 0
1837
1838 tf->buffer.end.timestamp = ltt_time_add(
1839 ltt_time_from_uint64(
1840 ltt_get_uint64(LTT_GET_BO(tf),
1841 &header->end.timestamp)
1842 - tf->trace->start_monotonic),
1843 tf->trace->start_time);
1844 #endif //0
1845 //g_debug("block %u end : %lu.%lu", block_num,
1846 // tf->buffer.end.timestamp.tv_sec, tf->buffer.end.timestamp.tv_nsec);
1847 tf->buffer.end.cycle_count = ltt_get_uint64(LTT_GET_BO(tf),
1848 &header->end.cycle_count);
1849 tf->buffer.end.freq = ltt_get_uint64(LTT_GET_BO(tf),
1850 &header->end.freq);
1851 tf->buffer.lost_size = ltt_get_uint32(LTT_GET_BO(tf),
1852 &header->lost_size);
1853 tf->buffer.end.timestamp = ltt_time_add(
1854 ltt_time_from_uint64(
1855 (double)(tf->buffer.end.cycle_count
1856 - tf->trace->start_tsc) * 1000000.0
1857 / (double)tf->trace->start_freq),
1858 tf->trace->start_time_from_tsc);
1859
1860 tf->buffer.tsc = tf->buffer.begin.cycle_count;
1861 tf->event.tsc = tf->buffer.tsc;
1862 tf->buffer.freq = tf->buffer.begin.freq;
1863
1864 /* FIXME
1865 * eventually support variable buffer size : will need a partial pre-read of
1866 * the headers to create an index when we open the trace... eventually. */
1867 g_assert(tf->buf_size == ltt_get_uint32(LTT_GET_BO(tf),
1868 &header->buf_size));
1869
1870 /* Now that the buffer is mapped, calculate the time interpolation for the
1871 * block. */
1872
1873 // tf->buffer.nsecs_per_cycle = calc_nsecs_per_cycle(tf);
1874 //tf->buffer.cyc2ns_scale = calc_nsecs_per_cycle(tf);
1875
1876 /* Make the current event point to the beginning of the buffer :
1877 * it means that the event read must get the first event. */
1878 tf->event.tracefile = tf;
1879 tf->event.block = block_num;
1880 tf->event.offset = 0;
1881
1882 return 0;
1883
1884 map_error:
1885 return -errno;
1886
1887 }
1888
1889 /* It will update the fields offsets too */
1890 void ltt_update_event_size(LttTracefile *tf)
1891 {
1892 off_t size = 0;
1893
1894 /* Specific handling of core events : necessary to read the facility control
1895 * tracefile. */
1896 LttFacility *f = ltt_trace_get_facility_by_num(tf->trace,
1897 tf->event.facility_id);
1898
1899 if(likely(tf->event.facility_id == LTT_FACILITY_CORE)) {
1900 switch((enum ltt_core_events)tf->event.event_id) {
1901 case LTT_EVENT_FACILITY_LOAD:
1902 size = strlen((char*)tf->event.data) + 1;
1903 //g_debug("Update Event facility load of facility %s", (char*)tf->event.data);
1904 size += ltt_align(size, sizeof(guint32), tf->has_alignment);
1905 size += sizeof(struct LttFacilityLoad);
1906 break;
1907 case LTT_EVENT_FACILITY_UNLOAD:
1908 //g_debug("Update Event facility unload");
1909 size = sizeof(struct LttFacilityUnload);
1910 break;
1911 case LTT_EVENT_STATE_DUMP_FACILITY_LOAD:
1912 size = strlen((char*)tf->event.data) + 1;
1913 size += ltt_align(size, sizeof(guint32), tf->has_alignment);
1914 //g_debug("Update Event facility load state dump of facility %s",
1915 // (char*)tf->event.data);
1916 size += sizeof(struct LttStateDumpFacilityLoad);
1917 break;
1918 case LTT_EVENT_HEARTBEAT:
1919 //g_debug("Update Event heartbeat");
1920 size = sizeof(TimeHeartbeat);
1921 break;
1922 default:
1923 g_warning("Error in getting event size : tracefile %s, "
1924 "unknown event id %hhu in core facility.",
1925 g_quark_to_string(tf->name),
1926 tf->event.event_id);
1927 goto event_id_error;
1928
1929 }
1930 } else {
1931 if(!f->exists) {
1932 g_error("Unknown facility %hhu (0x%hhx) in tracefile %s",
1933 tf->event.facility_id,
1934 tf->event.facility_id,
1935 g_quark_to_string(tf->name));
1936 goto facility_error;
1937 }
1938
1939 LttEventType *event_type =
1940 ltt_facility_eventtype_get(f, tf->event.event_id);
1941
1942 if(!event_type) {
1943 g_error("Unknown event id %hhu in facility %s in tracefile %s",
1944 tf->event.event_id,
1945 g_quark_to_string(f->name),
1946 g_quark_to_string(tf->name));
1947 goto event_type_error;
1948 }
1949
1950 /* Compute the dynamic offsets */
1951 compute_offsets(tf, f, event_type, &size, tf->event.data);
1952
1953 //g_debug("Event root field : f.e %hhu.%hhu size %zd",
1954 // tf->event.facility_id,
1955 // tf->event.event_id, size);
1956 }
1957
1958 tf->event.data_size = size;
1959
1960 /* Check consistency between kernel and LTTV structure sizes */
1961 g_assert(tf->event.data_size == tf->event.event_size);
1962
1963 return;
1964
1965 facility_error:
1966 event_type_error:
1967 event_id_error:
1968 tf->event.data_size = 0;
1969 }
1970
1971
1972 /* Take the tf current event offset and use the event facility id and event id
1973 * to figure out where is the next event offset.
1974 *
1975 * This is an internal function not aiming at being used elsewhere : it will
1976 * not jump over the current block limits. Please consider using
1977 * ltt_tracefile_read to do this.
1978 *
1979 * Returns 0 on success
1980 * ERANGE if we are at the end of the buffer.
1981 * ENOPROTOOPT if an error occured when getting the current event size.
1982 */
1983 static int ltt_seek_next_event(LttTracefile *tf)
1984 {
1985 int ret = 0;
1986 void *pos;
1987
1988 /* seek over the buffer header if we are at the buffer start */
1989 if(tf->event.offset == 0) {
1990 tf->event.offset += tf->buffer_header_size;
1991
1992 if(tf->event.offset == tf->buf_size - tf->buffer.lost_size) {
1993 ret = ERANGE;
1994 }
1995 goto found;
1996 }
1997
1998
1999 pos = tf->event.data;
2000
2001 if(tf->event.data_size < 0) goto error;
2002
2003 pos += (size_t)tf->event.data_size;
2004
2005 tf->event.offset = pos - tf->buffer.head;
2006
2007 if(tf->event.offset == tf->buf_size - tf->buffer.lost_size) {
2008 ret = ERANGE;
2009 goto found;
2010 }
2011 g_assert(tf->event.offset < tf->buf_size - tf->buffer.lost_size);
2012
2013 found:
2014 return ret;
2015
2016 error:
2017 g_error("Error in ltt_seek_next_event for tracefile %s",
2018 g_quark_to_string(tf->name));
2019 return ENOPROTOOPT;
2020 }
2021
2022 #if 0
2023 /*****************************************************************************
2024 *Function name
2025 * calc_nsecs_per_cycle : calculate nsecs per cycle for current block
2026 *
2027 * 1.0 / (freq(khz) *1000) * 1000000000
2028 *Input Params
2029 * t : tracefile
2030 ****************************************************************************/
2031 /* from timer_tsc.c */
2032 #define CYC2NS_SCALE_FACTOR 10
2033 static guint32 calc_nsecs_per_cycle(LttTracefile * tf)
2034 {
2035 //return 1e6 / (double)tf->buffer.freq;
2036 guint32 cpu_mhz = tf->buffer.freq / 1000;
2037 guint32 cyc2ns_scale = (1000 << CYC2NS_SCALE_FACTOR)/cpu_mhz;
2038
2039 return cyc2ns_scale;
2040 // return 1e6 / (double)tf->buffer.freq;
2041 }
2042
2043 static guint64 cycles_2_ns(LttTracefile *tf, guint64 cycles)
2044 {
2045 return (cycles * tf->buffer.cyc2ns_scale) >> CYC2NS_SCALE_FACTOR;
2046 }
2047 #endif //0
2048
2049 #if 0
2050 void setFieldsOffset(LttTracefile *tf, LttEventType *evT,void *evD)
2051 {
2052 LttField * rootFld = evT->root_field;
2053 // rootFld->base_address = evD;
2054
2055 if(likely(rootFld))
2056 rootFld->field_size = getFieldtypeSize(tf, evT->facility,
2057 evT, 0,0,rootFld, evD);
2058 }
2059 #endif //0
2060 #if 0
2061 /*****************************************************************************
2062 *Function name
2063 * set_fields_offsets : set the precomputable offset of the fields
2064 *Input params
2065 * tracefile : opened trace file
2066 * event_type : the event type
2067 ****************************************************************************/
2068
2069 void set_fields_offsets(LttTracefile *tf, LttEventType *event_type)
2070 {
2071 LttField *field = event_type->root_field;
2072 enum field_status fixed_root = FIELD_FIXED, fixed_parent = FIELD_FIXED;
2073
2074 if(likely(field))
2075 preset_field_type_size(tf, event_type, 0, 0,
2076 &fixed_root, &fixed_parent,
2077 field);
2078
2079 }
2080 #endif //0
2081
2082
2083 /*****************************************************************************
2084 *Function name
2085 * get_alignment : Get the alignment needed for a field.
2086 *Input params
2087 * field : field
2088 *
2089 * returns : The size on which it must be aligned.
2090 *
2091 ****************************************************************************/
2092 off_t get_alignment(LttField *field)
2093 {
2094 LttType *type = &field->field_type;
2095
2096 switch(type->type_class) {
2097 case LTT_INT_FIXED:
2098 case LTT_UINT_FIXED:
2099 case LTT_POINTER:
2100 case LTT_CHAR:
2101 case LTT_UCHAR:
2102 case LTT_SHORT:
2103 case LTT_USHORT:
2104 case LTT_INT:
2105 case LTT_UINT:
2106 case LTT_LONG:
2107 case LTT_ULONG:
2108 case LTT_SIZE_T:
2109 case LTT_SSIZE_T:
2110 case LTT_OFF_T:
2111 case LTT_FLOAT:
2112 case LTT_ENUM:
2113 /* Align offset on type size */
2114 return field->field_size;
2115 break;
2116 case LTT_STRING:
2117 return 0;
2118 break;
2119 case LTT_ARRAY:
2120 g_assert(type->fields->len == 1);
2121 {
2122 LttField *child = &g_array_index(type->fields, LttField, 0);
2123 return get_alignment(child);
2124 }
2125 break;
2126 case LTT_SEQUENCE:
2127 g_assert(type->fields->len == 2);
2128 {
2129 off_t localign = 0;
2130 LttField *child = &g_array_index(type->fields, LttField, 0);
2131
2132 localign = max(localign, get_alignment(child));
2133
2134 child = &g_array_index(type->fields, LttField, 1);
2135 localign = max(localign, get_alignment(child));
2136
2137 return localign;
2138 }
2139 break;
2140 case LTT_STRUCT:
2141 case LTT_UNION:
2142 {
2143 guint i;
2144 off_t localign = 0;
2145
2146 for(i=0; i<type->fields->len; i++) {
2147 LttField *child = &g_array_index(type->fields, LttField, i);
2148 localign = max(localign, get_alignment(child));
2149 }
2150 return localign;
2151 }
2152 break;
2153 case LTT_NONE:
2154 default:
2155 g_error("get_alignment : unknown type");
2156 }
2157
2158 }
2159
2160 /*****************************************************************************
2161 *Function name
2162 * field_compute_static_size : Determine the size of fields known by their
2163 * sole definition. Unions, arrays and struct sizes might be known, but
2164 * the parser does not give that information.
2165 *Input params
2166 * tf : tracefile
2167 * field : field
2168 *
2169 ****************************************************************************/
2170
2171 void field_compute_static_size(LttFacility *fac, LttField *field)
2172 {
2173 LttType *type = &field->field_type;
2174
2175 switch(type->type_class) {
2176 case LTT_INT_FIXED:
2177 case LTT_UINT_FIXED:
2178 case LTT_POINTER:
2179 case LTT_CHAR:
2180 case LTT_UCHAR:
2181 case LTT_SHORT:
2182 case LTT_USHORT:
2183 case LTT_INT:
2184 case LTT_UINT:
2185 case LTT_LONG:
2186 case LTT_ULONG:
2187 case LTT_SIZE_T:
2188 case LTT_SSIZE_T:
2189 case LTT_OFF_T:
2190 case LTT_FLOAT:
2191 case LTT_ENUM:
2192 case LTT_STRING:
2193 /* nothing to do */
2194 break;
2195 case LTT_ARRAY:
2196 /* note this : array type size is the number of elements in the array,
2197 * while array field size of the length of the array in bytes */
2198 g_assert(type->fields->len == 1);
2199 {
2200 LttField *child = &g_array_index(type->fields, LttField, 0);
2201 field_compute_static_size(fac, child);
2202
2203 if(child->field_size != 0) {
2204 field->field_size = type->size * child->field_size;
2205 field->dynamic_offsets = g_array_sized_new(FALSE, TRUE,
2206 sizeof(off_t), type->size);
2207 } else {
2208 field->field_size = 0;
2209 }
2210 }
2211 break;
2212 case LTT_SEQUENCE:
2213 g_assert(type->fields->len == 2);
2214 {
2215 off_t local_offset = 0;
2216 LttField *child = &g_array_index(type->fields, LttField, 1);
2217 field_compute_static_size(fac, child);
2218 field->field_size = 0;
2219 type->size = 0;
2220 if(child->field_size != 0) {
2221 field->dynamic_offsets = g_array_sized_new(FALSE, TRUE,
2222 sizeof(off_t), SEQUENCE_AVG_ELEMENTS);
2223 }
2224 }
2225 break;
2226 case LTT_STRUCT:
2227 case LTT_UNION:
2228 {
2229 guint i;
2230 for(i=0;i<type->fields->len;i++) {
2231 LttField *child = &g_array_index(type->fields, LttField, i);
2232 field_compute_static_size(fac, child);
2233 if(child->field_size != 0) {
2234 type->size += ltt_align(type->size, get_alignment(child),
2235 fac->alignment);
2236 type->size += child->field_size;
2237 } else {
2238 /* As soon as we find a child with variable size, we have
2239 * a variable size */
2240 type->size = 0;
2241 break;
2242 }
2243 }
2244 field->field_size = type->size;
2245 }
2246 break;
2247 default:
2248 g_error("field_static_size : unknown type");
2249 }
2250
2251 }
2252
2253
2254
2255 /*****************************************************************************
2256 *Function name
2257 * precompute_fields_offsets : set the precomputable offset of the fields
2258 *Input params
2259 * fac : facility
2260 * field : the field
2261 * offset : pointer to the current offset, must be incremented
2262 *
2263 * return : 1 : found a variable length field, stop the processing.
2264 * 0 otherwise.
2265 ****************************************************************************/
2266
2267
2268 gint precompute_fields_offsets(LttFacility *fac, LttField *field, off_t *offset)
2269 {
2270 LttType *type = &field->field_type;
2271
2272 switch(type->type_class) {
2273 case LTT_INT_FIXED:
2274 case LTT_UINT_FIXED:
2275 case LTT_POINTER:
2276 case LTT_CHAR:
2277 case LTT_UCHAR:
2278 case LTT_SHORT:
2279 case LTT_USHORT:
2280 case LTT_INT:
2281 case LTT_UINT:
2282 case LTT_LONG:
2283 case LTT_ULONG:
2284 case LTT_SIZE_T:
2285 case LTT_SSIZE_T:
2286 case LTT_OFF_T:
2287 case LTT_FLOAT:
2288 case LTT_ENUM:
2289 g_assert(field->field_size != 0);
2290 /* Align offset on type size */
2291 *offset += ltt_align(*offset, get_alignment(field),
2292 fac->alignment);
2293 /* remember offset */
2294 field->offset_root = *offset;
2295 field->fixed_root = FIELD_FIXED;
2296 /* Increment offset */
2297 *offset += field->field_size;
2298 return 0;
2299 break;
2300 case LTT_STRING:
2301 field->offset_root = *offset;
2302 field->fixed_root = FIELD_FIXED;
2303 return 1;
2304 break;
2305 case LTT_ARRAY:
2306 g_assert(type->fields->len == 1);
2307 {
2308 LttField *child = &g_array_index(type->fields, LttField, 0);
2309
2310 *offset += ltt_align(*offset, get_alignment(field),
2311 fac->alignment);
2312
2313 /* remember offset */
2314 field->offset_root = *offset;
2315 field->array_offset = *offset;
2316 field->fixed_root = FIELD_FIXED;
2317
2318 /* Let the child be variable */
2319 //precompute_fields_offsets(tf, child, offset);
2320
2321 if(field->field_size != 0) {
2322 /* Increment offset */
2323 /* field_size is the array size in bytes */
2324 *offset += field->field_size;
2325 return 0;
2326 } else {
2327 return 1;
2328 }
2329 }
2330 break;
2331 case LTT_SEQUENCE:
2332 g_assert(type->fields->len == 2);
2333 {
2334 LttField *child;
2335 guint ret;
2336
2337 *offset += ltt_align(*offset, get_alignment(field),
2338 fac->alignment);
2339
2340 /* remember offset */
2341 field->offset_root = *offset;
2342 field->fixed_root = FIELD_FIXED;
2343
2344 child = &g_array_index(type->fields, LttField, 0);
2345 ret = precompute_fields_offsets(fac, child, offset);
2346 g_assert(ret == 0); /* Seq len cannot have variable len */
2347
2348 child = &g_array_index(type->fields, LttField, 1);
2349 *offset += ltt_align(*offset, get_alignment(child),
2350 fac->alignment);
2351 field->array_offset = *offset;
2352 /* Let the child be variable. */
2353 //ret = precompute_fields_offsets(fac, child, offset);
2354
2355 /* Cannot precompute fields offsets of sequence members, and has
2356 * variable length. */
2357 return 1;
2358 }
2359 break;
2360 case LTT_STRUCT:
2361 {
2362 LttField *child;
2363 guint i;
2364 gint ret=0;
2365
2366 *offset += ltt_align(*offset, get_alignment(field),
2367 fac->alignment);
2368 /* remember offset */
2369 field->offset_root = *offset;
2370 field->fixed_root = FIELD_FIXED;
2371
2372 for(i=0; i< type->fields->len; i++) {
2373 child = &g_array_index(type->fields, LttField, i);
2374 ret = precompute_fields_offsets(fac, child, offset);
2375
2376 if(ret) break;
2377 }
2378 return ret;
2379 }
2380 break;
2381 case LTT_UNION:
2382 {
2383 LttField *child;
2384 guint i;
2385 gint ret=0;
2386
2387 *offset += ltt_align(*offset, get_alignment(field),
2388 fac->alignment);
2389 /* remember offset */
2390 field->offset_root = *offset;
2391 field->fixed_root = FIELD_FIXED;
2392
2393 for(i=0; i< type->fields->len; i++) {
2394 *offset = field->offset_root;
2395 child = &g_array_index(type->fields, LttField, i);
2396 ret = precompute_fields_offsets(fac, child, offset);
2397
2398 if(ret) break;
2399 }
2400 *offset = field->offset_root + field->field_size;
2401 return ret;
2402 }
2403
2404 break;
2405 case LTT_NONE:
2406 default:
2407 g_error("precompute_fields_offsets : unknown type");
2408 return 1;
2409 }
2410
2411 }
2412
2413
2414 /*****************************************************************************
2415 *Function name
2416 * precompute_offsets : set the precomputable offset of an event type
2417 *Input params
2418 * tf : tracefile
2419 * event : event type
2420 *
2421 ****************************************************************************/
2422 void precompute_offsets(LttFacility *fac, LttEventType *event)
2423 {
2424 guint i;
2425 off_t offset = 0;
2426 gint ret;
2427
2428 /* First, compute the size of fixed size fields. Will determine size for
2429 * arrays, struct and unions, which is not done by the parser */
2430 for(i=0; i<event->fields->len; i++) {
2431 LttField *field = &g_array_index(event->fields, LttField, i);
2432 field_compute_static_size(fac, field);
2433 }
2434
2435 /* Precompute all known offsets */
2436 for(i=0; i<event->fields->len; i++) {
2437 LttField *field = &g_array_index(event->fields, LttField, i);
2438 ret = precompute_fields_offsets(fac, field, &offset);
2439 if(ret) break;
2440 }
2441 }
2442
2443
2444
2445
2446 /*****************************************************************************
2447 *Function name
2448 * preset_field_type_size : set the fixed sizes of the field type
2449 *Input params
2450 * tf : tracefile
2451 * event_type : event type
2452 * offset_root : offset from the root
2453 * offset_parent : offset from the parent
2454 * fixed_root : Do we know a fixed offset to the root ?
2455 * fixed_parent : Do we know a fixed offset to the parent ?
2456 * field : field
2457 ****************************************************************************/
2458
2459
2460
2461 // preset the fixed size offsets. Calculate them just like genevent-new : an
2462 // increment of a *to value that represents the offset from the start of the
2463 // event data.
2464 // The preset information is : offsets up to (and including) the first element
2465 // of variable size. All subsequent fields must be flagged "VARIABLE OFFSET".
2466 #if 0
2467 void preset_field_type_size(LttTracefile *tf, LttEventType *event_type,
2468 off_t offset_root, off_t offset_parent,
2469 enum field_status *fixed_root, enum field_status *fixed_parent,
2470 LttField *field)
2471 {
2472 enum field_status local_fixed_root, local_fixed_parent;
2473 guint i;
2474 LttType *type;
2475
2476 g_assert(field->fixed_root == FIELD_UNKNOWN);
2477 g_assert(field->fixed_parent == FIELD_UNKNOWN);
2478 g_assert(field->fixed_size == FIELD_UNKNOWN);
2479
2480 type = field->field_type;
2481
2482 field->fixed_root = *fixed_root;
2483 if(field->fixed_root == FIELD_FIXED)
2484 field->offset_root = offset_root;
2485 else
2486 field->offset_root = 0;
2487
2488 field->fixed_parent = *fixed_parent;
2489 if(field->fixed_parent == FIELD_FIXED)
2490 field->offset_parent = offset_parent;
2491 else
2492 field->offset_parent = 0;
2493
2494 size_t current_root_offset;
2495 size_t current_offset;
2496 enum field_status current_child_status, final_child_status;
2497 size_t max_size;
2498
2499 switch(type->type_class) {
2500 case LTT_INT:
2501 case LTT_UINT:
2502 case LTT_FLOAT:
2503 case LTT_ENUM:
2504 field->field_size = ltt_type_size(tf->trace, type);
2505 field->fixed_size = FIELD_FIXED;
2506 break;
2507 case LTT_POINTER:
2508 field->field_size = (off_t)event_type->facility->pointer_size;
2509 field->fixed_size = FIELD_FIXED;
2510 break;
2511 case LTT_LONG:
2512 case LTT_ULONG:
2513 field->field_size = (off_t)event_type->facility->long_size;
2514 field->fixed_size = FIELD_FIXED;
2515 break;
2516 case LTT_SIZE_T:
2517 case LTT_SSIZE_T:
2518 case LTT_OFF_T:
2519 field->field_size = (off_t)event_type->facility->size_t_size;
2520 field->fixed_size = FIELD_FIXED;
2521 break;
2522 case LTT_SEQUENCE:
2523 local_fixed_root = FIELD_VARIABLE;
2524 local_fixed_parent = FIELD_VARIABLE;
2525 preset_field_type_size(tf, event_type,
2526 0, 0,
2527 &local_fixed_root, &local_fixed_parent,
2528 field->child[0]);
2529 field->fixed_size = FIELD_VARIABLE;
2530 field->field_size = 0;
2531 *fixed_root = FIELD_VARIABLE;
2532 *fixed_parent = FIELD_VARIABLE;
2533 break;
2534 case LTT_STRING:
2535 field->fixed_size = FIELD_VARIABLE;
2536 field->field_size = 0;
2537 *fixed_root = FIELD_VARIABLE;
2538 *fixed_parent = FIELD_VARIABLE;
2539 break;
2540 case LTT_ARRAY:
2541 local_fixed_root = FIELD_VARIABLE;
2542 local_fixed_parent = FIELD_VARIABLE;
2543 preset_field_type_size(tf, event_type,
2544 0, 0,
2545 &local_fixed_root, &local_fixed_parent,
2546 field->child[0]);
2547 field->fixed_size = field->child[0]->fixed_size;
2548 if(field->fixed_size == FIELD_FIXED) {
2549 field->field_size = type->element_number * field->child[0]->field_size;
2550 } else {
2551 field->field_size = 0;
2552 *fixed_root = FIELD_VARIABLE;
2553 *fixed_parent = FIELD_VARIABLE;
2554 }
2555 break;
2556 case LTT_STRUCT:
2557 current_root_offset = field->offset_root;
2558 current_offset = 0;
2559 current_child_status = FIELD_FIXED;
2560 for(i=0;i<type->element_number;i++) {
2561 preset_field_type_size(tf, event_type,
2562 current_root_offset, current_offset,
2563 fixed_root, &current_child_status,
2564 field->child[i]);
2565 if(current_child_status == FIELD_FIXED) {
2566 current_root_offset += field->child[i]->field_size;
2567 current_offset += field->child[i]->field_size;
2568 } else {
2569 current_root_offset = 0;
2570 current_offset = 0;
2571 }
2572 }
2573 if(current_child_status != FIELD_FIXED) {
2574 *fixed_parent = current_child_status;
2575 field->field_size = 0;
2576 field->fixed_size = current_child_status;
2577 } else {
2578 field->field_size = current_offset;
2579 field->fixed_size = FIELD_FIXED;
2580 }
2581 break;
2582 case LTT_UNION:
2583 current_root_offset = field->offset_root;
2584 current_offset = 0;
2585 max_size = 0;
2586 final_child_status = FIELD_FIXED;
2587 for(i=0;i<type->element_number;i++) {
2588 enum field_status current_root_child_status = FIELD_FIXED;
2589 enum field_status current_child_status = FIELD_FIXED;
2590 preset_field_type_size(tf, event_type,
2591 current_root_offset, current_offset,
2592 &current_root_child_status, &current_child_status,
2593 field->child[i]);
2594 if(current_child_status != FIELD_FIXED)
2595 final_child_status = current_child_status;
2596 else
2597 max_size = max(max_size, field->child[i]->field_size);
2598 }
2599 if(final_child_status != FIELD_FIXED) {
2600 g_error("LTTV does not support variable size fields in unions.");
2601 /* This will stop the application. */
2602 *fixed_root = final_child_status;
2603 *fixed_parent = final_child_status;
2604 field->field_size = 0;
2605 field->fixed_size = current_child_status;
2606 } else {
2607 field->field_size = max_size;
2608 field->fixed_size = FIELD_FIXED;
2609 }
2610 break;
2611 }
2612
2613 }
2614 #endif //0
2615
2616 /*****************************************************************************
2617 *Function name
2618 * check_fields_compatibility : Check for compatibility between two fields :
2619 * do they use the same inner structure ?
2620 *Input params
2621 * event_type1 : event type
2622 * event_type2 : event type
2623 * field1 : field
2624 * field2 : field
2625 *Returns : 0 if identical
2626 * 1 if not.
2627 ****************************************************************************/
2628 // this function checks for equality of field types. Therefore, it does not use
2629 // per se offsets. For instance, an aligned version of a structure is
2630 // compatible with an unaligned version of the same structure.
2631 gint check_fields_compatibility(LttEventType *event_type1,
2632 LttEventType *event_type2,
2633 LttField *field1, LttField *field2)
2634 {
2635 guint different = 0;
2636 LttType *type1;
2637 LttType *type2;
2638
2639 if(field1 == NULL) {
2640 if(field2 == NULL) goto end;
2641 else {
2642 different = 1;
2643 goto end;
2644 }
2645 } else if(field2 == NULL) {
2646 different = 1;
2647 goto end;
2648 }
2649
2650 type1 = &field1->field_type;
2651 type2 = &field2->field_type;
2652
2653 if(type1->type_class != type2->type_class) {
2654 different = 1;
2655 goto end;
2656 }
2657
2658 switch(type1->type_class) {
2659 case LTT_INT_FIXED:
2660 case LTT_UINT_FIXED:
2661 case LTT_POINTER:
2662 case LTT_CHAR:
2663 case LTT_UCHAR:
2664 case LTT_SHORT:
2665 case LTT_USHORT:
2666 case LTT_INT:
2667 case LTT_UINT:
2668 case LTT_LONG:
2669 case LTT_ULONG:
2670 case LTT_SIZE_T:
2671 case LTT_SSIZE_T:
2672 case LTT_OFF_T:
2673 case LTT_FLOAT:
2674 case LTT_ENUM:
2675 if(field1->field_size != field2->field_size)
2676 different = 1;
2677 break;
2678 case LTT_STRING:
2679 break;
2680 case LTT_ARRAY:
2681 {
2682 LttField *child1 = &g_array_index(type1->fields, LttField, 0);
2683 LttField *child2 = &g_array_index(type2->fields, LttField, 0);
2684
2685 if(type1->size != type2->size)
2686 different = 1;
2687 if(check_fields_compatibility(event_type1, event_type2, child1, child2))
2688 different = 1;
2689 }
2690 break;
2691 case LTT_SEQUENCE:
2692 {
2693 LttField *child1 = &g_array_index(type1->fields, LttField, 1);
2694 LttField *child2 = &g_array_index(type2->fields, LttField, 1);
2695
2696 if(check_fields_compatibility(event_type1, event_type2, child1, child2))
2697 different = 1;
2698 }
2699 break;
2700 case LTT_STRUCT:
2701 case LTT_UNION:
2702 {
2703 LttField *child;
2704 guint i;
2705
2706 if(type1->fields->len != type2->fields->len) {
2707 different = 1;
2708 goto end;
2709 }
2710
2711 for(i=0; i< type1->fields->len; i++) {
2712 LttField *child1;
2713 LttField *child2;
2714 child1 = &g_array_index(type1->fields, LttField, i);
2715 child2 = &g_array_index(type2->fields, LttField, i);
2716 different = check_fields_compatibility(event_type1,
2717 event_type2, child1, child2);
2718
2719 if(different) break;
2720 }
2721 }
2722 break;
2723 case LTT_NONE:
2724 default:
2725 g_error("precompute_fields_offsets : unknown type");
2726 }
2727
2728 end:
2729 return different;
2730 }
2731
2732
2733 #if 0
2734 gint check_fields_compatibility(LttEventType *event_type1,
2735 LttEventType *event_type2,
2736 LttField *field1, LttField *field2)
2737 {
2738 guint different = 0;
2739 guint i;
2740 LttType *type1;
2741 LttType *type2;
2742
2743 if(field1 == NULL) {
2744 if(field2 == NULL) goto end;
2745 else {
2746 different = 1;
2747 goto end;
2748 }
2749 } else if(field2 == NULL) {
2750 different = 1;
2751 goto end;
2752 }
2753
2754 g_assert(field1->fixed_root != FIELD_UNKNOWN);
2755 g_assert(field2->fixed_root != FIELD_UNKNOWN);
2756 g_assert(field1->fixed_parent != FIELD_UNKNOWN);
2757 g_assert(field2->fixed_parent != FIELD_UNKNOWN);
2758 g_assert(field1->fixed_size != FIELD_UNKNOWN);
2759 g_assert(field2->fixed_size != FIELD_UNKNOWN);
2760
2761 type1 = field1->field_type;
2762 type2 = field2->field_type;
2763
2764 if(type1->type_class != type2->type_class) {
2765 different = 1;
2766 goto end;
2767 }
2768 if(type1->element_name != type2->element_name) {
2769 different = 1;
2770 goto end;
2771 }
2772
2773 switch(type1->type_class) {
2774 case LTT_INT:
2775 case LTT_UINT:
2776 case LTT_FLOAT:
2777 case LTT_POINTER:
2778 case LTT_LONG:
2779 case LTT_ULONG:
2780 case LTT_SIZE_T:
2781 case LTT_SSIZE_T:
2782 case LTT_OFF_T:
2783 if(field1->field_size != field2->field_size) {
2784 different = 1;
2785 goto end;
2786 }
2787 break;
2788 case LTT_ENUM:
2789 if(type1->element_number != type2->element_number) {
2790 different = 1;
2791 goto end;
2792 }
2793 for(i=0;i<type1->element_number;i++) {
2794 if(type1->enum_strings[i] != type2->enum_strings[i]) {
2795 different = 1;
2796 goto end;
2797 }
2798 }
2799 break;
2800 case LTT_SEQUENCE:
2801 /* Two elements : size and child */
2802 g_assert(type1->element_number != type2->element_number);
2803 for(i=0;i<type1->element_number;i++) {
2804 if(check_fields_compatibility(event_type1, event_type2,
2805 field1->child[0], field2->child[0])) {
2806 different = 1;
2807 goto end;
2808 }
2809 }
2810 break;
2811 case LTT_STRING:
2812 break;
2813 case LTT_ARRAY:
2814 if(field1->field_size != field2->field_size) {
2815 different = 1;
2816 goto end;
2817 }
2818 /* Two elements : size and child */
2819 g_assert(type1->element_number != type2->element_number);
2820 for(i=0;i<type1->element_number;i++) {
2821 if(check_fields_compatibility(event_type1, event_type2,
2822 field1->child[0], field2->child[0])) {
2823 different = 1;
2824 goto end;
2825 }
2826 }
2827 break;
2828 case LTT_STRUCT:
2829 case LTT_UNION:
2830 if(type1->element_number != type2->element_number) {
2831 different = 1;
2832 break;
2833 }
2834 for(i=0;i<type1->element_number;i++) {
2835 if(check_fields_compatibility(event_type1, event_type2,
2836 field1->child[0], field2->child[0])) {
2837 different = 1;
2838 goto end;
2839 }
2840 }
2841 break;
2842 }
2843 end:
2844 return different;
2845 }
2846 #endif //0
2847
2848
2849 /*****************************************************************************
2850 *Function name
2851 * ltt_get_int : get an integer number
2852 *Input params
2853 * reverse_byte_order: must we reverse the byte order ?
2854 * size : the size of the integer
2855 * ptr : the data pointer
2856 *Return value
2857 * gint64 : a 64 bits integer
2858 ****************************************************************************/
2859
2860 gint64 ltt_get_int(gboolean reverse_byte_order, gint size, void *data)
2861 {
2862 gint64 val;
2863
2864 switch(size) {
2865 case 1: val = *((gint8*)data); break;
2866 case 2: val = ltt_get_int16(reverse_byte_order, data); break;
2867 case 4: val = ltt_get_int32(reverse_byte_order, data); break;
2868 case 8: val = ltt_get_int64(reverse_byte_order, data); break;
2869 default: val = ltt_get_int64(reverse_byte_order, data);
2870 g_critical("get_int : integer size %d unknown", size);
2871 break;
2872 }
2873
2874 return val;
2875 }
2876
2877 /*****************************************************************************
2878 *Function name
2879 * ltt_get_uint : get an unsigned integer number
2880 *Input params
2881 * reverse_byte_order: must we reverse the byte order ?
2882 * size : the size of the integer
2883 * ptr : the data pointer
2884 *Return value
2885 * guint64 : a 64 bits unsigned integer
2886 ****************************************************************************/
2887
2888 guint64 ltt_get_uint(gboolean reverse_byte_order, gint size, void *data)
2889 {
2890 guint64 val;
2891
2892 switch(size) {
2893 case 1: val = *((gint8*)data); break;
2894 case 2: val = ltt_get_uint16(reverse_byte_order, data); break;
2895 case 4: val = ltt_get_uint32(reverse_byte_order, data); break;
2896 case 8: val = ltt_get_uint64(reverse_byte_order, data); break;
2897 default: val = ltt_get_uint64(reverse_byte_order, data);
2898 g_critical("get_uint : unsigned integer size %d unknown",
2899 size);
2900 break;
2901 }
2902
2903 return val;
2904 }
2905
2906
2907 /* get the node name of the system */
2908
2909 char * ltt_trace_system_description_node_name (LttSystemDescription * s)
2910 {
2911 return s->node_name;
2912 }
2913
2914
2915 /* get the domain name of the system */
2916
2917 char * ltt_trace_system_description_domain_name (LttSystemDescription * s)
2918 {
2919 return s->domain_name;
2920 }
2921
2922
2923 /* get the description of the system */
2924
2925 char * ltt_trace_system_description_description (LttSystemDescription * s)
2926 {
2927 return s->description;
2928 }
2929
2930
2931 /* get the NTP corrected start time of the trace */
2932 LttTime ltt_trace_start_time(LttTrace *t)
2933 {
2934 return t->start_time;
2935 }
2936
2937 /* get the monotonic start time of the trace */
2938 LttTime ltt_trace_start_time_monotonic(LttTrace *t)
2939 {
2940 return t->start_time_from_tsc;
2941 }
2942
2943 LttTracefile *ltt_tracefile_new()
2944 {
2945 return g_new(LttTracefile, 1);
2946 }
2947
2948 void ltt_tracefile_destroy(LttTracefile *tf)
2949 {
2950 g_free(tf);
2951 }
2952
2953 void ltt_tracefile_copy(LttTracefile *dest, const LttTracefile *src)
2954 {
2955 *dest = *src;
2956 }
2957
2958 /* Before library loading... */
2959
2960 static void __attribute__((constructor)) init(void)
2961 {
2962 LTT_FACILITY_NAME_HEARTBEAT = g_quark_from_string("heartbeat");
2963 LTT_EVENT_NAME_HEARTBEAT = g_quark_from_string("heartbeat");
2964
2965 LTT_TRACEFILE_NAME_FACILITIES = g_quark_from_string("/control/facilities");
2966 }
2967
This page took 0.087551 seconds and 5 git commands to generate.