X-Git-Url: https://git.lttng.org/?a=blobdiff_plain;f=ltt%2Fbranches%2Fpoly%2Fltt%2Ftracefile.c;h=00ffc9bf71a6a403ea9c5ee18f875e9291e18151;hb=21ff84a0d872ff069d4ec62d0a5bed21bcfeeac5;hp=f16124f6daf041dc77894940c015b701a5a2f019;hpb=6cd62ccfe338056a2a7571addbb63e0e16354e86;p=lttv.git diff --git a/ltt/branches/poly/ltt/tracefile.c b/ltt/branches/poly/ltt/tracefile.c index f16124f6..00ffc9bf 100644 --- a/ltt/branches/poly/ltt/tracefile.c +++ b/ltt/branches/poly/ltt/tracefile.c @@ -1,473 +1,862 @@ +/* This file is part of the Linux Trace Toolkit viewer + * Copyright (C) 2003-2004 Xiangxiu Yang, Mathieu Desnoyers + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License Version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. + */ + #include #include +#include +#include #include #include -#include +#include +#include +#include + +// For realpath +#include +#include + -#include "LTTTypes.h" #include "parser.h" -#include +#include +#include "ltt-private.h" +#include +#include +#include +#include + +#define DIR_NAME_SIZE 256 +#define __UNUSED__ __attribute__((__unused__)) + +#define g_info(format...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, format) +#define g_debug(format...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, format) + + +/* obtain the time of an event */ + +static inline LttTime getEventTime(LttTracefile * tf); -#include "default.h" //yxx test /* set the offset of the fields belonging to the event, need the information of the archecture */ -void setFieldsOffset(ltt_tracefile * t, ltt_eventtype *evT, void *evD); +void setFieldsOffset(LttTracefile *tf,LttEventType *evT,void *evD,LttTrace *t); /* get the size of the field type according to the archtecture's size and endian type(info of the archecture) */ -int getFieldtypeSize(ltt_tracefile * t, ltt_eventtype * evT, int offsetRoot, - int offsetParent, ltt_field * fld, void * evD ); +static inline gint getFieldtypeSize(LttTracefile * tf, + LttEventType * evT, gint offsetRoot, + gint offsetParent, LttField *fld, void *evD, LttTrace* t); /* read a fixed size or a block information from the file (fd) */ int readFile(int fd, void * buf, size_t size, char * mesg); -int readBlock(ltt_tracefile * tf, int whichBlock); +int readBlock(LttTracefile * tf, int whichBlock); /* calculate cycles per nsec for current block */ -void getCyclePerNsec(ltt_tracefile * t); - -/* functions to release the memory occupied by the tables of a tracefile */ -void freeKey (gpointer key, gpointer value, gpointer user_data); -void freeValue (gpointer key, gpointer value, gpointer user_data); -void freeFacilityNameTable (gpointer key, gpointer value, gpointer user_data); +void getCyclePerNsec(LttTracefile * t); /* reinitialize the info of the block which is already in the buffer */ -void updateTracefile(ltt_tracefile * tf); +void updateTracefile(LttTracefile * tf); /* go to the next event */ -int skipEvent(ltt_tracefile * t); - -/* compare two time (ltt_time), 0:t1=t2, -1:t1t2 */ -int timecmp(ltt_time * t1, ltt_time * t2); - -/* get an integer number */ -int getIntNumber(int size1, void *evD); - - -/* Time operation macros for ltt_time (struct timespec) */ -/* (T3 = T2 - T1) */ -#define TimeSub(T3, T2, T1) \ -do \ -{\ - (T3).tv_sec = (T2).tv_sec - (T1).tv_sec; \ - (T3).tv_nsec = (T2).tv_nsec - (T1).tv_nsec; \ - if((T3).tv_nsec < 0)\ - {\ - (T3).tv_sec--;\ - (T3).tv_nsec += 1000000000;\ - }\ -} while(0) - -/* (T3 = T2 + T1) */ -#define TimeAdd(T3, T2, T1) \ -do \ -{\ - (T3).tv_sec = (T2).tv_sec + (T1).tv_sec; \ - (T3).tv_nsec = (T2).tv_nsec + (T1).tv_nsec; \ - if((T3).tv_nsec >= 1000000000)\ - {\ - (T3).tv_sec += (T3).tv_nsec / 1000000000;\ - (T3).tv_nsec = (T3).tv_nsec % 1000000000;\ - }\ -} while(0) +int skipEvent(LttTracefile * t); + + +/* Functions to parse system.xml file (using glib xml parser) */ +static void parser_start_element (GMarkupParseContext __UNUSED__ *context, + const gchar *element_name, + const gchar **attribute_names, + const gchar **attribute_values, + gpointer user_data, + GError **error) +{ + int i=0; + LttSystemDescription* des = (LttSystemDescription* )user_data; + if(strcmp("system", element_name)){ + *error = g_error_new(G_MARKUP_ERROR, + G_LOG_LEVEL_WARNING, + "This is not system.xml file"); + return; + } + + while(attribute_names[i]){ + if(strcmp("node_name", attribute_names[i])==0){ + des->node_name = g_strdup(attribute_values[i]); + }else if(strcmp("domainname", attribute_names[i])==0){ + des->domain_name = g_strdup(attribute_values[i]); + }else if(strcmp("cpu", attribute_names[i])==0){ + des->nb_cpu = atoi(attribute_values[i]); + }else if(strcmp("arch_size", attribute_names[i])==0){ + if(strcmp(attribute_values[i],"LP32") == 0) des->size = LTT_LP32; + else if(strcmp(attribute_values[i],"ILP32") == 0) des->size = LTT_ILP32; + else if(strcmp(attribute_values[i],"LP64") == 0) des->size = LTT_LP64; + else if(strcmp(attribute_values[i],"ILP64") == 0) des->size = LTT_ILP64; + else if(strcmp(attribute_values[i],"UNKNOWN") == 0) des->size = LTT_UNKNOWN; + }else if(strcmp("endian", attribute_names[i])==0){ + if(strcmp(attribute_values[i],"LITTLE_ENDIAN") == 0) + des->endian = LTT_LITTLE_ENDIAN; + else if(strcmp(attribute_values[i],"BIG_ENDIAN") == 0) + des->endian = LTT_BIG_ENDIAN; + }else if(strcmp("kernel_name", attribute_names[i])==0){ + des->kernel_name = g_strdup(attribute_values[i]); + }else if(strcmp("kernel_release", attribute_names[i])==0){ + des->kernel_release = g_strdup(attribute_values[i]); + }else if(strcmp("kernel_version", attribute_names[i])==0){ + des->kernel_version = g_strdup(attribute_values[i]); + }else if(strcmp("machine", attribute_names[i])==0){ + des->machine = g_strdup(attribute_values[i]); + }else if(strcmp("processor", attribute_names[i])==0){ + des->processor = g_strdup(attribute_values[i]); + }else if(strcmp("hardware_platform", attribute_names[i])==0){ + des->hardware_platform = g_strdup(attribute_values[i]); + }else if(strcmp("operating_system", attribute_names[i])==0){ + des->operating_system = g_strdup(attribute_values[i]); + }else if(strcmp("ltt_major_version", attribute_names[i])==0){ + des->ltt_major_version = atoi(attribute_values[i]); + }else if(strcmp("ltt_minor_version", attribute_names[i])==0){ + des->ltt_minor_version = atoi(attribute_values[i]); + }else if(strcmp("ltt_block_size", attribute_names[i])==0){ + des->ltt_block_size = atoi(attribute_values[i]); + }else{ + *error = g_error_new(G_MARKUP_ERROR, + G_LOG_LEVEL_WARNING, + "Not a valid attribute"); + return; + } + i++; + } +} +static void parser_characters (GMarkupParseContext __UNUSED__ *context, + const gchar *text, + gsize __UNUSED__ text_len, + gpointer user_data, + GError __UNUSED__ **error) +{ + LttSystemDescription* des = (LttSystemDescription* )user_data; + des->description = g_strdup(text); +} /***************************************************************************** *Function name - * ltt_tracefile_open : open a trace file, construct a ltt_tracefile + * ltt_tracefile_open : open a trace file, construct a LttTracefile *Input params - * pathname : path name of the trace file + * t : the trace containing the tracefile + * fileName : path name of the trace file *Return value - * ltt_tracefile * : the structure represents the opened trace file + * : a pointer to a tracefile ****************************************************************************/ -ltt_tracefile *ltt_tracefile_open(char * fileName) +LttTracefile* ltt_tracefile_open(LttTrace * t, char * fileName) { - ltt_tracefile * tf; - struct stat lTDFStat; /* Trace data file status */ - trace_header_event *trace_header; - block_header a_block_header; + LttTracefile * tf; + struct stat lTDFStat; /* Trace data file status */ - tf = g_new(ltt_tracefile, 1); + tf = g_new(LttTracefile, 1); //open the file + tf->name = g_strdup(fileName); + tf->trace = t; tf->fd = open(fileName, O_RDONLY, 0); if(tf->fd < 0){ - g_error("Unable to open input data file %s\n", fileName); + g_warning("Unable to open input data file %s\n", fileName); + g_free(tf->name); + g_free(tf); + return NULL; } // Get the file's status if(fstat(tf->fd, &lTDFStat) < 0){ - g_error("Unable to get the status of the input data file %s\n", fileName); + g_warning("Unable to get the status of the input data file %s\n", fileName); + g_free(tf->name); + close(tf->fd); + g_free(tf); + return NULL; } // Is the file large enough to contain a trace - if(lTDFStat.st_size < sizeof(block_header) + sizeof(trace_header_event)){ - g_error("The input data file %s does not contain a trace\n", fileName); + if(lTDFStat.st_size < (off_t)(sizeof(BlockStart) + EVENT_HEADER_SIZE)){ + g_print("The input data file %s does not contain a trace\n", fileName); + g_free(tf->name); + close(tf->fd); + g_free(tf); + return NULL; } //store the size of the file tf->file_size = lTDFStat.st_size; - - //read the first block header - if(readFile(tf->fd,(void*)&a_block_header, sizeof(block_header), - "Unable to read block header")) - exit(1); - - //read the trace header event - trace_header = g_new(trace_header_event, 1); - if(readFile(tf->fd,(void*)trace_header, sizeof(trace_header_event), - "Unable to read trace header event")) - exit(1); - - tf->block_number = tf->file_size / trace_header->buffer_size; - tf->trace_header = (trace_header_event *)trace_header; + tf->block_size = t->system_description->ltt_block_size; + tf->block_number = tf->file_size / tf->block_size; + tf->which_block = 0; //allocate memory to contain the info of a block - tf->buffer = (void *) g_new(char, trace_header->buffer_size); + tf->buffer = (void *) g_new(char, t->system_description->ltt_block_size); - //read the last block, get the trace end time - if(readBlock(tf,tf->block_number)) exit(1); - tf->end_time = tf->a_block_footer->time; - - //read the first block, get the trace start time - if(tf->block_number != 1) - if(readBlock(tf,1)) exit(1); - tf->start_time = tf->a_block_header->time; - - //get local machine's data type size and endian type - getDataEndianType(&(tf->my_arch_size), &(tf->my_arch_endian)); - - //initialize all tables - tf->eventtype_number = 0; - tf->facility_number = 0; - tf->index_facility = g_hash_table_new (g_int_hash, g_int_equal); - tf->facility_name = g_hash_table_new (g_str_hash, g_str_equal); - tf->base_id_name = g_hash_table_new (g_str_hash, g_int_equal); - tf->eventtype_event_id = g_ptr_array_new(); + //read the first block + if(readBlock(tf,1)) exit(1); return tf; } + /***************************************************************************** - *Function name - * ltt_tracefile_close: close a trace file, release all facilities if their - * usage count == 0 when close_facilities is true - *Input params - * t : tracefile which will be closed - * close_facilities : bool to show if the facilities need to be released - *Return value - * int : ???? + *Open control and per cpu tracefiles ****************************************************************************/ -int ltt_tracefile_close(ltt_tracefile *t, int close_facilities) +void ltt_tracefile_open_cpu(LttTrace *t, char * tracefile_name) { - //free index_facility table - g_hash_table_foreach (t->index_facility, freeKey, NULL); - g_hash_table_destroy(t->index_facility); - - //free base_id_facility table - g_hash_table_foreach (t->base_id_name, freeValue, NULL); - g_hash_table_destroy(t->base_id_name); - - //free eventtype_event_id array - g_ptr_array_free (t->eventtype_event_id, TRUE); - - //free facility_name table - g_hash_table_foreach (t->facility_name, freeFacilityNameTable, - GINT_TO_POINTER(1)); - g_hash_table_destroy(t->facility_name); + LttTracefile * tf; + tf = ltt_tracefile_open(t,tracefile_name); + if(!tf) return; + t->per_cpu_tracefile_number++; + g_ptr_array_add(t->per_cpu_tracefiles, tf); +} - //free tracefile structure - g_free(t->trace_header); - g_free(t->buffer); - g_free(t); +gint ltt_tracefile_open_control(LttTrace *t, char * control_name) +{ + LttTracefile * tf; + LttEvent ev; + LttFacility * f; + void * pos; + FacilityLoad fLoad; + unsigned int i; + + tf = ltt_tracefile_open(t,control_name); + if(!tf) { + g_warning("ltt_tracefile_open_control : bad file descriptor"); + return -1; + } + t->control_tracefile_number++; + g_ptr_array_add(t->control_tracefiles,tf); + + //parse facilities tracefile to get base_id + if(strcmp(&control_name[strlen(control_name)-10],"facilities") ==0){ + while(1){ + if(!ltt_tracefile_read(tf,&ev)) return 0; // end of file + + if(ev.event_id == TRACE_FACILITY_LOAD){ + pos = ev.data; + fLoad.name = (char*)pos; + fLoad.checksum = *(LttChecksum*)(pos + strlen(fLoad.name)); + fLoad.base_code = *(guint32 *)(pos + strlen(fLoad.name) + sizeof(LttChecksum)); + + for(i=0;ifacility_number;i++){ + f = (LttFacility*)g_ptr_array_index(t->facilities,i); + if(strcmp(f->name,fLoad.name)==0 && fLoad.checksum==f->checksum){ + f->base_id = fLoad.base_code; + break; + } + } + if(i==t->facility_number) { + g_warning("Facility: %s, checksum: %u is not found", + fLoad.name,(unsigned int)fLoad.checksum); + return -1; + } + }else if(ev.event_id == TRACE_BLOCK_START){ + continue; + }else if(ev.event_id == TRACE_BLOCK_END){ + break; + }else { + g_warning("Not valid facilities trace file"); + return -1; + } + } + } return 0; } /***************************************************************************** - * functions to release the memory occupied by the tables of a tracefile + *Function name + * ltt_tracefile_close: close a trace file, + *Input params + * t : tracefile which will be closed ****************************************************************************/ -void freeKey (gpointer key, gpointer value, gpointer user_data) +void ltt_tracefile_close(LttTracefile *t) { - g_free(key); + g_free(t->name); + g_free(t->buffer); + close(t->fd); + g_free(t); } -void freeValue (gpointer key, gpointer value, gpointer user_data) -{ - g_free(value); -} -void freeFacilityNameTable (gpointer key, gpointer value, gpointer user_data) +/***************************************************************************** + *Get system information + ****************************************************************************/ +gint getSystemInfo(LttSystemDescription* des, char * pathname) { - ltt_facility * fac = (ltt_facility*) value; - fac->usage_count--; - if(GPOINTER_TO_INT(user_data) != 0) - ltt_facility_close(fac); + FILE * fp; + char buf[DIR_NAME_SIZE]; + + GMarkupParseContext * context; + GError * error = NULL; + GMarkupParser markup_parser = + { + parser_start_element, + NULL, + parser_characters, + NULL, /* passthrough */ + NULL /* error */ + }; + + fp = fopen(pathname,"r"); + if(!fp){ + g_warning("Can not open file : %s\n", pathname); + return -1; + } + + context = g_markup_parse_context_new(&markup_parser, 0, des,NULL); + + while(fgets(buf,DIR_NAME_SIZE, fp) != NULL){ + if(!g_markup_parse_context_parse(context, buf, DIR_NAME_SIZE, &error)){ + if(error != NULL) { + g_warning("Can not parse xml file: \n%s\n", error->message); + g_error_free(error); + } + g_markup_parse_context_free(context); + fclose(fp); + return -1; + } + } + g_markup_parse_context_free(context); + fclose(fp); + return 0; } /***************************************************************************** - *Function name - * ltt_tracefile_facility_add: increases the facility usage count and also - * specifies the base of the numeric range - * assigned to the event types in the facility - * for this tracefile - *Input params - * t : tracefile that the facility will be added - * f : facility that will be attached to the tracefile - * base_id : the id for the first event of the facility in the - * trace file - *Return value - * int : ???? + *The following functions get facility/tracefile information ****************************************************************************/ -int ltt_tracefile_facility_add(ltt_tracefile *t,ltt_facility *f,int base_id) +gint getFacilityInfo(LttTrace *t, char* eventdefs) { - int * id, *index; - int i, j, k; - ltt_eventtype * et; - gpointer tmpPtr; - - //increase the facility usage count - f->usage_count++; - t->eventtype_number += f->event_number; - t->facility_number++; - - //insert the facility into index_facility table - id = g_new(int,1); - *id = t->facility_number; - g_hash_table_insert(t->index_facility, (gpointer)id,(gpointer)f); - - //insert facility name into table: base_id_name - id = g_new(int,1); - *id = base_id; - g_hash_table_insert(t->base_id_name, (gpointer)(f->name), (gpointer)id); + DIR * dir; + struct dirent *entry; + char * ptr; + unsigned int i,j; + LttFacility * f; + LttEventType * et; + char name[DIR_NAME_SIZE]; + + dir = opendir(eventdefs); + if(!dir) { + g_warning("Can not open directory: %s\n", eventdefs); + return -1; + } - //insert facility name into table: facility_name - g_hash_table_insert(t->facility_name, (gpointer)(f->name), (gpointer)f); + while((entry = readdir(dir)) != NULL){ + ptr = &entry->d_name[strlen(entry->d_name)-4]; + if(strcmp(ptr,".xml") != 0) continue; + strcpy(name,eventdefs); + strcat(name,entry->d_name); + ltt_facility_open(t,name); + } + closedir(dir); - //insert eventtype into the array: eventtype_event_id - j = base_id + f->event_number; - k = t->eventtype_event_id->len; - if(j > t->eventtype_event_id->len){ - for(i=0; i < j - k; i++){ - tmpPtr = (gpointer)g_new(ptr_wrap, 1); - g_ptr_array_add(t->eventtype_event_id,tmpPtr); - } + for(j=0;jfacility_number;j++){ + f = (LttFacility*)g_ptr_array_index(t->facilities, j); + for(i=0; ievent_number; i++){ + et = f->events[i]; + setFieldsOffset(NULL, et, NULL, t); + } } + return 0; +} - //initialize the unused elements: NULL - if(j-k > f->event_number){ - for(i=k; ieventtype_event_id, i); - ((ptr_wrap*)tmpPtr)->ptr = NULL; - } +gint getControlFileInfo(LttTrace *t, char* control) +{ + DIR * dir; + struct dirent *entry; + char name[DIR_NAME_SIZE]; + + dir = opendir(control); + if(!dir) { + g_warning("Can not open directory: %s\n", control); + return -1; } - //initialize the elements with the eventtypes belonging to the facility - for(i=0; ievent_number; i++){ - tmpPtr = g_ptr_array_index(t->eventtype_event_id, base_id + i); - ((ptr_wrap*)tmpPtr)->ptr = (gpointer)(f->events[i]); - } - - //update offset - for(i=0; ievent_number; i++){ - et = f->events[i]; - setFieldsOffset(t, et, NULL); - } + while((entry = readdir(dir)) != NULL){ + if(strcmp(entry->d_name,"facilities") != 0 && + strcmp(entry->d_name,"interrupts") != 0 && + strcmp(entry->d_name,"processes") != 0) continue; + + strcpy(name,control); + strcat(name,entry->d_name); + if(ltt_tracefile_open_control(t,name)) + return -1; + } + closedir(dir); + return 0; +} +gint getCpuFileInfo(LttTrace *t, char* cpu) +{ + DIR * dir; + struct dirent *entry; + char name[DIR_NAME_SIZE]; + + dir = opendir(cpu); + if(!dir) { + g_warning("Can not open directory: %s\n", cpu); + return -1; + } + while((entry = readdir(dir)) != NULL){ + if(strcmp(entry->d_name,".") != 0 && + strcmp(entry->d_name,"..") != 0 && + strcmp(entry->d_name,".svn") != 0){ + strcpy(name,cpu); + strcat(name,entry->d_name); + ltt_tracefile_open_cpu(t,name); + }else continue; + } + closedir(dir); return 0; } /***************************************************************************** - * The following functions used to query the info of the machine where the - * tracefile was generated. A tracefile may be queried for its architecture - * type(e.g.,"i386", "powerpc", "powerpcle", "s390", "s390x"), its architecture - * variant(e.g., "att" versus "sun" for m68k), its operating system (e.g., - * "linux","bsd"), its generic architecture, and the machine identity (e.g., - * system host name). All character strings belong to the associated tracefile - * and are freed when it is closed - ****************************************************************************/ + *A trace is specified as a pathname to the directory containing all the + *associated data (control tracefiles, per cpu tracefiles, event + *descriptions...). + * + *When a trace is closed, all the associated facilities, types and fields + *are released as well. + */ -uint32_t ltt_tracefile_arch_type(ltt_tracefile *t) -{ - return t->trace_header->arch_type; -} -uint32_t ltt_tracefile_arch_variant(ltt_tracefile *t) +/**************************************************************************** + * get_absolute_pathname + * + * return the unique pathname in the system + * + * MD : Fixed this function so it uses realpath, dealing well with + * forgotten cases (.. were not used correctly before). + * + ****************************************************************************/ +void get_absolute_pathname(const char *pathname, char * abs_pathname) { - return t->trace_header->arch_variant; + abs_pathname[0] = '\0'; + + if ( realpath (pathname, abs_pathname) != NULL) + return; + else + { + /* error, return the original path unmodified */ + strcpy(abs_pathname, pathname); + return; + } + return; } -ltt_arch_size ltt_tracefile_arch_size(ltt_tracefile *t) +LttTrace *ltt_trace_open(const char *pathname) { - return t->trace_header->arch_size; + LttTrace * t; + LttSystemDescription * sys_description; + char eventdefs[DIR_NAME_SIZE]; + char info[DIR_NAME_SIZE]; + char control[DIR_NAME_SIZE]; + char cpu[DIR_NAME_SIZE]; + char tmp[DIR_NAME_SIZE]; + char abs_path[DIR_NAME_SIZE]; + gboolean has_slash = FALSE; + + get_absolute_pathname(pathname, abs_path); + //establish the pathname to different directories + if(abs_path[strlen(abs_path)-1] == '/')has_slash = TRUE; + strcpy(eventdefs,abs_path); + if(!has_slash)strcat(eventdefs,"/"); + strcat(eventdefs,"eventdefs/"); + + strcpy(info,abs_path); + if(!has_slash)strcat(info,"/"); + strcat(info,"info/"); + + strcpy(control,abs_path); + if(!has_slash)strcat(control,"/"); + strcat(control,"control/"); + + strcpy(cpu,abs_path); + if(!has_slash)strcat(cpu,"/"); + strcat(cpu,"cpu/"); + + //new trace + sys_description = g_new(LttSystemDescription, 1); + t = g_new(LttTrace, 1); + t->pathname = g_strdup(abs_path); + t->facility_number = 0; + t->control_tracefile_number = 0; + t->per_cpu_tracefile_number = 0; + t->system_description = sys_description; + t->control_tracefiles = g_ptr_array_new(); + t->per_cpu_tracefiles = g_ptr_array_new(); + t->facilities = g_ptr_array_new(); + getDataEndianType(&(t->my_arch_size), &(t->my_arch_endian)); + + //get system description + strcpy(tmp,info); + strcat(tmp,"system.xml"); + if(getSystemInfo(sys_description, tmp)) { + g_ptr_array_free(t->facilities, TRUE); + g_ptr_array_free(t->per_cpu_tracefiles, TRUE); + g_ptr_array_free(t->control_tracefiles, TRUE); + g_free(sys_description); + g_free(t->pathname); + g_free(t); + return NULL; + } + + + + //get facilities info + if(getFacilityInfo(t,eventdefs)) { + g_ptr_array_free(t->facilities, TRUE); + g_ptr_array_free(t->per_cpu_tracefiles, TRUE); + g_ptr_array_free(t->control_tracefiles, TRUE); + g_free(sys_description); + g_free(t->pathname); + g_free(t); + return NULL; + } + + //get control tracefile info + getControlFileInfo(t,control); + /* + if(getControlFileInfo(t,control)) { + g_ptr_array_free(t->facilities, TRUE); + g_ptr_array_free(t->per_cpu_tracefiles, TRUE); + g_ptr_array_free(t->control_tracefiles, TRUE); + g_free(sys_description); + g_free(t->pathname); + g_free(t); + return NULL; + }*/ // With fatal error + + //get cpu tracefile info + if(getCpuFileInfo(t,cpu)) { + g_ptr_array_free(t->facilities, TRUE); + g_ptr_array_free(t->per_cpu_tracefiles, TRUE); + g_ptr_array_free(t->control_tracefiles, TRUE); + g_free(sys_description); + g_free(t->pathname); + g_free(t); + return NULL; + } + + return t; } -ltt_arch_endian ltt_tracefile_arch_endian(ltt_tracefile *t) +char * ltt_trace_name(LttTrace *t) { - return t->trace_header->arch_endian; -} + return t->pathname; +} -uint32_t ltt_tracefile_system_type(ltt_tracefile *t) + +/****************************************************************************** + * When we copy a trace, we want all the opening actions to happen again : + * the trace will be reopened and totally independant from the original. + * That's why we call ltt_trace_open. + *****************************************************************************/ +LttTrace *ltt_trace_copy(LttTrace *self) { - return t->trace_header->system_type; + return ltt_trace_open(self->pathname); } -char *ltt_tracefile_system_name(ltt_tracefile *t) +void ltt_trace_close(LttTrace *t) { - return t->trace_header->system_name; + unsigned int i; + LttTracefile * tf; + LttFacility * f; + + g_free(t->pathname); + + //free system_description + g_free(t->system_description->description); + g_free(t->system_description->node_name); + g_free(t->system_description->domain_name); + g_free(t->system_description->kernel_name); + g_free(t->system_description->kernel_release); + g_free(t->system_description->kernel_version); + g_free(t->system_description->machine); + g_free(t->system_description->processor); + g_free(t->system_description->hardware_platform); + g_free(t->system_description->operating_system); + g_free(t->system_description); + + //free control_tracefiles + for(i=0;icontrol_tracefile_number;i++){ + tf = (LttTracefile*)g_ptr_array_index(t->control_tracefiles,i); + ltt_tracefile_close(tf); + } + g_ptr_array_free(t->control_tracefiles, TRUE); + + //free per_cpu_tracefiles + for(i=0;iper_cpu_tracefile_number;i++){ + tf = (LttTracefile*)g_ptr_array_index(t->per_cpu_tracefiles,i); + ltt_tracefile_close(tf); + } + g_ptr_array_free(t->per_cpu_tracefiles, TRUE); + + //free facilities + for(i=0;ifacility_number;i++){ + f = (LttFacility*)g_ptr_array_index(t->facilities,i); + ltt_facility_close(f); + } + g_ptr_array_free(t->facilities, TRUE); + + g_free(t); + + g_blow_chunks(); } + /***************************************************************************** - *Function name - * ltt_tracefile_cpu_number: get the number of the cpu - *Input params - * t : tracefile - *Return value - * unsigned : the number of cpu the system has + *Get the system description of the trace ****************************************************************************/ -unsigned ltt_tracefile_cpu_number(ltt_tracefile *t) +LttSystemDescription *ltt_trace_system_description(LttTrace *t) { - return (unsigned)(t->trace_header->cpu_number); + return t->system_description; } /***************************************************************************** - *Function name - * ltt_tracefile_cpu_single: does the tracefile contain events only for a - * single CPU ? - *Input params - * t : tracefile - *Return value - * int : 1 for YES, 0 for NO + * The following functions discover the facilities of the trace ****************************************************************************/ -int ltt_tracefile_cpu_single(ltt_tracefile *t) +unsigned ltt_trace_facility_number(LttTrace *t) +{ + return (unsigned)(t->facility_number); +} + +LttFacility *ltt_trace_facility_get(LttTrace *t, unsigned i) { - if(t->trace_header->cpu_number_used == 1) return 1; - else return 0; + return (LttFacility*)g_ptr_array_index(t->facilities, i); } /***************************************************************************** *Function name - * ltt_tracefile_cpu_id: which CPU is contained in the tracefile? + * ltt_trace_facility_find : find facilities in the trace *Input params - * t : tracefile + * t : the trace + * name : facility name + *Output params + * position : position of the facility in the trace *Return value - * unsigned : cpu id + * : the number of facilities ****************************************************************************/ -unsigned ltt_tracefile_cpu_id(ltt_tracefile *t) +unsigned ltt_trace_facility_find(LttTrace *t, char *name, unsigned *position) { - return (unsigned)(t->trace_header->cpu_id); + unsigned int i, count=0; + LttFacility * f; + for(i=0;ifacility_number;i++){ + f = (LttFacility*)g_ptr_array_index(t->facilities, i); + if(strcmp(f->name,name)==0){ + count++; + if(count==1) *position = i; + }else{ + if(count) break; + } + } + return count; } /***************************************************************************** - * The following functions get the times related to the tracefile + * Functions to discover all the event types in the trace ****************************************************************************/ -ltt_time ltt_tracefile_time_start(ltt_tracefile *t) +unsigned ltt_trace_eventtype_number(LttTrace *t) { - return t->start_time; + unsigned int i; + unsigned count = 0; + unsigned int num = t->facility_number; + LttFacility * f; + + for(i=0;ifacilities, i); + count += f->event_number; + } + return count; } -ltt_time ltt_tracefile_time_end(ltt_tracefile *t) +/* FIXME : performances could be improved with a better design for this + * function : sequential search through a container has never been the + * best on the critical path. */ +LttFacility * ltt_trace_facility_by_id(LttTrace * trace, unsigned id) { - return t->end_time; + LttFacility * facility = NULL; + unsigned int i; + unsigned int num = trace->facility_number; + GPtrArray *facilities = trace->facilities; + + for(i=0;unlikely(ibase_id; + + if(likely(id >= base_id && + id < base_id + iter_facility->event_number)) { + facility = iter_facility; + break; + } else { + i++; + } + } + + return facility; } -ltt_time ltt_tracefile_duration(ltt_tracefile *t) +LttEventType *ltt_trace_eventtype_get(LttTrace *t, unsigned evId) { - ltt_time T; - TimeSub(T, t->end_time, t->start_time); - return T; + LttEventType *event_type; + + LttFacility * f; + f = ltt_trace_facility_by_id(t,evId); + + if(unlikely(!f)) event_type = NULL; + else event_type = f->events[evId - f->base_id]; + + return event_type; } /***************************************************************************** - * The following functions discover the facilities added to the tracefile + *There is one "per cpu" tracefile for each CPU, numbered from 0 to + *the maximum number of CPU in the system. When the number of CPU installed + *is less than the maximum, some positions are unused. There are also a + *number of "control" tracefiles (facilities, interrupts...). ****************************************************************************/ +unsigned ltt_trace_control_tracefile_number(LttTrace *t) +{ + return t->control_tracefile_number; +} -unsigned ltt_tracefile_facility_number(ltt_tracefile *t) +unsigned ltt_trace_per_cpu_tracefile_number(LttTrace *t) { - return (unsigned)(t->facility_number); + return t->per_cpu_tracefile_number; } -ltt_facility *ltt_tracefile_facility_get(ltt_tracefile *t, unsigned i) +/***************************************************************************** + *It is possible to search for the tracefiles by name or by CPU position. + *The index within the tracefiles of the same type is returned if found + *and a negative value otherwise. + ****************************************************************************/ + +int ltt_trace_control_tracefile_find(LttTrace *t, const gchar *name) { - gconstpointer ptr = (gconstpointer)(&i); - if(i<=0 || i> t->facility_number)return NULL; - return (ltt_facility*)g_hash_table_lookup(t->index_facility,ptr); + LttTracefile * tracefile; + unsigned int i; + for(i=0;icontrol_tracefile_number;i++){ + tracefile = (LttTracefile*)g_ptr_array_index(t->control_tracefiles, i); + if(strcmp(tracefile->name, name)==0)break; + } + if(i == t->control_tracefile_number) return -1; + return i; } -ltt_facility *ltt_tracefile_facility_get_by_name(ltt_tracefile *t,char *name) +/* not really useful. We just have to know that cpu tracefiles + * comes before control tracefiles. + */ +int ltt_trace_per_cpu_tracefile_find(LttTrace *t, const gchar *name) { - ltt_facility * fac; - fac=(ltt_facility*)g_hash_table_lookup(t->facility_name,(gconstpointer)name); - return fac; + LttTracefile * tracefile; + unsigned int i; + for(i=0;iper_cpu_tracefile_number;i++){ + tracefile = (LttTracefile*)g_ptr_array_index(t->per_cpu_tracefiles, i); + if(strcmp(tracefile->name, name)==0)break; + } + if(i == t->per_cpu_tracefile_number) return -1; + return i; } /***************************************************************************** - * The following functions to discover all the event types in the facilities - * added to the tracefile. The event type integer id, unique for the trace, - * is used + *Get a specific tracefile ****************************************************************************/ -unsigned ltt_tracefile_eventtype_number(ltt_tracefile *t) +LttTracefile *ltt_trace_control_tracefile_get(LttTrace *t, unsigned i) { - return t->eventtype_number; + return (LttTracefile*)g_ptr_array_index(t->control_tracefiles, i); } -ltt_eventtype *ltt_tracefile_eventtype_get(ltt_tracefile *t, unsigned evId) +LttTracefile *ltt_trace_per_cpu_tracefile_get(LttTrace *t, unsigned i) { - ptr_wrap * ptr; - ptr = (ptr_wrap *)g_ptr_array_index(t->eventtype_event_id, (gint)evId); - return (ltt_eventtype *)(ptr->ptr); + return (LttTracefile*)g_ptr_array_index(t->per_cpu_tracefiles, i); } /***************************************************************************** - *Function name - * ltt_tracefile_eventtype_id - * : given an event type, find its unique id within - * the tracefile - *Input params - * t : tracefile - * et : event type - *Return value - * unsigned : id of the event type in the tracefile + * Get the start time and end time of the trace ****************************************************************************/ -unsigned ltt_tracefile_eventtype_id(ltt_tracefile *t, ltt_eventtype *et) +void ltt_trace_time_span_get(LttTrace *t, LttTime *start, LttTime *end) { - int *id; - char *name = et->facility->name; - - id = (int*)g_hash_table_lookup(t->base_id_name, (gconstpointer)name); - if(!id)return 0; - return (unsigned)(*id + et->index); + LttTime startSmall, startTmp, endBig, endTmp; + unsigned int i, j=0; + LttTracefile * tf; + + for(i=0;icontrol_tracefile_number;i++){ + tf = g_ptr_array_index(t->control_tracefiles, i); + readBlock(tf,1); + startTmp = tf->a_block_start->time; + readBlock(tf,tf->block_number); + endTmp = tf->a_block_end->time; + if(i==0){ + startSmall = startTmp; + endBig = endTmp; + j = 1; + continue; + } + if(ltt_time_compare(startSmall,startTmp) > 0) startSmall = startTmp; + if(ltt_time_compare(endBig,endTmp) < 0) endBig = endTmp; + } + + for(i=0;iper_cpu_tracefile_number;i++){ + tf = g_ptr_array_index(t->per_cpu_tracefiles, i); + readBlock(tf,1); + startTmp = tf->a_block_start->time; + readBlock(tf,tf->block_number); + endTmp = tf->a_block_end->time; + if(j == 0 && i==0){ + startSmall = startTmp; + endBig = endTmp; + continue; + } + if(ltt_time_compare(startSmall,startTmp) > 0) startSmall = startTmp; + if(ltt_time_compare(endBig,endTmp) < 0) endBig = endTmp; + } + + if(start != NULL) *start = startSmall; + if(end != NULL) *end = endBig; } + /***************************************************************************** - *Function name - * ltt_tracefile_eventtype_root_field - * : get the root field associated with an event type - * for the tracefile - *Input params - * t : tracefile - * id : event id - *Return value - * ltt_field * : root field of the event + *Get the name of a tracefile + ****************************************************************************/ + +char *ltt_tracefile_name(LttTracefile *tf) +{ + return tf->name; +} + +/***************************************************************************** + * Get the number of blocks in the tracefile ****************************************************************************/ -ltt_field *ltt_tracefile_eventtype_root_field(ltt_tracefile *t, unsigned id) +unsigned ltt_tracefile_block_number(LttTracefile *tf) { - ltt_eventtype * et; - et = ltt_tracefile_eventtype_get(t, id); - if(!et) return NULL; - return et->root_field; + return tf->block_number; } /***************************************************************************** @@ -477,93 +866,252 @@ ltt_field *ltt_tracefile_eventtype_root_field(ltt_tracefile *t, unsigned id) *Input params * t : tracefile * time : criteria of the time - *Return value - * int : error code - * ENOENT, end of the file - * EINVAL, lseek fail - * EIO, can not read from the file ****************************************************************************/ +void ltt_tracefile_find_time_block(LttTracefile *t, LttTime time, + int start_block, int end_block) +{ + int err, tmp_block, s, e; + int headTime; + int tailTime; + + err=readBlock(t,start_block); + if(err) g_error("Can not read tracefile: %s\n", t->name); + if(start_block == end_block)return; + + tailTime = ltt_time_compare(t->a_block_end->time, time); + if(tailTime >= 0) return; + + err=readBlock(t,end_block); + if(err) g_error("Can not read tracefile: %s\n", t->name); + if(start_block+1 == end_block)return; + + headTime = ltt_time_compare(t->a_block_start->time, time); + if(headTime <= 0 ) return; + + tmp_block = (end_block + start_block)/2; + err=readBlock(t,tmp_block); + if(err) g_error("Can not read tracefile: %s\n", t->name); + + headTime = ltt_time_compare(t->a_block_start->time, time); + tailTime = ltt_time_compare(t->a_block_end->time, time); + if(headTime <= 0 && tailTime >= 0) return; + + if(headTime > 0){ + s = start_block + 1; + e = tmp_block - 1; + if(s <= e) + ltt_tracefile_find_time_block(t, time, s, e); + else return; + } + + if(tailTime < 0){ + s = tmp_block + 1; + e = end_block - 1; + if(s <= e) + ltt_tracefile_find_time_block(t, time, s, e); + else return; + } +} + +void ltt_tracefile_backward_find_time_block(LttTracefile *t, LttTime time) +{ + int t_time, h_time, err; + err=readBlock(t,t->which_block-1); + if(err) g_error("Can not read tracefile: %s\n", t->name); + h_time = ltt_time_compare(t->a_block_start->time, time); + t_time = ltt_time_compare(t->a_block_end->time, time); + if(h_time == 0){ + int tmp; + if(t->which_block == 1) return; + err=readBlock(t,t->which_block-1); + if(err) g_error("Can not read tracefile: %s\n", t->name); + tmp = ltt_time_compare(t->a_block_end->time, time); + if(tmp == 0) return ltt_tracefile_seek_time(t, time); + err=readBlock(t,t->which_block+1); + if(err) g_error("Can not read tracefile: %s\n", t->name); + }else if(h_time > 0){ + ltt_tracefile_find_time_block(t, time, 1, t->which_block); + return ltt_tracefile_seek_time(t, time) ; + }else{ + if(t_time >= 0) return ltt_tracefile_seek_time(t, time); + err=readBlock(t,t->which_block+1); + if(err) g_error("Can not read tracefile: %s\n", t->name); + } +} -int ltt_tracefile_seek_time(ltt_tracefile *t, ltt_time time) +void ltt_tracefile_seek_time(LttTracefile *t, LttTime time) { int err; - ltt_time lttTime; - int headTime = timecmp(&(t->a_block_header->time), &time); - int tailTime = timecmp(&(t->a_block_footer->time), &time); - + LttTime lttTime; + int headTime = ltt_time_compare(t->a_block_start->time, time); + int tailTime = ltt_time_compare(t->a_block_end->time, time); + LttEvent ev; + if(headTime < 0 && tailTime > 0){ - lttTime = getEventTime(t); - err = timecmp(<tTime, &time); - if(err >= 0){ - if( ( (t->which_block != 1 && t->which_event != 0) || - (t->which_block == 1 && t->which_event != 1) ) && - ((t->prev_event_time.tv_sec==0 && t->prev_event_time.tv_nsec==0) || - timecmp(&t->prev_event_time, &time) >= 0 ) ){ - updateTracefile(t); - return ltt_tracefile_seek_time(t, time); - } - }else if(err < 0){ - err = t->which_block; - if(ltt_tracefile_read(t) == NULL) return ENOENT; - if(t->which_block == err) - return ltt_tracefile_seek_time(t,time); - } - }else if(headTime > 0){ + if(ltt_time_compare(t->a_block_end->time, t->current_event_time) !=0) { + lttTime = getEventTime(t); + err = ltt_time_compare(lttTime, time); + if(err > 0){ + if(t->which_event==2 || ltt_time_compare(t->prev_event_time,time)<0){ + return; + }else{ + updateTracefile(t); + return ltt_tracefile_seek_time(t, time); + } + }else if(err < 0){ + while(1){ + if(ltt_tracefile_read(t,&ev) == NULL) { + g_print("End of file\n"); + return; + } + lttTime = getEventTime(t); + err = ltt_time_compare(lttTime, time); + if(err >= 0)return; + } + }else return; + }else{//we are at the end of the block + updateTracefile(t); + return ltt_tracefile_seek_time(t, time); + } + }else if(headTime >= 0){ if(t->which_block == 1){ updateTracefile(t); }else{ - if( (t->prev_block_end_time.tv_sec == 0 && - t->prev_block_end_time.tv_nsec == 0 ) || - timecmp(&(t->prev_block_end_time),&time) > 0 ){ - err=readBlock(t,t->which_block-1); - if(err) return err; - return ltt_tracefile_seek_time(t, time) ; + if(ltt_time_compare(t->prev_block_end_time, time) >= 0 || + (t->prev_block_end_time.tv_sec == 0 && + t->prev_block_end_time.tv_nsec == 0 )){ + ltt_tracefile_backward_find_time_block(t, time); }else{ updateTracefile(t); } } - }else if(tailTime <= 0){ + }else if(tailTime < 0){ if(t->which_block != t->block_number){ - err=readBlock(t,t->which_block+1); - if(err) return err; - }else return ENOENT; - if(tailTime < 0) return ltt_tracefile_seek_time(t, time); - }else if(headTime == 0){ - updateTracefile(t); + ltt_tracefile_find_time_block(t, time, t->which_block+1, t->block_number); + return ltt_tracefile_seek_time(t, time); + }else { + t->cur_event_pos = t->buffer + t->block_size; + g_print("End of file\n"); + return; + } + }else if(tailTime == 0){ + t->cur_event_pos = t->last_event_pos; + t->current_event_time = time; + t->cur_heart_beat_number = 0; + t->prev_event_time.tv_sec = 0; + t->prev_event_time.tv_nsec = 0; + return; } - return 0; +} + +/***************************************************************************** + * Seek to the first event with position equal or larger to ep + * + * Modified by Mathieu Desnoyers to used faster offset position instead of + * re-reading the whole buffer. + ****************************************************************************/ + +void ltt_tracefile_seek_position(LttTracefile *t, const LttEventPosition *ep) +{ + //if we are at the right place, just return + if(likely(t->which_block == ep->block_num && t->which_event == ep->event_num)) + return; + + if(likely(t->which_block == ep->block_num)) updateTracefile(t); + else readBlock(t,ep->block_num); + //event offset is available + if(likely(ep->old_position)){ + int err; + + t->which_event = ep->event_num; + t->cur_event_pos = t->buffer + ep->event_offset; + t->prev_event_time = ep->event_time; + t->current_event_time = ep->event_time; + t->cur_heart_beat_number = ep->heart_beat_number; + t->cur_cycle_count = ep->event_cycle_count; + + /* This is a workaround for fast position seek */ + t->last_event_pos = ep->last_event_pos; + t->prev_block_end_time = ep->prev_block_end_time; + t->prev_event_time = ep->prev_event_time; + t->pre_cycle_count = ep->pre_cycle_count; + t->count = ep->count; + t->overflow_nsec = ep->overflow_nsec; + t->last_heartbeat = ep->last_heartbeat; + /* end of workaround */ + + //update the fields of the current event and go to the next event + err = skipEvent(t); + if(unlikely(err == ERANGE)) g_error("event id is out of range\n"); + + return; + } + + //only block number and event index are available + //MD: warning : this is slow! + g_warning("using slow O(n) tracefile seek position"); + + LttEvent event; + while(likely(t->which_event < ep->event_num)) ltt_tracefile_read(t, &event); + + return; } /***************************************************************************** *Function name - * ltt_tracefile_read : read the next event + * ltt_tracefile_read : read the current event, set the pointer to the next *Input params * t : tracefile *Return value - * ltt_event * : an event to be processed + * LttEvent * : an event to be processed ****************************************************************************/ -ltt_event *ltt_tracefile_read(ltt_tracefile *t) +LttEvent *ltt_tracefile_read(LttTracefile *t, LttEvent *event) { - ltt_event * lttEvent = (ltt_event *)g_new(ltt_event, 1); - ltt_eventtype * evT; - ltt_facility * fac; - - //update the fields of the current event and go to the next event - if(skipEvent(t)) return NULL; + int err; - t->current_event_time = getEventTime(t); + if(unlikely(t->cur_event_pos == t->buffer + t->block_size)){ + if(unlikely(t->which_block == t->block_number)){ + return NULL; + } + err = readBlock(t, t->which_block + 1); + if(unlikely(err))g_error("Can not read tracefile"); + } - lttEvent->event_id = (int)(*(uint8_t *)(t->cur_event_pos)); - evT = ltt_tracefile_eventtype_get(t, (unsigned)lttEvent->event_id); - fac = evT->facility; - if(evT->index == TRACE_EV_HEARTBEAT && strcmp(fac->name, "default")==0) + event->event_id = (int)(*(guint16 *)(t->cur_event_pos)); + if(unlikely(event->event_id == TRACE_TIME_HEARTBEAT)) t->cur_heart_beat_number++; - lttEvent->cycle_count=*(uint32_t*)(t->cur_event_pos + EVENT_ID_SIZE); - lttEvent->tracefile = t; - lttEvent->data = t->cur_event_pos + EVENT_HEADER_SIZE; - return lttEvent; + t->prev_event_time = t->current_event_time; + // t->current_event_time = getEventTime(t); + + event->time_delta = *(guint32 *)(t->cur_event_pos + EVENT_ID_SIZE); + event->event_time = t->current_event_time; + event->event_cycle_count = t->cur_cycle_count; + + event->tracefile = t; + event->data = t->cur_event_pos + EVENT_HEADER_SIZE; + event->which_block = t->which_block; + event->which_event = t->which_event; + + /* This is a workaround for fast position seek */ + event->last_event_pos = t->last_event_pos; + event->prev_block_end_time = t->prev_block_end_time; + event->prev_event_time = t->prev_event_time; + event->pre_cycle_count = t->pre_cycle_count; + event->count = t->count; + event->overflow_nsec = t->overflow_nsec; + event->last_heartbeat = t->last_heartbeat; + + /* end of workaround */ + + + + //update the fields of the current event and go to the next event + err = skipEvent(t); + if(unlikely(err == ERANGE)) g_error("event id is out of range\n"); + + return event; } /**************************************************************************** @@ -581,15 +1129,20 @@ ltt_event *ltt_tracefile_read(ltt_tracefile *t) int readFile(int fd, void * buf, size_t size, char * mesg) { - ssize_t nbBytes; - nbBytes = read(fd, buf, size); - if(nbBytes != size){ - printf("%s\n",mesg); + ssize_t nbBytes = read(fd, buf, size); + + if((size_t)nbBytes != size) { + if(nbBytes < 0) { + perror("Error in readFile : "); + } else { + g_warning("%s",mesg); + } return EIO; } return 0; } + /**************************************************************************** *Function name * readBlock : read a block from the file @@ -602,47 +1155,57 @@ int readFile(int fd, void * buf, size_t size, char * mesg) * EIO : can not read from the file ****************************************************************************/ -int readBlock(ltt_tracefile * tf, int whichBlock) +int readBlock(LttTracefile * tf, int whichBlock) { off_t nbBytes; - uint32_t lostSize; + guint32 lostSize; - if(whichBlock - tf->which_block == 1 && tf->which_block != 0){ - tf->prev_block_end_time = tf->a_block_footer->time; + /* same block already opened requested */ + if((guint)whichBlock == tf->which_block) return 0; + + if(likely(whichBlock - tf->which_block == 1 && tf->which_block != 0)){ + tf->prev_block_end_time = tf->a_block_end->time; + tf->prev_event_time = tf->a_block_end->time; }else{ tf->prev_block_end_time.tv_sec = 0; tf->prev_block_end_time.tv_nsec = 0; + tf->prev_event_time.tv_sec = 0; + tf->prev_event_time.tv_nsec = 0; } - tf->prev_event_time.tv_sec = 0; - tf->prev_event_time.tv_nsec = 0; - nbBytes=lseek(tf->fd,(off_t)((whichBlock-1)*tf->trace_header->buffer_size), - SEEK_SET); - if(nbBytes == -1) return EINVAL; + nbBytes=lseek(tf->fd,(off_t)((whichBlock-1)*tf->block_size), SEEK_SET); + if(unlikely(nbBytes == -1)) return EINVAL; - if(readFile(tf->fd,tf->buffer,tf->trace_header->buffer_size, - "Unable to read a block")) return EIO; + if(unlikely(readFile(tf->fd,tf->buffer,tf->block_size,"Unable to read a block"))) + return EIO; + tf->a_block_start=(BlockStart *) (tf->buffer + EVENT_HEADER_SIZE); + lostSize = *(guint32 *)(tf->buffer + tf->block_size - sizeof(guint32)); + tf->a_block_end=(BlockEnd *)(tf->buffer + tf->block_size + - sizeof(guint32) - lostSize - sizeof(BlockEnd)); + tf->last_event_pos = tf->buffer + tf->block_size - + sizeof(guint32) - lostSize + - sizeof(BlockEnd) - EVENT_HEADER_SIZE; - tf->a_block_header=(block_header *) tf->buffer; - lostSize = *(uint32_t*)(tf->buffer + tf->trace_header->buffer_size - - sizeof(uint32_t)); - /* skip event ID and time delta to get the address of the block foot */ - tf->a_block_footer=(block_footer *)(tf->buffer+tf->trace_header->buffer_size - -lostSize+sizeof(uint8_t)+sizeof(uint32_t)); tf->which_block = whichBlock; - tf->which_event = 0; - tf->first_event_pos = tf->buffer + sizeof(block_header); - if(tf->which_block == 1){ - tf->which_event++; - tf->first_event_pos += sizeof(trace_header_event); - } - tf->cur_event_pos = tf->first_event_pos; - tf->current_event_time = tf->a_block_header->time; + tf->which_event = 1; + tf->cur_event_pos = tf->buffer;//the beginning of the block, block start ev tf->cur_heart_beat_number = 0; + tf->last_heartbeat = NULL; + /* read the whole block to precalculate total of cycles in it */ + tf->count = 0; + tf->pre_cycle_count = 0; + tf->cur_cycle_count = 0; + getCyclePerNsec(tf); + tf->overflow_nsec = + (-((double)(tf->a_block_start->cycle_count&0xFFFFFFFF)) + * tf->nsec_per_cycle); + + tf->current_event_time = getEventTime(tf); + return 0; } @@ -654,16 +1217,20 @@ int readBlock(ltt_tracefile * tf, int whichBlock) * tf : tracefile ****************************************************************************/ -void updateTracefile(ltt_tracefile * tf) +void updateTracefile(LttTracefile * tf) { - if(tf->which_block == 1)tf->which_event = 1; - else tf->which_event = 0; - tf->cur_event_pos = tf->first_event_pos; - tf->current_event_time = tf->a_block_header->time; + tf->which_event = 1; + tf->cur_event_pos = tf->buffer; + tf->current_event_time = getEventTime(tf); tf->cur_heart_beat_number = 0; tf->prev_event_time.tv_sec = 0; tf->prev_event_time.tv_nsec = 0; + tf->count = 0; + + tf->overflow_nsec = (-((double)tf->a_block_start->cycle_count) + * tf->nsec_per_cycle); + } /***************************************************************************** @@ -673,108 +1240,141 @@ void updateTracefile(ltt_tracefile * tf) * t : tracefile *return value * 0 : success - * EINVAL : lseek fail - * EIO : can not read from the file - * ENOENT : end of file * ERANGE : event id is out of range ****************************************************************************/ -int skipEvent(ltt_tracefile * t) +int skipEvent(LttTracefile * t) { - int evId, err; + int evId; void * evData; - ltt_eventtype * evT; - ltt_field * rootFld; + LttEventType * evT; + LttField * rootFld; - evId = (int)(*(uint8_t *)(t->cur_event_pos)); + evId = (int)(*(guint16 *)(t->cur_event_pos)); evData = t->cur_event_pos + EVENT_HEADER_SIZE; - evT = ltt_tracefile_eventtype_get(t,(unsigned)evId); - if(evT) rootFld = evT->root_field; + evT = ltt_trace_eventtype_get(t->trace,(unsigned)evId); + + if(likely(evT)) rootFld = evT->root_field; else return ERANGE; - - t->prev_event_time = getEventTime(t); - //event has string/sequence or the last event is not the same event - if((evT->latest_block!=t->which_block || evT->latest_event!=t->which_event) - && rootFld->field_fixed == 0){ - setFieldsOffset(t, evT, evData); - } - t->cur_event_pos += EVENT_HEADER_SIZE + rootFld->field_size; - + if(likely(rootFld)){ + //event has string/sequence or the last event is not the same event + if(likely((evT->latest_block!=t->which_block || evT->latest_event!=t->which_event) + && rootFld->field_fixed == 0)){ + setFieldsOffset(t, evT, evData, t->trace); + } + t->cur_event_pos += EVENT_HEADER_SIZE + rootFld->field_size; + }else t->cur_event_pos += EVENT_HEADER_SIZE; + evT->latest_block = t->which_block; evT->latest_event = t->which_event; - + //the next event is in the next block - if(t->which_event == t->a_block_header->event_count - 1){ - if(t->which_block == t->block_number) return ENOENT; - err = readBlock(t, t->which_block + 1); - if(err) return err; + if(unlikely(evId == TRACE_BLOCK_END)){ + t->cur_event_pos = t->buffer + t->block_size; }else{ t->which_event++; + t->current_event_time = getEventTime(t); } return 0; } + /***************************************************************************** *Function name * getCyclePerNsec : calculate cycles per nsec for current block + * MD: should have tracefile_read the whole block, so we know the + * total of cycles in it before being called. *Input Params * t : tracefile ****************************************************************************/ -void getCyclePerNsec(ltt_tracefile * t) +void getCyclePerNsec(LttTracefile * t) { - ltt_time lBufTotalTime; /* Total time for this buffer */ - ltt_cycle_count lBufTotalNSec; /* Total time for this buffer in nsecs */ - ltt_cycle_count lBufTotalCycle;/* Total cycles for this buffer */ + LttTime lBufTotalTime; /* Total time for this buffer */ + double lBufTotalNSec; /* Total time for this buffer in nsecs */ + LttCycleCount lBufTotalCycle;/* Total cycles for this buffer */ /* Calculate the total time for this buffer */ - TimeSub(lBufTotalTime,t->a_block_footer->time, t->a_block_header->time); + lBufTotalTime = ltt_time_sub(t->a_block_end->time, t->a_block_start->time); /* Calculate the total cycles for this bufffer */ - lBufTotalCycle = t->a_block_footer->cycle_count - - t->a_block_header->cycle_count; + lBufTotalCycle = t->a_block_end->cycle_count; + lBufTotalCycle -= t->a_block_start->cycle_count; - /* Convert the total time to nsecs */ - lBufTotalNSec = lBufTotalTime.tv_sec * 1000000000 + lBufTotalTime.tv_nsec; + /* Convert the total time to double */ + lBufTotalNSec = ltt_time_to_double(lBufTotalTime); - t->cycle_per_nsec = (double)lBufTotalCycle / (double)lBufTotalNSec; + t->nsec_per_cycle = (double)lBufTotalNSec / (double)lBufTotalCycle; + + /* Pre-multiply one overflow (2^32 cycles) by nsec_per_cycle */ + t->one_overflow_nsec = t->nsec_per_cycle * (double)0x100000000ULL; + } /**************************************************************************** *Function name * getEventTime : obtain the time of an event + * NOTE : this function _really_ is on critical path. *Input params * tf : tracefile *Return value - * ltt_time : the time of the event + * LttTime : the time of the event ****************************************************************************/ -ltt_time getEventTime(ltt_tracefile * tf) +static inline LttTime getEventTime(LttTracefile * tf) { - ltt_time time; - ltt_cycle_count cycle_count; /* cycle count for the current event */ - ltt_cycle_count lEventTotalCycle; /* Total cycles from start for event */ - double lEventNSec; /* Total usecs from start for event */ - ltt_time lTimeOffset; /* Time offset in struct ltt_time */ + LttTime time; + LttCycleCount cycle_count; // cycle count for the current event + //LttCycleCount lEventTotalCycle; // Total cycles from start for event + gint64 lEventNSec; // Total nsecs from start for event + LttTime lTimeOffset; // Time offset in struct LttTime + guint16 evId; + + evId = *(guint16 *)tf->cur_event_pos; - /* Calculate total time in cycles from start of buffer for this event */ - cycle_count = *(uint32_t*)(tf->cur_event_pos + EVENT_ID_SIZE); - if(tf->cur_heart_beat_number) - cycle_count += ((uint64_t)1)<<32 * tf->cur_heart_beat_number; - lEventTotalCycle=cycle_count-(tf->a_block_header->cycle_count & 0xFFFFFFFF); - - /* Convert it to nsecs */ - lEventNSec = lEventTotalCycle / tf->cycle_per_nsec; + cycle_count = (LttCycleCount)*(guint32 *)(tf->cur_event_pos + EVENT_ID_SIZE); + + gboolean comp_count = cycle_count < tf->pre_cycle_count; + + tf->pre_cycle_count = cycle_count; - /* Determine offset in struct ltt_time */ - lTimeOffset.tv_nsec = (long)lEventNSec % 1000000000; - lTimeOffset.tv_sec = (long)lEventNSec / 1000000000; + if(unlikely(comp_count)) { + /* Overflow */ + tf->overflow_nsec += tf->one_overflow_nsec; + tf->count++; //increment overflow count + } - TimeAdd(time, tf->a_block_header->time, lTimeOffset); + if(unlikely(evId == TRACE_BLOCK_START)) { + lEventNSec = 0; + } else if(unlikely(evId == TRACE_BLOCK_END)) { + lEventNSec = ((double) + (tf->a_block_end->cycle_count - tf->a_block_start->cycle_count) + * tf->nsec_per_cycle); + } +#if 0 + /* If you want to make heart beat a special case and use their own 64 bits + * TSC, activate this. + */ + else if(unlikely(evId == TRACE_TIME_HEARTBEAT)) { + + tf->last_heartbeat = (TimeHeartbeat*)(tf->cur_event_pos+EVENT_HEADER_SIZE); + lEventNSec = ((double)(tf->last_heartbeat->cycle_count + - tf->a_block_start->cycle_count) + * tf->nsec_per_cycle); + } +#endif //0 + else { + lEventNSec = (gint64)((double)cycle_count * tf->nsec_per_cycle) + +tf->overflow_nsec; + } + lTimeOffset = ltt_time_from_uint64(lEventNSec); + + time = ltt_time_add(tf->a_block_start->time, lTimeOffset); + return time; } @@ -787,12 +1387,13 @@ ltt_time getEventTime(ltt_tracefile * tf) * evD : event data, it may be NULL ****************************************************************************/ -void setFieldsOffset(ltt_tracefile * t, ltt_eventtype * evT, void * evD) +void setFieldsOffset(LttTracefile *tf,LttEventType *evT,void *evD,LttTrace* t) { - ltt_field * rootFld = evT->root_field; + LttField * rootFld = evT->root_field; // rootFld->base_address = evD; - rootFld->field_size = getFieldtypeSize(t, evT, 0,0,rootFld, evD); + if(likely(rootFld)) + rootFld->field_size = getFieldtypeSize(tf, evT, 0,0,rootFld, evD,t); } /***************************************************************************** @@ -809,137 +1410,162 @@ void setFieldsOffset(ltt_tracefile * t, ltt_eventtype * evT, void * evD) * int : size of the field ****************************************************************************/ -int getFieldtypeSize(ltt_tracefile * t, ltt_eventtype * evT, int offsetRoot, - int offsetParent, ltt_field * fld, void * evD) -{ - int size, size1, element_number, i, offset1, offset2; - ltt_type * type = fld->field_type; - - if(evT->latest_block==t->which_block && evT->latest_event==t->which_event){ - return fld->field_size; - } - - if(fld->field_fixed == 1){ - if(fld == evT->root_field) return fld->field_size; - } - - if(type->type_class != LTT_STRUCT && type->type_class != LTT_ARRAY && - type->type_class != LTT_SEQUENCE && type->type_class != LTT_STRING){ - if(fld->field_fixed == -1){ - size = (int) ltt_type_size(t, type); - fld->field_fixed = 1; - }else size = fld->field_size; - - }else if(type->type_class == LTT_ARRAY){ - element_number = (int) type->element_number; - if(fld->field_fixed == -1){ - size = getFieldtypeSize(t, evT, offsetRoot,0,fld->child[0], NULL); - if(size == 0){ //has string or sequence - fld->field_fixed = 0; - }else{ - fld->field_fixed = 1; - size *= element_number; - } - }else if(fld->field_fixed == 0){// has string or sequence - size = 0; - for(i=0;ichild[0], evD+size); - } - }else size = fld->field_size; - - }else if(type->type_class == LTT_SEQUENCE){ - size1 = (int) ltt_type_size(t, type); - if(fld->field_fixed == -1){ - fld->field_fixed = 0; - size = getFieldtypeSize(t, evT, offsetRoot,0,fld->child[0], NULL); - fld->element_size = size; - }else{//0: sequence - element_number = getIntNumber(size1,evD); - type->element_number = element_number; - if(fld->element_size > 0){ - size = element_number * fld->element_size; - }else{//sequence has string or sequence - size = 0; - for(i=0;ichild[0], evD+size+size1); - } +static inline gint getFieldtypeSize(LttTracefile * t, + LttEventType * evT, gint offsetRoot, + gint offsetParent, LttField * fld, void *evD, LttTrace *trace) +{ + gint size, size1, element_number, i, offset1, offset2; + LttType * type = fld->field_type; + + if(unlikely(t && evT->latest_block==t->which_block && + evT->latest_event==t->which_event)){ + size = fld->field_size; + goto end_getFieldtypeSize; + } else { + /* This likely has been tested with gcov : half of them.. */ + if(unlikely(fld->field_fixed == 1)){ + /* tested : none */ + if(unlikely(fld == evT->root_field)) { + size = fld->field_size; + goto end_getFieldtypeSize; } - size += size1; } - }else if(type->type_class == LTT_STRING){ - size = 0; - if(fld->field_fixed == -1){ - fld->field_fixed = 0; - }else{//0: string - size = sizeof((char*)evD) + 1; //include end : '\0' + /* From gcov profiling : half string, half struct, can we gain something + * from that ? (Mathieu) */ + switch(type->type_class) { + case LTT_ARRAY: + element_number = (int) type->element_number; + if(fld->field_fixed == -1){ + size = getFieldtypeSize(t, evT, offsetRoot, + 0,fld->child[0], NULL, trace); + if(size == 0){ //has string or sequence + fld->field_fixed = 0; + }else{ + fld->field_fixed = 1; + size *= element_number; + } + }else if(fld->field_fixed == 0){// has string or sequence + size = 0; + for(i=0;ichild[0], evD+size, trace); + } + }else size = fld->field_size; + if(unlikely(!evD)){ + fld->fixed_root = (offsetRoot==-1) ? 0 : 1; + fld->fixed_parent = (offsetParent==-1) ? 0 : 1; + } + + break; + + case LTT_SEQUENCE: + size1 = (int) ltt_type_size(trace, type); + if(fld->field_fixed == -1){ + fld->sequ_number_size = size1; + fld->field_fixed = 0; + size = getFieldtypeSize(t, evT, offsetRoot, + 0,fld->child[0], NULL, trace); + fld->element_size = size; + }else{//0: sequence + element_number = getIntNumber(size1,evD); + type->element_number = element_number; + if(fld->element_size > 0){ + size = element_number * fld->element_size; + }else{//sequence has string or sequence + size = 0; + for(i=0;ichild[0], evD+size+size1, trace); + } + } + size += size1; + } + if(unlikely(!evD)){ + fld->fixed_root = (offsetRoot==-1) ? 0 : 1; + fld->fixed_parent = (offsetParent==-1) ? 0 : 1; + } + + break; + + case LTT_STRING: + size = 0; + if(fld->field_fixed == -1){ + fld->field_fixed = 0; + }else{//0: string + /* Hope my implementation is faster than strlen (Mathieu) */ + char *ptr=(char*)evD; + size = 1; + /* from gcov : many many strings are empty, make it the common case.*/ + while(unlikely(*ptr != '\0')) { size++; ptr++; } + //size = ptr - (char*)evD + 1; //include end : '\0' + } + fld->fixed_root = (offsetRoot==-1) ? 0 : 1; + fld->fixed_parent = (offsetParent==-1) ? 0 : 1; + + break; + + case LTT_STRUCT: + element_number = (int) type->element_number; + size = 0; + /* tested with gcov */ + if(unlikely(fld->field_fixed == -1)){ + offset1 = offsetRoot; + offset2 = 0; + for(i=0;ichild[i], NULL, trace); + if(likely(size1 > 0 && size >= 0)){ + size += size1; + if(likely(offset1 >= 0)) offset1 += size1; + offset2 += size1; + }else{ + size = -1; + offset1 = -1; + offset2 = -1; + } + } + if(unlikely(size == -1)){ + fld->field_fixed = 0; + size = 0; + }else fld->field_fixed = 1; + }else if(likely(fld->field_fixed == 0)){ + offset1 = offsetRoot; + offset2 = 0; + for(i=0;unlikely(ichild[i],evD+offset2, trace); + offset1 += size; + offset2 += size; + } + size = offset2; + }else size = fld->field_size; + fld->fixed_root = (offsetRoot==-1) ? 0 : 1; + fld->fixed_parent = (offsetParent==-1) ? 0 : 1; + break; + + default: + if(unlikely(fld->field_fixed == -1)){ + size = (int) ltt_type_size(trace, type); + fld->field_fixed = 1; + }else size = fld->field_size; + if(unlikely(!evD)){ + fld->fixed_root = (offsetRoot==-1) ? 0 : 1; + fld->fixed_parent = (offsetParent==-1) ? 0 : 1; + } + break; } - - }else if(type->type_class == LTT_STRUCT){ - element_number = (int) type->element_number; - size = 0; - if(fld->field_fixed == -1){ - offset1 = offsetRoot; - offset2 = 0; - for(i=0;ichild[i], NULL); - if(size1 > 0 && size >= 0){ - size += size1; - if(offset1 >= 0) offset1 += size1; - offset2 += size1; - }else{ - size = -1; - offset1 = -1; - offset2 = -1; - } - } - if(size == -1){ - fld->field_fixed = 0; - size = 0; - }else fld->field_fixed = 1; - }else if(fld->field_fixed == 0){ - offset1 = offsetRoot; - offset2 = 0; - for(i=0;ichild[i],evD+offset2); - offset1 += size; - offset2 += size; - } - size = offset2; - }else size = fld->field_size; } fld->offset_root = offsetRoot; fld->offset_parent = offsetParent; - if(!evD){ - fld->fixed_root = (offsetRoot==-1) ? 0 : 1; - fld->fixed_parent = (offsetParent==-1) ? 0 : 1; - } fld->field_size = size; +end_getFieldtypeSize: + return size; } -/***************************************************************************** - *Function name - * timecmp : compare two time - *Input params - * t1 : first time - * t2 : second time - *Return value - * int : 0: t1 == t2; -1: t1 < t2; 1: t1 > t2 - ****************************************************************************/ - -int timecmp(ltt_time * t1, ltt_time * t2) -{ - ltt_time T; - TimeSub(T, *t1, *t2); - if(T.tv_sec == 0 && T.tv_nsec == 0) return 0; - else if(T.tv_sec > 0 || (T.tv_sec==0 && T.tv_nsec > 0)) return 1; - else return -1; -} /***************************************************************************** *Function name @@ -948,18 +1574,24 @@ int timecmp(ltt_time * t1, ltt_time * t2) * size : the size of the integer * evD : the event data *Return value - * int : an integer + * gint64 : a 64 bits integer ****************************************************************************/ -int getIntNumber(int size, void *evD) +gint64 getIntNumber(int size, void *evD) { - int64_t i; - if(size == 1) i = *(int8_t *)evD; - else if(size == 2) i = *(int16_t *)evD; - else if(size == 4) i = *(int32_t *)evD; - else if(size == 8) i = *(int64_t *)evD; - - return (int) i; + gint64 i; + + switch(size) { + case 1: i = *(gint8 *)evD; break; + case 2: i = *(gint16 *)evD; break; + case 4: i = *(gint32 *)evD; break; + case 8: i = *(gint64 *)evD; break; + default: i = *(gint64 *)evD; + g_critical("getIntNumber : integer size %d unknown", size); + break; + } + + return (gint64)i; } /***************************************************************************** @@ -971,7 +1603,7 @@ int getIntNumber(int size, void *evD) * endian : endian type, little or big ****************************************************************************/ -void getDataEndianType(ltt_arch_size * size, ltt_arch_endian * endian) +void getDataEndianType(LttArchSize * size, LttArchEndian * endian) { int i = 1; char c = (char) i; @@ -991,3 +1623,50 @@ void getDataEndianType(ltt_arch_size * size, ltt_arch_endian * endian) else *size = LTT_UNKNOWN; } +/* get the node name of the system */ + +char * ltt_trace_system_description_node_name (LttSystemDescription * s) +{ + return s->node_name; +} + + +/* get the domain name of the system */ + +char * ltt_trace_system_description_domain_name (LttSystemDescription * s) +{ + return s->domain_name; +} + + +/* get the description of the system */ + +char * ltt_trace_system_description_description (LttSystemDescription * s) +{ + return s->description; +} + + +/* get the start time of the trace */ + +LttTime ltt_trace_system_description_trace_start_time(LttSystemDescription *s) +{ + return s->trace_start; +} + + +LttTracefile *ltt_tracefile_new() +{ + return g_new(LttTracefile, 1); +} + +void ltt_tracefile_destroy(LttTracefile *tf) +{ + g_free(tf); +} + +void ltt_tracefile_copy(LttTracefile *dest, const LttTracefile *src) +{ + *dest = *src; +} +