X-Git-Url: http://git.liburcu.org/?a=blobdiff_plain;f=ltt%2Ftracefile.c;h=af03d0c2d54449b9c01cae9958781f0a92ff1c36;hb=7c3c01d14690eee4d3c262f300a888680ae7a053;hp=cbb39d0e88cf1c38f9016833734f4f91f309e842;hpb=a5ea8f1b4774e8c80ce8b0a5478a5fe8c4d46b07;p=lttv.git diff --git a/ltt/tracefile.c b/ltt/tracefile.c index cbb39d0e..af03d0c2 100644 --- a/ltt/tracefile.c +++ b/ltt/tracefile.c @@ -51,8 +51,12 @@ #include #include +#define DEFAULT_N_BLOCKS 32 + /* from marker.c */ extern long marker_update_fields_offsets(struct marker_info *info, const char *data); +extern void marker_update_event_fields_offsets(GArray *fields_offsets, + struct marker_info *info); /* Tracefile names used in this file */ @@ -78,8 +82,6 @@ GQuark LTT_TRACEFILE_NAME_METADATA; #define PAGE_MASK (~(page_size-1)) #define PAGE_ALIGN(addr) (((addr)+page_size-1)&PAGE_MASK) -LttTrace *father_trace = NULL; - /* set the offset of the fields belonging to the event, need the information of the archecture */ //void set_fields_offsets(LttTracefile *tf, LttEventType *event_type); @@ -105,6 +107,9 @@ static void ltt_tracefile_time_span_get(LttTracefile *tf, static void group_time_span_get(GQuark name, gpointer data, gpointer user_data); static gint map_block(LttTracefile * tf, guint block_num); static void ltt_update_event_size(LttTracefile *tf); +static LttTrace *_ltt_trace_open(const gchar *pathname, gboolean is_live); +static int ltt_tracefile_update(LttTracefile *tf); +static void update_tracefile_group(GQuark name, gpointer data, gpointer user_data); /* Enable event debugging */ static int a_event_debug = 0; @@ -148,9 +153,9 @@ static int parse_trace_header(ltt_subbuffer_header_t *header, break; case 2: switch(header->minor_version) { - case 4: + case 6: { - struct ltt_subbuffer_header_2_4 *vheader = header; + struct ltt_subbuffer_header_2_6 *vheader = header; tf->buffer_header_size = ltt_subbuffer_header_size(); tf->tscbits = 27; tf->eventbits = 5; @@ -162,12 +167,6 @@ static int parse_trace_header(ltt_subbuffer_header_t *header, &vheader->start_freq); t->freq_scale = ltt_get_uint32(LTT_GET_BO(tf), &vheader->freq_scale); - if(father_trace) { - t->start_freq = father_trace->start_freq; - t->freq_scale = father_trace->freq_scale; - } else { - father_trace = t; - } t->start_tsc = ltt_get_uint64(LTT_GET_BO(tf), &vheader->cycle_count_begin); t->start_monotonic = 0; @@ -177,10 +176,9 @@ static int parse_trace_header(ltt_subbuffer_header_t *header, &vheader->start_time_usec); t->start_time.tv_nsec *= 1000; /* microsec to nanosec */ - t->start_time_from_tsc = ltt_time_from_uint64( - (double)t->start_tsc - * 1000000000.0 * tf->trace->freq_scale - / (double)t->start_freq); + t->start_time_from_tsc = + ltt_time_from_uint64(tsc_to_uint64(t->freq_scale, + t->start_freq, t->start_tsc)); } } break; @@ -198,7 +196,186 @@ static int parse_trace_header(ltt_subbuffer_header_t *header, return 0; } +int get_block_offset_size(LttTracefile *tf, guint block_num, + uint64_t *offset, uint32_t *size) +{ + uint64_t offa, offb; + + if (unlikely(block_num >= tf->num_blocks)) + return -1; + + offa = g_array_index(tf->buf_index, uint64_t, block_num); + if (likely(block_num < tf->num_blocks - 1)) + offb = g_array_index(tf->buf_index, uint64_t, block_num + 1); + else + offb = tf->file_size; + *offset = offa; + *size = offb - offa; + return 0; +} + +static int ltt_trace_update_block_index(LttTracefile *tf, uint64_t offset, + unsigned long firstBlock) +{ + int i = firstBlock; + int page_size = getpagesize(); + unsigned int header_map_size = PAGE_ALIGN(ltt_subbuffer_header_size()); + + g_assert(tf->buf_index->len == i); + while (offset < tf->file_size) { + ltt_subbuffer_header_t *header; + uint64_t *off; + uint64_t size; + + /* map block header */ + header = mmap(0, header_map_size, PROT_READ, + MAP_PRIVATE, tf->fd, (off_t)offset); + if(header == MAP_FAILED) { + perror("Error in allocating memory for buffer of tracefile"); + return -1; + } + + /* read len, offset += len */ + size = ltt_get_uint32(LTT_GET_BO(tf), &header->sb_size); + + /* Only index completly writen blocks */ + if (offset + size <= tf->file_size) { + + tf->buf_index = g_array_set_size(tf->buf_index, i + 1); + off = &g_array_index(tf->buf_index, uint64_t, i); + *off = offset; + + /* Store current buffer end cycle as the last file timestamp */ + /* TODO ybrosseau 2010-11-04: Might want to convert it to a LttTime */ + tf->end_timestamp = ltt_get_uint64(LTT_GET_BO(tf), + &header->cycle_count_end); + + ++i; + } + offset += size; + /* unmap block header */ + if(munmap(header, header_map_size)) { + g_warning("unmap size : %u\n", header_map_size); + perror("munmap error"); + return -1; + } + } + tf->num_blocks = i; + + return 0; +} + +/* parse the new information from the file and reajust the number of blocks. + * + * Return value : 0 success, -1 error + */ +int ltt_trace_continue_block_index(LttTracefile *tf) +{ + int ret; + uint64_t offset; + uint32_t last_block_size; + unsigned long i = tf->num_blocks; + int page_size = getpagesize(); + unsigned int header_map_size = PAGE_ALIGN(ltt_subbuffer_header_size()); + + get_block_offset_size(tf, tf->num_blocks-1, &offset, &last_block_size); + + ltt_subbuffer_header_t *header_tmp = mmap(0, header_map_size, PROT_READ, + MAP_PRIVATE, tf->fd, (off_t)offset); + if(header_tmp == MAP_FAILED) { + perror("Error in allocating memory for buffer of tracefile"); + return -1; + } + + /* read len, offset += len */ + offset += ltt_get_uint32(LTT_GET_BO(tf), &header_tmp->sb_size); + + ret = ltt_trace_update_block_index(tf, offset, i); + + return ret; +} + +int ltt_trace_create_block_index(LttTracefile *tf) +{ + int ret; + uint64_t offset = 0; + unsigned long i = 0; + + tf->buf_index = g_array_sized_new(FALSE, TRUE, sizeof(uint64_t), + DEFAULT_N_BLOCKS); + if(!tf->buf_index) + return -1; + ret = ltt_trace_update_block_index(tf, offset, i); + return ret; +} +/* + Read file header and initialise buffer indexes + + Return value : 0 for success, -1 otherwise. +*/ +static int ltt_tracefile_init(LttTracefile *tf) +{ + ltt_subbuffer_header_t *header; + int page_size = getpagesize(); + + /* Temporarily map the buffer start header to get trace information */ + /* Multiple of pages aligned head */ + tf->buffer.head = mmap(0, + PAGE_ALIGN(ltt_subbuffer_header_size()), PROT_READ, + MAP_PRIVATE, tf->fd, 0); + if(tf->buffer.head == MAP_FAILED) { + perror("Error in allocating memory for buffer of tracefile"); + goto unmap_file; + } + g_assert( ( (gulong)tf->buffer.head&(8-1) ) == 0); // make sure it's aligned. + + header = (ltt_subbuffer_header_t *)tf->buffer.head; + + if(parse_trace_header(header, tf, tf->trace)) + { + g_warning("parse_trace_header error"); + goto unmap_file; + } + + if(munmap(tf->buffer.head, + PAGE_ALIGN(ltt_subbuffer_header_size()))) + { + g_warning("unmap size : %zu\n", + PAGE_ALIGN(ltt_subbuffer_header_size())); + perror("munmap error"); + g_assert(0); + } + tf->buffer.head = NULL; + + /* Create fields offset table */ + tf->event.fields_offsets = g_array_sized_new(FALSE, FALSE, + sizeof(struct LttField), 1); + if (!tf->event.fields_offsets) { + g_warning("Cannot create fields offset table"); + goto unmap_file; + } + + /* Create block index */ + ltt_trace_create_block_index(tf); + + if(map_block(tf,0)) + { + perror("Cannot map block for tracefile"); + goto unmap_file; + } + return 0; + /* Error */ +unmap_file: + if(munmap(tf->buffer.head, + PAGE_ALIGN(ltt_subbuffer_header_size()))) { + g_warning("unmap size : %zu\n", + PAGE_ALIGN(ltt_subbuffer_header_size())); + perror("munmap error"); + g_assert(0); + } + return -1; +} /***************************************************************************** *Function name @@ -210,93 +387,59 @@ static int parse_trace_header(ltt_subbuffer_header_t *header, *Return value * : 0 for success, -1 otherwise. ****************************************************************************/ - static gint ltt_tracefile_open(LttTrace *t, gchar * fileName, LttTracefile *tf) { struct stat lTDFStat; /* Trace data file status */ - ltt_subbuffer_header_t *header; - int page_size = getpagesize(); //open the file tf->long_name = g_quark_from_string(fileName); tf->trace = t; tf->fd = open(fileName, O_RDONLY); + tf->buf_index = NULL; + tf->num_blocks = 0; if(tf->fd < 0){ g_warning("Unable to open input data file %s\n", fileName); goto end; } - + // Get the file's status if(fstat(tf->fd, &lTDFStat) < 0){ g_warning("Unable to get the status of the input data file %s\n", fileName); goto close_file; } - - // Is the file large enough to contain a trace - if(lTDFStat.st_size < - (off_t)(ltt_subbuffer_header_size())){ - g_print("The input data file %s does not contain a trace\n", fileName); - goto close_file; - } - - /* Temporarily map the buffer start header to get trace information */ - /* Multiple of pages aligned head */ - tf->buffer.head = mmap(0, - PAGE_ALIGN(ltt_subbuffer_header_size()), PROT_READ, - MAP_PRIVATE, tf->fd, 0); - if(tf->buffer.head == MAP_FAILED) { - perror("Error in allocating memory for buffer of tracefile"); - goto close_file; - } - g_assert( ( (gulong)tf->buffer.head&(8-1) ) == 0); // make sure it's aligned. - - header = (ltt_subbuffer_header_t *)tf->buffer.head; - - if(parse_trace_header(header, tf, NULL)) { - g_warning("parse_trace_header error"); - goto unmap_file; - } - //store the size of the file tf->file_size = lTDFStat.st_size; - tf->buf_size = ltt_get_uint32(LTT_GET_BO(tf), &header->buf_size); - tf->num_blocks = tf->file_size / tf->buf_size; tf->events_lost = 0; tf->subbuf_corrupt = 0; - - if(munmap(tf->buffer.head, - PAGE_ALIGN(ltt_subbuffer_header_size()))) { - g_warning("unmap size : %zu\n", - PAGE_ALIGN(ltt_subbuffer_header_size())); - perror("munmap error"); - g_assert(0); - } tf->buffer.head = NULL; - - //read the first block - if(map_block(tf,0)) { - perror("Cannot map block for tracefile"); - goto close_file; + tf->event.fields_offsets = NULL; + + /* Is the file large enough to contain a trace */ + if(lTDFStat.st_size < (off_t)(ltt_subbuffer_header_size())){ + if (t->is_live) { + /* It a live trace so the file can be empty at the start of the analysis */ + goto end; + } else { + g_print("The input data file %s does not contain a trace\n", fileName); + goto close_file; + } } + if(ltt_tracefile_init(tf) < 0) { + goto close_file; + } + return 0; /* Error */ -unmap_file: - if(munmap(tf->buffer.head, - PAGE_ALIGN(ltt_subbuffer_header_size()))) { - g_warning("unmap size : %zu\n", - PAGE_ALIGN(ltt_subbuffer_header_size())); - perror("munmap error"); - g_assert(0); - } close_file: close(tf->fd); end: + if (tf->buf_index) + g_array_free(tf->buf_index, TRUE); return -1; } - /***************************************************************************** *Function name * ltt_tracefile_close: close a trace file, @@ -309,14 +452,19 @@ static void ltt_tracefile_close(LttTracefile *t) int page_size = getpagesize(); if(t->buffer.head != NULL) - if(munmap(t->buffer.head, PAGE_ALIGN(t->buf_size))) { + if(munmap(t->buffer.head, PAGE_ALIGN(t->buffer.size))) { g_warning("unmap size : %u\n", - PAGE_ALIGN(t->buf_size)); + PAGE_ALIGN(t->buffer.size)); perror("munmap error"); g_assert(0); } close(t->fd); + if (t->buf_index) + g_array_free(t->buf_index, TRUE); + if (t->event.fields_offsets) { + g_array_free(t->event.fields_offsets, TRUE); + } } /**************************************************************************** @@ -556,7 +704,6 @@ static int open_tracefiles(LttTrace *trace, gchar *root_path, gchar *relative_pa rel_path_ptr = rel_path + rel_path_len; while((entry = readdir(dir)) != NULL) { - if(entry->d_name[0] == '.') continue; strncpy(path_ptr, entry->d_name, PATH_MAX - path_len); @@ -591,9 +738,12 @@ static int open_tracefiles(LttTrace *trace, gchar *root_path, gchar *relative_pa g_debug("Opening file.\n"); if(ltt_tracefile_open(trace, path, &tmp_tf)) { - g_info("Error opening tracefile %s", path); - - continue; /* error opening the tracefile : bad magic number ? */ + /* Only consider the error for non live trace */ + if (!trace->is_live) { + + g_info("Error opening tracefile %s", path); + continue; /* error opening the tracefile : bad magic number ? */ + } } g_debug("Tracefile name is %s and number is %u", @@ -738,13 +888,24 @@ seek_error: return err; } + +LttTrace *ltt_trace_open(const gchar *pathname) +{ + return _ltt_trace_open(pathname, FALSE); +} + +LttTrace *ltt_trace_open_live(const gchar *pathname) +{ + return _ltt_trace_open(pathname, TRUE); +} + /* * Open a trace and return its LttTrace handle. * * pathname must be the directory of the trace */ -LttTrace *ltt_trace_open(const gchar *pathname) +static LttTrace *_ltt_trace_open(const gchar *pathname, gboolean is_live) { gchar abs_path[PATH_MAX]; LttTrace * t; @@ -783,7 +944,10 @@ LttTrace *ltt_trace_open(const gchar *pathname) } } closedir(dir); - + + t->is_live = is_live; + t->live_safe_timestamp = ltt_time_zero; + /* Open all the tracefiles */ t->start_freq= 0; if(open_tracefiles(t, abs_path, "")) { @@ -799,19 +963,33 @@ LttTrace *ltt_trace_open(const gchar *pathname) } /* - * Get the trace information for the metadata_0 tracefile. + * Get the trace information for the first valid metadata tracefile. + * In live trace mode, the metadata_0 might be empty * Getting a correct trace start_time and start_tsc is insured by the fact * that no subbuffers are supposed to be lost in the metadata channel. * Therefore, the first subbuffer contains the start_tsc timestamp in its * buffer header. */ g_assert(group->len > 0); - tf = &g_array_index (group, LttTracefile, 0); - header = (ltt_subbuffer_header_t *)tf->buffer.head; + header = NULL; + for(i=0; ilen; i++) { + tf = &g_array_index (group, LttTracefile, i); + header = (ltt_subbuffer_header_t *)tf->buffer.head; + if (header) { + break; + } + } + if (header == NULL) { + g_warning("Trace %s has not one valid metadata tracefile", abs_path); + goto find_error; + } + ret = parse_trace_header(header, tf, t); g_assert(!ret); t->num_cpu = group->len; + t->drift = 1.; + t->offset = 0.; //ret = allocate_marker_data(t); //if (ret) @@ -819,7 +997,7 @@ LttTrace *ltt_trace_open(const gchar *pathname) for(i=0; ilen; i++) { tf = &g_array_index (group, LttTracefile, i); - if (tf->cpu_online) + if (tf->cpu_online && tf->buffer.head ) if(ltt_process_metadata_tracefile(tf)) goto find_error; // goto metadata_error; @@ -839,6 +1017,135 @@ alloc_error: } + +/***************************************************************************** + Update the informations concerning the tracefile + + Must be called periodically to update trace file and file size + information. + +Input params + tf : the tracefile +Return value + : Number of tracefile with available events + -1 on error. + ****************************************************************************/ +int ltt_trace_update(LttTrace *trace) +{ + int trace_updated_count = 0; + + /* Only update live traces */ + if(trace->is_live) { + + /* Iterate on all tracefiles */ + g_datalist_foreach(&trace->tracefiles, + &update_tracefile_group, + &trace_updated_count); + + return trace_updated_count; + } + return 0; + +} + +static void update_tracefile_group(GQuark name, gpointer data, gpointer user_data) +{ + int *trace_updated_count = (int *)user_data; + unsigned int i; + LttTracefile *tf; + GArray *group = (GArray *)data; + + g_debug("Updating tracefile group %s", g_quark_to_string(name)); + for(i=0; ilen; i++) { + tf = &g_array_index (group, LttTracefile, i); + + /* Update safe timestamp */ + tf->trace->live_safe_timestamp = + LTT_TIME_MAX(tf->trace->live_safe_timestamp, + ltt_interpolate_time_from_tsc(tf, + tf->end_timestamp)); + + /* Update tracefile */ + int ret = ltt_tracefile_update(tf); + if(ret < 0) { + g_warning("LIVE: Cannot update tracefile %s", + g_quark_to_string(ltt_tracefile_long_name(tf))); + *trace_updated_count = -1; + break; + } else { + *trace_updated_count += 1; + } + } +} + + +/***************************************************************************** + *Function name + * ltt_tracefile_update : Update the informations concerning a tracefile + * Must be called periodically to update trace file and file size + information. + *Input params + * tf : the tracefile + *Return value + * : 1 for success and an event is available + 0 for success but no event available, + * -1 on error. + ****************************************************************************/ +static int ltt_tracefile_update(LttTracefile *tf) +{ + struct stat lTDFStat; /* Trace data file status */ + if(fstat(tf->fd, &lTDFStat) < 0){ + perror("error in getting the tracefile informations."); + } + + + /* Process the file only on size change */ + if(tf->file_size < lTDFStat.st_size) { + /* Update the size of the file */ + tf->file_size = lTDFStat.st_size; + g_debug("Updating tracefile %s", g_quark_to_string(tf->long_name)); + + if( tf->file_size >= (off_t)(ltt_subbuffer_header_size()) ) { + + if(tf->buf_index == NULL) { + if(ltt_tracefile_init(tf) < 0) { + return -1; + } + if(tf->name == LTT_TRACEFILE_NAME_METADATA) { + + LttTime start; + start.tv_sec = 0; + start.tv_nsec = 0; + ltt_process_metadata_tracefile(tf); + + ltt_tracefile_seek_time(tf, start); + tf->event.offset = 0; + + } + } + else + { + /* Retrieve the new subbuffers and index them */ + ltt_trace_continue_block_index(tf); + + if(tf->name == LTT_TRACEFILE_NAME_METADATA) { + LttEventPosition *pos = ltt_event_position_new(); + ltt_tracefile_get_current_position(tf, pos); + ltt_process_metadata_tracefile(tf); + ltt_tracefile_seek_position(tf, pos); + g_free(pos); + + } + } + + return 1; + } + } + + return 0; + +} + /* Open another, completely independant, instance of a trace. * * A read on this new instance will read the first event of the trace. @@ -849,7 +1156,7 @@ alloc_error: */ LttTrace *ltt_trace_copy(LttTrace *self) { - return ltt_trace_open(g_quark_to_string(self->pathname)); + return _ltt_trace_open(g_quark_to_string(self->pathname), self->is_live); } /* @@ -871,9 +1178,15 @@ void ltt_tracefile_time_span_get(LttTracefile *tf, LttTime *start, LttTime *end) { int err; + err = map_block(tf, 0); - if(unlikely(err)) { + /* Only empty live traces will return ERANGE */ + if(err == ERANGE) { + *start = ltt_time_infinite; + *end = ltt_time_zero; + return; + } else if(unlikely(err)) { g_error("Can not map block"); *start = ltt_time_infinite; } else @@ -969,7 +1282,9 @@ int ltt_tracefile_seek_time(LttTracefile *tf, LttTime time) /* seek at the beginning of trace */ err = map_block(tf, 0); /* First block */ - if(unlikely(err)) { + if(unlikely(err == ERANGE)) { + goto range; + } else if(unlikely(err)) { g_error("Can not map block"); goto fail; } @@ -1024,8 +1339,11 @@ int ltt_tracefile_seek_time(LttTracefile *tf, LttTime time) } } else if(ltt_time_compare(time, tf->buffer.begin.timestamp) < 0) { - /* go to lower part */ - high = block_num - 1; + /* + * Go to lower part. We don't want block_num - 1 since block_num + * can equal low , in which case high < low. + */ + high = block_num; } else if(ltt_time_compare(time, tf->buffer.end.timestamp) > 0) { /* go to higher part */ low = block_num + 1; @@ -1055,6 +1373,17 @@ fail: return EPERM; } + +/* Save the current tracefile position in the passed position pointer */ +int ltt_tracefile_get_current_position(const LttTracefile *tf, LttEventPosition *ep) +{ + /* TODO ybrosseau 2011-06-07: Maybe add some error checking + (ex: check the validity of the arguments pointer) */ + ltt_event_position(&(tf->event), ep); + return 0; +} + + /* Seek to a position indicated by an LttEventPosition */ @@ -1094,28 +1423,22 @@ fail: return 1; } +/* + * Convert a value in "TSC scale" to a value in nanoseconds + */ +guint64 tsc_to_uint64(guint32 freq_scale, uint64_t start_freq, guint64 tsc) +{ + return (double) tsc * NANOSECONDS_PER_SECOND * freq_scale / start_freq; +} + /* Given a TSC value, return the LttTime (seconds,nanoseconds) it * corresponds to. */ - LttTime ltt_interpolate_time_from_tsc(LttTracefile *tf, guint64 tsc) { - LttTime time; - - if(tsc > tf->trace->start_tsc) { - time = ltt_time_from_uint64( - (double)(tsc - tf->trace->start_tsc) - * 1000000000.0 * tf->trace->freq_scale - / (double)tf->trace->start_freq); - time = ltt_time_add(tf->trace->start_time_from_tsc, time); - } else { - time = ltt_time_from_uint64( - (double)(tf->trace->start_tsc - tsc) - * 1000000000.0 * tf->trace->freq_scale - / (double)tf->trace->start_freq); - time = ltt_time_sub(tf->trace->start_time_from_tsc, time); - } - return time; + return ltt_time_from_uint64(tsc_to_uint64(tf->trace->freq_scale, + tf->trace->start_freq, tf->trace->drift * tsc + + tf->trace->offset)); } /* Calculate the real event time based on the buffer boundaries */ @@ -1131,8 +1454,6 @@ LttEvent *ltt_tracefile_get_event(LttTracefile *tf) return &tf->event; } - - /***************************************************************************** *Function name * ltt_tracefile_read : Read the next event in the tracefile @@ -1226,8 +1547,8 @@ static void print_debug_event_header(LttEvent *ev, void *start_pos, void *end_po g_printf("Event header (tracefile %s offset %" PRIx64 "):\n", g_quark_to_string(ev->tracefile->long_name), - ((uint64_t)ev->tracefile->buffer.index * ev->tracefile->buf_size) - + (long)start_pos - (long)ev->tracefile->buffer.head); + (uint64_t)ev->tracefile->buffer.offset + + (long)start_pos - (long)ev->tracefile->buffer.head); while (offset < (long)end_pos - (long)start_pos) { g_printf("%8lx", (long)start_pos - (long)ev->tracefile->buffer.head + offset); @@ -1355,23 +1676,35 @@ static gint map_block(LttTracefile * tf, guint block_num) { int page_size = getpagesize(); ltt_subbuffer_header_t *header; + uint64_t offset; + uint32_t size; + int ret; + if(tf->num_blocks == 0) { + errno = ERANGE; + return ERANGE; + } + g_assert(block_num < tf->num_blocks); if(tf->buffer.head != NULL) { - if(munmap(tf->buffer.head, PAGE_ALIGN(tf->buf_size))) { + if(munmap(tf->buffer.head, PAGE_ALIGN(tf->buffer.size))) { g_warning("unmap size : %u\n", - PAGE_ALIGN(tf->buf_size)); + PAGE_ALIGN(tf->buffer.size)); perror("munmap error"); g_assert(0); } } - + + ret = get_block_offset_size(tf, block_num, &offset, &size); + g_assert(!ret); + + g_debug("Map block %u, offset %llu, size %u\n", block_num, + (unsigned long long)offset, (unsigned int)size); + /* Multiple of pages aligned head */ - tf->buffer.head = mmap(0, - PAGE_ALIGN(tf->buf_size), - PROT_READ, MAP_PRIVATE, tf->fd, - PAGE_ALIGN((off_t)tf->buf_size * (off_t)block_num)); + tf->buffer.head = mmap(0, (size_t)size, PROT_READ, MAP_PRIVATE, + tf->fd, (off_t)offset); if(tf->buffer.head == MAP_FAILED) { perror("Error in allocating memory for buffer of tracefile"); @@ -1379,7 +1712,6 @@ static gint map_block(LttTracefile * tf, guint block_num) goto map_error; } g_assert( ( (gulong)tf->buffer.head&(8-1) ) == 0); // make sure it's aligned. - tf->buffer.index = block_num; @@ -1389,12 +1721,18 @@ static gint map_block(LttTracefile * tf, guint block_num) &header->cycle_count_begin); tf->buffer.end.cycle_count = ltt_get_uint64(LTT_GET_BO(tf), &header->cycle_count_end); - tf->buffer.lost_size = ltt_get_uint32(LTT_GET_BO(tf), - &header->lost_size); + tf->buffer.offset = offset; + tf->buffer.size = ltt_get_uint32(LTT_GET_BO(tf), + &header->sb_size); + tf->buffer.data_size = ltt_get_uint32(LTT_GET_BO(tf), + &header->data_size); tf->buffer.tsc = tf->buffer.begin.cycle_count; tf->event.tsc = tf->buffer.tsc; tf->buffer.freq = tf->buffer.begin.freq; + g_assert(size == tf->buffer.size); + g_assert(tf->buffer.data_size <= tf->buffer.size); + if (tf->trace->start_freq) { tf->buffer.begin.freq = tf->trace->start_freq; @@ -1405,12 +1743,6 @@ static gint map_block(LttTracefile * tf, guint block_num) tf->buffer.end.cycle_count); } - /* FIXME - * eventually support variable buffer size : will need a partial pre-read of - * the headers to create an index when we open the trace... eventually. */ - g_assert(tf->buf_size == ltt_get_uint32(LTT_GET_BO(tf), - &header->buf_size)); - /* Make the current event point to the beginning of the buffer : * it means that the event read must get the first event. */ tf->event.tracefile = tf; @@ -1448,7 +1780,7 @@ static void print_debug_event_data(LttEvent *ev) g_printf("Event data (tracefile %s offset %" PRIx64 "):\n", g_quark_to_string(ev->tracefile->long_name), - ((uint64_t)ev->tracefile->buffer.index * ev->tracefile->buf_size) + (uint64_t)ev->tracefile->buffer.offset + (long)ev->data - (long)ev->tracefile->buffer.head); while (offset < max(ev->event_size, ev->data_size)) { @@ -1532,8 +1864,9 @@ void ltt_update_event_size(LttTracefile *tf) if (info->size != -1) size = info->size; else - size = marker_update_fields_offsets(marker_get_info_from_id(tf->mdata, - tf->event.event_id), tf->event.data); + size = marker_update_fields_offsets(info, tf->event.data); + /* Update per-tracefile offsets */ + marker_update_event_fields_offsets(tf->event.fields_offsets, info); } tf->event.data_size = size; @@ -1581,7 +1914,7 @@ static int ltt_seek_next_event(LttTracefile *tf) if(tf->event.offset == 0) { tf->event.offset += tf->buffer_header_size; - if(tf->event.offset == tf->buf_size - tf->buffer.lost_size) { + if(tf->event.offset == tf->buffer.data_size) { ret = ERANGE; } goto found; @@ -1594,12 +1927,12 @@ static int ltt_seek_next_event(LttTracefile *tf) pos += (size_t)tf->event.data_size; tf->event.offset = pos - tf->buffer.head; - - if(tf->event.offset == tf->buf_size - tf->buffer.lost_size) { + + if(tf->event.offset >= tf->buffer.data_size) { ret = ERANGE; goto found; } - g_assert(tf->event.offset < tf->buf_size - tf->buffer.lost_size); + g_assert(tf->event.offset < tf->buffer.data_size); found: return ret; @@ -1729,3 +2062,140 @@ static __attribute__((constructor)) void init(void) { LTT_TRACEFILE_NAME_METADATA = g_quark_from_string("metadata"); } + +/***************************************************************************** + *Function name + * ltt_tracefile_open_header : based on ltt_tracefile_open but it stops + * when it gets the header + *Input params + * fileName : path to the tracefile + * tf : the tracefile (metadata_0) where the header will be read + *Return value + * ltt_subbuffer_header_t : the header containing the version number + ****************************************************************************/ +static ltt_subbuffer_header_t * ltt_tracefile_open_header(gchar *fileName, LttTracefile *tf) +{ + struct stat lTDFStat; /* Trace data file status */ + ltt_subbuffer_header_t *header; + int page_size = getpagesize(); + + /* open the file */ + tf->long_name = g_quark_from_string(fileName); + tf->fd = open(fileName, O_RDONLY); + if(tf->fd < 0){ + g_warning("Unable to open input data file %s\n", fileName); + goto end; + } + + /* Get the file's status */ + if(fstat(tf->fd, &lTDFStat) < 0){ + g_warning("Unable to get the status of the input data file %s\n", fileName); + goto close_file; + } + + /* Is the file large enough to contain a trace */ + if(lTDFStat.st_size < (off_t)(ltt_subbuffer_header_size())) { + g_print("The input data file %s does not contain a trace\n", fileName); + goto close_file; + } + + /* Temporarily map the buffer start header to get trace information */ + /* Multiple of pages aligned head */ + tf->buffer.head = mmap(0,PAGE_ALIGN(ltt_subbuffer_header_size()), PROT_READ, MAP_PRIVATE, tf->fd, 0); + + if(tf->buffer.head == MAP_FAILED) { + perror("Error in allocating memory for buffer of tracefile"); + goto close_file; + } + g_assert( ( (gulong)tf->buffer.head&(8-1) ) == 0); // make sure it's aligned. + + header = (ltt_subbuffer_header_t *)tf->buffer.head; + + return header; + + close_file: + close(tf->fd); + end: + return 0; +} + + +/***************************************************************************** + *Function name + * get_version : get the trace version from a metadata_0 trace file + *Input params + * pathname : path to the trace + * version_number : the struct that will get the version number + *Return value + * int : 1 if succeed, -1 if error + ****************************************************************************/ +int ltt_get_trace_version(const gchar *pathname, struct LttTraceVersion *version_number) +{ + gchar abs_path[PATH_MAX]; + int ret = 0; + DIR *dir; + struct dirent *entry; + struct stat stat_buf; + gchar path[PATH_MAX]; + + LttTracefile tmp_tf; + LttTrace * t; + ltt_subbuffer_header_t *header; + + t = g_new(LttTrace, 1); + + get_absolute_pathname(pathname, abs_path); + + /* Test to see if it looks like a trace */ + dir = opendir(abs_path); + + if(dir == NULL) { + perror(abs_path); + goto open_error; + } + + while((entry = readdir(dir)) != NULL) { + strcpy(path, abs_path); + strcat(path, "/"); + strcat(path, entry->d_name); + ret = stat(path, &stat_buf); + if(ret == -1) { + perror(path); + continue; + } + } + + closedir(dir); + dir = opendir(abs_path); + + while((entry = readdir(dir)) != NULL) { + if(entry->d_name[0] == '.') continue; + if(g_str_has_prefix(entry->d_name, "metadata_") != 0) continue; + + strcpy(path, abs_path); + strcat(path, "/"); + strcat(path, entry->d_name); + if(ret == -1) { + perror(path); + continue; + } + + header = ltt_tracefile_open_header(path, &tmp_tf); + + if(header == NULL) { + g_info("Error getting the header %s", path); + continue; /* error opening the tracefile : bad magic number ? */ + } + + version_number->ltt_major_version = header->major_version; + version_number->ltt_minor_version = header->minor_version; + + return 1; + } + + return -1; + + open_error: + g_free(t); + return -1; +}