[ltt-dev] [LTTV PATCH] Introduce the live trace read functionality

Yannick Brosseau yannick.brosseau at gmail.com
Tue Jan 25 13:18:05 EST 2011


This functionality allow the display and analysis of traces
which have not been closed and are still producing data.

Add a live option to the libtraceread ltt_trace_open function
Add live support in the batchanalysis module
Add a live option in the trace file open dialog in the GUI
Add necessary update hooks in some window
Disable statistics for live traces

This patch is built on the previous timebar patch
---
 ltt/jni_interface.c                                |    3 +-
 ltt/ltt-private.h                                  |    2 +-
 ltt/trace.h                                        |   11 +-
 ltt/tracefile.c                                    |  245 +++++++++++++++++---
 lttv/lttv/batchtest.c                              |    2 +-
 lttv/lttv/tracecontext.c                           |   95 ++++++++-
 lttv/lttv/tracecontext.h                           |    2 +
 lttv/modules/gui/detailedevents/events.c           |   27 +++
 lttv/modules/gui/lttvwindow/lttvwindow/callbacks.c |  182 ++++++++-------
 .../modules/gui/lttvwindow/lttvwindow/lttvwindow.c |   47 ++++
 .../modules/gui/lttvwindow/lttvwindow/lttvwindow.h |   30 +++
 lttv/modules/gui/statistics/statistics.c           |   56 ++++-
 lttv/modules/text/batchAnalysis.c                  |   32 ++-
 runlttv                                            |    2 +
 14 files changed, 595 insertions(+), 141 deletions(-)

diff --git a/ltt/jni_interface.c b/ltt/jni_interface.c
index d1bd993..12685d4 100644
--- a/ltt/jni_interface.c
+++ b/ltt/jni_interface.c
@@ -142,7 +142,8 @@ JNIEXPORT jlong JNICALL Java_org_eclipse_linuxtools_lttng_jni_JniTrace_ltt_1open
         }
         
         const char *c_pathname = (*env)->GetStringUTFChars(env, pathname, 0);
-        LttTrace *newPtr = ltt_trace_open( c_pathname );
+	/* TODO ybrosseau 2010-12-06: Enable live trace read in JNI API */
+        LttTrace *newPtr = ltt_trace_open( c_pathname, FALSE );
         
         (*env)->ReleaseStringUTFChars(env, pathname, c_pathname);
         
diff --git a/ltt/ltt-private.h b/ltt/ltt-private.h
index 65d73d1..593ce44 100644
--- a/ltt/ltt-private.h
+++ b/ltt/ltt-private.h
@@ -165,7 +165,7 @@ struct LttTracefile {
   uint32_t  subbuf_corrupt;
 
   GArray *buf_index;                 /* index mapping buffer index to offset */
-
+	uint64_t end_timestamp; /* Last timestamp of file */
   /* Current event */
   LttEvent event;                    //Event currently accessible in the trace
 
diff --git a/ltt/trace.h b/ltt/trace.h
index e16c66f..26ed4b5 100644
--- a/ltt/trace.h
+++ b/ltt/trace.h
@@ -45,8 +45,10 @@ struct LttTrace {
   double    offset;
   LttTime   start_time;
   LttTime   start_time_from_tsc;
+	gboolean  is_live; /* Flag indicating that read trace is currently being recorded */
+	LttTime live_safe_timestamp; /* In a live trace, timestamp were all data should be readable */  
 
-  GData     *tracefiles;                    //tracefiles groups
+	GData     *tracefiles;                    /*tracefiles groups*/
 };
 
 static inline guint ltt_trace_get_num_cpu(LttTrace *t)
@@ -65,7 +67,7 @@ static inline guint ltt_trace_get_num_cpu(LttTrace *t)
    
    */
 
-LttTrace *ltt_trace_open(const gchar *pathname);
+LttTrace *ltt_trace_open(const gchar *pathname, gboolean is_live);
 
 /* copy reopens a trace 
  *
@@ -155,6 +157,11 @@ int ltt_tracefile_read_seek(LttTracefile *t);
 int ltt_tracefile_read_update_event(LttTracefile *t);
 int ltt_tracefile_read_op(LttTracefile *t);
 
+/* TODO ybrosseau 2011-01-25: Maybe to want to hide this function and expose 
+                              an upper level one. */
+/* Update the informations concerning a tracefile, normal a live one */
+int ltt_tracefile_update(LttTracefile *tf);
+
 /* Get the current event of the tracefile : valid until the next read */
 LttEvent *ltt_tracefile_get_event(LttTracefile *tf);
 
diff --git a/ltt/tracefile.c b/ltt/tracefile.c
index 012ce10..7674518 100644
--- a/ltt/tracefile.c
+++ b/ltt/tracefile.c
@@ -211,18 +211,13 @@ int get_block_offset_size(LttTracefile *tf, guint block_num,
   return 0;
 }
 
-int ltt_trace_create_block_index(LttTracefile *tf)
+static int ltt_trace_update_block_index(LttTracefile *tf, uint64_t offset, unsigned long firstBlock)
 {
-  int page_size = getpagesize();
-  uint64_t offset = 0;
-  unsigned long i = 0;
-  unsigned int header_map_size = PAGE_ALIGN(ltt_subbuffer_header_size());
-
-  tf->buf_index = g_array_sized_new(FALSE, TRUE, sizeof(uint64_t),
-                                    DEFAULT_N_BLOCKS);
-
-  g_assert(tf->buf_index->len == i);
+      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;
@@ -241,6 +236,9 @@ int ltt_trace_create_block_index(LttTracefile *tf)
 
     /* read len, offset += len */
     offset += ltt_get_uint32(LTT_GET_BO(tf), &header->sb_size);
+    /* 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);
 
     /* unmap block header */
     if(munmap(header, header_map_size)) {
@@ -255,6 +253,50 @@ int ltt_trace_create_block_index(LttTracefile *tf)
   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;
+}
+
 /*****************************************************************************
  *Function name
  *    ltt_tracefile_open : open a trace file, construct a LttTracefile
@@ -277,6 +319,7 @@ static gint ltt_tracefile_open(LttTrace *t, gchar * fileName, LttTracefile *tf)
   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;
@@ -287,12 +330,21 @@ static gint ltt_tracefile_open(LttTrace *t, gchar * fileName, LttTracefile *tf)
     g_warning("Unable to get the status of the input data file %s\n", fileName);
     goto close_file;
   }
+  //store the size of the file
+  tf->file_size = lTDFStat.st_size;
+  tf->events_lost = 0;
+  tf->subbuf_corrupt = 0;
+  tf->buffer.head = NULL;
 
   // 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;
+  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;
+	  }
   }
   
   /* Temporarily map the buffer start header to get trace information */
@@ -313,10 +365,7 @@ static gint ltt_tracefile_open(LttTrace *t, gchar * fileName, LttTracefile *tf)
     goto unmap_file;
   }
     
-  //store the size of the file
-  tf->file_size = lTDFStat.st_size;
-  tf->events_lost = 0;
-  tf->subbuf_corrupt = 0;
+ 
 
   if(munmap(tf->buffer.head,
         PAGE_ALIGN(ltt_subbuffer_header_size()))) {
@@ -324,8 +373,10 @@ static gint ltt_tracefile_open(LttTrace *t, gchar * fileName, LttTracefile *tf)
         PAGE_ALIGN(ltt_subbuffer_header_size()));
     perror("munmap error");
     g_assert(0);
+  } else {
+	  tf->buffer.head = 0;
   }
