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