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