-  tf->buffer.head = NULL;
+
 
   /* Create block index */
   ltt_trace_create_block_index(tf);
@@ -659,9 +710,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", 
@@ -812,7 +866,7 @@ seek_error:
  * pathname must be the directory of the trace
  */
 
-LttTrace *ltt_trace_open(const gchar *pathname)
+LttTrace *ltt_trace_open(const gchar *pathname, gboolean is_live)
 {
   gchar abs_path[PATH_MAX];
   LttTrace  * t;
@@ -851,7 +905,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, "")) {
@@ -867,15 +924,27 @@ 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);
 
@@ -889,7 +958,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;
@@ -908,6 +977,104 @@ alloc_error:
   return NULL;
 
 }
+/* TODO ybrosseau 2010-10-25: Merge/share code with ltt_open_trace*/
+/*****************************************************************************
+ *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
+ *                       : 0 for success, -1 otherwise.
+ ****************************************************************************/
+int ltt_tracefile_update(LttTracefile *tf)
+{
+	struct stat    lTDFStat;    /* Trace data file status */
+	int page_size = getpagesize();
+	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;
+
+		if( tf->file_size >= (off_t)(ltt_subbuffer_header_size()) ) {
+
+			if(tf->buf_index == NULL) {
+				ltt_subbuffer_header_t *header;
+				
+				/* 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 block index */
+				ltt_trace_create_block_index(tf);
+				
+				if(map_block(tf,0)) 
+				{
+					perror("Cannot map block for tracefile");
+					goto unmap_file;
+				}
+				
+			}
+			else
+			{
+				//Retrieve the new subbuffers and index them
+				ltt_trace_continue_block_index(tf);
+			}
+			
+			//Update the metadata table if applicable
+			if(tf->name == LTT_TRACEFILE_NAME_METADATA)
+			{
+				//TODO REMOVE?map_block(tf, tf->buffer.index + 1);
+				ltt_process_metadata_tracefile(tf);
+			}
+			ltt_tracefile_read(tf);
+			
+			return 1;
+		}
+	}
+
+	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;
+}
 
 /* Open another, completely independant, instance of a trace.
  *
@@ -919,7 +1086,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);
 }
 
 /*
@@ -941,9 +1108,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
@@ -1039,7 +1212,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;
   }
@@ -1198,8 +1373,6 @@ LttEvent *ltt_tracefile_get_event(LttTracefile *tf)
   return &tf->event;
 }
 
-
-
 /*****************************************************************************
  *Function name
  *    ltt_tracefile_read : Read the next event in the tracefile
@@ -1426,6 +1599,8 @@ static gint map_block(LttTracefile * tf, guint block_num)
   uint32_t size;
   int ret;
 
+  if(tf->num_blocks == 0) return ERANGE;
+  
   g_assert(block_num < tf->num_blocks);
 
   if(tf->buffer.head != NULL) {
@@ -1668,8 +1843,8 @@ 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->buffer.data_size) {
+
+  if(tf->event.offset >= tf->buffer.data_size) {
     ret = ERANGE;
     goto found;
   }
diff --git a/lttv/lttv/batchtest.c b/lttv/lttv/batchtest.c
index 08b892b..fd4a218 100644
--- a/lttv/lttv/batchtest.c
+++ b/lttv/lttv/batchtest.c
@@ -100,7 +100,7 @@ static void lttv_trace_option(void __UNUSED__ *hook_data)
 { 
 	LttTrace *trace;
 
-	trace = ltt_trace_open(a_trace);
+	trace = ltt_trace_open(a_trace, FALSE);
 	if(trace == NULL) {
 		g_critical("cannot open trace %s", a_trace);
 	} else {
diff --git a/lttv/lttv/tracecontext.c b/lttv/lttv/tracecontext.c
index 136b2ee..45a810d 100644
--- a/lttv/lttv/tracecontext.c
+++ b/lttv/lttv/tracecontext.c
@@ -27,6 +27,7 @@
 #include <ltt/trace.h>
 #include <lttv/filter.h>
 #include <errno.h>
+#include <ltt/time.h>
 
 gint compare_tracefile(gconstpointer a, gconstpointer b)
 {
@@ -689,6 +690,8 @@ guint lttv_process_traceset_middle(LttvTracesetContext *self,
 
 	unsigned count = 0;
 
+	gboolean is_live = FALSE; /* set this flag if we detect a live trace */
+
 	guint read_ret;
 
 	//enum read_state last_read_state = LAST_NONE;
