Rework about dialog by using gtk_show_about_dialog
[lttv.git] / ltt / tracefile.c
index 1b6545514f95224fe3e3459299de7f5a93f82487..af03d0c2d54449b9c01cae9958781f0a92ff1c36 100644 (file)
 #include <ltt/ltt-types.h>
 #include <ltt/marker.h>
 
+#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 3:
+    case 6:
       {
-        struct ltt_subbuffer_header_2_3 *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; i<group->len; 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; i<group->len; 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; i<group->len; 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
@@ -885,6 +1198,8 @@ void ltt_tracefile_time_span_get(LttTracefile *tf,
     *end = ltt_time_zero;
   } else
     *end = tf->buffer.end.timestamp;
+
+  g_assert(end->tv_sec <= G_MAXUINT);
 }
 
 struct tracefile_time_span_get_args {
@@ -967,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;
   }
@@ -1022,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;
@@ -1053,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
  */
 
@@ -1092,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 */
@@ -1129,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
@@ -1224,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);
@@ -1353,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");
@@ -1377,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;
 
@@ -1387,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;
@@ -1403,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;
@@ -1446,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)) {
@@ -1530,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;
@@ -1579,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;
@@ -1592,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;
@@ -1727,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;
+}
This page took 0.034561 seconds and 4 git commands to generate.