get new block fix
[lttv.git] / ltt / branches / poly / ltt-newlib / tracefile.c
CommitLineData
54ecbf38 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 program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License Version 2 as
8 * published by the Free Software Foundation;
9 *
10 * This program 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
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
18 * MA 02111-1307, USA.
19 */
20
21#ifdef HAVE_CONFIG_H
22#include <config.h>
23#endif
24
25#include <stdio.h>
26#include <fcntl.h>
27#include <string.h>
28#include <dirent.h>
29#include <sys/stat.h>
30#include <sys/types.h>
31#include <errno.h>
32#include <unistd.h>
33#include <math.h>
34#include <glib.h>
35#include <malloc.h>
36#include <sys/mman.h>
37
38// For realpath
39#include <limits.h>
40#include <stdlib.h>
41
42
43#include "parser.h"
44#include <ltt/ltt.h>
45#include "ltt-private.h"
46#include <ltt/trace.h>
47#include <ltt/facility.h>
48#include <ltt/event.h>
49#include <ltt/type.h>
50#include <ltt/ltt-types.h>
51
52
53/* Facility names used in this file */
54
55GQuark LTT_FACILITY_NAME_HEARTBEAT,
56 LTT_EVENT_NAME_HEARTBEAT;
57
58#ifndef g_open
59#define g_open open
60#endif
61
62
63#define __UNUSED__ __attribute__((__unused__))
64
65#define g_info(format...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, format)
66#define g_debug(format...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, format)
67
68#define g_close close
69
70/* obtain the time of an event */
71
72static inline LttTime getEventTime(LttTracefile * tf);
73
74
75/* set the offset of the fields belonging to the event,
76 need the information of the archecture */
77void setFieldsOffset(LttTracefile *tf,LttEventType *evT,void *evD,LttTrace *t);
78
79/* get the size of the field type according to the archtecture's
80 size and endian type(info of the archecture) */
81static inline gint getFieldtypeSize(LttTracefile * tf,
82 LttEventType * evT, gint offsetRoot,
83 gint offsetParent, LttField *fld, void *evD, LttTrace* t);
84
85/* read a fixed size or a block information from the file (fd) */
86int map_block(LttTracefile * tf, unsigned int block_num);
87
88/* calculate cycles per nsec for current block */
89void getCyclePerNsec(LttTracefile * t);
90
91/* reinitialize the info of the block which is already in the buffer */
92void updateTracefile(LttTracefile * tf);
93
94/* go to the next event */
95int skipEvent(LttTracefile * t);
96
97
98/* Functions to parse system.xml file (using glib xml parser) */
99static void parser_start_element (GMarkupParseContext __UNUSED__ *context,
100 const gchar *element_name,
101 const gchar **attribute_names,
102 const gchar **attribute_values,
103 gpointer user_data,
104 GError **error)
105{
106 int i=0;
107 LttSystemDescription* des = (LttSystemDescription* )user_data;
108 if(strcmp("system", element_name)){
109 *error = g_error_new(G_MARKUP_ERROR,
110 G_LOG_LEVEL_WARNING,
111 "This is not system.xml file");
112 return;
113 }
114
115 while(attribute_names[i]){
116 if(strcmp("node_name", attribute_names[i])==0){
117 des->node_name = g_strdup(attribute_values[i]);
118 }else if(strcmp("domainname", attribute_names[i])==0){
119 des->domain_name = g_strdup(attribute_values[i]);
120 }else if(strcmp("cpu", attribute_names[i])==0){
121 des->nb_cpu = atoi(attribute_values[i]);
122 }else if(strcmp("arch_size", attribute_names[i])==0){
123 if(strcmp(attribute_values[i],"LP32") == 0) des->size = LTT_LP32;
124 else if(strcmp(attribute_values[i],"ILP32") == 0) des->size = LTT_ILP32;
125 else if(strcmp(attribute_values[i],"LP64") == 0) des->size = LTT_LP64;
126 else if(strcmp(attribute_values[i],"ILP64") == 0) des->size = LTT_ILP64;
127 else if(strcmp(attribute_values[i],"UNKNOWN") == 0) des->size = LTT_UNKNOWN;
128 }else if(strcmp("endian", attribute_names[i])==0){
129 if(strcmp(attribute_values[i],"LITTLE_ENDIAN") == 0)
130 des->endian = LTT_LITTLE_ENDIAN;
131 else if(strcmp(attribute_values[i],"BIG_ENDIAN") == 0)
132 des->endian = LTT_BIG_ENDIAN;
133 }else if(strcmp("kernel_name", attribute_names[i])==0){
134 des->kernel_name = g_strdup(attribute_values[i]);
135 }else if(strcmp("kernel_release", attribute_names[i])==0){
136 des->kernel_release = g_strdup(attribute_values[i]);
137 }else if(strcmp("kernel_version", attribute_names[i])==0){
138 des->kernel_version = g_strdup(attribute_values[i]);
139 }else if(strcmp("machine", attribute_names[i])==0){
140 des->machine = g_strdup(attribute_values[i]);
141 }else if(strcmp("processor", attribute_names[i])==0){
142 des->processor = g_strdup(attribute_values[i]);
143 }else if(strcmp("hardware_platform", attribute_names[i])==0){
144 des->hardware_platform = g_strdup(attribute_values[i]);
145 }else if(strcmp("operating_system", attribute_names[i])==0){
146 des->operating_system = g_strdup(attribute_values[i]);
147 }else if(strcmp("ltt_major_version", attribute_names[i])==0){
148 des->ltt_major_version = atoi(attribute_values[i]);
149 }else if(strcmp("ltt_minor_version", attribute_names[i])==0){
150 des->ltt_minor_version = atoi(attribute_values[i]);
151 }else if(strcmp("ltt_block_size", attribute_names[i])==0){
152 des->ltt_block_size = atoi(attribute_values[i]);
153 }else{
154 *error = g_error_new(G_MARKUP_ERROR,
155 G_LOG_LEVEL_WARNING,
156 "Not a valid attribute");
157 return;
158 }
159 i++;
160 }
161}
162
163static void parser_characters (GMarkupParseContext __UNUSED__ *context,
164 const gchar *text,
165 gsize __UNUSED__ text_len,
166 gpointer user_data,
167 GError __UNUSED__ **error)
168{
169 LttSystemDescription* des = (LttSystemDescription* )user_data;
170 des->description = g_strdup(text);
171}
172
173
174/*****************************************************************************
175 *Function name
176 * ltt_tracefile_open : open a trace file, construct a LttTracefile
177 *Input params
178 * t : the trace containing the tracefile
179 * fileName : path name of the trace file
180 * tf : the tracefile structure
181 *Return value
182 * : 0 for success, -1 otherwise.
183 ****************************************************************************/
184
185int ltt_tracefile_open(LttTrace *t, gchar * fileName, LttTracefile *tf)
186{
187 struct stat lTDFStat; /* Trace data file status */
188 struct ltt_block_start_header *header;
189
190 //open the file
191 tf->name = g_quark_from_string(fileName);
192 tf->trace = t;
193 tf->fd = g_open(fileName, O_RDONLY, 0);
194 if(tf->fd < 0){
195 g_warning("Unable to open input data file %s\n", fileName);
196 goto end;
197 }
198
199 // Get the file's status
200 if(fstat(tf->fd, &lTDFStat) < 0){
201 g_warning("Unable to get the status of the input data file %s\n", fileName);
202 goto close_file;
203 }
204
205 // Is the file large enough to contain a trace
206 if(lTDFStat.st_size < (off_t)(sizeof(BlockStart))){
207 g_print("The input data file %s does not contain a trace\n", fileName);
208 goto close_file;
209 }
210
211 /* Temporarily map the buffer start header to get trace information */
212 /* Multiple of pages aligned head */
213 tf->buffer.head = mmap(0, sizeof(struct ltt_block_start_header), PROT_READ,
214 tf->fd, 0);
215 if(tf->buffer == NULL) {
216 perror("Error in allocating memory for buffer of tracefile %s\n", fileName);
217 goto close_file;
218 }
219 g_assert(tf->buffer.head & (8-1) == 0); // make sure it's aligned.
220
221 header = (struct ltt_block_start_header*)tf->buffer.head;
222
223 if(header->traceset.magic_number == LTT_MAGIC_NUMBER)
224 tf->reverse_bo = 0;
225 else if(header->traceset.magic_number == LTT_REV_MAGIC_NUMBER)
226 tf->reverse_bo = 1;
227 else /* invalid magic number, bad tracefile ! */
228 goto unmap_file;
229
230 //store the size of the file
231 tf->file_size = lTDFStat.st_size;
232 tf->block_size = header->buf_size;
233 tf->block_number = tf->file_size / tf->block_size;
234
235 vfree(tf->buffer.head);
236 tf->buffer.head = NULL;
237
238 //read the first block
239 if(map_block(tf,0)) {
240 perror("Cannot map block %u for tracefile %s\n", 0, fileName);
241 goto close_file;
242 }
243
244 return 0;
245
246 /* Error */
247unmap_file:
248 munmap(tf->buffer.head, sizeof(struct ltt_block_start_header));
249close_file:
250 g_close(tf->fd);
251end:
252 return -1;
253}
254
255
256/*****************************************************************************
257 *Open control and per cpu tracefiles
258 ****************************************************************************/
259
260void ltt_tracefile_open_cpu(LttTrace *t, gchar * tracefile_name)
261{
262 LttTracefile * tf;
263 tf = ltt_tracefile_open(t,tracefile_name);
264 if(!tf) return;
265 t->per_cpu_tracefile_number++;
266 g_ptr_array_add(t->per_cpu_tracefiles, tf);
267}
268
269gint ltt_tracefile_open_control(LttTrace *t, gchar * control_name)
270{
271 LttTracefile * tf;
272 LttEvent ev;
273 LttFacility * f;
274 void * pos;
275 FacilityLoad fLoad;
276 unsigned int i;
277
278 tf = ltt_tracefile_open(t,control_name);
279 if(!tf) {
280 g_warning("ltt_tracefile_open_control : bad file descriptor");
281 return -1;
282 }
283 t->control_tracefile_number++;
284 g_ptr_array_add(t->control_tracefiles,tf);
285
286 //parse facilities tracefile to get base_id
287 if(strcmp(&control_name[strlen(control_name)-10],"facilities") ==0){
288 while(1){
289 if(!ltt_tracefile_read(tf,&ev)) return 0; // end of file
290
291 if(ev.event_id == TRACE_FACILITY_LOAD){
292 pos = ev.data;
293 fLoad.name = (gchar*)pos;
294 fLoad.checksum = *(LttChecksum*)(pos + strlen(fLoad.name));
295 fLoad.base_code = *(guint32 *)(pos + strlen(fLoad.name) + sizeof(LttChecksum));
296
297 for(i=0;i<t->facility_number;i++){
298 f = (LttFacility*)g_ptr_array_index(t->facilities,i);
299 if(strcmp(f->name,fLoad.name)==0 && fLoad.checksum==f->checksum){
300 f->base_id = fLoad.base_code;
301 break;
302 }
303 }
304 if(i==t->facility_number) {
305 g_warning("Facility: %s, checksum: %u is not found",
306 fLoad.name,(unsigned int)fLoad.checksum);
307 return -1;
308 }
309 }else if(ev.event_id == TRACE_BLOCK_START){
310 continue;
311 }else if(ev.event_id == TRACE_BLOCK_END){
312 break;
313 }else {
314 g_warning("Not valid facilities trace file");
315 return -1;
316 }
317 }
318 }
319 return 0;
320}
321
322/*****************************************************************************
323 *Function name
324 * ltt_tracefile_close: close a trace file,
325 *Input params
326 * t : tracefile which will be closed
327 ****************************************************************************/
328
329void ltt_tracefile_close(LttTracefile *t)
330{
331 if(t->buffer.head != NULL)
332 munmap(t->buffer.head, t->buf_size);
333 g_close(t->fd);
334}
335
336
337/*****************************************************************************
338 *Get system information
339 ****************************************************************************/
340gint getSystemInfo(LttSystemDescription* des, gchar * pathname)
341{
342 int fd;
343 GIOChannel *iochan;
344 gchar *buf = NULL;
345 gsize length;
346
347 GMarkupParseContext * context;
348 GError * error = NULL;
349 GMarkupParser markup_parser =
350 {
351 parser_start_element,
352 NULL,
353 parser_characters,
354 NULL, /* passthrough */
355 NULL /* error */
356 };
357
358 fd = g_open(pathname, O_RDONLY, 0);
359 if(fd == -1){
360 g_warning("Can not open file : %s\n", pathname);
361 return -1;
362 }
363
364 iochan = g_io_channel_unix_new(fd);
365
366 context = g_markup_parse_context_new(&markup_parser, 0, des,NULL);
367
368 //while(fgets(buf,DIR_NAME_SIZE, fp) != NULL){
369 while(g_io_channel_read_line(iochan, &buf, &length, NULL, &error)
370 != G_IO_STATUS_EOF) {
371
372 if(error != NULL) {
373 g_warning("Can not read xml file: \n%s\n", error->message);
374 g_error_free(error);
375 }
376 if(!g_markup_parse_context_parse(context, buf, length, &error)){
377 if(error != NULL) {
378 g_warning("Can not parse xml file: \n%s\n", error->message);
379 g_error_free(error);
380 }
381 g_markup_parse_context_free(context);
382
383 g_io_channel_shutdown(iochan, FALSE, &error); /* No flush */
384 if(error != NULL) {
385 g_warning("Can not close file: \n%s\n", error->message);
386 g_error_free(error);
387 }
388
389 close(fd);
390 return -1;
391 }
392 }
393 g_markup_parse_context_free(context);
394
395 g_io_channel_shutdown(iochan, FALSE, &error); /* No flush */
396 if(error != NULL) {
397 g_warning("Can not close file: \n%s\n", error->message);
398 g_error_free(error);
399 }
400
401 g_close(fd);
402
403 g_free(buf);
404 return 0;
405}
406
407/*****************************************************************************
408 *The following functions get facility/tracefile information
409 ****************************************************************************/
410
411gint getFacilityInfo(LttTrace *t, gchar* eventdefs)
412{
413 GDir * dir;
414 const gchar * name;
415 unsigned int i,j;
416 LttFacility * f;
417 LttEventType * et;
418 gchar fullname[DIR_NAME_SIZE];
419 GError * error = NULL;
420
421 dir = g_dir_open(eventdefs, 0, &error);
422
423 if(error != NULL) {
424 g_warning("Can not open directory: %s, %s\n", eventdefs, error->message);
425 g_error_free(error);
426 return -1;
427 }
428
429 while((name = g_dir_read_name(dir)) != NULL){
430 if(!g_pattern_match_simple("*.xml", name)) continue;
431 strcpy(fullname,eventdefs);
432 strcat(fullname,name);
433 ltt_facility_open(t,fullname);
434 }
435 g_dir_close(dir);
436
437 for(j=0;j<t->facility_number;j++){
438 f = (LttFacility*)g_ptr_array_index(t->facilities, j);
439 for(i=0; i<f->event_number; i++){
440 et = f->events[i];
441 setFieldsOffset(NULL, et, NULL, t);
442 }
443 }
444 return 0;
445}
446
447/*****************************************************************************
448 *A trace is specified as a pathname to the directory containing all the
449 *associated data (control tracefiles, per cpu tracefiles, event
450 *descriptions...).
451 *
452 *When a trace is closed, all the associated facilities, types and fields
453 *are released as well.
454 */
455
456
457/****************************************************************************
458 * get_absolute_pathname
459 *
460 * return the unique pathname in the system
461 *
462 * MD : Fixed this function so it uses realpath, dealing well with
463 * forgotten cases (.. were not used correctly before).
464 *
465 ****************************************************************************/
466void get_absolute_pathname(const gchar *pathname, gchar * abs_pathname)
467{
468 abs_pathname[0] = '\0';
469
470 if ( realpath (pathname, abs_pathname) != NULL)
471 return;
472 else
473 {
474 /* error, return the original path unmodified */
475 strcpy(abs_pathname, pathname);
476 return;
477 }
478 return;
479}
480
481/* Search for something like : .*_.*
482 *
483 * The left side is the name, the right side is the number.
484 */
485
486int get_tracefile_name_number(const gchar *raw_name,
487 GQuark *name,
488 guint *num)
489{
490 guint raw_name_len = strlen(raw_name);
491 gchar char_name[PATH_MAX]
492 gchar *digit_begin;
493 int i;
494 int underscore_pos;
495 long int cpu_num;
496 gchar *endptr;
497
498 for(i=raw_name_len-1;i>=0;i--) {
499 if(raw_name[i] == '_') break;
500 }
501 if(i==0) /* Either not found or name length is 0 */
502 return -1;
503 underscore_pos = i;
504
505 cpu_num = strtol(raw_name+underscore_pos+1, &endptr, 10);
506
507 if(endptr == raw_name+underscore_pos+1)
508 return -1; /* No digit */
509 if(cpu_num == LONG_MIN || cpu_num == LONG_MAX)
510 return -1; /* underflow / overflow */
511
512 char_name = strncpy(char_name, raw_name, underscore_pos);
513
514 *name = g_quark_from_string(char_name);
515 *num = cpu_num;
516
517 return 0;
518}
519
520
521void ltt_tracefile_group_destroy(gpointer data)
522{
523 GArray *group = (GArray *)data;
524 int i;
525 LttTracefile *tf;
526
527 for(i=0; i<group->len; i++) {
528 tf = &g_array_index (group, LttTracefile, i);
529 if(tf->cpu_online)
530 ltt_tracefile_close(tf);
531 }
532}
533
534gboolean ltt_tracefile_group_has_cpu_online(gpointer data)
535{
536 GArray *group = (GArray *)data;
537 int i;
538 LttTracefile *tf;
539
540 for(i=0; i<group->len; i++) {
541 tf = &g_array_index (group, LttTracefile, i);
542 if(tf->cpu_online) return 1;
543 }
544 return 0;
545}
546
547
548/* Open each tracefile under a specific directory. Put them in a
549 * GData : permits to access them using their tracefile group pathname.
550 * i.e. access control/modules tracefile group by index :
551 * "control/module".
552 *
553 * A tracefile group is simply an array where all the per cpu tracefiles sits.
554 */
555
556static int open_tracefiles(LttTrace *trace, char *root_path, GData *tracefiles)
557{
558 DIR *dir = opendir(root_path);
559 struct dirent *entry;
560 struct stat stat_buf;
561 int ret;
562 char path[PATH_MAX];
563 int path_len;
564 char *path_ptr;
565
566 if(channel_dir == NULL) {
567 perror(subchannel_name);
568 return ENOENT;
569 }
570
571 strncpy(path, root_path, PATH_MAX-1);
572 path_len = strlen(path);
573 path[path_len] = '/';
574 path_len++;
575 path_ptr = path + path_len;
576
577 while((entry = readdir(channel_dir)) != NULL) {
578
579 if(entry->d_name[0] == '.') continue;
580
581 strncpy(path_ptr, entry->d_name, PATH_MAX - path_len);
582
583 ret = stat(path, &stat_buf);
584 if(ret == -1) {
585 perror(path);
586 continue;
587 }
588
589 g_debug("Tracefile file or directory : %s\n", path);
590
591 if(S_ISDIR(stat_buf.st_mode)) {
592
593 g_debug("Entering subdirectory...\n");
594 ret = open_tracefiles(path, tracefiles);
595 if(ret < 0) continue;
596 } else if(S_ISREG(stat_buf.st_mode)) {
597 g_debug("Opening file.\n");
598
599 GQuark name;
600 guint num;
601 GArray *group;
602 LttTracefile *tf;
603 guint len;
604
605 if(get_tracefile_name_number(path, &name, &num))
606 continue; /* invalid name */
607
608 group = g_datalist_get_data(tracefiles, name);
609 if(group == NULL) {
610 /* Elements are automatically cleared when the array is allocated.
611 * It makes the cpu_online variable set to 0 : cpu offline, by default.
612 */
613 group = g_array_sized_new (FALSE, TRUE, sizeof(LttTracefile), 10);
614 g_datalist_set_data_full(tracefiles, name,
615 group, ltt_tracefile_group_destroy);
616 }
617 /* Add the per cpu tracefile to the named group */
618 unsigned int old_len = group->len;
619 if(num+1 > old_len)
620 g_array_set_size(group, num+1);
621 tf = &g_array_index (group, LttTracefile, num);
622
623 if(ltt_tracefile_open(trace, path, tf)) {
624 g_info("Error opening tracefile %s", path);
625 g_array_set_size(group, old_len);
626
627 if(!ltt_tracefile_group_has_cpu_online(group))
628 g_datalist_remove_data(tracefiles, name);
629
630 continue; /* error opening the tracefile : bad magic number ? */
631 }
632 tf->cpu_online = 1;
633 }
634 }
635
636 closedir(dir);
637
638 return 0;
639}
640
641LttTrace *ltt_trace_open(const gchar *pathname)
642{
643 gchar abs_path[PATH_MAX];
644 LttTrace * t;
645 LttTracefile tf;
646 GArray *group;
647 int i;
648
649 LttTrace * t = g_new(LttTrace, 1);
650 if(!t) goto alloc_error;
651
652 get_absolute_pathname(pathname, abs_path);
653 t->pathname = g_quark_from_string(abs_path);
654
655 /* Open all the tracefiles */
656 g_datalist_init(t->tracefiles);
657 if(open_tracefiles(t, abs_path, t->tracefiles))
658 goto open_error;
659
660 /* Load trace XML event descriptions */
661 //TODO
662
663 /* Parse each trace control/facilitiesN files : get runtime fac. info */
664 group = g_datalist_get_data(t->tracefiles, LTT_TRACEFILE_NAME_FACILITIES);
665 if(group == NULL) {
666 g_error("Trace %s has no facility tracefile", abs_path);
667 goto facilities_error;
668 }
669
670 for(i=0; i<group->len; i++) {
671 tf = &g_array_index (group, LttTracefile, i);
672 //TODO
673 process_facility_tracefile(tf);
674 }
675
676
677
678 return t;
679
680 /* Error handling */
681facilities_error:
682open_error:
683 g_datalist_clear(t->tracefiles);
684 g_free(t);
685alloc_error:
686 return NULL;
687
688
689
690 LttSystemDescription * sys_description;
691 gchar eventdefs[DIR_NAME_SIZE];
692 gchar info[DIR_NAME_SIZE];
693 gchar cpu[DIR_NAME_SIZE];
694 gchar tmp[DIR_NAME_SIZE];
695 gboolean has_slash = FALSE;
696
697 //establish the pathname to different directories
698 if(abs_path[strlen(abs_path)-1] == '/')has_slash = TRUE;
699 strcpy(eventdefs,abs_path);
700 if(!has_slash)strcat(eventdefs,"/");
701 strcat(eventdefs,"eventdefs/");
702
703 strcpy(info,abs_path);
704 if(!has_slash)strcat(info,"/");
705 strcat(info,"info/");
706
707 strcpy(control,abs_path);
708 if(!has_slash)strcat(control,"/");
709 strcat(control,"control/");
710
711 strcpy(cpu,abs_path);
712 if(!has_slash)strcat(cpu,"/");
713 strcat(cpu,"cpu/");
714
715 //new trace
716 sys_description = g_new(LttSystemDescription, 1);
717 t = g_new(LttTrace, 1);
718 t->pathname = g_strdup(abs_path);
719 t->facility_number = 0;
720 t->control_tracefile_number = 0;
721 t->per_cpu_tracefile_number = 0;
722 t->system_description = sys_description;
723 t->control_tracefiles = g_ptr_array_new();
724 t->per_cpu_tracefiles = g_ptr_array_new();
725 t->facilities = g_ptr_array_new();
726 //getDataEndianType(&(t->my_arch_size), &(t->my_arch_endian));
727
728 //get system description
729 strcpy(tmp,info);
730 strcat(tmp,"system.xml");
731 if(getSystemInfo(sys_description, tmp)) {
732 g_ptr_array_free(t->facilities, TRUE);
733 g_ptr_array_free(t->per_cpu_tracefiles, TRUE);
734 g_ptr_array_free(t->control_tracefiles, TRUE);
735 g_free(sys_description);
736 g_free(t->pathname);
737 g_free(t);
738 return NULL;
739 }
740
741 /* Set the reverse byte order between trace and reader */
742 if(sys_description->endian == LTT_LITTLE_ENDIAN
743 && G_BYTE_ORDER != G_LITTLE_ENDIAN) {
744 t->reverse_byte_order = 1;
745 } else if(sys_description->endian == LTT_BIG_ENDIAN
746 && G_BYTE_ORDER != G_BIG_ENDIAN) {
747 t->reverse_byte_order = 1;
748 } else t->reverse_byte_order = 0;
749
750 //get facilities info
751 if(getFacilityInfo(t,eventdefs)) {
752 g_ptr_array_free(t->facilities, TRUE);
753 g_ptr_array_free(t->per_cpu_tracefiles, TRUE);
754 g_ptr_array_free(t->control_tracefiles, TRUE);
755 g_free(sys_description);
756 g_free(t->pathname);
757 g_free(t);
758 return NULL;
759 }
760
761 //get control tracefile info
762 getControlFileInfo(t,control);
763 /*
764 if(getControlFileInfo(t,control)) {
765 g_ptr_array_free(t->facilities, TRUE);
766 g_ptr_array_free(t->per_cpu_tracefiles, TRUE);
767 g_ptr_array_free(t->control_tracefiles, TRUE);
768 g_free(sys_description);
769 g_free(t->pathname);
770 g_free(t);
771 return NULL;
772 }*/ // With fatal error
773
774 //get cpu tracefile info
775 if(getCpuFileInfo(t,cpu)) {
776 g_ptr_array_free(t->facilities, TRUE);
777 g_ptr_array_free(t->per_cpu_tracefiles, TRUE);
778 g_ptr_array_free(t->control_tracefiles, TRUE);
779 g_free(sys_description);
780 g_free(t->pathname);
781 g_free(t);
782 return NULL;
783 }
784
785 return t;
786}
787
788char * ltt_trace_name(LttTrace *t)
789{
790 return t->pathname;
791}
792
793
794/******************************************************************************
795 * When we copy a trace, we want all the opening actions to happen again :
796 * the trace will be reopened and totally independant from the original.
797 * That's why we call ltt_trace_open.
798 *****************************************************************************/
799LttTrace *ltt_trace_copy(LttTrace *self)
800{
801 return ltt_trace_open(self->pathname);
802}
803
804void ltt_trace_close(LttTrace *t)
805{
806 unsigned int i;
807 LttTracefile * tf;
808 LttFacility * f;
809
810 g_free(t->pathname);
811
812 //free system_description
813 g_free(t->system_description->description);
814 g_free(t->system_description->node_name);
815 g_free(t->system_description->domain_name);
816 g_free(t->system_description->kernel_name);
817 g_free(t->system_description->kernel_release);
818 g_free(t->system_description->kernel_version);
819 g_free(t->system_description->machine);
820 g_free(t->system_description->processor);
821 g_free(t->system_description->hardware_platform);
822 g_free(t->system_description->operating_system);
823 g_free(t->system_description);
824
825 //free control_tracefiles
826 for(i=0;i<t->control_tracefile_number;i++){
827 tf = (LttTracefile*)g_ptr_array_index(t->control_tracefiles,i);
828 ltt_tracefile_close(tf);
829 }
830 g_ptr_array_free(t->control_tracefiles, TRUE);
831
832 //free per_cpu_tracefiles
833 for(i=0;i<t->per_cpu_tracefile_number;i++){
834 tf = (LttTracefile*)g_ptr_array_index(t->per_cpu_tracefiles,i);
835 ltt_tracefile_close(tf);
836 }
837 g_ptr_array_free(t->per_cpu_tracefiles, TRUE);
838
839 //free facilities
840 for(i=0;i<t->facility_number;i++){
841 f = (LttFacility*)g_ptr_array_index(t->facilities,i);
842 ltt_facility_close(f);
843 }
844 g_ptr_array_free(t->facilities, TRUE);
845
846 g_free(t);
847
848 g_blow_chunks();
849}
850
851
852/*****************************************************************************
853 *Get the system description of the trace
854 ****************************************************************************/
855
856LttSystemDescription *ltt_trace_system_description(LttTrace *t)
857{
858 return t->system_description;
859}
860
861/*****************************************************************************
862 * The following functions discover the facilities of the trace
863 ****************************************************************************/
864
865unsigned ltt_trace_facility_number(LttTrace *t)
866{
867 return (unsigned)(t->facility_number);
868}
869
870LttFacility *ltt_trace_facility_get(LttTrace *t, unsigned i)
871{
872 return (LttFacility*)g_ptr_array_index(t->facilities, i);
873}
874
875/*****************************************************************************
876 *Function name
877 * ltt_trace_facility_find : find facilities in the trace
878 *Input params
879 * t : the trace
880 * name : facility name
881 *Output params
882 * position : position of the facility in the trace
883 *Return value
884 * : the number of facilities
885 ****************************************************************************/
886
887unsigned ltt_trace_facility_find(LttTrace *t, char *name, unsigned *position)
888{
889 unsigned int i, count=0;
890 LttFacility * f;
891 for(i=0;i<t->facility_number;i++){
892 f = (LttFacility*)g_ptr_array_index(t->facilities, i);
893 if(strcmp(f->name,name)==0){
894 count++;
895 if(count==1) *position = i;
896 }else{
897 if(count) break;
898 }
899 }
900 return count;
901}
902
903/*****************************************************************************
904 * Functions to discover all the event types in the trace
905 ****************************************************************************/
906
907unsigned ltt_trace_eventtype_number(LttTrace *t)
908{
909 unsigned int i;
910 unsigned count = 0;
911 unsigned int num = t->facility_number;
912 LttFacility * f;
913
914 for(i=0;i<num;i++){
915 f = (LttFacility*)g_ptr_array_index(t->facilities, i);
916 count += f->event_number;
917 }
918 return count;
919}
920
921/* FIXME : performances could be improved with a better design for this
922 * function : sequential search through a container has never been the
923 * best on the critical path. */
924LttFacility * ltt_trace_facility_by_id(LttTrace * trace, unsigned id)
925{
926 LttFacility * facility = NULL;
927 unsigned int i;
928 unsigned int num = trace->facility_number;
929 GPtrArray *facilities = trace->facilities;
930
931 for(i=0;unlikely(i<num);){
932 LttFacility *iter_facility =
933 (LttFacility*) g_ptr_array_index(facilities,i);
934 unsigned base_id = iter_facility->base_id;
935
936 if(likely(id >= base_id &&
937 id < base_id + iter_facility->event_number)) {
938 facility = iter_facility;
939 break;
940 } else {
941 i++;
942 }
943 }
944
945 return facility;
946}
947
948LttEventType *ltt_trace_eventtype_get(LttTrace *t, unsigned evId)
949{
950 LttEventType *event_type;
951
952 LttFacility * f;
953 f = ltt_trace_facility_by_id(t,evId);
954
955 if(unlikely(!f)) event_type = NULL;
956 else event_type = f->events[evId - f->base_id];
957
958 return event_type;
959}
960
961/*****************************************************************************
962 *There is one "per cpu" tracefile for each CPU, numbered from 0 to
963 *the maximum number of CPU in the system. When the number of CPU installed
964 *is less than the maximum, some positions are unused. There are also a
965 *number of "control" tracefiles (facilities, interrupts...).
966 ****************************************************************************/
967unsigned ltt_trace_control_tracefile_number(LttTrace *t)
968{
969 return t->control_tracefile_number;
970}
971
972unsigned ltt_trace_per_cpu_tracefile_number(LttTrace *t)
973{
974 return t->per_cpu_tracefile_number;
975}
976
977/*****************************************************************************
978 *It is possible to search for the tracefiles by name or by CPU position.
979 *The index within the tracefiles of the same type is returned if found
980 *and a negative value otherwise.
981 ****************************************************************************/
982
983int ltt_trace_control_tracefile_find(LttTrace *t, const gchar *name)
984{
985 LttTracefile * tracefile;
986 unsigned int i;
987 for(i=0;i<t->control_tracefile_number;i++){
988 tracefile = (LttTracefile*)g_ptr_array_index(t->control_tracefiles, i);
989 if(strcmp(tracefile->name, name)==0)break;
990 }
991 if(i == t->control_tracefile_number) return -1;
992 return i;
993}
994
995/* not really useful. We just have to know that cpu tracefiles
996 * comes before control tracefiles.
997 */
998int ltt_trace_per_cpu_tracefile_find(LttTrace *t, const gchar *name)
999{
1000 LttTracefile * tracefile;
1001 unsigned int i;
1002 for(i=0;i<t->per_cpu_tracefile_number;i++){
1003 tracefile = (LttTracefile*)g_ptr_array_index(t->per_cpu_tracefiles, i);
1004 if(strcmp(tracefile->name, name)==0)break;
1005 }
1006 if(i == t->per_cpu_tracefile_number) return -1;
1007 return i;
1008}
1009
1010/*****************************************************************************
1011 *Get a specific tracefile
1012 ****************************************************************************/
1013
1014LttTracefile *ltt_trace_control_tracefile_get(LttTrace *t, unsigned i)
1015{
1016 return (LttTracefile*)g_ptr_array_index(t->control_tracefiles, i);
1017}
1018
1019LttTracefile *ltt_trace_per_cpu_tracefile_get(LttTrace *t, unsigned i)
1020{
1021 return (LttTracefile*)g_ptr_array_index(t->per_cpu_tracefiles, i);
1022}
1023
1024/*****************************************************************************
1025 * Get the start time and end time of the trace
1026 ****************************************************************************/
1027
1028static void ltt_tracefile_time_span_get(LttTracefile *tf,
1029 LttTime *start, LttTime *end)
1030{
1031 struct ltt_block_start_header * header;
1032 int err;
1033
1034 err = map_block(tf, 0);
1035 if(unlikely(err)) {
1036 g_error("Can not map block");
1037 *start = { 0xFFFFFFFF, 0xFFFFFFFF };
1038 } else
1039 *start = tf->buffer.begin.timestamp;
1040
1041 err = map_block(tf, tf->num_blocks - 1); /* Last block */
1042 if(unlikely(err)) {
1043 g_error("Can not map block");
1044 *end = { 0, 0 };
1045 } else
1046 *end = tf->buffer.end.timestamp;
1047}
1048
1049struct tracefile_time_span_get_args {
1050 LttTrace *t;
1051 LttTime *start;
1052 LttTime *end;
1053};
1054
1055static void group_time_span_get(GQuark name, gpointer data, gpointer user_data)
1056{
1057 struct tracefile_time_span_get_args *args =
1058 (struct tracefile_time_span_get_args*)user_data;
1059
1060 GArray *group = (GArray *)data;
1061 int i;
1062 LttTracefile *tf;
1063 LttTime tmp_start;
1064 LttTime tmp_end;
1065
1066 for(i=0; i<group->len; i++) {
1067 tf = &g_array_index (group, LttTracefile, i);
1068 if(tf->cpu_online) {
1069 ltt_tracefile_time_span_get(tf, &tmp_start, &tmp_end);
1070 if(ltt_time_compare(*args->start, tmp_start)>0) *args->start = tmp_start;
1071 if(ltt_time_compare(*args->end, tmp_end)<0) *args->end = tmp_end;
1072 }
1073 }
1074}
1075
1076void ltt_trace_time_span_get(LttTrace *t, LttTime *start, LttTime *end)
1077{
1078 LttTime min_start = { 0xFFFFFFFF, 0xFFFFFFFF };
1079 LttTime max_end = { 0, 0 };
1080 struct tracefile_time_span_get_args args = { t, &min_start, &max_end };
1081
1082 g_datalist_foreach(t->tracefiles, &group_time_span_get, &args);
1083
1084 if(start != NULL) *start = min_start;
1085 if(end != NULL) *end = max_end;
1086
1087}
1088
1089
1090/*****************************************************************************
1091 *Get the name of a tracefile
1092 ****************************************************************************/
1093
1094char *ltt_tracefile_name(LttTracefile *tf)
1095{
1096 return tf->name;
1097}
1098
1099/*****************************************************************************
1100 * Get the number of blocks in the tracefile
1101 ****************************************************************************/
1102
1103unsigned ltt_tracefile_block_number(LttTracefile *tf)
1104{
1105 return tf->block_number;
1106}
1107
1108
1109/* Seek to the first event in a tracefile that has a time equal or greater than
1110 * the time passed in parameter.
1111 *
1112 * If the time parameter is outside the tracefile time span, seek to the first
1113 * or the last event of the tracefile.
1114 *
1115 * If the time parameter is before the first event, we have to seek specially to
1116 * there.
1117 *
1118 * If the time is after the end of the trace, get the last event.
1119 *
1120 * Do a binary search to find the right block, then a sequential search in the
1121 * block to find the event.
1122 *
1123 * In the special case where the time requested fits inside a block that has no
1124 * event corresponding to the requested time, the first event of the next block
1125 * will be seeked.
1126 *
1127 * IMPORTANT NOTE : // FIXME everywhere...
1128 *
1129 * You MUST NOT do a ltt_tracefile_read right after a ltt_tracefile_seek_time :
1130 * you will jump over an event if you do.
1131 *
1132 * */
1133
1134void ltt_tracefile_seek_time(LttTracefile *tf, LttTime time)
1135{
1136 int err;
1137 unsigned int block_num, high, low;
1138
1139 /* seek at the beginning of trace */
1140 err = map_block(tf, 0); /* First block */
1141 if(unlikely(err)) {
1142 g_error("Can not map block");
1143 goto fail;
1144 }
1145
1146 /* If the time is lower or equal the beginning of the trace,
1147 * go to the first event. */
1148 if(ltt_time_compare(time, tf->buffer.start.timestamp) <= 0) {
1149 ltt_tracefile_read(tf)
1150 goto found; /* There is either no event in the trace or the event points
1151 to the first event in the trace */
1152 }
1153
1154 err = map_block(tf, tf->num_blocks - 1); /* Last block */
1155 if(unlikely(err)) {
1156 g_error("Can not map block");
1157 goto fail;
1158 }
1159
1160 /* If the time is after the end of the trace, get the last event. */
1161 if(ltt_time_compare(time, tf->buffer.end.timestamp) >= 0) {
1162 /* While the ltt_tracefile_read_event doesn't return NULL, continue reading
1163 */
1164 while(ltt_tracefile_read(tf));
1165 goto found;
1166 }
1167
1168 /* Binary search the block */
1169 high = tf->num_blocks - 1;
1170 low = 0;
1171
1172 while(1) {
1173 block_num = ((high-low) / 2) + low;
1174
1175 err = map_block(tf, block_num);
1176 if(unlikely(err)) {
1177 g_error("Can not map block");
1178 goto fail;
1179 }
bed09760 1180 if(high == low) {
1181 /* We cannot divide anymore : this is what would happen if the time
1182 * requested was exactly between two consecutive buffers'end and start
1183 * timestamps. This is also what would happend if we didn't deal with out
1184 * of span cases prior in this function. */
1185 /* The event is right in the buffer!
1186 * (or in the next buffer first event) */
1187 while(1) {
1188 ltt_tracefile_read(tf);
1189 if(ltt_time_compare(time, tf->event.event_time) >= 0)
1190 break;
1191 }
1192
1193 } if(ltt_time_compare(time, tf->buffer.start.timestamp) < 0) {
54ecbf38 1194 /* go to lower part */
1195 high = block_num;
1196 } else if(ltt_time_compare(time, tf->buffer.end.timestamp) > 0) {
1197 /* go to higher part */
1198 low = block_num;
1199 } else {/* The event is right in the buffer!
1200 (or in the next buffer first event) */
1201 while(1) {
1202 ltt_tracefile_read(tf);
1203 if(ltt_time_compare(time, tf->event.event_time) >= 0)
1204 break;
1205 }
1206 goto found;
1207 }
1208 }
1209
1210found:
1211
1212 return;
1213
1214 /* Error handling */
1215fail:
1216 g_error("ltt_tracefile_seek_time failed on tracefile %s",
1217 g_quark_to_string(tf->name));
1218}
1219
1220
1221int ltt_tracefile_seek_position(LttTracefile *tf, const LttEventPosition *ep) {
1222
1223 int err;
1224
1225 if(ep->tracefile != tf) {
1226 goto fail;
1227 }
1228
1229 err = map_block(tf, ep->block);
1230 if(unlikely(err)) {
1231 g_error("Can not map block");
1232 goto fail;
1233 }
1234
1235 tf->event.offset = ep->offset;
1236
1237 if(!ltt_tracefile_read(tf)) goto fail;
1238
1239 return;
1240
1241fail:
1242 g_error("ltt_tracefile_seek_time failed on tracefile %s",
1243 g_quark_to_string(tf->name));
1244}
1245
1246
1247
1248/*****************************************************************************
1249 * Seek to the first event with position equal or larger to ep
1250 *
1251 * Modified by Mathieu Desnoyers to used faster offset position instead of
1252 * re-reading the whole buffer.
1253 ****************************************************************************/
1254
1255void ltt_tracefile_seek_position(LttTracefile *t, const LttEventPosition *ep)
1256{
1257 //if we are at the right place, just return
1258 if(likely(t->which_block == ep->block_num && t->which_event == ep->event_num))
1259 return;
1260
1261 if(likely(t->which_block == ep->block_num)) updateTracefile(t);
1262 else readBlock(t,ep->block_num);
1263 //event offset is available
1264 if(likely(ep->old_position)){
1265 int err;
1266
1267 t->which_event = ep->event_num;
1268 t->cur_event_pos = t->buffer + ep->event_offset;
1269 t->prev_event_time = ep->event_time;
1270 t->current_event_time = ep->event_time;
1271 t->cur_heart_beat_number = ep->heart_beat_number;
1272 t->cur_cycle_count = ep->event_cycle_count;
1273
1274 /* This is a workaround for fast position seek */
1275 t->last_event_pos = ep->last_event_pos;
1276 t->prev_block_end_time = ep->prev_block_end_time;
1277 t->prev_event_time = ep->prev_event_time;
1278 t->pre_cycle_count = ep->pre_cycle_count;
1279 t->count = ep->count;
1280 t->overflow_nsec = ep->overflow_nsec;
1281 t->last_heartbeat = ep->last_heartbeat;
1282 /* end of workaround */
1283
1284 //update the fields of the current event and go to the next event
1285 err = skipEvent(t);
1286 if(unlikely(err == ERANGE)) g_error("event id is out of range\n");
1287
1288 return;
1289 }
1290
1291 //only block number and event index are available
1292 //MD: warning : this is slow!
1293 g_warning("using slow O(n) tracefile seek position");
1294
1295 LttEvent event;
1296 while(likely(t->which_event < ep->event_num)) ltt_tracefile_read(t, &event);
1297
1298 return;
1299}
1300
1301/* Calculate the real event time based on the buffer boundaries */
1302LttTime ltt_interpolate_time(LttTracefile *tf, LttEvent *event)
1303{
1304 LttTime time;
1305
1306 g_assert(t->trace->has_tsc);
1307
1308 time = ltt_time_from_uint64(
1309 (guint64)tf->buffer.tsc*tf->buffer.nsecs_per_cycle);
1310 time = ltt_time_add(tf->buffer.begin.timestamp, time);
1311
1312 return time;
1313}
1314
1315
1316/*****************************************************************************
1317 *Function name
1318 * ltt_tracefile_read : Read the next event in the tracefile
1319 *Input params
1320 * t : tracefile
1321 *Return value
1322 * LttEvent * : an event to be processed
1323 * Note : it points to the current tf->event. It will be overwritten
1324 * by the next call to ltt_tracefile_read or any map_block.
1325 *
1326 * Returns NULL on end of trace (or error).
1327 *
1328 *
1329 * This function does make the tracefile event structure point to the event
1330 * currently pointed to by the
1331 ****************************************************************************/
1332
1333LttEvent *ltt_tracefile_read(LttTracefile *tf)
1334{
1335 int err;
1336 LttFacility *f;
1337 void * pos;
1338
1339 /* Skip the current event to go to the next, or point to the
1340 * t->buffer.head + t->buffer.lost_size if we were on the last
1341 * event of a buffer.
1342 */
1343 err = ltt_seek_next_event(tf);
1344 if(unlikely(err == ERANGE)) {
1345 g_error("event id is out of range\n");
1346 return NULL;
1347 }
1348
1349 pos = tf->event.offset;
1350
1351 /* Are we at the end of the buffer ? */
1352 if(unlikely(pos == tf->buffer.head + tf->buffer.lost_size)) {
1353 if(unlikely(tf->buffer.index == tf->num_blocks-1)){ /* end of trace ? */
1354 return NULL;
1355 } else {
1356 /* get next block */
1357 err = map_block(tf, tf->buffer.index + 1);
1358 if(unlikely(err)) {
1359 g_error("Can not map block");
1360 return NULL;
1361 }
ea45889a 1362 /* seek to the first event */
1363 err = ltt_seek_next_event(tf);
1364 if(unlikely(err == ERANGE)) {
1365 g_error("event id is out of range\n");
1366 return NULL;
1367 }
1368
54ecbf38 1369 pos = tf->event.offset;
1370 }
1371 }
1372
1373 /* Read event header */
1374
1375 //TODO align
1376
1377 if(tf->trace->has_tsc) {
1378 event->time.timestamp = ltt_get_uint32(LTT_GET_BO(t),
1379 tf->cur_event_pos);
1380 /* 32 bits -> 64 bits tsc */
1381 if(event->time.timestamp < (0xFFFFFFFFULL&tf->buffer.tsc)) {
1382 tf->buffer.tsc = ((tf->buffer.tsc&0xFFFFFFFF00000000ULL)
1383 + 0x100000000ULL)
1384 | (guint64)event->time.timestamp;
1385
1386 event->event_time = ltt_interpolate_time(tf, event);
1387 } else {
1388 /* no overflow */
1389 tf->buffer.tsc = (tf->buffer.tsc&0xFFFFFFFF00000000ULL)
1390 | (guint64)event->time.timestamp;
1391 }
1392 pos += sizeof(uint32);
1393 } else {
1394 event->time.delta = ltt_get_uint32(LTT_GET_BO(tf),
1395 tf->cur_event_pos);
1396 tf->buffer.tsc = 0;
1397
1398 event->event_time = ltt_time_add(tf->buffer.begin.timestamp,
1399 event->time_delta);
1400 pos += sizeof(uint32);
1401 }
1402
1403 event->facility_id = ltt_get_uint8(LTT_GET_BO(tf),
1404 tf->cur_event_pos);
1405 pos += sizeof(uint8);
1406
1407 event->event_id = ltt_get_uint8(LTT_GET_BO(tf),
1408 tf->cur_event_pos);
1409 pos += sizeof(uint8);
1410
1411 event->data = tf->cur_event_pos + EVENT_HEADER_SIZE;
1412
1413 event->data = pos;
1414
1415 /* do event specific operation */
1416
1417 /* do something if its an heartbeat event : increment the heartbeat count */
1418 if(event->facility_id != 0) { /* except core */
1419 f = (LttFacility*)g_ptr_array_index(tf->trace->facilities,
1420 event->facility_id);
1421 g_assert(f != NULL);
1422
1423 if(unlikely(ltt_facility_name(f)
1424 != LTT_FACILITY_NAME_HEARTBEAT)) {
1425 LttEventType *et = ltt_facility_eventtype_get_by_name(f,
1426 LTT_EVENT_NAME_HEARTBEAT);
1427 if(et->id == event->event_id)
1428 t->cur_heart_beat_number++;
1429
1430 }
1431 }
1432
1433 return event;
1434}
1435
1436/****************************************************************************
1437 *Function name
1438 * readFile : wrap function to read from a file
1439 *Input Params
1440 * fd : file descriptor
1441 * buf : buf to contain the content
1442 * size : number of bytes to be read
1443 * mesg : message to be printed if some thing goes wrong
1444 *return value
1445 * 0 : success
1446 * EIO : can not read from the file
1447 ****************************************************************************/
1448#if 0
1449int readFile(int fd, void * buf, size_t size, char * mesg)
1450{
1451 ssize_t nbBytes = read(fd, buf, size);
1452
1453 if((size_t)nbBytes != size) {
1454 if(nbBytes < 0) {
1455 perror("Error in readFile : ");
1456 } else {
1457 g_warning("%s",mesg);
1458 }
1459 return EIO;
1460 }
1461 return 0;
1462}
1463#endif //0
1464
1465/****************************************************************************
1466 *Function name
1467 * map_block : map a block from the file
1468 *Input Params
1469 * lttdes : ltt trace file
1470 * whichBlock : the block which will be read
1471 *return value
1472 * 0 : success
1473 * EINVAL : lseek fail
1474 * EIO : can not read from the file
1475 ****************************************************************************/
1476
1477static int map_block(LttTracefile * tf, int block_num)
1478{
1479 struct ltt_block_start_header *header;
1480
1481 g_assert(block_num < tf->num_blocks);
1482
1483 if(tf->buffer.head != NULL)
1484 munmap(tf->buffer.head, tf->buf_size);
1485
1486 /* Multiple of pages aligned head */
1487 tf->buffer.head = mmap(0, tf->block_size, PROT_READ, tf->fd,
1488 (off_t)tf->block_size * (off_t)block_num);
1489
1490 if(tf->buffer.head == NULL) {
1491 perror("Error in allocating memory for buffer of tracefile %s\n", fileName);
1492 goto map_error;
1493 }
1494 g_assert(tf->buffer.head & (8-1) == 0); // make sure it's aligned.
1495
1496
1497 tf->buffer.index = block_num;
1498
1499 header = (struct ltt_block_start_header*)tf->buffer.head;
1500
1501 tf->buffer.begin.timestamp = ltt_get_uint64(LTT_GET_BO(tf),
1502 header->begin.timestamp)
1503 * NSEC_PER_USEC;
1504 tf->buffer.begin.cycle_count = ltt_get_uint64(LTT_GET_BO(tf),
1505 header->begin.cycle_count);
1506 tf->buffer.end.timestamp = ltt_get_uint64(LTT_GET_BO(tf),
1507 header->end.timestamp)
1508 * NSEC_PER_USEC;
1509 tf->buffer.end.cycle_count = ltt_get_uint64(LTT_GET_BO(tf),
1510 header->end.cycle_count);
1511 tf->buffer.lost_size = ltt_get_uint32(LTT_GET_BO(tf),
1512 header->lost_size);
1513
1514 tf->buffer.tsc = tf->buffer.begin.cycle_count;
1515
1516 /* FIXME
1517 * eventually support variable buffer size : will need a partial pre-read of
1518 * the headers to create an index when we open the trace... eventually. */
1519 g_assert(tf->block_size == ltt_get_uint32(header->buf_size));
1520
1521 /* Now that the buffer is mapped, calculate the time interpolation for the
1522 * block. */
1523
1524 tf->buffer.nsecs_per_cycle = calc_nsecs_per_cycle(&tf->buffer);
1525
1526 /* Make the current event point to the beginning of the buffer :
1527 * it means that the event read must get the first event. */
1528 tf->event.tracefile = tf;
1529 tf->event.block = block_num;
1530 tf->event.offset = tf->buffer.head;
1531
1532 return 0;
1533
1534map_error:
1535 return -errno;
1536
1537}
1538
1539/*****************************************************************************
1540 *Function name
1541 * updateTracefile : reinitialize the info of the block which is already
1542 * in the buffer
1543 *Input params
1544 * tf : tracefile
1545 ****************************************************************************/
1546
1547void updateTracefile(LttTracefile * tf)
1548{
1549 tf->which_event = 1;
1550 tf->cur_event_pos = tf->buffer;
1551 tf->current_event_time = getEventTime(tf);
1552 tf->cur_heart_beat_number = 0;
1553
1554 tf->prev_event_time.tv_sec = 0;
1555 tf->prev_event_time.tv_nsec = 0;
1556 tf->count = 0;
1557
1558 tf->overflow_nsec =
1559 (-((double)ltt_get_uint64(tf->trace->reverse_byte_order,
1560 &tf->a_block_start->cycle_count))
1561 * tf->nsec_per_cycle);
1562
1563}
1564
1565/* Take the tf current event offset and use the event facility id and event id
1566 * to figure out where is the next event offset.
1567 *
1568 * This is an internal function not aiming at being used elsewhere : it will
1569 * not jump over the current block limits. Please consider using
1570 * ltt_tracefile_read to do this.
1571 *
1572 * Returns 0 on success
1573 * ERANGE if we are at the end of the buffer.
1574 */
1575static int ltt_seek_next_event(LttTracefile *tf)
1576{
1577 void *pos;
1578
1579 /* seek over the buffer header if we are at the buffer start */
1580 if(tf->event.offset == tf->buffer.head) {
1581 tf->event.offset += sizeof(struct ltt_block_start_header);
1582 goto found;
1583 }
1584
1585 /* if we are at the end of a buffer, generate an error, not supposed to
1586 * happen. */
1587 if(tf->event.offset == tf->buffer.head + tf->buffer.lost_size)
1588 goto error;
1589
1590 pos = tf->event.data;
1591
1592 pos += ltt_facility_get_event_size(tf->event.facility_id, tf->event.event_id);
1593
1594 tf->event.offset = pos;
1595
1596found:
1597 return 0;
1598
1599error:
1600 g_error("Error in ltt_seek_next_event for tracefile %s",
1601 g_quark_to_string(tf->name));
1602 return ERANGE;
1603}
1604
1605
1606/*****************************************************************************
1607 *Function name
1608 * calc_nsecs_per_cycle : calculate nsecs per cycle for current block
1609 *Input Params
1610 * t : tracefile
1611 ****************************************************************************/
1612
1613static double calc_nsecs_per_cycle(LttTracefile * t)
1614{
1615 LttTime lBufTotalTime; /* Total time for this buffer */
1616 double lBufTotalNSec; /* Total time for this buffer in nsecs */
1617 LttCycleCount lBufTotalCycle;/* Total cycles for this buffer */
1618
1619 /* Calculate the total time for this buffer */
1620 lBufTotalTime = ltt_time_sub(
1621 ltt_get_time(t->buffer.end.timestamp),
1622 ltt_get_time(t->buffer.begin.timestamp));
1623
1624 /* Calculate the total cycles for this bufffer */
1625 lBufTotalCycle = t->buffer.end.cycle_count;
1626 lBufTotalCycle -= t->buffer.start.cycle_count;
1627
1628 /* Convert the total time to double */
1629 lBufTotalNSec = ltt_time_to_double(lBufTotalTime);
1630
1631 return lBufTotalNSec / (double)lBufTotalCycle;
1632
1633}
1634
1635/*****************************************************************************
1636 *Function name
1637 * setFieldsOffset : set offset of the fields
1638 *Input params
1639 * tracefile : opened trace file
1640 * evT : the event type
1641 * evD : event data, it may be NULL
1642 ****************************************************************************/
1643
1644void setFieldsOffset(LttTracefile *tf,LttEventType *evT,void *evD,LttTrace* t)
1645{
1646 LttField * rootFld = evT->root_field;
1647 // rootFld->base_address = evD;
1648
1649 if(likely(rootFld))
1650 rootFld->field_size = getFieldtypeSize(tf, evT, 0,0,rootFld, evD,t);
1651}
1652
1653/*****************************************************************************
1654 *Function name
1655 * getFieldtypeSize: get the size of the field type (primitive type)
1656 *Input params
1657 * tracefile : opened trace file
1658 * evT : event type
1659 * offsetRoot : offset from the root
1660 * offsetParent : offset from the parrent
1661 * fld : field
1662 * evD : event data, it may be NULL
1663 *Return value
1664 * int : size of the field
1665 ****************************************************************************/
1666
1667static inline gint getFieldtypeSize(LttTracefile * t,
1668 LttEventType * evT, gint offsetRoot,
1669 gint offsetParent, LttField * fld, void *evD, LttTrace *trace)
1670{
1671 gint size, size1, element_number, i, offset1, offset2;
1672 LttType * type = fld->field_type;
1673
1674 if(unlikely(t && evT->latest_block==t->which_block &&
1675 evT->latest_event==t->which_event)){
1676 size = fld->field_size;
1677 goto end_getFieldtypeSize;
1678 } else {
1679 /* This likely has been tested with gcov : half of them.. */
1680 if(unlikely(fld->field_fixed == 1)){
1681 /* tested : none */
1682 if(unlikely(fld == evT->root_field)) {
1683 size = fld->field_size;
1684 goto end_getFieldtypeSize;
1685 }
1686 }
1687
1688 /* From gcov profiling : half string, half struct, can we gain something
1689 * from that ? (Mathieu) */
1690 switch(type->type_class) {
1691 case LTT_ARRAY:
1692 element_number = (int) type->element_number;
1693 if(fld->field_fixed == -1){
1694 size = getFieldtypeSize(t, evT, offsetRoot,
1695 0,fld->child[0], NULL, trace);
1696 if(size == 0){ //has string or sequence
1697 fld->field_fixed = 0;
1698 }else{
1699 fld->field_fixed = 1;
1700 size *= element_number;
1701 }
1702 }else if(fld->field_fixed == 0){// has string or sequence
1703 size = 0;
1704 for(i=0;i<element_number;i++){
1705 size += getFieldtypeSize(t, evT, offsetRoot+size,size,
1706 fld->child[0], evD+size, trace);
1707 }
1708 }else size = fld->field_size;
1709 if(unlikely(!evD)){
1710 fld->fixed_root = (offsetRoot==-1) ? 0 : 1;
1711 fld->fixed_parent = (offsetParent==-1) ? 0 : 1;
1712 }
1713
1714 break;
1715
1716 case LTT_SEQUENCE:
1717 size1 = (int) ltt_type_size(trace, type);
1718 if(fld->field_fixed == -1){
1719 fld->sequ_number_size = size1;
1720 fld->field_fixed = 0;
1721 size = getFieldtypeSize(t, evT, offsetRoot,
1722 0,fld->child[0], NULL, trace);
1723 fld->element_size = size;
1724 }else{//0: sequence
1725 element_number = getIntNumber(t->trace->reverse_byte_order,size1,evD);
1726 type->element_number = element_number;
1727 if(fld->element_size > 0){
1728 size = element_number * fld->element_size;
1729 }else{//sequence has string or sequence
1730 size = 0;
1731 for(i=0;i<element_number;i++){
1732 size += getFieldtypeSize(t, evT, offsetRoot+size+size1,size+size1,
1733 fld->child[0], evD+size+size1, trace);
1734 }
1735 }
1736 size += size1;
1737 }
1738 if(unlikely(!evD)){
1739 fld->fixed_root = (offsetRoot==-1) ? 0 : 1;
1740 fld->fixed_parent = (offsetParent==-1) ? 0 : 1;
1741 }
1742
1743 break;
1744
1745 case LTT_STRING:
1746 size = 0;
1747 if(fld->field_fixed == -1){
1748 fld->field_fixed = 0;
1749 }else{//0: string
1750 /* Hope my implementation is faster than strlen (Mathieu) */
1751 char *ptr=(char*)evD;
1752 size = 1;
1753 /* from gcov : many many strings are empty, make it the common case.*/
1754 while(unlikely(*ptr != '\0')) { size++; ptr++; }
1755 //size = ptr - (char*)evD + 1; //include end : '\0'
1756 }
1757 fld->fixed_root = (offsetRoot==-1) ? 0 : 1;
1758 fld->fixed_parent = (offsetParent==-1) ? 0 : 1;
1759
1760 break;
1761
1762 case LTT_STRUCT:
1763 element_number = (int) type->element_number;
1764 size = 0;
1765 /* tested with gcov */
1766 if(unlikely(fld->field_fixed == -1)){
1767 offset1 = offsetRoot;
1768 offset2 = 0;
1769 for(i=0;i<element_number;i++){
1770 size1=getFieldtypeSize(t, evT,offset1,offset2,
1771 fld->child[i], NULL, trace);
1772 if(likely(size1 > 0 && size >= 0)){
1773 size += size1;
1774 if(likely(offset1 >= 0)) offset1 += size1;
1775 offset2 += size1;
1776 }else{
1777 size = -1;
1778 offset1 = -1;
1779 offset2 = -1;
1780 }
1781 }
1782 if(unlikely(size == -1)){
1783 fld->field_fixed = 0;
1784 size = 0;
1785 }else fld->field_fixed = 1;
1786 }else if(likely(fld->field_fixed == 0)){
1787 offset1 = offsetRoot;
1788 offset2 = 0;
1789 for(i=0;unlikely(i<element_number);i++){
1790 size=getFieldtypeSize(t,evT,offset1,offset2,
1791 fld->child[i],evD+offset2, trace);
1792 offset1 += size;
1793 offset2 += size;
1794 }
1795 size = offset2;
1796 }else size = fld->field_size;
1797 fld->fixed_root = (offsetRoot==-1) ? 0 : 1;
1798 fld->fixed_parent = (offsetParent==-1) ? 0 : 1;
1799 break;
1800
1801 default:
1802 if(unlikely(fld->field_fixed == -1)){
1803 size = (int) ltt_type_size(trace, type);
1804 fld->field_fixed = 1;
1805 }else size = fld->field_size;
1806 if(unlikely(!evD)){
1807 fld->fixed_root = (offsetRoot==-1) ? 0 : 1;
1808 fld->fixed_parent = (offsetParent==-1) ? 0 : 1;
1809 }
1810 break;
1811 }
1812 }
1813
1814 fld->offset_root = offsetRoot;
1815 fld->offset_parent = offsetParent;
1816 fld->field_size = size;
1817
1818end_getFieldtypeSize:
1819
1820 return size;
1821}
1822
1823
1824/*****************************************************************************
1825 *Function name
1826 * getIntNumber : get an integer number
1827 *Input params
1828 * size : the size of the integer
1829 * evD : the event data
1830 *Return value
1831 * gint64 : a 64 bits integer
1832 ****************************************************************************/
1833
1834gint64 getIntNumber(gboolean reverse_byte_order, int size, void *evD)
1835{
1836 gint64 i;
1837
1838 switch(size) {
1839 case 1: i = *((gint8*)evD); break;
1840 case 2: i = ltt_get_int16(reverse_byte_order, evD); break;
1841 case 4: i = ltt_get_int32(reverse_byte_order, evD); break;
1842 case 8: i = ltt_get_int64(reverse_byte_order, evD); break;
1843 default: i = ltt_get_int64(reverse_byte_order, evD);
1844 g_critical("getIntNumber : integer size %d unknown", size);
1845 break;
1846 }
1847
1848 return i;
1849}
1850#if 0
1851/*****************************************************************************
1852 *Function name
1853 * getDataEndianType : get the data type size and endian type of the local
1854 * machine
1855 *Input params
1856 * size : size of data type
1857 * endian : endian type, little or big
1858 ****************************************************************************/
1859
1860void getDataEndianType(LttArchSize * size, LttArchEndian * endian)
1861{
1862 int i = 1;
1863 char c = (char) i;
1864 int sizeInt=sizeof(int), sizeLong=sizeof(long), sizePointer=sizeof(void *);
1865
1866 if(c == 1) *endian = LTT_LITTLE_ENDIAN;
1867 else *endian = LTT_BIG_ENDIAN;
1868
1869 if(sizeInt == 2 && sizeLong == 4 && sizePointer == 4)
1870 *size = LTT_LP32;
1871 else if(sizeInt == 4 && sizeLong == 4 && sizePointer == 4)
1872 *size = LTT_ILP32;
1873 else if(sizeInt == 4 && sizeLong == 8 && sizePointer == 8)
1874 *size = LTT_LP64;
1875 else if(sizeInt == 8 && sizeLong == 8 && sizePointer == 8)
1876 *size = LTT_ILP64;
1877 else *size = LTT_UNKNOWN;
1878}
1879#endif //0
1880/* get the node name of the system */
1881
1882char * ltt_trace_system_description_node_name (LttSystemDescription * s)
1883{
1884 return s->node_name;
1885}
1886
1887
1888/* get the domain name of the system */
1889
1890char * ltt_trace_system_description_domain_name (LttSystemDescription * s)
1891{
1892 return s->domain_name;
1893}
1894
1895
1896/* get the description of the system */
1897
1898char * ltt_trace_system_description_description (LttSystemDescription * s)
1899{
1900 return s->description;
1901}
1902
1903
1904/* get the start time of the trace */
1905
1906LttTime ltt_trace_system_description_trace_start_time(LttSystemDescription *s)
1907{
1908 return s->trace_start;
1909}
1910
1911
1912LttTracefile *ltt_tracefile_new()
1913{
1914 return g_new(LttTracefile, 1);
1915}
1916
1917void ltt_tracefile_destroy(LttTracefile *tf)
1918{
1919 g_free(tf);
1920}
1921
1922void ltt_tracefile_copy(LttTracefile *dest, const LttTracefile *src)
1923{
1924 *dest = *src;
1925}
1926
1927/* Before library loading... */
1928
1929static void __attribute__((constructor)) init(void)
1930{
1931 LTT_FACILITY_NAME_HEARTBEAT = g_quark_from_string("heartbeat");
1932 LTT_EVENT_NAME_HEARTBEAT = g_quark_from_string("heartbeat");
1933
1934 LTT_TRACEFILE_NAME_FACILITIES = g_quark_from_string("control/facilities");
1935}
1936
This page took 0.091172 seconds and 4 git commands to generate.