@@ -706,7 +709,7 @@ guint lttv_process_traceset_middle(LttvTracesetContext *self,
 		/* End of traceset : tfc is NULL */
 		if(unlikely(tfc == NULL))
 		{
-			return count;
+			break;
 		}
 
 		/* Have we reached :
@@ -723,7 +726,7 @@ guint lttv_process_traceset_middle(LttvTracesetContext *self,
 						end_position) == 0)
 				|| ltt_time_compare(end, tfc->timestamp) <= 0))
 		{
-			return count;
+			break;
 		}
 
 		/* Get the tracefile with an event for the smallest time found. If two
@@ -765,7 +768,8 @@ guint lttv_process_traceset_middle(LttvTracesetContext *self,
 	 if(unlikely(last_ret == 2)) {
 			/* This is a case where we want to stay at this position and stop read. */
 			g_tree_insert(pqueue, tfc, tfc);
-			return count - 1;
+			count--;
+			break;
 		}
 #endif //0
 		read_ret = ltt_tracefile_read(tfc->tf);
@@ -774,6 +778,12 @@ guint lttv_process_traceset_middle(LttvTracesetContext *self,
 		if(likely(!read_ret)) {
 			//g_debug("An event is ready");
 			tfc->timestamp = ltt_event_time(e);
+			if(tfc->tf->trace->is_live && ltt_time_compare(tfc->timestamp, tfc->tf->trace->live_safe_timestamp) >= 0)
+			{
+				is_live |= TRUE;
+				break;
+			}
+
 			g_assert(ltt_time_compare(tfc->timestamp, ltt_time_infinite) != 0);
 			g_tree_insert(pqueue, tfc, tfc);
 #ifdef DEBUG
@@ -794,6 +804,12 @@ guint lttv_process_traceset_middle(LttvTracesetContext *self,
 				g_error("Error happened in lttv_process_traceset_middle");
 		}
 	}
+
+	if (unlikely(count == 0 && is_live)) {
+		return -1;
+	} else {
+		return count;
+	}
 }
 
 
@@ -856,6 +872,79 @@ void lttv_process_trace_seek_time(LttvTraceContext *self, LttTime start)
 #endif //DEBUG
 }
 
+/****************************************************************************
+ * lttv_process_trace_update
+ *
+ * process the changes that occur in the trace. Use a regular file polling to
+ * monitor the tracefile.
+ *
+ * Return the number of tracefile updated
+ ***************************************************************************/
+guint lttv_process_trace_update(LttvTraceContext *self)
+{
+	guint i; 
+	guint nb_tracefile = 0;
+
+	gint ret;
+
+	LttvTracefileContext **tfc;
+
+	/* Skip non live traces */
+	if(self->t->is_live) {
+
+		nb_tracefile = self->tracefiles->len;
+		
+		GTree *pqueue = self->ts_context->pqueue;
+		
+		for(i = 0 ; i < nb_tracefile ; i++) {
+			tfc = &g_array_index(self->tracefiles, LttvTracefileContext*, i);
+			
+			g_tree_remove(pqueue, *tfc);
+			
+			(*tfc)->tf->trace->live_safe_timestamp = LTT_TIME_MAX((*tfc)->tf->trace->live_safe_timestamp,
+									ltt_interpolate_time_from_tsc((*tfc)->tf, 
+												(*tfc)->tf->end_timestamp));
+
+			ret = ltt_tracefile_update((*tfc)->tf);
+			if(ret == 1 || ltt_time_compare((*tfc)->timestamp,ltt_time_infinite) != 0)
+			{
+				(*tfc)->timestamp = ltt_event_time(ltt_tracefile_get_event((*tfc)->tf));
+				g_tree_insert(pqueue, (*tfc), (*tfc));
+				
+			}
+		}
+		//Update self time span
+		self->time_span.end_time = LTT_TIME_MAX(self->t->live_safe_timestamp, 
+							self->time_span.end_time);
+		//Update self tscontext time span
+		self->ts_context->time_span.end_time = LTT_TIME_MAX(self->time_span.end_time, 
+								self->ts_context->time_span.end_time);
+	}
+	return nb_tracefile;
+	
+}
+
+/****************************************************************************
+ * lttv_process_traceset_update
+ *
+ * process the changes that occur in the traceset.
+ *
+ * Return the number of file presently monitor(open for writting). If 0, the
+ * current traceset probably received all the data.
+ ***************************************************************************/
+guint lttv_process_traceset_update(LttvTracesetContext *self)
+{
+	guint i;
+	guint nb_trace;
+	guint open_counter = 0;
+
+	nb_trace = lttv_traceset_number(self->ts);
+
+	for(i = 0 ; i < nb_trace ; i++) {
+		open_counter += lttv_process_trace_update(self->traces[i]);
+	}
+	return open_counter;
+}
 
 void lttv_process_traceset_seek_time(LttvTracesetContext *self, LttTime start)
 {
diff --git a/lttv/lttv/tracecontext.h b/lttv/lttv/tracecontext.h
index acedeea..e509811 100644
--- a/lttv/lttv/tracecontext.h
+++ b/lttv/lttv/tracecontext.h
@@ -220,6 +220,8 @@ void lttv_process_traceset_end(LttvTracesetContext *self,
 		LttvHooks *event,
 		LttvHooksByIdChannelArray *event_by_id_channel);
 
+guint lttv_process_traceset_update(LttvTracesetContext *self);
+
 
 void lttv_process_traceset_seek_time(LttvTracesetContext *self, LttTime start);
 
diff --git a/lttv/modules/gui/detailedevents/events.c b/lttv/modules/gui/detailedevents/events.c
index 0c1a153..ae749ea 100644
--- a/lttv/modules/gui/detailedevents/events.c
+++ b/lttv/modules/gui/detailedevents/events.c
@@ -99,6 +99,7 @@ gboolean update_current_time(void * hook_data, void * call_data);
 gboolean update_current_position(void * hook_data, void * call_data);
 //gboolean show_event_detail(void * hook_data, void * call_data);
 gboolean traceset_changed(void * hook_data, void * call_data);
+gboolean timespan_changed(void * hook_data, void * call_data);
 gboolean filter_changed(void * hook_data, void * call_data);
 
 static void request_background_data(EventViewerData *event_viewer_data);
@@ -211,6 +212,8 @@ gui_events(LttvPluginTab *ptab)
                 update_current_position,event_viewer_data);
   lttvwindow_register_traceset_notify(tab, 
                 traceset_changed,event_viewer_data);
