Add live trace reading support to lttvtraceread lib
authorYannick Brosseau <yannick.brosseau@gmail.com>
Tue, 6 Dec 2011 17:11:52 +0000 (12:11 -0500)
committerMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Tue, 6 Dec 2011 17:11:52 +0000 (12:11 -0500)
Add support to read trace that were not previously closed. Useful to
read live trace or incorrectly closed trace.  Support the opening of
incomplete tracefile and its delayed initialisation Rework the block
index management Add a ltt_tracefile_update, ltt_trace_update and
ltt_trace_open_live interface JNI interface for ltt_openTraceLive and
ltt_updateTrace

Update: Remove dead code and fix const correctness

Signed-off-by: Yannick Brosseau <yannick.brosseau@gmail.com>
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
ltt/event.c
ltt/event.h
ltt/jni_interface.c
ltt/ltt-private.h
ltt/lttvtraceread_loader.c
ltt/trace.h
ltt/tracefile.c

index 3745d896d8362d8d25b3670f8d2bfa303444558b..47f6f4185efe1b20145fb087b5fed8373f73b823 100644 (file)
@@ -69,7 +69,7 @@ void ltt_event_position_set(LttEventPosition *ep, LttTracefile *tf,
  *    ep                 : a pointer to event's position structure
  ****************************************************************************/
 
-void ltt_event_position(LttEvent *e, LttEventPosition *ep)
+void ltt_event_position(const LttEvent *e, LttEventPosition *ep)
 {
   ep->tracefile = e->tracefile;
   ep->block = e->block;
index 456f229edf5736fe83ad6815d6a3fb4adcd853de..ab73ed925c05a274d6fe99f84a20626514b46962 100644 (file)
@@ -70,7 +70,7 @@ static inline LttTime ltt_event_time(const struct LttEvent *event)
    of which are user accessible: block number and event index
    within the block. */
 
-void ltt_event_position(LttEvent *e, LttEventPosition *ep);
+void ltt_event_position(const LttEvent *e, LttEventPosition *ep);
 
 LttEventPosition * ltt_event_position_new();
 
index d1bd993740cbab25be544648a93c73ff31384dae..52c9993c5e035f3319a838d858e7f2cab2c8ac6e 100644 (file)
@@ -30,7 +30,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <stdint.h>
-
+#include <errno.h>
 /* 
 ***FIXME***
 ***HACK***
@@ -142,7 +142,24 @@ 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 );
+        LttTrace *newPtr = ltt_trace_open(c_pathname);
+        
+        (*env)->ReleaseStringUTFChars(env, pathname, c_pathname);
+        
+        return CONVERT_PTR_TO_JLONG(newPtr); 
+}
+
+/* JNI mapping of   < LttTrace *ltt_trace_open_live(const gchar *pathname)  > (trace.h) */
+JNIEXPORT jlong JNICALL Java_org_eclipse_linuxtools_lttng_jni_JniTrace_ltt_1openTraceLive(JNIEnv *env, jobject jobj, jstring pathname, jboolean show_debug) {
+        
+        if ( !show_debug) {
+                /* Make sure we don't use any debug (speed up the read) */
+                g_log_set_handler(NULL, G_LOG_LEVEL_INFO, ignore_and_drop_message, NULL);
+                g_log_set_handler(NULL, G_LOG_LEVEL_DEBUG, ignore_and_drop_message, NULL);
+        }
+        
+        const char *c_pathname = (*env)->GetStringUTFChars(env, pathname, 0);
+        LttTrace *newPtr = ltt_trace_open_live(c_pathname);
         
         (*env)->ReleaseStringUTFChars(env, pathname, c_pathname);
         
@@ -242,6 +259,14 @@ JNIEXPORT jlong JNICALL Java_org_eclipse_linuxtools_lttng_jni_JniTrace_ltt_1getS
         return CONVERT_UINT64_TO_JLONG(newPtr->start_monotonic);
 }
 
+/* JNI mapping of  < int ltt_trace_update(LttTrace *t)  > (trace.h) */
+JNIEXPORT jint JNICALL Java_org_eclipse_linuxtools_lttng_jni_JniTrace_ltt_1updateTrace(JNIEnv *env, jobject jobj, jlong trace_ptr){
+        
+        LttTrace *newPtr = (LttTrace*)CONVERT_JLONG_TO_PTR(trace_ptr);
+        
+        return (jint)ltt_trace_update(newPtr);
+}
+
 /* Access to start_time */
 /* Note that we are calling the setTimeFromC function in Jaf_Time from here */
 JNIEXPORT void JNICALL Java_org_eclipse_linuxtools_lttng_jni_JniTrace_ltt_1feedStartTime(JNIEnv *env, jobject jobj, jlong trace_ptr, jobject time_jobj) {
@@ -671,6 +696,9 @@ JNIEXPORT jint JNICALL Java_org_eclipse_linuxtools_lttng_jni_JniEvent_ltt_1posit
             ERANGE  = 34    out of range, back to last event (might be system dependent?)
             EPERM   = 1     error while reading              (might be system dependent?)  */
         
+        if (tracefilePtr->trace == NULL) {
+            return (jint) EPERM;
+        }
         
         /* Seek to the start time... this will also read the first event, as we want. */
         int returnedValue = ltt_tracefile_seek_time(tracefilePtr, ((struct LttTrace)*(tracefilePtr->trace)).start_time_from_tsc);
index 65d73d18746fe2e21c3becf50a2b5f34a95919ec..593ce4413b44cf6e98ed930275a208f0711a95bf 100644 (file)
@@ -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
 
index ce1ebbb8c279c2aa10d7013b386bb101c724ff71..a72d41ab685c913495b851f02f5a50db7557032e 100644 (file)
@@ -27,6 +27,7 @@ struct version_correlation *version_table = NULL;
 struct function_tables {
         void (*Java_org_eclipse_linuxtools_lttng_jni_Jni_1C_1Common_ltt_1printC)(JNIEnv *env, jobject jobj, jstring new_string);
         jlong (*Java_org_eclipse_linuxtools_lttng_jni_JniTrace_ltt_1openTrace)(JNIEnv *env, jobject jobj, jstring pathname, jboolean show_debug);
+        jlong (*Java_org_eclipse_linuxtools_lttng_jni_JniTrace_ltt_1openTraceLive)(JNIEnv *env, jobject jobj, jstring pathname, jboolean show_debug);
         void (*Java_org_eclipse_linuxtools_lttng_jni_JniTrace_ltt_1closeTrace)(JNIEnv *env, jobject jobj, jlong trace_ptr);
         jstring (*Java_org_eclipse_linuxtools_lttng_jni_JniTrace_ltt_1getTracepath)(JNIEnv *env, jobject jobj, jlong trace_ptr);
         jint (*Java_org_eclipse_linuxtools_lttng_jni_JniTrace_ltt_1getCpuNumber)(JNIEnv *env, jobject jobj, jlong trace_ptr);
@@ -40,6 +41,7 @@ struct function_tables {
         jlong (*Java_org_eclipse_linuxtools_lttng_jni_JniTrace_ltt_1getStartFreq)(JNIEnv *env, jobject jobj, jlong trace_ptr);
         jlong (*Java_org_eclipse_linuxtools_lttng_jni_JniTrace_ltt_1getStartTimestampCurrentCounter)(JNIEnv *env, jobject jobj, jlong trace_ptr);
         jlong (*Java_org_eclipse_linuxtools_lttng_jni_JniTrace_ltt_1getStartMonotonic)(JNIEnv *env, jobject jobj, jlong trace_ptr);
+        jint (*Java_org_eclipse_linuxtools_lttng_jni_JniTrace_ltt_1updateTrace)(JNIEnv *env, jobject jobj, jlong trace_ptr);
         void (*Java_org_eclipse_linuxtools_lttng_jni_JniTrace_ltt_1feedStartTime)(JNIEnv *env, jobject jobj, jlong trace_ptr, jobject time_jobj);
         void (*Java_org_eclipse_linuxtools_lttng_jni_JniTrace_ltt_1feedStartTimeFromTimestampCurrentCounter)(JNIEnv *env, jobject jobj, jlong trace_ptr, jobject time_jobj);
         void (*Java_org_eclipse_linuxtools_lttng_jni_JniTrace_ltt_1feedAllTracefiles)(JNIEnv *env, jobject jobj, jlong trace_ptr);
@@ -223,6 +225,7 @@ JNIEXPORT jint JNICALL Java_org_eclipse_linuxtools_lttng_jni_JniTrace_ltt_1initi
 
                         version_functions_table[lib_id].Java_org_eclipse_linuxtools_lttng_jni_Jni_1C_1Common_ltt_1printC = dlsym(version_table[lib_id].static_handle, "Java_org_eclipse_linuxtools_lttng_jni_Jni_1C_1Common_ltt_1printC");
                         version_functions_table[lib_id].Java_org_eclipse_linuxtools_lttng_jni_JniTrace_ltt_1openTrace = dlsym(version_table[lib_id].static_handle, "Java_org_eclipse_linuxtools_lttng_jni_JniTrace_ltt_1openTrace");
+                        version_functions_table[lib_id].Java_org_eclipse_linuxtools_lttng_jni_JniTrace_ltt_1openTraceLive = dlsym(version_table[lib_id].static_handle, "Java_org_eclipse_linuxtools_lttng_jni_JniTrace_ltt_1openTraceLive");
                         version_functions_table[lib_id].Java_org_eclipse_linuxtools_lttng_jni_JniTrace_ltt_1closeTrace = dlsym(version_table[lib_id].static_handle, "Java_org_eclipse_linuxtools_lttng_jni_JniTrace_ltt_1closeTrace");
                         version_functions_table[lib_id].Java_org_eclipse_linuxtools_lttng_jni_JniTrace_ltt_1getTracepath = dlsym(version_table[lib_id].static_handle, "Java_org_eclipse_linuxtools_lttng_jni_JniTrace_ltt_1getTracepath");
                         version_functions_table[lib_id].Java_org_eclipse_linuxtools_lttng_jni_JniTrace_ltt_1getCpuNumber = dlsym(version_table[lib_id].static_handle, "Java_org_eclipse_linuxtools_lttng_jni_JniTrace_ltt_1getCpuNumber");
@@ -236,6 +239,7 @@ JNIEXPORT jint JNICALL Java_org_eclipse_linuxtools_lttng_jni_JniTrace_ltt_1initi
                         version_functions_table[lib_id].Java_org_eclipse_linuxtools_lttng_jni_JniTrace_ltt_1getStartFreq = dlsym(version_table[lib_id].static_handle, "Java_org_eclipse_linuxtools_lttng_jni_JniTrace_ltt_1getStartFreq");
                         version_functions_table[lib_id].Java_org_eclipse_linuxtools_lttng_jni_JniTrace_ltt_1getStartTimestampCurrentCounter = dlsym(version_table[lib_id].static_handle, "Java_org_eclipse_linuxtools_lttng_jni_JniTrace_ltt_1getStartTimestampCurrentCounter");
                         version_functions_table[lib_id].Java_org_eclipse_linuxtools_lttng_jni_JniTrace_ltt_1getStartMonotonic = dlsym(version_table[lib_id].static_handle, "Java_org_eclipse_linuxtools_lttng_jni_JniTrace_ltt_1getStartMonotonic");
+                        version_functions_table[lib_id].Java_org_eclipse_linuxtools_lttng_jni_JniTrace_ltt_1updateTrace = dlsym(version_table[lib_id].static_handle, "Java_org_eclipse_linuxtools_lttng_jni_JniTrace_ltt_1updateTrace");
                         version_functions_table[lib_id].Java_org_eclipse_linuxtools_lttng_jni_JniTrace_ltt_1feedStartTime = dlsym(version_table[lib_id].static_handle, "Java_org_eclipse_linuxtools_lttng_jni_JniTrace_ltt_1feedStartTime");
                         version_functions_table[lib_id].Java_org_eclipse_linuxtools_lttng_jni_JniTrace_ltt_1feedStartTimeFromTimestampCurrentCounter = dlsym(version_table[lib_id].static_handle, "Java_org_eclipse_linuxtools_lttng_jni_JniTrace_ltt_1feedStartTimeFromTimestampCurrentCounter");
                         version_functions_table[lib_id].Java_org_eclipse_linuxtools_lttng_jni_JniTrace_ltt_1feedAllTracefiles = dlsym(version_table[lib_id].static_handle, "Java_org_eclipse_linuxtools_lttng_jni_JniTrace_ltt_1feedAllTracefiles");
@@ -319,6 +323,12 @@ JNIEXPORT void JNICALL Java_org_eclipse_linuxtools_lttng_jni_Jni_1C_1Common_ltt_
 JNIEXPORT jlong JNICALL Java_org_eclipse_linuxtools_lttng_jni_JniTrace_ltt_1openTrace(JNIEnv *env, jobject jobj, jint lib_id, jstring pathname, jboolean show_debug) {
         return (version_functions_table[lib_id].Java_org_eclipse_linuxtools_lttng_jni_JniTrace_ltt_1openTrace)(env, jobj, pathname, show_debug);
 }
+JNIEXPORT jlong JNICALL Java_org_eclipse_linuxtools_lttng_jni_JniTrace_ltt_1openTraceLive(JNIEnv *env, jobject jobj, jint lib_id, jstring pathname, jboolean show_debug) {
+        if (version_functions_table[lib_id].Java_org_eclipse_linuxtools_lttng_jni_JniTrace_ltt_1openTraceLive == NULL) {
+            return 0;
+        }
+        return (version_functions_table[lib_id].Java_org_eclipse_linuxtools_lttng_jni_JniTrace_ltt_1openTraceLive)(env, jobj, pathname, show_debug);
+}
 JNIEXPORT void JNICALL Java_org_eclipse_linuxtools_lttng_jni_JniTrace_ltt_1closeTrace(JNIEnv *env, jobject jobj, jint lib_id, jlong trace_ptr) {
         (version_functions_table[lib_id].Java_org_eclipse_linuxtools_lttng_jni_JniTrace_ltt_1closeTrace)(env, jobj, trace_ptr);
 }
@@ -358,6 +368,12 @@ JNIEXPORT jlong JNICALL Java_org_eclipse_linuxtools_lttng_jni_JniTrace_ltt_1getS
 JNIEXPORT jlong JNICALL Java_org_eclipse_linuxtools_lttng_jni_JniTrace_ltt_1getStartMonotonic(JNIEnv *env, jobject jobj, jint lib_id, jlong trace_ptr) {
         return (version_functions_table[lib_id].Java_org_eclipse_linuxtools_lttng_jni_JniTrace_ltt_1getStartMonotonic)(env, jobj, trace_ptr);
 }
+JNIEXPORT void JNICALL Java_org_eclipse_linuxtools_lttng_jni_JniTrace_ltt_1updateTrace(JNIEnv *env, jobject jobj, jint lib_id, jlong trace_ptr) {
+        if (version_functions_table[lib_id].Java_org_eclipse_linuxtools_lttng_jni_JniTrace_ltt_1updateTrace == NULL) {
+            return;
+        }
+        (version_functions_table[lib_id].Java_org_eclipse_linuxtools_lttng_jni_JniTrace_ltt_1updateTrace)(env, jobj, trace_ptr);
+}
 JNIEXPORT void JNICALL Java_org_eclipse_linuxtools_lttng_jni_JniTrace_ltt_1feedStartTime(JNIEnv *env, jobject jobj, jint lib_id, jlong trace_ptr, jobject time_jobj) {
         (version_functions_table[lib_id].Java_org_eclipse_linuxtools_lttng_jni_JniTrace_ltt_1feedStartTime)(env, jobj, trace_ptr, time_jobj);
 }
index e16c66f29f43ca44f5d317322f003788cdcb4488..64c38da4a18c91859efb23f8ed25b0839324327e 100644 (file)
@@ -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)
@@ -67,6 +69,10 @@ static inline guint ltt_trace_get_num_cpu(LttTrace *t)
 
 LttTrace *ltt_trace_open(const gchar *pathname);
 
+/* Same as ltt_trace_open but open the trace in live mode */
+LttTrace *ltt_trace_open_live(const gchar *pathname);
+
+
 /* copy reopens a trace 
  *
  * return value NULL if error while opening the trace 
@@ -77,7 +83,8 @@ static inline GQuark ltt_trace_name(const LttTrace *t)
 {
   return t->pathname;
 }
-
+/* Update the informations concerning a trace, normally a live one */
+int ltt_trace_update(LttTrace *trace);
 
 void ltt_trace_close(LttTrace *t); 
 
@@ -141,6 +148,9 @@ static inline guint ltt_tracefile_block_number(LttTracefile *tf)
 
 int ltt_tracefile_seek_time(LttTracefile *t, LttTime time);
 
+
+int ltt_tracefile_get_current_position(const LttTracefile *tf,  LttEventPosition *ep);
+
 /* Seek to the first event with position equal or larger to ep */
 
 int ltt_tracefile_seek_position(LttTracefile *t,
index 012ce10801ec27cf63819614a477ccf5fa173e3d..af03d0c2d54449b9c01cae9958781f0a92ff1c36 100644 (file)
@@ -107,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;
@@ -211,25 +214,18 @@ 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;
-
-    tf->buf_index = g_array_set_size(tf->buf_index, i + 1);
-    off = &g_array_index(tf->buf_index, uint64_t, i);
-    *off = offset;
+    uint64_t size;
 
     /* map block header */
     header = mmap(0, header_map_size, PROT_READ, 
@@ -240,21 +236,147 @@ int ltt_trace_create_block_index(LttTracefile *tf)
     }
 
     /* read len, offset += len */
-    offset += ltt_get_uint32(LTT_GET_BO(tf), &header->sb_size);
+    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;
     }
-    ++i;
   }
   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
  *    ltt_tracefile_open : open a trace file, construct a LttTracefile
@@ -265,94 +387,51 @@ int ltt_trace_create_block_index(LttTracefile *tf)
  *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->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;
-
-  /* Create block index */
-  ltt_trace_create_block_index(tf);
-
-  //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;
   }
-  /* Create fields offset table */
-  tf->event.fields_offsets = g_array_sized_new(FALSE, FALSE,
-                                               sizeof(struct LttField), 1);
-  if (!tf->event.fields_offsets)
-    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:
@@ -361,7 +440,6 @@ end:
   return -1;
 }
 
-
 /*****************************************************************************
  *Function name
  *    ltt_tracefile_close: close a trace file, 
@@ -384,7 +462,9 @@ static void ltt_tracefile_close(LttTracefile *t)
   close(t->fd);
   if (t->buf_index)
     g_array_free(t->buf_index, TRUE);
-  g_array_free(t->event.fields_offsets, TRUE);
+  if (t->event.fields_offsets) {
+         g_array_free(t->event.fields_offsets, TRUE);
+  }
 }
 
 /****************************************************************************
@@ -624,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);
@@ -659,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", 
@@ -806,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;
@@ -851,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, "")) {
@@ -867,15 +963,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 +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;
@@ -909,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.
@@ -919,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);
 }
 
 /*
@@ -941,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
@@ -1039,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;
   }
@@ -1128,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
  */
 
@@ -1198,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
@@ -1426,6 +1680,11 @@ static gint map_block(LttTracefile * tf, guint block_num)
   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) {
@@ -1668,8 +1927,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;
   }
@@ -1911,7 +2170,7 @@ int ltt_get_trace_version(const gchar *pathname, struct LttTraceVersion *version
 
        while((entry = readdir(dir)) != NULL) {
                if(entry->d_name[0] == '.') continue;
-               if(g_strcmp0(entry->d_name, "metadata_0") != 0) continue;
+               if(g_str_has_prefix(entry->d_name, "metadata_") != 0) continue;
 
                strcpy(path, abs_path);
                strcat(path, "/");
@@ -1930,9 +2189,11 @@ int ltt_get_trace_version(const gchar *pathname, struct LttTraceVersion *version
 
                 version_number->ltt_major_version = header->major_version;
                 version_number->ltt_minor_version = header->minor_version;
+
+               return 1;
        }
 
-       return 0;
+       return -1;
 
        open_error:
                 g_free(t);
This page took 0.034675 seconds and 4 git commands to generate.