1 /* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2005 Mathieu Desnoyers
4 * Complete rewrite from the original version made by XangXiu Yang.
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;
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.
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,
30 #include <sys/types.h>
45 #include "ltt-private.h"
46 #include <ltt/trace.h>
47 #include <ltt/facility.h>
48 #include <ltt/event.h>
50 #include <ltt/ltt-types.h>
53 /* Facility names used in this file */
55 GQuark LTT_FACILITY_NAME_HEARTBEAT
,
56 LTT_EVENT_NAME_HEARTBEAT
;
63 #define __UNUSED__ __attribute__((__unused__))
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)
70 /* obtain the time of an event */
72 static inline LttTime
getEventTime(LttTracefile
* tf
);
75 /* set the offset of the fields belonging to the event,
76 need the information of the archecture */
77 void setFieldsOffset(LttTracefile
*tf
,LttEventType
*evT
,void *evD
,LttTrace
*t
);
79 /* get the size of the field type according to the archtecture's
80 size and endian type(info of the archecture) */
81 static inline gint
getFieldtypeSize(LttTracefile
* tf
,
82 LttEventType
* evT
, gint offsetRoot
,
83 gint offsetParent
, LttField
*fld
, void *evD
, LttTrace
* t
);
85 /* read a fixed size or a block information from the file (fd) */
86 int map_block(LttTracefile
* tf
, unsigned int block_num
);
88 /* calculate cycles per nsec for current block */
89 void getCyclePerNsec(LttTracefile
* t
);
91 /* reinitialize the info of the block which is already in the buffer */
92 void updateTracefile(LttTracefile
* tf
);
94 /* go to the next event */
95 int skipEvent(LttTracefile
* t
);
98 /* Functions to parse system.xml file (using glib xml parser) */
99 static void parser_start_element (GMarkupParseContext __UNUSED__
*context
,
100 const gchar
*element_name
,
101 const gchar
**attribute_names
,
102 const gchar
**attribute_values
,
107 LttSystemDescription
* des
= (LttSystemDescription
* )user_data
;
108 if(strcmp("system", element_name
)){
109 *error
= g_error_new(G_MARKUP_ERROR
,
111 "This is not system.xml file");
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
]);
154 *error
= g_error_new(G_MARKUP_ERROR
,
156 "Not a valid attribute");
163 static void parser_characters (GMarkupParseContext __UNUSED__
*context
,
165 gsize __UNUSED__ text_len
,
167 GError __UNUSED__
**error
)
169 LttSystemDescription
* des
= (LttSystemDescription
* )user_data
;
170 des
->description
= g_strdup(text
);
174 /*****************************************************************************
176 * ltt_tracefile_open : open a trace file, construct a LttTracefile
178 * t : the trace containing the tracefile
179 * fileName : path name of the trace file
180 * tf : the tracefile structure
182 * : 0 for success, -1 otherwise.
183 ****************************************************************************/
185 int ltt_tracefile_open(LttTrace
*t
, gchar
* fileName
, LttTracefile
*tf
)
187 struct stat lTDFStat
; /* Trace data file status */
188 struct ltt_block_start_header
*header
;
191 tf
->name
= g_quark_from_string(fileName
);
193 tf
->fd
= g_open(fileName
, O_RDONLY
, 0);
195 g_warning("Unable to open input data file %s\n", fileName
);
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
);
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
);
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
,
215 if(tf
->buffer
== NULL
) {
216 perror("Error in allocating memory for buffer of tracefile %s\n", fileName
);
219 g_assert(tf
->buffer
.head
& (8-1) == 0); // make sure it's aligned.
221 header
= (struct ltt_block_start_header
*)tf
->buffer
.head
;
223 if(header
->traceset
.magic_number
== LTT_MAGIC_NUMBER
)
225 else if(header
->traceset
.magic_number
== LTT_REV_MAGIC_NUMBER
)
227 else /* invalid magic number, bad tracefile ! */
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
;
235 vfree(tf
->buffer
.head
);
236 tf
->buffer
.head
= NULL
;
238 //read the first block
239 if(map_block(tf
,0)) {
240 perror("Cannot map block %u for tracefile %s\n", 0, fileName
);
248 munmap(tf
->buffer
.head
, sizeof(struct ltt_block_start_header
));
256 /*****************************************************************************
257 *Open control and per cpu tracefiles
258 ****************************************************************************/
260 void ltt_tracefile_open_cpu(LttTrace
*t
, gchar
* tracefile_name
)
263 tf
= ltt_tracefile_open(t
,tracefile_name
);
265 t
->per_cpu_tracefile_number
++;
266 g_ptr_array_add(t
->per_cpu_tracefiles
, tf
);
269 gint
ltt_tracefile_open_control(LttTrace
*t
, gchar
* control_name
)
278 tf
= ltt_tracefile_open(t
,control_name
);
280 g_warning("ltt_tracefile_open_control : bad file descriptor");
283 t
->control_tracefile_number
++;
284 g_ptr_array_add(t
->control_tracefiles
,tf
);
286 //parse facilities tracefile to get base_id
287 if(strcmp(&control_name
[strlen(control_name
)-10],"facilities") ==0){
289 if(!ltt_tracefile_read(tf
,&ev
)) return 0; // end of file
291 if(ev
.event_id
== TRACE_FACILITY_LOAD
){
293 fLoad
.name
= (gchar
*)pos
;
294 fLoad
.checksum
= *(LttChecksum
*)(pos
+ strlen(fLoad
.name
));
295 fLoad
.base_code
= *(guint32
*)(pos
+ strlen(fLoad
.name
) + sizeof(LttChecksum
));
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
;
304 if(i
==t
->facility_number
) {
305 g_warning("Facility: %s, checksum: %u is not found",
306 fLoad
.name
,(unsigned int)fLoad
.checksum
);
309 }else if(ev
.event_id
== TRACE_BLOCK_START
){
311 }else if(ev
.event_id
== TRACE_BLOCK_END
){
314 g_warning("Not valid facilities trace file");
322 /*****************************************************************************
324 * ltt_tracefile_close: close a trace file,
326 * t : tracefile which will be closed
327 ****************************************************************************/
329 void ltt_tracefile_close(LttTracefile
*t
)
331 if(t
->buffer
.head
!= NULL
)
332 munmap(t
->buffer
.head
, t
->buf_size
);
337 /*****************************************************************************
338 *Get system information
339 ****************************************************************************/
340 gint
getSystemInfo(LttSystemDescription
* des
, gchar
* pathname
)
347 GMarkupParseContext
* context
;
348 GError
* error
= NULL
;
349 GMarkupParser markup_parser
=
351 parser_start_element
,
354 NULL
, /* passthrough */
358 fd
= g_open(pathname
, O_RDONLY
, 0);
360 g_warning("Can not open file : %s\n", pathname
);
364 iochan
= g_io_channel_unix_new(fd
);
366 context
= g_markup_parse_context_new(&markup_parser
, 0, des
,NULL
);
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
) {
373 g_warning("Can not read xml file: \n%s\n", error
->message
);
376 if(!g_markup_parse_context_parse(context
, buf
, length
, &error
)){
378 g_warning("Can not parse xml file: \n%s\n", error
->message
);
381 g_markup_parse_context_free(context
);
383 g_io_channel_shutdown(iochan
, FALSE
, &error
); /* No flush */
385 g_warning("Can not close file: \n%s\n", error
->message
);
393 g_markup_parse_context_free(context
);
395 g_io_channel_shutdown(iochan
, FALSE
, &error
); /* No flush */
397 g_warning("Can not close file: \n%s\n", error
->message
);
407 /*****************************************************************************
408 *The following functions get facility/tracefile information
409 ****************************************************************************/
411 gint
getFacilityInfo(LttTrace
*t
, gchar
* eventdefs
)
418 gchar fullname
[DIR_NAME_SIZE
];
419 GError
* error
= NULL
;
421 dir
= g_dir_open(eventdefs
, 0, &error
);
424 g_warning("Can not open directory: %s, %s\n", eventdefs
, error
->message
);
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
);
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
++){
441 setFieldsOffset(NULL
, et
, NULL
, t
);
447 /*****************************************************************************
448 *A trace is specified as a pathname to the directory containing all the
449 *associated data (control tracefiles, per cpu tracefiles, event
452 *When a trace is closed, all the associated facilities, types and fields
453 *are released as well.
457 /****************************************************************************
458 * get_absolute_pathname
460 * return the unique pathname in the system
462 * MD : Fixed this function so it uses realpath, dealing well with
463 * forgotten cases (.. were not used correctly before).
465 ****************************************************************************/
466 void get_absolute_pathname(const gchar
*pathname
, gchar
* abs_pathname
)
468 abs_pathname
[0] = '\0';
470 if ( realpath (pathname
, abs_pathname
) != NULL
)
474 /* error, return the original path unmodified */
475 strcpy(abs_pathname
, pathname
);
481 /* Search for something like : .*_.*
483 * The left side is the name, the right side is the number.
486 int get_tracefile_name_number(const gchar
*raw_name
,
490 guint raw_name_len
= strlen(raw_name
);
491 gchar char_name
[PATH_MAX
]
498 for(i
=raw_name_len
-1;i
>=0;i
--) {
499 if(raw_name
[i
] == '_') break;
501 if(i
==0) /* Either not found or name length is 0 */
505 cpu_num
= strtol(raw_name
+underscore_pos
+1, &endptr
, 10);
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 */
512 char_name
= strncpy(char_name
, raw_name
, underscore_pos
);
514 *name
= g_quark_from_string(char_name
);
521 void ltt_tracefile_group_destroy(gpointer data
)
523 GArray
*group
= (GArray
*)data
;
527 for(i
=0; i
<group
->len
; i
++) {
528 tf
= &g_array_index (group
, LttTracefile
, i
);
530 ltt_tracefile_close(tf
);
534 gboolean
ltt_tracefile_group_has_cpu_online(gpointer data
)
536 GArray
*group
= (GArray
*)data
;
540 for(i
=0; i
<group
->len
; i
++) {
541 tf
= &g_array_index (group
, LttTracefile
, i
);
542 if(tf
->cpu_online
) return 1;
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 :
553 * A tracefile group is simply an array where all the per cpu tracefiles sits.
556 static int open_tracefiles(LttTrace
*trace
, char *root_path
, GData
*tracefiles
)
558 DIR *dir
= opendir(root_path
);
559 struct dirent
*entry
;
560 struct stat stat_buf
;
566 if(channel_dir
== NULL
) {
567 perror(subchannel_name
);
571 strncpy(path
, root_path
, PATH_MAX
-1);
572 path_len
= strlen(path
);
573 path
[path_len
] = '/';
575 path_ptr
= path
+ path_len
;
577 while((entry
= readdir(channel_dir
)) != NULL
) {
579 if(entry
->d_name
[0] == '.') continue;
581 strncpy(path_ptr
, entry
->d_name
, PATH_MAX
- path_len
);
583 ret
= stat(path
, &stat_buf
);
589 g_debug("Tracefile file or directory : %s\n", path
);
591 if(S_ISDIR(stat_buf
.st_mode
)) {
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");
605 if(get_tracefile_name_number(path
, &name
, &num
))
606 continue; /* invalid name */
608 group
= g_datalist_get_data(tracefiles
, name
);
610 /* Elements are automatically cleared when the array is allocated.
611 * It makes the cpu_online variable set to 0 : cpu offline, by default.
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
);
617 /* Add the per cpu tracefile to the named group */
618 unsigned int old_len
= group
->len
;
620 g_array_set_size(group
, num
+1);
621 tf
= &g_array_index (group
, LttTracefile
, num
);
623 if(ltt_tracefile_open(trace
, path
, tf
)) {
624 g_info("Error opening tracefile %s", path
);
625 g_array_set_size(group
, old_len
);
627 if(!ltt_tracefile_group_has_cpu_online(group
))
628 g_datalist_remove_data(tracefiles
, name
);
630 continue; /* error opening the tracefile : bad magic number ? */
641 LttTrace
*ltt_trace_open(const gchar
*pathname
)
643 gchar abs_path
[PATH_MAX
];
649 LttTrace
* t
= g_new(LttTrace
, 1);
650 if(!t
) goto alloc_error
;
652 get_absolute_pathname(pathname
, abs_path
);
653 t
->pathname
= g_quark_from_string(abs_path
);
655 /* Open all the tracefiles */
656 g_datalist_init(t
->tracefiles
);
657 if(open_tracefiles(t
, abs_path
, t
->tracefiles
))
660 /* Load trace XML event descriptions */
663 /* Parse each trace control/facilitiesN files : get runtime fac. info */
664 group
= g_datalist_get_data(t
->tracefiles
, LTT_TRACEFILE_NAME_FACILITIES
);
666 g_error("Trace %s has no facility tracefile", abs_path
);
667 goto facilities_error
;
670 for(i
=0; i
<group
->len
; i
++) {
671 tf
= &g_array_index (group
, LttTracefile
, i
);
673 process_facility_tracefile(tf
);
683 g_datalist_clear(t
->tracefiles
);
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
;
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/");
703 strcpy(info
,abs_path
);
704 if(!has_slash
)strcat(info
,"/");
705 strcat(info
,"info/");
707 strcpy(control
,abs_path
);
708 if(!has_slash
)strcat(control
,"/");
709 strcat(control
,"control/");
711 strcpy(cpu
,abs_path
);
712 if(!has_slash
)strcat(cpu
,"/");
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));
728 //get system description
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
);
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;
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
);
761 //get control tracefile info
762 getControlFileInfo(t
,control
);
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);
772 }*/ // With fatal error
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
);
788 char * ltt_trace_name(LttTrace
*t
)
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 *****************************************************************************/
799 LttTrace
*ltt_trace_copy(LttTrace
*self
)
801 return ltt_trace_open(self
->pathname
);
804 void ltt_trace_close(LttTrace
*t
)
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
);
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
);
830 g_ptr_array_free(t
->control_tracefiles
, TRUE
);
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
);
837 g_ptr_array_free(t
->per_cpu_tracefiles
, TRUE
);
840 for(i
=0;i
<t
->facility_number
;i
++){
841 f
= (LttFacility
*)g_ptr_array_index(t
->facilities
,i
);
842 ltt_facility_close(f
);
844 g_ptr_array_free(t
->facilities
, TRUE
);
852 /*****************************************************************************
853 *Get the system description of the trace
854 ****************************************************************************/
856 LttSystemDescription
*ltt_trace_system_description(LttTrace
*t
)
858 return t
->system_description
;
861 /*****************************************************************************
862 * The following functions discover the facilities of the trace
863 ****************************************************************************/
865 unsigned ltt_trace_facility_number(LttTrace
*t
)
867 return (unsigned)(t
->facility_number
);
870 LttFacility
*ltt_trace_facility_get(LttTrace
*t
, unsigned i
)
872 return (LttFacility
*)g_ptr_array_index(t
->facilities
, i
);
875 /*****************************************************************************
877 * ltt_trace_facility_find : find facilities in the trace
880 * name : facility name
882 * position : position of the facility in the trace
884 * : the number of facilities
885 ****************************************************************************/
887 unsigned ltt_trace_facility_find(LttTrace
*t
, char *name
, unsigned *position
)
889 unsigned int i
, count
=0;
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){
895 if(count
==1) *position
= i
;
903 /*****************************************************************************
904 * Functions to discover all the event types in the trace
905 ****************************************************************************/
907 unsigned ltt_trace_eventtype_number(LttTrace
*t
)
911 unsigned int num
= t
->facility_number
;
915 f
= (LttFacility
*)g_ptr_array_index(t
->facilities
, i
);
916 count
+= f
->event_number
;
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. */
924 LttFacility
* ltt_trace_facility_by_id(LttTrace
* trace
, unsigned id
)
926 LttFacility
* facility
= NULL
;
928 unsigned int num
= trace
->facility_number
;
929 GPtrArray
*facilities
= trace
->facilities
;
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
;
936 if(likely(id
>= base_id
&&
937 id
< base_id
+ iter_facility
->event_number
)) {
938 facility
= iter_facility
;
948 LttEventType
*ltt_trace_eventtype_get(LttTrace
*t
, unsigned evId
)
950 LttEventType
*event_type
;
953 f
= ltt_trace_facility_by_id(t
,evId
);
955 if(unlikely(!f
)) event_type
= NULL
;
956 else event_type
= f
->events
[evId
- f
->base_id
];
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 ****************************************************************************/
967 unsigned ltt_trace_control_tracefile_number(LttTrace
*t
)
969 return t
->control_tracefile_number
;
972 unsigned ltt_trace_per_cpu_tracefile_number(LttTrace
*t
)
974 return t
->per_cpu_tracefile_number
;
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 ****************************************************************************/
983 int ltt_trace_control_tracefile_find(LttTrace
*t
, const gchar
*name
)
985 LttTracefile
* tracefile
;
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;
991 if(i
== t
->control_tracefile_number
) return -1;
995 /* not really useful. We just have to know that cpu tracefiles
996 * comes before control tracefiles.
998 int ltt_trace_per_cpu_tracefile_find(LttTrace
*t
, const gchar
*name
)
1000 LttTracefile
* tracefile
;
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;
1006 if(i
== t
->per_cpu_tracefile_number
) return -1;
1010 /*****************************************************************************
1011 *Get a specific tracefile
1012 ****************************************************************************/
1014 LttTracefile
*ltt_trace_control_tracefile_get(LttTrace
*t
, unsigned i
)
1016 return (LttTracefile
*)g_ptr_array_index(t
->control_tracefiles
, i
);
1019 LttTracefile
*ltt_trace_per_cpu_tracefile_get(LttTrace
*t
, unsigned i
)
1021 return (LttTracefile
*)g_ptr_array_index(t
->per_cpu_tracefiles
, i
);
1024 /*****************************************************************************
1025 * Get the start time and end time of the trace
1026 ****************************************************************************/
1028 static void ltt_tracefile_time_span_get(LttTracefile
*tf
,
1029 LttTime
*start
, LttTime
*end
)
1031 struct ltt_block_start_header
* header
;
1034 err
= map_block(tf
, 0);
1036 g_error("Can not map block");
1037 *start
= { 0xFFFFFFFF, 0xFFFFFFFF };
1039 *start
= tf
->buffer
.begin
.timestamp
;
1041 err
= map_block(tf
, tf
->num_blocks
- 1); /* Last block */
1043 g_error("Can not map block");
1046 *end
= tf
->buffer
.end
.timestamp
;
1049 struct tracefile_time_span_get_args
{
1055 static void group_time_span_get(GQuark name
, gpointer data
, gpointer user_data
)
1057 struct tracefile_time_span_get_args
*args
=
1058 (struct tracefile_time_span_get_args
*)user_data
;
1060 GArray
*group
= (GArray
*)data
;
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
;
1076 void ltt_trace_time_span_get(LttTrace
*t
, LttTime
*start
, LttTime
*end
)
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
};
1082 g_datalist_foreach(t
->tracefiles
, &group_time_span_get
, &args
);
1084 if(start
!= NULL
) *start
= min_start
;
1085 if(end
!= NULL
) *end
= max_end
;
1090 /*****************************************************************************
1091 *Get the name of a tracefile
1092 ****************************************************************************/
1094 char *ltt_tracefile_name(LttTracefile
*tf
)
1099 /*****************************************************************************
1100 * Get the number of blocks in the tracefile
1101 ****************************************************************************/
1103 unsigned ltt_tracefile_block_number(LttTracefile
*tf
)
1105 return tf
->block_number
;
1109 /* Seek to the first event in a tracefile that has a time equal or greater than
1110 * the time passed in parameter.
1112 * If the time parameter is outside the tracefile time span, seek to the first
1113 * or the last event of the tracefile.
1115 * If the time parameter is before the first event, we have to seek specially to
1118 * If the time is after the end of the trace, get the last event.
1120 * Do a binary search to find the right block, then a sequential search in the
1121 * block to find the event.
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
1127 * IMPORTANT NOTE : // FIXME everywhere...
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.
1134 void ltt_tracefile_seek_time(LttTracefile
*tf
, LttTime time
)
1137 unsigned int block_num
, high
, low
;
1139 /* seek at the beginning of trace */
1140 err
= map_block(tf
, 0); /* First block */
1142 g_error("Can not map block");
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 */
1154 err
= map_block(tf
, tf
->num_blocks
- 1); /* Last block */
1156 g_error("Can not map block");
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
1164 while(ltt_tracefile_read(tf
));
1168 /* Binary search the block */
1169 high
= tf
->num_blocks
- 1;
1173 block_num
= ((high
-low
) / 2) + low
;
1175 err
= map_block(tf
, block_num
);
1177 g_error("Can not map block");
1180 if(ltt_time_compare(time
, tf
->buffer
.start
.timestamp
) < 0) {
1181 /* go to lower part */
1183 } else if(ltt_time_compare(time
, tf
->buffer
.end
.timestamp
) > 0) {
1184 /* go to higher part */
1186 } else {/* The event is right in the buffer!
1187 (or in the next buffer first event) */
1189 ltt_tracefile_read(tf
);
1190 if(ltt_time_compare(time
, tf
->event
.event_time
) >= 0)
1201 /* Error handling */
1203 g_error("ltt_tracefile_seek_time failed on tracefile %s",
1204 g_quark_to_string(tf
->name
));
1208 int ltt_tracefile_seek_position(LttTracefile
*tf
, const LttEventPosition
*ep
) {
1212 if(ep
->tracefile
!= tf
) {
1216 err
= map_block(tf
, ep
->block
);
1218 g_error("Can not map block");
1222 tf
->event
.offset
= ep
->offset
;
1224 if(!ltt_tracefile_read(tf
)) goto fail
;
1229 g_error("ltt_tracefile_seek_time failed on tracefile %s",
1230 g_quark_to_string(tf
->name
));
1235 /*****************************************************************************
1236 * Seek to the first event with position equal or larger to ep
1238 * Modified by Mathieu Desnoyers to used faster offset position instead of
1239 * re-reading the whole buffer.
1240 ****************************************************************************/
1242 void ltt_tracefile_seek_position(LttTracefile
*t
, const LttEventPosition
*ep
)
1244 //if we are at the right place, just return
1245 if(likely(t
->which_block
== ep
->block_num
&& t
->which_event
== ep
->event_num
))
1248 if(likely(t
->which_block
== ep
->block_num
)) updateTracefile(t
);
1249 else readBlock(t
,ep
->block_num
);
1250 //event offset is available
1251 if(likely(ep
->old_position
)){
1254 t
->which_event
= ep
->event_num
;
1255 t
->cur_event_pos
= t
->buffer
+ ep
->event_offset
;
1256 t
->prev_event_time
= ep
->event_time
;
1257 t
->current_event_time
= ep
->event_time
;
1258 t
->cur_heart_beat_number
= ep
->heart_beat_number
;
1259 t
->cur_cycle_count
= ep
->event_cycle_count
;
1261 /* This is a workaround for fast position seek */
1262 t
->last_event_pos
= ep
->last_event_pos
;
1263 t
->prev_block_end_time
= ep
->prev_block_end_time
;
1264 t
->prev_event_time
= ep
->prev_event_time
;
1265 t
->pre_cycle_count
= ep
->pre_cycle_count
;
1266 t
->count
= ep
->count
;
1267 t
->overflow_nsec
= ep
->overflow_nsec
;
1268 t
->last_heartbeat
= ep
->last_heartbeat
;
1269 /* end of workaround */
1271 //update the fields of the current event and go to the next event
1273 if(unlikely(err
== ERANGE
)) g_error("event id is out of range\n");
1278 //only block number and event index are available
1279 //MD: warning : this is slow!
1280 g_warning("using slow O(n) tracefile seek position");
1283 while(likely(t
->which_event
< ep
->event_num
)) ltt_tracefile_read(t
, &event
);
1288 /* Calculate the real event time based on the buffer boundaries */
1289 LttTime
ltt_interpolate_time(LttTracefile
*tf
, LttEvent
*event
)
1293 g_assert(t
->trace
->has_tsc
);
1295 time
= ltt_time_from_uint64(
1296 (guint64
)tf
->buffer
.tsc
*tf
->buffer
.nsecs_per_cycle
);
1297 time
= ltt_time_add(tf
->buffer
.begin
.timestamp
, time
);
1303 /*****************************************************************************
1305 * ltt_tracefile_read : Read the next event in the tracefile
1309 * LttEvent * : an event to be processed
1310 * Note : it points to the current tf->event. It will be overwritten
1311 * by the next call to ltt_tracefile_read or any map_block.
1313 * Returns NULL on end of trace (or error).
1316 * This function does make the tracefile event structure point to the event
1317 * currently pointed to by the
1318 ****************************************************************************/
1320 LttEvent
*ltt_tracefile_read(LttTracefile
*tf
)
1326 /* Skip the current event to go to the next, or point to the
1327 * t->buffer.head + t->buffer.lost_size if we were on the last
1328 * event of a buffer.
1330 err
= ltt_seek_next_event(tf
);
1331 if(unlikely(err
== ERANGE
)) {
1332 g_error("event id is out of range\n");
1336 pos
= tf
->event
.offset
;
1338 /* Are we at the end of the buffer ? */
1339 if(unlikely(pos
== tf
->buffer
.head
+ tf
->buffer
.lost_size
)) {
1340 if(unlikely(tf
->buffer
.index
== tf
->num_blocks
-1)){ /* end of trace ? */
1343 /* get next block */
1344 err
= map_block(tf
, tf
->buffer
.index
+ 1);
1346 g_error("Can not map block");
1349 pos
= tf
->event
.offset
;
1353 /* Read event header */
1357 if(tf
->trace
->has_tsc
) {
1358 event
->time
.timestamp
= ltt_get_uint32(LTT_GET_BO(t
),
1360 /* 32 bits -> 64 bits tsc */
1361 if(event
->time
.timestamp
< (0xFFFFFFFFULL
&tf
->buffer
.tsc
)) {
1362 tf
->buffer
.tsc
= ((tf
->buffer
.tsc
&0xFFFFFFFF00000000ULL
)
1364 | (guint64
)event
->time
.timestamp
;
1366 event
->event_time
= ltt_interpolate_time(tf
, event
);
1369 tf
->buffer
.tsc
= (tf
->buffer
.tsc
&0xFFFFFFFF00000000ULL
)
1370 | (guint64
)event
->time
.timestamp
;
1372 pos
+= sizeof(uint32
);
1374 event
->time
.delta
= ltt_get_uint32(LTT_GET_BO(tf
),
1378 event
->event_time
= ltt_time_add(tf
->buffer
.begin
.timestamp
,
1380 pos
+= sizeof(uint32
);
1383 event
->facility_id
= ltt_get_uint8(LTT_GET_BO(tf
),
1385 pos
+= sizeof(uint8
);
1387 event
->event_id
= ltt_get_uint8(LTT_GET_BO(tf
),
1389 pos
+= sizeof(uint8
);
1391 event
->data
= tf
->cur_event_pos
+ EVENT_HEADER_SIZE
;
1395 /* do event specific operation */
1397 /* do something if its an heartbeat event : increment the heartbeat count */
1398 if(event
->facility_id
!= 0) { /* except core */
1399 f
= (LttFacility
*)g_ptr_array_index(tf
->trace
->facilities
,
1400 event
->facility_id
);
1401 g_assert(f
!= NULL
);
1403 if(unlikely(ltt_facility_name(f
)
1404 != LTT_FACILITY_NAME_HEARTBEAT
)) {
1405 LttEventType
*et
= ltt_facility_eventtype_get_by_name(f
,
1406 LTT_EVENT_NAME_HEARTBEAT
);
1407 if(et
->id
== event
->event_id
)
1408 t
->cur_heart_beat_number
++;
1416 /****************************************************************************
1418 * readFile : wrap function to read from a file
1420 * fd : file descriptor
1421 * buf : buf to contain the content
1422 * size : number of bytes to be read
1423 * mesg : message to be printed if some thing goes wrong
1426 * EIO : can not read from the file
1427 ****************************************************************************/
1429 int readFile(int fd
, void * buf
, size_t size
, char * mesg
)
1431 ssize_t nbBytes
= read(fd
, buf
, size
);
1433 if((size_t)nbBytes
!= size
) {
1435 perror("Error in readFile : ");
1437 g_warning("%s",mesg
);
1445 /****************************************************************************
1447 * map_block : map a block from the file
1449 * lttdes : ltt trace file
1450 * whichBlock : the block which will be read
1453 * EINVAL : lseek fail
1454 * EIO : can not read from the file
1455 ****************************************************************************/
1457 static int map_block(LttTracefile
* tf
, int block_num
)
1459 struct ltt_block_start_header
*header
;
1461 g_assert(block_num
< tf
->num_blocks
);
1463 if(tf
->buffer
.head
!= NULL
)
1464 munmap(tf
->buffer
.head
, tf
->buf_size
);
1466 /* Multiple of pages aligned head */
1467 tf
->buffer
.head
= mmap(0, tf
->block_size
, PROT_READ
, tf
->fd
,
1468 (off_t
)tf
->block_size
* (off_t
)block_num
);
1470 if(tf
->buffer
.head
== NULL
) {
1471 perror("Error in allocating memory for buffer of tracefile %s\n", fileName
);
1474 g_assert(tf
->buffer
.head
& (8-1) == 0); // make sure it's aligned.
1477 tf
->buffer
.index
= block_num
;
1479 header
= (struct ltt_block_start_header
*)tf
->buffer
.head
;
1481 tf
->buffer
.begin
.timestamp
= ltt_get_uint64(LTT_GET_BO(tf
),
1482 header
->begin
.timestamp
)
1484 tf
->buffer
.begin
.cycle_count
= ltt_get_uint64(LTT_GET_BO(tf
),
1485 header
->begin
.cycle_count
);
1486 tf
->buffer
.end
.timestamp
= ltt_get_uint64(LTT_GET_BO(tf
),
1487 header
->end
.timestamp
)
1489 tf
->buffer
.end
.cycle_count
= ltt_get_uint64(LTT_GET_BO(tf
),
1490 header
->end
.cycle_count
);
1491 tf
->buffer
.lost_size
= ltt_get_uint32(LTT_GET_BO(tf
),
1494 tf
->buffer
.tsc
= tf
->buffer
.begin
.cycle_count
;
1497 * eventually support variable buffer size : will need a partial pre-read of
1498 * the headers to create an index when we open the trace... eventually. */
1499 g_assert(tf
->block_size
== ltt_get_uint32(header
->buf_size
));
1501 /* Now that the buffer is mapped, calculate the time interpolation for the
1504 tf
->buffer
.nsecs_per_cycle
= calc_nsecs_per_cycle(&tf
->buffer
);
1506 /* Make the current event point to the beginning of the buffer :
1507 * it means that the event read must get the first event. */
1508 tf
->event
.tracefile
= tf
;
1509 tf
->event
.block
= block_num
;
1510 tf
->event
.offset
= tf
->buffer
.head
;
1519 /*****************************************************************************
1521 * updateTracefile : reinitialize the info of the block which is already
1525 ****************************************************************************/
1527 void updateTracefile(LttTracefile
* tf
)
1529 tf
->which_event
= 1;
1530 tf
->cur_event_pos
= tf
->buffer
;
1531 tf
->current_event_time
= getEventTime(tf
);
1532 tf
->cur_heart_beat_number
= 0;
1534 tf
->prev_event_time
.tv_sec
= 0;
1535 tf
->prev_event_time
.tv_nsec
= 0;
1539 (-((double)ltt_get_uint64(tf
->trace
->reverse_byte_order
,
1540 &tf
->a_block_start
->cycle_count
))
1541 * tf
->nsec_per_cycle
);
1545 /* Take the tf current event offset and use the event facility id and event id
1546 * to figure out where is the next event offset.
1548 * This is an internal function not aiming at being used elsewhere : it will
1549 * not jump over the current block limits. Please consider using
1550 * ltt_tracefile_read to do this.
1552 * Returns 0 on success
1553 * ERANGE if we are at the end of the buffer.
1555 static int ltt_seek_next_event(LttTracefile
*tf
)
1559 /* seek over the buffer header if we are at the buffer start */
1560 if(tf
->event
.offset
== tf
->buffer
.head
) {
1561 tf
->event
.offset
+= sizeof(struct ltt_block_start_header
);
1565 /* if we are at the end of a buffer, generate an error, not supposed to
1567 if(tf
->event
.offset
== tf
->buffer
.head
+ tf
->buffer
.lost_size
)
1570 pos
= tf
->event
.data
;
1572 pos
+= ltt_facility_get_event_size(tf
->event
.facility_id
, tf
->event
.event_id
);
1574 tf
->event
.offset
= pos
;
1580 g_error("Error in ltt_seek_next_event for tracefile %s",
1581 g_quark_to_string(tf
->name
));
1586 /*****************************************************************************
1588 * calc_nsecs_per_cycle : calculate nsecs per cycle for current block
1591 ****************************************************************************/
1593 static double calc_nsecs_per_cycle(LttTracefile
* t
)
1595 LttTime lBufTotalTime
; /* Total time for this buffer */
1596 double lBufTotalNSec
; /* Total time for this buffer in nsecs */
1597 LttCycleCount lBufTotalCycle
;/* Total cycles for this buffer */
1599 /* Calculate the total time for this buffer */
1600 lBufTotalTime
= ltt_time_sub(
1601 ltt_get_time(t
->buffer
.end
.timestamp
),
1602 ltt_get_time(t
->buffer
.begin
.timestamp
));
1604 /* Calculate the total cycles for this bufffer */
1605 lBufTotalCycle
= t
->buffer
.end
.cycle_count
;
1606 lBufTotalCycle
-= t
->buffer
.start
.cycle_count
;
1608 /* Convert the total time to double */
1609 lBufTotalNSec
= ltt_time_to_double(lBufTotalTime
);
1611 return lBufTotalNSec
/ (double)lBufTotalCycle
;
1615 /*****************************************************************************
1617 * setFieldsOffset : set offset of the fields
1619 * tracefile : opened trace file
1620 * evT : the event type
1621 * evD : event data, it may be NULL
1622 ****************************************************************************/
1624 void setFieldsOffset(LttTracefile
*tf
,LttEventType
*evT
,void *evD
,LttTrace
* t
)
1626 LttField
* rootFld
= evT
->root_field
;
1627 // rootFld->base_address = evD;
1630 rootFld
->field_size
= getFieldtypeSize(tf
, evT
, 0,0,rootFld
, evD
,t
);
1633 /*****************************************************************************
1635 * getFieldtypeSize: get the size of the field type (primitive type)
1637 * tracefile : opened trace file
1639 * offsetRoot : offset from the root
1640 * offsetParent : offset from the parrent
1642 * evD : event data, it may be NULL
1644 * int : size of the field
1645 ****************************************************************************/
1647 static inline gint
getFieldtypeSize(LttTracefile
* t
,
1648 LttEventType
* evT
, gint offsetRoot
,
1649 gint offsetParent
, LttField
* fld
, void *evD
, LttTrace
*trace
)
1651 gint size
, size1
, element_number
, i
, offset1
, offset2
;
1652 LttType
* type
= fld
->field_type
;
1654 if(unlikely(t
&& evT
->latest_block
==t
->which_block
&&
1655 evT
->latest_event
==t
->which_event
)){
1656 size
= fld
->field_size
;
1657 goto end_getFieldtypeSize
;
1659 /* This likely has been tested with gcov : half of them.. */
1660 if(unlikely(fld
->field_fixed
== 1)){
1662 if(unlikely(fld
== evT
->root_field
)) {
1663 size
= fld
->field_size
;
1664 goto end_getFieldtypeSize
;
1668 /* From gcov profiling : half string, half struct, can we gain something
1669 * from that ? (Mathieu) */
1670 switch(type
->type_class
) {
1672 element_number
= (int) type
->element_number
;
1673 if(fld
->field_fixed
== -1){
1674 size
= getFieldtypeSize(t
, evT
, offsetRoot
,
1675 0,fld
->child
[0], NULL
, trace
);
1676 if(size
== 0){ //has string or sequence
1677 fld
->field_fixed
= 0;
1679 fld
->field_fixed
= 1;
1680 size
*= element_number
;
1682 }else if(fld
->field_fixed
== 0){// has string or sequence
1684 for(i
=0;i
<element_number
;i
++){
1685 size
+= getFieldtypeSize(t
, evT
, offsetRoot
+size
,size
,
1686 fld
->child
[0], evD
+size
, trace
);
1688 }else size
= fld
->field_size
;
1690 fld
->fixed_root
= (offsetRoot
==-1) ? 0 : 1;
1691 fld
->fixed_parent
= (offsetParent
==-1) ? 0 : 1;
1697 size1
= (int) ltt_type_size(trace
, type
);
1698 if(fld
->field_fixed
== -1){
1699 fld
->sequ_number_size
= size1
;
1700 fld
->field_fixed
= 0;
1701 size
= getFieldtypeSize(t
, evT
, offsetRoot
,
1702 0,fld
->child
[0], NULL
, trace
);
1703 fld
->element_size
= size
;
1705 element_number
= getIntNumber(t
->trace
->reverse_byte_order
,size1
,evD
);
1706 type
->element_number
= element_number
;
1707 if(fld
->element_size
> 0){
1708 size
= element_number
* fld
->element_size
;
1709 }else{//sequence has string or sequence
1711 for(i
=0;i
<element_number
;i
++){
1712 size
+= getFieldtypeSize(t
, evT
, offsetRoot
+size
+size1
,size
+size1
,
1713 fld
->child
[0], evD
+size
+size1
, trace
);
1719 fld
->fixed_root
= (offsetRoot
==-1) ? 0 : 1;
1720 fld
->fixed_parent
= (offsetParent
==-1) ? 0 : 1;
1727 if(fld
->field_fixed
== -1){
1728 fld
->field_fixed
= 0;
1730 /* Hope my implementation is faster than strlen (Mathieu) */
1731 char *ptr
=(char*)evD
;
1733 /* from gcov : many many strings are empty, make it the common case.*/
1734 while(unlikely(*ptr
!= '\0')) { size
++; ptr
++; }
1735 //size = ptr - (char*)evD + 1; //include end : '\0'
1737 fld
->fixed_root
= (offsetRoot
==-1) ? 0 : 1;
1738 fld
->fixed_parent
= (offsetParent
==-1) ? 0 : 1;
1743 element_number
= (int) type
->element_number
;
1745 /* tested with gcov */
1746 if(unlikely(fld
->field_fixed
== -1)){
1747 offset1
= offsetRoot
;
1749 for(i
=0;i
<element_number
;i
++){
1750 size1
=getFieldtypeSize(t
, evT
,offset1
,offset2
,
1751 fld
->child
[i
], NULL
, trace
);
1752 if(likely(size1
> 0 && size
>= 0)){
1754 if(likely(offset1
>= 0)) offset1
+= size1
;
1762 if(unlikely(size
== -1)){
1763 fld
->field_fixed
= 0;
1765 }else fld
->field_fixed
= 1;
1766 }else if(likely(fld
->field_fixed
== 0)){
1767 offset1
= offsetRoot
;
1769 for(i
=0;unlikely(i
<element_number
);i
++){
1770 size
=getFieldtypeSize(t
,evT
,offset1
,offset2
,
1771 fld
->child
[i
],evD
+offset2
, trace
);
1776 }else size
= fld
->field_size
;
1777 fld
->fixed_root
= (offsetRoot
==-1) ? 0 : 1;
1778 fld
->fixed_parent
= (offsetParent
==-1) ? 0 : 1;
1782 if(unlikely(fld
->field_fixed
== -1)){
1783 size
= (int) ltt_type_size(trace
, type
);
1784 fld
->field_fixed
= 1;
1785 }else size
= fld
->field_size
;
1787 fld
->fixed_root
= (offsetRoot
==-1) ? 0 : 1;
1788 fld
->fixed_parent
= (offsetParent
==-1) ? 0 : 1;
1794 fld
->offset_root
= offsetRoot
;
1795 fld
->offset_parent
= offsetParent
;
1796 fld
->field_size
= size
;
1798 end_getFieldtypeSize
:
1804 /*****************************************************************************
1806 * getIntNumber : get an integer number
1808 * size : the size of the integer
1809 * evD : the event data
1811 * gint64 : a 64 bits integer
1812 ****************************************************************************/
1814 gint64
getIntNumber(gboolean reverse_byte_order
, int size
, void *evD
)
1819 case 1: i
= *((gint8
*)evD
); break;
1820 case 2: i
= ltt_get_int16(reverse_byte_order
, evD
); break;
1821 case 4: i
= ltt_get_int32(reverse_byte_order
, evD
); break;
1822 case 8: i
= ltt_get_int64(reverse_byte_order
, evD
); break;
1823 default: i
= ltt_get_int64(reverse_byte_order
, evD
);
1824 g_critical("getIntNumber : integer size %d unknown", size
);
1831 /*****************************************************************************
1833 * getDataEndianType : get the data type size and endian type of the local
1836 * size : size of data type
1837 * endian : endian type, little or big
1838 ****************************************************************************/
1840 void getDataEndianType(LttArchSize
* size
, LttArchEndian
* endian
)
1844 int sizeInt
=sizeof(int), sizeLong
=sizeof(long), sizePointer
=sizeof(void *);
1846 if(c
== 1) *endian
= LTT_LITTLE_ENDIAN
;
1847 else *endian
= LTT_BIG_ENDIAN
;
1849 if(sizeInt
== 2 && sizeLong
== 4 && sizePointer
== 4)
1851 else if(sizeInt
== 4 && sizeLong
== 4 && sizePointer
== 4)
1853 else if(sizeInt
== 4 && sizeLong
== 8 && sizePointer
== 8)
1855 else if(sizeInt
== 8 && sizeLong
== 8 && sizePointer
== 8)
1857 else *size
= LTT_UNKNOWN
;
1860 /* get the node name of the system */
1862 char * ltt_trace_system_description_node_name (LttSystemDescription
* s
)
1864 return s
->node_name
;
1868 /* get the domain name of the system */
1870 char * ltt_trace_system_description_domain_name (LttSystemDescription
* s
)
1872 return s
->domain_name
;
1876 /* get the description of the system */
1878 char * ltt_trace_system_description_description (LttSystemDescription
* s
)
1880 return s
->description
;
1884 /* get the start time of the trace */
1886 LttTime
ltt_trace_system_description_trace_start_time(LttSystemDescription
*s
)
1888 return s
->trace_start
;
1892 LttTracefile
*ltt_tracefile_new()
1894 return g_new(LttTracefile
, 1);
1897 void ltt_tracefile_destroy(LttTracefile
*tf
)
1902 void ltt_tracefile_copy(LttTracefile
*dest
, const LttTracefile
*src
)
1907 /* Before library loading... */
1909 static void __attribute__((constructor
)) init(void)
1911 LTT_FACILITY_NAME_HEARTBEAT
= g_quark_from_string("heartbeat");
1912 LTT_EVENT_NAME_HEARTBEAT
= g_quark_from_string("heartbeat");
1914 LTT_TRACEFILE_NAME_FACILITIES
= g_quark_from_string("control/facilities");