+  lttvwindow_register_time_span_notify(tab, 
+                timespan_changed,event_viewer_data);
   lttvwindow_register_filter_notify(tab,
                 filter_changed, event_viewer_data);
   lttvwindow_register_redraw_notify(tab,
@@ -449,12 +452,14 @@ gui_events(LttvPluginTab *ptab)
   g_signal_connect (G_OBJECT (event_viewer_data->vadjust_c), "value-changed",
         G_CALLBACK (v_scroll_cb),
         event_viewer_data);
+  //TODO ybrosseau 2011-01-06: Fix comment
   /* Set the upper bound to the last event number */
   event_viewer_data->previous_value = 0;
   event_viewer_data->vadjust_c->lower = 0.0;
     //event_viewer_data->vadjust_c->upper = event_viewer_data->number_of_events;
   LttTime time = lttvwindow_get_current_time(tab);
   time = ltt_time_sub(time, tsc->time_span.start_time);
+  //TODO ybrosseau 2011-01-06: Which one do we keep?
   event_viewer_data->vadjust_c->value = ltt_time_to_double(time);
   event_viewer_data->vadjust_c->value = 0.0;
   event_viewer_data->vadjust_c->step_increment = 1.0;
@@ -1769,7 +1774,27 @@ gboolean update_current_position(void * hook_data, void * call_data)
   return FALSE;
 }
 
+gboolean timespan_changed(void * hook_data, void * call_data)
+{
+  EventViewerData *event_viewer_data = (EventViewerData*) hook_data;
+  LttvTracesetContext * tsc =
+        lttvwindow_get_traceset_context(event_viewer_data->tab);
+  TimeInterval time_span = tsc->time_span;
+ 
+  LttTime end;
 
+  end = ltt_time_sub(time_span.end_time, time_span.start_time);
+  event_viewer_data->vadjust_c->upper = ltt_time_to_double(end);
+
+  if(event_viewer_data->pos->len < event_viewer_data->num_visible_events ) {
+
+	  
+	  get_events(event_viewer_data->vadjust_c->value, event_viewer_data);
+	  
+	  request_background_data(event_viewer_data);
+  }
+  return FALSE;
+}
 
 gboolean traceset_changed(void * hook_data, void * call_data)
 {
@@ -1863,6 +1888,8 @@ void gui_events_free(gpointer data)
     //                    show_event_detail, event_viewer_data);
     lttvwindow_unregister_traceset_notify(tab,
                         traceset_changed, event_viewer_data);
+    lttvwindow_unregister_time_span_notify(tab,
+				    timespan_changed,event_viewer_data);
     lttvwindow_unregister_filter_notify(tab,
                         filter_changed, event_viewer_data);
     lttvwindow_unregister_redraw_notify(tab,
diff --git a/lttv/modules/gui/lttvwindow/lttvwindow/callbacks.c b/lttv/modules/gui/lttvwindow/lttvwindow/callbacks.c
index aabd2ac..5cd2eb1 100644
--- a/lttv/modules/gui/lttvwindow/lttvwindow/callbacks.c
+++ b/lttv/modules/gui/lttvwindow/lttvwindow/callbacks.c
@@ -87,6 +87,7 @@ static void on_timebar_endtime_changed(Timebar *timebar,
 				gpointer user_data);
 static void on_timebar_currenttime_changed(Timebar *timebar,
 				gpointer user_data);
+int update_traceset(Tab *tab, LttvTraceset *traceset);
 
 enum {
   CHECKBOX_COLUMN,
@@ -100,8 +101,6 @@ enum
   N_COLUMNS
 };
 
-
-
 #if 0
 static void on_top_notify(GObject    *gobject,
 		GParamSpec *arg1,
@@ -303,71 +302,8 @@ int SetTraceset(Tab * tab, LttvTraceset *traceset)
                                             new_time_window.time_width) ;
   }
 
- 
- 
-#if 0
-  /* Set scrollbar */
-  GtkAdjustment *adjustment = gtk_range_get_adjustment(GTK_RANGE(tab->scrollbar));
-  LttTime upper = ltt_time_sub(time_span.end_time, time_span.start_time);
-      
-  g_object_set(G_OBJECT(adjustment),
-               "lower",
-                 0.0, /* lower */
-               "upper",
-               ltt_time_to_double(upper) 
-                 * NANOSECONDS_PER_SECOND, /* upper */
-               "step_increment",
-               ltt_time_to_double(tab->time_window.time_width)
-                             / SCROLL_STEP_PER_PAGE
-                             * NANOSECONDS_PER_SECOND, /* step increment */
-               "page_increment",
-               ltt_time_to_double(tab->time_window.time_width) 
-                 * NANOSECONDS_PER_SECOND, /* page increment */
-               "page_size",
-               ltt_time_to_double(tab->time_window.time_width) 
-                 * NANOSECONDS_PER_SECOND, /* page size */
-               NULL);
-  gtk_adjustment_changed(adjustment);
-
-  g_object_set(G_OBJECT(adjustment),
-               "value",
-               ltt_time_to_double(
-                ltt_time_sub(tab->time_window.start_time, time_span.start_time))
-                   * NANOSECONDS_PER_SECOND, /* value */
-               NULL);
-  gtk_adjustment_value_changed(adjustment);
-
-  /* set the time bar. The value callbacks will change their nsec themself */
-  /* start seconds */
-  gtk_spin_button_set_range(GTK_SPIN_BUTTON(tab->MEntry1),
-                            (double)time_span.start_time.tv_sec,
-                            (double)time_span.end_time.tv_sec);
-
-  /* end seconds */
-  gtk_spin_button_set_range(GTK_SPIN_BUTTON(tab->MEntry3),
-                            (double)time_span.start_time.tv_sec,
-                            (double)time_span.end_time.tv_sec);
-
-   /* current seconds */
-  gtk_spin_button_set_range(GTK_SPIN_BUTTON(tab->MEntry5),
-                            (double)time_span.start_time.tv_sec,
-                            (double)time_span.end_time.tv_sec);
-#endif //0
-  
   /* Finally, call the update hooks of the viewers */
-  LttvHooks * tmp;
-  LttvAttributeValue value;
-  gint retval = 0;
- 
-  retval= lttv_iattribute_find_by_path(tab->attributes,
-    "hooks/updatetraceset", LTTV_POINTER, &value);
-  g_assert(retval);
-
-  tmp = (LttvHooks*)*(value.v_pointer);
-  if(tmp == NULL)
-	  retval = 1;
-  else
-	  lttv_hooks_call(tmp,traceset);
+  gint retval = update_traceset(tab,traceset);
 
   time_change_manager(tab, new_time_window);
   current_time_change_manager(tab, new_current_time);
@@ -408,20 +344,48 @@ int SetFilter(Tab * tab, gpointer filter)
  * @param tab viewer's tab 
  */
 
-void update_traceset(Tab *tab)
+int update_traceset(Tab *tab, LttvTraceset *traceset)
 {
   LttvAttributeValue value;
   LttvHooks * tmp;
   gboolean retval;
 
   retval= lttv_iattribute_find_by_path(tab->attributes,
-    "hooks/updatetraceset", LTTV_POINTER, &value);
+				  "hooks/updatetraceset", 
+				  LTTV_POINTER, 
+				  &value);
   g_assert(retval);
   tmp = (LttvHooks*)*(value.v_pointer);
-  if(tmp == NULL) return;
-  lttv_hooks_call(tmp, NULL);
+  if(tmp == NULL) {
+	  retval = 1;
+  } else {
+	  lttv_hooks_call(tmp, traceset);
+  }
+  return retval;
 }
 
