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");
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) */
1188 ltt_tracefile_read(tf
);
1189 if(ltt_time_compare(time
, tf
->event
.event_time
) >= 0)
1193 } if(ltt_time_compare(time
, tf
->buffer
.start
.timestamp
) < 0) {
1194 /* go to lower part */
1196 } else if(ltt_time_compare(time
, tf
->buffer
.end
.timestamp
) > 0) {
1197 /* go to higher part */
1199 } else {/* The event is right in the buffer!
1200 (or in the next buffer first event) */
1202 ltt_tracefile_read(tf
);
1203 if(ltt_time_compare(time
, tf
->event
.event_time
) >= 0)
1214 /* Error handling */
1216 g_error("ltt_tracefile_seek_time failed on tracefile %s",
1217 g_quark_to_string(tf
->name
));
1221 int ltt_tracefile_seek_position(LttTracefile
*tf
, const LttEventPosition
*ep
) {
1225 if(ep
->tracefile
!= tf
) {
1229 err
= map_block(tf
, ep
->block
);
1231 g_error("Can not map block");
1235 tf
->event
.offset
= ep
->offset
;
1237 if(!ltt_tracefile_read(tf
)) goto fail
;
1242 g_error("ltt_tracefile_seek_time failed on tracefile %s",
1243 g_quark_to_string(tf
->name
));
1248 /*****************************************************************************
1249 * Seek to the first event with position equal or larger to ep
1251 * Modified by Mathieu Desnoyers to used faster offset position instead of
1252 * re-reading the whole buffer.
1253 ****************************************************************************/
1255 void ltt_tracefile_seek_position(LttTracefile
*t
, const LttEventPosition
*ep
)
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
))
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
)){
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
;
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 */
1284 //update the fields of the current event and go to the next event
1286 if(unlikely(err
== ERANGE
)) g_error("event id is out of range\n");
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");
1296 while(likely(t
->which_event
< ep
->event_num
)) ltt_tracefile_read(t
, &event
);
1301 /* Calculate the real event time based on the buffer boundaries */
1302 LttTime
ltt_interpolate_time(LttTracefile
*tf
, LttEvent
*event
)
1306 g_assert(t
->trace
->has_tsc
);
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
);
1316 /*****************************************************************************
1318 * ltt_tracefile_read : Read the next event in the tracefile
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.
1326 * Returns NULL on end of trace (or error).
1329 * This function does make the tracefile event structure point to the event
1330 * currently pointed to by the
1331 ****************************************************************************/
1333 LttEvent
*ltt_tracefile_read(LttTracefile
*tf
)
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.
1343 err
= ltt_seek_next_event(tf
);
1344 if(unlikely(err
== ERANGE
)) {
1345 g_error("event id is out of range\n");
1349 pos
= tf
->event
.offset
;
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 ? */
1356 /* get next block */
1357 err
= map_block(tf
, tf
->buffer
.index
+ 1);
1359 g_error("Can not map block");
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");
1369 pos
= tf
->event
.offset
;
1373 /* Read event header */
1377 if(tf
->trace
->has_tsc
) {
1378 event
->time
.timestamp
= ltt_get_uint32(LTT_GET_BO(t
),
1380 /* 32 bits -> 64 bits tsc */
1381 if(event
->time
.timestamp
< (0xFFFFFFFFULL
&tf
->buffer
.tsc
)) {
1382 tf
->buffer
.tsc
= ((tf
->buffer
.tsc
&0xFFFFFFFF00000000ULL
)
1384 | (guint64
)event
->time
.timestamp
;
1386 event
->event_time
= ltt_interpolate_time(tf
, event
);
1389 tf
->buffer
.tsc
= (tf
->buffer
.tsc
&0xFFFFFFFF00000000ULL
)
1390 | (guint64
)event
->time
.timestamp
;
1392 pos
+= sizeof(uint32
);
1394 event
->time
.delta
= ltt_get_uint32(LTT_GET_BO(tf
),
1398 event
->event_time
= ltt_time_add(tf
->buffer
.begin
.timestamp
,
1400 pos
+= sizeof(uint32
);
1403 event
->facility_id
= ltt_get_uint8(LTT_GET_BO(tf
),
1405 pos
+= sizeof(uint8
);
1407 event
->event_id
= ltt_get_uint8(LTT_GET_BO(tf
),
1409 pos
+= sizeof(uint8
);
1411 event
->data
= tf
->cur_event_pos
+ EVENT_HEADER_SIZE
;
1415 /* do event specific operation */
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
);
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
++;
1436 /****************************************************************************
1438 * readFile : wrap function to read from a file
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
1446 * EIO : can not read from the file
1447 ****************************************************************************/
1449 int readFile(int fd
, void * buf
, size_t size
, char * mesg
)
1451 ssize_t nbBytes
= read(fd
, buf
, size
);
1453 if((size_t)nbBytes
!= size
) {
1455 perror("Error in readFile : ");
1457 g_warning("%s",mesg
);
1465 /****************************************************************************
1467 * map_block : map a block from the file
1469 * lttdes : ltt trace file
1470 * whichBlock : the block which will be read
1473 * EINVAL : lseek fail
1474 * EIO : can not read from the file
1475 ****************************************************************************/
1477 static int map_block(LttTracefile
* tf
, int block_num
)
1479 struct ltt_block_start_header
*header
;
1481 g_assert(block_num
< tf
->num_blocks
);
1483 if(tf
->buffer
.head
!= NULL
)
1484 munmap(tf
->buffer
.head
, tf
->buf_size
);
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
);
1490 if(tf
->buffer
.head
== NULL
) {
1491 perror("Error in allocating memory for buffer of tracefile %s\n", fileName
);
1494 g_assert(tf
->buffer
.head
& (8-1) == 0); // make sure it's aligned.
1497 tf
->buffer
.index
= block_num
;
1499 header
= (struct ltt_block_start_header
*)tf
->buffer
.head
;
1501 tf
->buffer
.begin
.timestamp
= ltt_get_uint64(LTT_GET_BO(tf
),
1502 header
->begin
.timestamp
)
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
)
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
),
1514 tf
->buffer
.tsc
= tf
->buffer
.begin
.cycle_count
;
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
));
1521 /* Now that the buffer is mapped, calculate the time interpolation for the
1524 tf
->buffer
.nsecs_per_cycle
= calc_nsecs_per_cycle(&tf
->buffer
);
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
;
1539 /*****************************************************************************
1541 * updateTracefile : reinitialize the info of the block which is already
1545 ****************************************************************************/
1547 void updateTracefile(LttTracefile
* tf
)
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;
1554 tf
->prev_event_time
.tv_sec
= 0;
1555 tf
->prev_event_time
.tv_nsec
= 0;
1559 (-((double)ltt_get_uint64(tf
->trace
->reverse_byte_order
,
1560 &tf
->a_block_start
->cycle_count
))
1561 * tf
->nsec_per_cycle
);
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.
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.
1572 * Returns 0 on success
1573 * ERANGE if we are at the end of the buffer.
1575 static int ltt_seek_next_event(LttTracefile
*tf
)
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
);
1585 /* if we are at the end of a buffer, generate an error, not supposed to
1587 if(tf
->event
.offset
== tf
->buffer
.head
+ tf
->buffer
.lost_size
)
1590 pos
= tf
->event
.data
;
1592 pos
+= ltt_facility_get_event_size(tf
->event
.facility_id
, tf
->event
.event_id
);
1594 tf
->event
.offset
= pos
;
1600 g_error("Error in ltt_seek_next_event for tracefile %s",
1601 g_quark_to_string(tf
->name
));
1606 /*****************************************************************************
1608 * calc_nsecs_per_cycle : calculate nsecs per cycle for current block
1611 ****************************************************************************/
1613 static double calc_nsecs_per_cycle(LttTracefile
* t
)
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 */
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
));
1624 /* Calculate the total cycles for this bufffer */
1625 lBufTotalCycle
= t
->buffer
.end
.cycle_count
;
1626 lBufTotalCycle
-= t
->buffer
.start
.cycle_count
;
1628 /* Convert the total time to double */
1629 lBufTotalNSec
= ltt_time_to_double(lBufTotalTime
);
1631 return lBufTotalNSec
/ (double)lBufTotalCycle
;
1635 /*****************************************************************************
1637 * setFieldsOffset : set offset of the fields
1639 * tracefile : opened trace file
1640 * evT : the event type
1641 * evD : event data, it may be NULL
1642 ****************************************************************************/
1644 void setFieldsOffset(LttTracefile
*tf
,LttEventType
*evT
,void *evD
,LttTrace
* t
)
1646 LttField
* rootFld
= evT
->root_field
;
1647 // rootFld->base_address = evD;
1650 rootFld
->field_size
= getFieldtypeSize(tf
, evT
, 0,0,rootFld
, evD
,t
);
1653 /*****************************************************************************
1655 * getFieldtypeSize: get the size of the field type (primitive type)
1657 * tracefile : opened trace file
1659 * offsetRoot : offset from the root
1660 * offsetParent : offset from the parrent
1662 * evD : event data, it may be NULL
1664 * int : size of the field
1665 ****************************************************************************/
1667 static inline gint
getFieldtypeSize(LttTracefile
* t
,
1668 LttEventType
* evT
, gint offsetRoot
,
1669 gint offsetParent
, LttField
* fld
, void *evD
, LttTrace
*trace
)
1671 gint size
, size1
, element_number
, i
, offset1
, offset2
;
1672 LttType
* type
= fld
->field_type
;
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
;
1679 /* This likely has been tested with gcov : half of them.. */
1680 if(unlikely(fld
->field_fixed
== 1)){
1682 if(unlikely(fld
== evT
->root_field
)) {
1683 size
= fld
->field_size
;
1684 goto end_getFieldtypeSize
;
1688 /* From gcov profiling : half string, half struct, can we gain something
1689 * from that ? (Mathieu) */
1690 switch(type
->type_class
) {
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;
1699 fld
->field_fixed
= 1;
1700 size
*= element_number
;
1702 }else if(fld
->field_fixed
== 0){// has string or sequence
1704 for(i
=0;i
<element_number
;i
++){
1705 size
+= getFieldtypeSize(t
, evT
, offsetRoot
+size
,size
,
1706 fld
->child
[0], evD
+size
, trace
);
1708 }else size
= fld
->field_size
;
1710 fld
->fixed_root
= (offsetRoot
==-1) ? 0 : 1;
1711 fld
->fixed_parent
= (offsetParent
==-1) ? 0 : 1;
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
;
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
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
);
1739 fld
->fixed_root
= (offsetRoot
==-1) ? 0 : 1;
1740 fld
->fixed_parent
= (offsetParent
==-1) ? 0 : 1;
1747 if(fld
->field_fixed
== -1){
1748 fld
->field_fixed
= 0;
1750 /* Hope my implementation is faster than strlen (Mathieu) */
1751 char *ptr
=(char*)evD
;
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'
1757 fld
->fixed_root
= (offsetRoot
==-1) ? 0 : 1;
1758 fld
->fixed_parent
= (offsetParent
==-1) ? 0 : 1;
1763 element_number
= (int) type
->element_number
;
1765 /* tested with gcov */
1766 if(unlikely(fld
->field_fixed
== -1)){
1767 offset1
= offsetRoot
;
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)){
1774 if(likely(offset1
>= 0)) offset1
+= size1
;
1782 if(unlikely(size
== -1)){
1783 fld
->field_fixed
= 0;
1785 }else fld
->field_fixed
= 1;
1786 }else if(likely(fld
->field_fixed
== 0)){
1787 offset1
= offsetRoot
;
1789 for(i
=0;unlikely(i
<element_number
);i
++){
1790 size
=getFieldtypeSize(t
,evT
,offset1
,offset2
,
1791 fld
->child
[i
],evD
+offset2
, trace
);
1796 }else size
= fld
->field_size
;
1797 fld
->fixed_root
= (offsetRoot
==-1) ? 0 : 1;
1798 fld
->fixed_parent
= (offsetParent
==-1) ? 0 : 1;
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
;
1807 fld
->fixed_root
= (offsetRoot
==-1) ? 0 : 1;
1808 fld
->fixed_parent
= (offsetParent
==-1) ? 0 : 1;
1814 fld
->offset_root
= offsetRoot
;
1815 fld
->offset_parent
= offsetParent
;
1816 fld
->field_size
= size
;
1818 end_getFieldtypeSize
:
1824 /*****************************************************************************
1826 * getIntNumber : get an integer number
1828 * size : the size of the integer
1829 * evD : the event data
1831 * gint64 : a 64 bits integer
1832 ****************************************************************************/
1834 gint64
getIntNumber(gboolean reverse_byte_order
, int size
, void *evD
)
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
);
1851 /*****************************************************************************
1853 * getDataEndianType : get the data type size and endian type of the local
1856 * size : size of data type
1857 * endian : endian type, little or big
1858 ****************************************************************************/
1860 void getDataEndianType(LttArchSize
* size
, LttArchEndian
* endian
)
1864 int sizeInt
=sizeof(int), sizeLong
=sizeof(long), sizePointer
=sizeof(void *);
1866 if(c
== 1) *endian
= LTT_LITTLE_ENDIAN
;
1867 else *endian
= LTT_BIG_ENDIAN
;
1869 if(sizeInt
== 2 && sizeLong
== 4 && sizePointer
== 4)
1871 else if(sizeInt
== 4 && sizeLong
== 4 && sizePointer
== 4)
1873 else if(sizeInt
== 4 && sizeLong
== 8 && sizePointer
== 8)
1875 else if(sizeInt
== 8 && sizeLong
== 8 && sizePointer
== 8)
1877 else *size
= LTT_UNKNOWN
;
1880 /* get the node name of the system */
1882 char * ltt_trace_system_description_node_name (LttSystemDescription
* s
)
1884 return s
->node_name
;
1888 /* get the domain name of the system */
1890 char * ltt_trace_system_description_domain_name (LttSystemDescription
* s
)
1892 return s
->domain_name
;
1896 /* get the description of the system */
1898 char * ltt_trace_system_description_description (LttSystemDescription
* s
)
1900 return s
->description
;
1904 /* get the start time of the trace */
1906 LttTime
ltt_trace_system_description_trace_start_time(LttSystemDescription
*s
)
1908 return s
->trace_start
;
1912 LttTracefile
*ltt_tracefile_new()
1914 return g_new(LttTracefile
, 1);
1917 void ltt_tracefile_destroy(LttTracefile
*tf
)
1922 void ltt_tracefile_copy(LttTracefile
*dest
, const LttTracefile
*src
)
1927 /* Before library loading... */
1929 static void __attribute__((constructor
)) init(void)
1931 LTT_FACILITY_NAME_HEARTBEAT
= g_quark_from_string("heartbeat");
1932 LTT_EVENT_NAME_HEARTBEAT
= g_quark_from_string("heartbeat");
1934 LTT_TRACEFILE_NAME_FACILITIES
= g_quark_from_string("control/facilities");