+/** 
+    Call hooks register to get update on traceset time span changes
+*/
+int notify_time_span_changed(Tab *tab)
+{
+  LttvAttributeValue value;
+  LttvHooks * tmp;
+  gboolean retval;
+
+  retval= lttv_iattribute_find_by_path(tab->attributes,
+				  "hooks/updatetimespan", 
+				  LTTV_POINTER, 
+				  &value);
+  g_assert(retval);
+  tmp = (LttvHooks*)*(value.v_pointer);
+  if(tmp == NULL) {
+	  retval = 1;
+  } else {
+	  lttv_hooks_call(tmp, NULL);
+  }
+  return retval;
+}
 
 /* get_label function is used to get user input, it displays an input
  * box, which allows user to input a string 
@@ -1506,7 +1470,51 @@ gboolean lttvwindow_process_pending_requests(Tab *tab)
 }
 
 #undef list_out
+/** 
+    Manage the periodic update of a live trace
+*/
+static gboolean
+live_trace_update_handler(gpointer data)
+{  
+
+	Tab *tab = (Tab *)data;
+	unsigned int updated_count;
+
+	LttvTracesetContext *tsc = LTTV_TRACESET_CONTEXT(tab->traceset_info->traceset_context);
+	TimeInterval initial_time_span = tsc->time_span;
+	TimeInterval updated_time_span;
+
+	updated_count = lttv_process_traceset_update(tsc);
+	
+	/* TODO ybrosseau 2011-01-12: Add trace resynchronization  */
+
+	/* Get the changed period bounds */
+	updated_time_span = tsc->time_span;
+
+	if(ltt_time_compare(updated_time_span.start_time, 
+				initial_time_span.start_time) != 0) {
+		/* The initial time should not change on a live update */
+		g_assert(FALSE);
+	}
+
+	/* Notify viewers (only on updates) */
+	if(ltt_time_compare(updated_time_span.end_time, 
+				initial_time_span.end_time) != 0) {
+		
+		notify_time_span_changed(tab);
+		/* TODO ybrosseau 2011-01-12: Change the timebar to register 
+		   to the time_span hook */
+		timebar_set_minmax_time(TIMEBAR(tab->MTimebar),
+					&updated_time_span.start_time,
+					&updated_time_span.end_time );
+		
+		/* To update the min max */
+		time_change_manager(tab, tab->time_window);
+	}
 
+	/* Timer will be recalled as long as there is files to update */
+	return (updated_count > 0);
+}
 
 static void lttvwindow_add_trace(Tab *tab, LttvTrace *trace_v)
 {
@@ -1561,6 +1569,16 @@ static void lttvwindow_add_trace(Tab *tab, LttvTrace *trace_v)
 
   //FIXME
   //add_trace_into_traceset_selector(GTK_MULTIVPANED(tab->multivpaned), lttv_trace(trace_v));
+
+
+  if (lttv_trace(trace_v)->is_live) {
+	  /* Add timer for live update */
+	  /* TODO ybrosseau 2011-01-12: Parametrize the hardcoded 1 seconds */
+	  g_timeout_add_seconds (1,
+			  live_trace_update_handler,
+			  tab);
+  }
+
 }
 
 /* add_trace adds a trace into the current traceset. It first displays a 
@@ -1593,6 +1611,7 @@ void add_trace(GtkWidget * widget, gpointer user_data)
   }
 
   /* File open dialog management */
+  GtkWidget *extra_live_button; 
   GtkFileChooser * file_chooser = 
 	  GTK_FILE_CHOOSER(
 		  gtk_file_chooser_dialog_new ("Select a trace",
@@ -1602,6 +1621,11 @@ void add_trace(GtkWidget * widget, gpointer user_data)
 					  GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
 					  NULL));
 
+  /* Button to indicate the opening of a live trace */
+  extra_live_button = gtk_check_button_new_with_mnemonic ("Trace is live (currently being writen)");
+  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (extra_live_button), FALSE);
+  gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER (file_chooser), extra_live_button);
+
   gtk_file_chooser_set_show_hidden (file_chooser, TRUE);
   if(remember_trace_dir[0] != '\0')
 	  gtk_file_chooser_set_filename(file_chooser, remember_trace_dir);
@@ -1612,6 +1636,7 @@ void add_trace(GtkWidget * widget, gpointer user_data)
     case GTK_RESPONSE_ACCEPT:
     case GTK_RESPONSE_OK:
       dir = gtk_file_chooser_get_filename (file_chooser);
+
       strncpy(remember_trace_dir, dir, PATH_MAX);
       strncat(remember_trace_dir, "/", PATH_MAX);
       if(!dir || strlen(dir) == 0){
@@ -1620,7 +1645,9 @@ void add_trace(GtkWidget * widget, gpointer user_data)
       get_absolute_pathname(dir, abs_path);
       trace_v = lttvwindowtraces_get_trace_by_name(abs_path);
       if(trace_v == NULL) {
-        trace = ltt_trace_open(abs_path);
+
+	      trace = ltt_trace_open(abs_path,
+			      gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (extra_live_button)));
         if(trace == NULL) {
           g_warning("cannot open trace %s", abs_path);
 
@@ -3196,7 +3223,6 @@ void time_change_manager               (Tab *tab,
   TimeInterval time_span = tsc->time_span;
   LttTime start_time = new_time_window.start_time;
   LttTime end_time = new_time_window.end_time;
-  LttTime time_width = new_time_window.time_width;
 
   g_assert(ltt_time_compare(start_time, end_time) < 0);
   
@@ -3252,7 +3278,6 @@ void time_change_manager               (Tab *tab,
   timebar_set_end_time(TIMEBAR(tab->MTimebar),&end_time);
 
 
-
   /* call viewer hooks for new time window */
   set_time_window(tab, &new_time_window);
 
@@ -3260,9 +3285,6 @@ void time_change_manager               (Tab *tab,
 }
 
 
-
-
-
 void current_time_change_manager       (Tab *tab,
                                         LttTime new_current_time)
 {
@@ -3271,9 +3293,6 @@ void current_time_change_manager       (Tab *tab,
 
   tab->current_time_manager_lock = TRUE;
 
-  LttvTracesetContext *tsc = LTTV_TRACESET_CONTEXT(tab->traceset_info->traceset_context);
-  TimeInterval time_span = tsc->time_span;
-
   timebar_set_current_time(TIMEBAR(tab->MTimebar), &new_current_time);
 
   set_current_time(tab, &new_current_time);
@@ -3299,7 +3318,6 @@ void current_position_change_manager(Tab *tab,
   set_current_position(tab, pos);
 }
 
-
 static void on_timebar_starttime_changed(Timebar *timebar,
 				gpointer user_data)
 {
@@ -3382,6 +3400,7 @@ static void on_timebar_currenttime_changed(Timebar *timebar,
 	current_time_change_manager(tab, new_current_time);
 }
 
+
 void scroll_value_changed_cb(GtkWidget *scrollbar,
                              gpointer user_data)
 {
@@ -4120,7 +4139,8 @@ __EXPORT void create_main_window_with_trace_list(GSList *traces)
     get_absolute_pathname(path, abs_path);
     trace_v = lttvwindowtraces_get_trace_by_name(abs_path);
     if(trace_v == NULL) {
-      trace = ltt_trace_open(abs_path);
+	    /* TODO ybrosseau: 2010-10-25: Add support for live trace*/
+	    trace = ltt_trace_open(abs_path, FALSE);
       if(trace == NULL) {
         g_warning("cannot open trace %s", abs_path);
 
diff --git a/lttv/modules/gui/lttvwindow/lttvwindow/lttvwindow.c b/lttv/modules/gui/lttvwindow/lttvwindow/lttvwindow.c
index ee3f924..acb968b 100644
--- a/lttv/modules/gui/lttvwindow/lttvwindow/lttvwindow.c
+++ b/lttv/modules/gui/lttvwindow/lttvwindow/lttvwindow.c
@@ -468,6 +468,53 @@ __EXPORT void lttvwindow_unregister_time_window_notify(Tab *tab,
 }
 
 /**
+ * Function to register a hook function for a viewer to set/update its
+ * allowed time span.
+ * @param tab viewer's tab 
+ * @param hook hook function of the viewer.
+ * @param hook_data hook data associated with the hook function.
+ */
+__EXPORT void lttvwindow_register_time_span_notify(Tab *tab,
+    LttvHook hook, gpointer hook_data)
+{
+  LttvAttributeValue value;
+  LttvHooks * tmp;
+  gboolean retval;
+
+  retval= lttv_iattribute_find_by_path(tab->attributes,
+    "hooks/updatetimespan", LTTV_POINTER, &value);
+  g_assert(retval);
+  tmp = (LttvHooks*)*(value.v_pointer);
+  if(tmp == NULL){    
+    tmp = lttv_hooks_new();
+    *(value.v_pointer) = tmp;
+  }
+  lttv_hooks_add(tmp, hook,hook_data, LTTV_PRIO_DEFAULT);
+}
+/**
+ * Function to unregister a viewer's hook function which is used to 
+ * set/update the time span allowed for the viewer.
+ * @param tab viewer's tab 
+ * @param hook hook function of the viewer.
+ * @param hook_data hook data associated with the hook function.
+ */
+
+__EXPORT void lttvwindow_unregister_time_span_notify(Tab *tab,
+    LttvHook hook, gpointer hook_data)
+{
+  LttvAttributeValue value;
+  LttvHooks * tmp;
+  gboolean retval;
+
+  retval= lttv_iattribute_find_by_path(tab->attributes,
+    "hooks/updatetimespan", LTTV_POINTER, &value);
+  g_assert(retval);
+  tmp = (LttvHooks*)*(value.v_pointer);
+  if(tmp == NULL) return;
+  lttv_hooks_remove_data(tmp, hook, hook_data);
+}
+
+/**
  * Function to register a hook function for a viewer to set/update its 
  * traceset.
  * @param tab viewer's tab 
diff --git a/lttv/modules/gui/lttvwindow/lttvwindow/lttvwindow.h b/lttv/modules/gui/lttvwindow/lttvwindow/lttvwindow.h
index 30fa5c6..72b1414 100644
--- a/lttv/modules/gui/lttvwindow/lttvwindow/lttvwindow.h
+++ b/lttv/modules/gui/lttvwindow/lttvwindow/lttvwindow.h
@@ -361,6 +361,36 @@ void lttvwindow_unregister_time_window_notify(Tab *tab,
                                               LttvHook    hook, 
                                               gpointer    hook_data);
 
+/**
+ * Function to register a hook function that will be called by the main window
+ * when the time span of the traceset is updated.
+ * 
+ * This register function is typically called by the constructor of the viewer.
+ * 
+ * @param tab the tab the viewer belongs to.
+ * @param hook hook that sould be called by the main window when the time
+ *             interval changes. 
+ * @param hook_data hook data associated with the hook function. It will
+ *                  be typically a pointer to the viewer's data structure.
+ */
+void lttvwindow_register_time_span_notify(Tab *tab,
+                                            LttvHook    hook,
+                                            gpointer    hook_data);
+
+/**
+ * Function to unregister the time_span notification hook.
+ * 
+ * This unregister function is typically called by the destructor of the viewer.
+ * 
+ * @param tab the tab the viewer belongs to.
+ * @param hook hook that sould be called by the main window when the time
+ *             interval changes. 
+ * @param hook_data hook data associated with the hook function. It will
+ *                  be typically a pointer to the viewer's data structure.
+ */
+void lttvwindow_unregister_time_span_notify(Tab *tab,
+                                            LttvHook    hook,
+                                            gpointer    hook_data);
 
 /**
  * Function to register a hook function that will be called by the main window
diff --git a/lttv/modules/gui/statistics/statistics.c b/lttv/modules/gui/statistics/statistics.c
index 2b40d6b..1645c5d 100644
--- a/lttv/modules/gui/statistics/statistics.c
+++ b/lttv/modules/gui/statistics/statistics.c
@@ -116,6 +116,7 @@ struct _StatisticViewerData{
   GHashTable *statistic_hash;
 
   guint background_info_waiting;
+	guint live_trace_count;
 };
 
 
@@ -290,6 +291,7 @@ gui_statistic(LttvPluginTab *ptab)
   GtkTreeViewColumn *column;
 
   StatisticViewerData* statistic_viewer_data = g_new(StatisticViewerData,1);
+  statistic_viewer_data->live_trace_count = 0;
   Tab *tab = ptab->tab;
   statistic_viewer_data->tab  = tab;
   statistic_viewer_data->ptab  = ptab;
@@ -301,7 +303,6 @@ gui_statistic(LttvPluginTab *ptab)
   lttvwindow_register_traceset_notify(statistic_viewer_data->tab,
                                       statistic_traceset_changed,
                                       statistic_viewer_data);
- 
   statistic_viewer_data->statistic_hash = g_hash_table_new_full(g_str_hash,
                                                   g_str_equal,
                                                   statistic_destroy_hash_key,
@@ -424,6 +425,8 @@ extern FILE *stdout;
 extern FILE *stderr;
 #endif //DEBUG
 
+static char *live_msg = "Statistics for traceset containing live traces are inaccurate";
+
 void show_traceset_stats(StatisticViewerData * statistic_viewer_data)
 {
   Tab *tab = statistic_viewer_data->tab;
@@ -451,6 +454,21 @@ void show_traceset_stats(StatisticViewerData * statistic_viewer_data)
           -1);  
   path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iter);
   str = gtk_tree_path_to_string (path);
+
+  for(i = 0 ; i < nb ; i++) {
+	  if (LTTV_TRACESET_CONTEXT(tscs)->traces[i]->t->is_live) {
+		  statistic_viewer_data->live_trace_count++;
+	  }
+
+  }
+  if (statistic_viewer_data->live_trace_count) {
+	  LttvAttributeValue value;
+	  value = lttv_attribute_add(tscs->stats,
+				     g_quark_from_static_string("WARNING: Live traceset"),
+				     LTTV_STRING);
+	  *(value.v_string) = live_msg;
+	  
+  }
   g_hash_table_insert(statistic_viewer_data->statistic_hash,
           (gpointer)str, tscs->stats);
   show_tree(statistic_viewer_data, tscs->stats, &iter);
@@ -467,16 +485,30 @@ void show_traceset_stats(StatisticViewerData * statistic_viewer_data)
             start_time.tv_nsec);
 #endif //0
     sprintf(trace_str, "%s", g_quark_to_string(ltt_trace_name(tcs->parent.parent.t)));
-    gtk_tree_store_append (store, &iter, NULL);  
-    gtk_tree_store_set (store, &iter,NAME_COLUMN,trace_str,-1);  
-    path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iter);
-    str = gtk_tree_path_to_string (path);
-    g_hash_table_insert(statistic_viewer_data->statistic_hash,
-      (gpointer)str,tcs->stats);
-    show_tree(statistic_viewer_data, tcs->stats, &iter);
+    /* TODO ybrosseau 2011-01-12: Reenable stats for live trace */
+    if (LTTV_TRACE_CONTEXT(tcs)->t->is_live) {
+	    strcat(trace_str, " [LIVE]");
+	    gtk_tree_store_append (store, &iter, NULL);  
+	    gtk_tree_store_set (store, &iter,NAME_COLUMN,trace_str,-1); 
+
+	    path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iter);
+	    str = gtk_tree_path_to_string (path);
+	    g_hash_table_insert(statistic_viewer_data->statistic_hash,
+			    (gpointer)str,0);
+	    
+    } else {
+    
+	    gtk_tree_store_append (store, &iter, NULL);  
+	    gtk_tree_store_set (store, &iter,NAME_COLUMN,trace_str,-1);  
+	    path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iter);
+	    str = gtk_tree_path_to_string (path);
+	    g_hash_table_insert(statistic_viewer_data->statistic_hash,
+			    (gpointer)str,tcs->stats);
+	    show_tree(statistic_viewer_data, tcs->stats, &iter);
 #ifdef DEBUG
-    lttv_attribute_write_xml(tcs->stats, stdout, 3, 4);
+	    lttv_attribute_write_xml(tcs->stats, stdout, 3, 4);
 #endif //DEBUG
+    }
   }
 }
 
@@ -523,7 +555,7 @@ void show_tree(StatisticViewerData * statistic_viewer_data,
 void show_statistic(StatisticViewerData * statistic_viewer_data,
         LttvAttribute* stats, GtkTextBuffer* buf)
 {
-  int i, nb , flag;
+  int i, nb = 0, flag;
   LttvAttributeName name;
   LttvAttributeValue value;
   LttvAttributeType type;
@@ -532,7 +564,9 @@ void show_statistic(StatisticViewerData * statistic_viewer_data,
   GtkTextIter   text_iter;
   
   flag = 0;
-  nb = lttv_attribute_get_number(stats);
+  if(stats) {
+	  nb = lttv_attribute_get_number(stats);
+  }
   for(i = 0 ; i < nb ; i++) {
     type = lttv_attribute_get(stats, i, &name, &value, &is_named);
 		if(is_named)
diff --git a/lttv/modules/text/batchAnalysis.c b/lttv/modules/text/batchAnalysis.c
index 7d55f44..7937796 100644
--- a/lttv/modules/text/batchAnalysis.c
+++ b/lttv/modules/text/batchAnalysis.c
@@ -22,7 +22,7 @@
 #ifdef HAVE_CONFIG_H
 #include <config.h>
 #endif
-
+#include <unistd.h>
 #include <glib.h>
 #include <lttv/lttv.h>
 #include <lttv/attribute.h>
@@ -51,12 +51,13 @@ static LttvHooks
 static char *a_trace;
 
 static gboolean a_stats;
+static gboolean a_live;
 
 void lttv_trace_option(void *hook_data)
 { 
   LttTrace *trace;
 
-  trace = ltt_trace_open(a_trace);
+  trace = ltt_trace_open(a_trace, a_live);
   if(trace == NULL) g_critical("cannot open trace %s", a_trace);
   lttv_traceset_add(traceset, lttv_trace_new(trace));
 }
@@ -134,10 +135,22 @@ static gboolean process_traceset(void *hook_data, void *call_data)
   g_info("BatchAnalysis process traceset");
 
   lttv_process_traceset_seek_time(tc, start);
-  lttv_process_traceset_middle(tc,
-                               end,
-                               G_MAXULONG,
-                               NULL);
+  /* Read as long a we do not reach the end (0) */
+  unsigned int count;
+  unsigned int updated_count;
+  do {
+	  count = lttv_process_traceset_middle(tc,
+							  end,
+							  G_MAXULONG,
+							  NULL);
+	  
+	  updated_count = lttv_process_traceset_update(tc); 
+		
+	
+	  
+	  /* TODO YB 2010-10-18: Use a more flexible time frame between reading ticks */
+	  sleep(1);
+  } while(count != 0 || updated_count > 0);
 
 
   //lttv_traceset_context_remove_hooks(tc,
@@ -186,6 +199,12 @@ static void init()
       "", 
       LTTV_OPT_NONE, &a_stats, NULL, NULL);
 
+  a_live = FALSE;
+  lttv_option_add("live", 'L',
+      "define if the traceset is receiving live informations",
+      "",
+      LTTV_OPT_NONE, &a_live, NULL, NULL);
+
 
   traceset = lttv_traceset_new();
 
@@ -251,6 +270,7 @@ static void destroy()
 
   lttv_option_remove("trace");
   lttv_option_remove("stats");
+  lttv_option_remove("live");
 
   lttv_hooks_destroy(before_traceset);
   lttv_hooks_destroy(after_traceset);
diff --git a/runlttv b/runlttv
index 9dfc6bf..6869d3f 100755
--- a/runlttv
+++ b/runlttv
@@ -94,6 +94,8 @@ elif [ "$HELPER" = "massif" ]; then
 	LD_LIBRARY_PATH=${BUILDPATH}/ltt/.libs valgrind --tool=massif $LTTV_EXEC $LTTV_ARGS
 elif [ "$HELPER" = "strace" ]; then
 	LD_LIBRARY_PATH=${BUILDPATH}/ltt/.libs strace $LTTV_EXEC $LTTV_ARGS
+elif [ "$HELPER" = "ginspector" ]; then
+        LD_LIBRARY_PATH=${BUILDPATH}/ltt/.libs g-inspector $LTTV_EXEC $LTTV_ARGS
 else
 	LD_LIBRARY_PATH=${BUILDPATH}/ltt/.libs $LTTV_EXEC $LTTV_ARGS
 fi
-- 
1.7.2.3





More information about the lttng-dev mailing list