reparent the process if unordered schedule + fork
[lttv.git] / ltt / branches / poly / lttv / lttv / state.c
index b333729ca003c9ff5718fbf735bd4443b90210f4..c06ba340e25fa77d7bfc97002f3e2de001f8c070 100644 (file)
@@ -35,7 +35,8 @@
 
 GQuark
     LTT_FACILITY_KERNEL,
-    LTT_FACILITY_PROCESS;
+    LTT_FACILITY_PROCESS,
+    LTT_FACILITY_FS;
 
 /* Events Quarks */
 
@@ -49,7 +50,8 @@ GQuark
     LTT_EVENT_SCHEDCHANGE,
     LTT_EVENT_FORK,
     LTT_EVENT_EXIT,
-    LTT_EVENT_FREE;
+    LTT_EVENT_FREE,
+    LTT_EVENT_EXEC;
 
 /* Fields Quarks */
 
@@ -62,7 +64,8 @@ GQuark
     LTT_FIELD_OUT_STATE,
     LTT_FIELD_PARENT_PID,
     LTT_FIELD_CHILD_PID,
-    LTT_FIELD_PID;
+    LTT_FIELD_PID,
+    LTT_FIELD_FILENAME;
 
 LttvExecutionMode
   LTTV_STATE_MODE_UNKNOWN,
@@ -171,10 +174,14 @@ restore_init_state(LttvTraceState *self)
   self->nb_event = 0;
 
   /* Seek time to beginning */
-  g_tree_destroy(self->parent.ts_context->pqueue);
-  self->parent.ts_context->pqueue = g_tree_new(compare_tracefile);
+  // Mathieu : fix : don't seek traceset here : causes inconsistency in seek
+  // closest. It's the tracecontext job to seek the trace to the beginning
+  // anyway : the init state might be used at the middle of the trace as well...
+  //g_tree_destroy(self->parent.ts_context->pqueue);
+  //self->parent.ts_context->pqueue = g_tree_new(compare_tracefile);
   
-  lttv_process_trace_seek_time(&self->parent, ltt_time_zero);
+  
+  //lttv_process_trace_seek_time(&self->parent, ltt_time_zero);
 
   nb_cpus = ltt_trace_get_num_cpu(self->parent.t);
   
@@ -467,7 +474,8 @@ static void state_save(LttvTraceState *self, LttvAttribute *container)
   value = lttv_attribute_add(container, LTTV_STATE_RUNNING_PROCESS, 
                              LTTV_POINTER);
   *(value.v_pointer) = running_process;
-
+  
+  g_info("State save");
   
   nb_tracefile = self->parent.tracefiles->len;
 
@@ -501,7 +509,7 @@ static void state_save(LttvTraceState *self, LttvAttribute *container)
       guint64 tsc;
       LttTracefile *tf;
       ltt_event_position_get(ep, &tf, &nb_block, &offset, &tsc);
-      g_debug("Block %u offset %u tsc %llu time %lu.%lu", nb_block, offset,
+      g_info("Block %u offset %u tsc %llu time %lu.%lu", nb_block, offset,
           tsc,
           tfcs->parent.timestamp.tv_sec, tfcs->parent.timestamp.tv_nsec);
     }
@@ -584,6 +592,7 @@ static void state_restore(LttvTraceState *self, LttvAttribute *container)
       tfc->timestamp = ltt_event_time(ltt_tracefile_get_event(tfc->tf));
       g_assert(ltt_time_compare(tfc->timestamp, ltt_time_infinite) != 0);
       g_tree_insert(tsc->pqueue, tfc, tfc);
+      g_info("Restoring state for a tf at time %lu.%lu", tfc->timestamp.tv_sec, tfc->timestamp.tv_nsec);
     } else {
       tfc->timestamp = ltt_time_infinite;
     }
@@ -623,7 +632,7 @@ static void state_saved_free(LttvTraceState *self, LttvAttribute *container)
 
   /* Free running processes array */
   nb_cpus = ltt_trace_get_num_cpu(self->parent.t);
-  type = lttv_attribute_get_by_name(tracefile_tree, LTTV_STATE_RUNNING_PROCESS, 
+  type = lttv_attribute_get_by_name(container, LTTV_STATE_RUNNING_PROCESS, 
         &value);
   g_assert(type == LTTV_POINTER);
   running_process = *(value.v_pointer);
@@ -878,6 +887,25 @@ free_name_tables(LttvTraceState *tcs)
   g_free(name_tables);
 } 
 
+#ifdef HASH_TABLE_DEBUG
+
+static void test_process(gpointer key, gpointer value, gpointer user_data)
+{
+  LttvProcessState *process = (LttvProcessState *)value;
+  
+  /* Test for process corruption */
+  guint stack_len = process->execution_stack->len;
+}
+
+static void hash_table_check(GHashTable *table)
+{
+  g_hash_table_foreach(table, test_process, NULL);
+}
+
+
+#endif
+
+
 static void push_state(LttvTracefileState *tfs, LttvExecutionMode t, 
     guint state_id)
 {
@@ -885,6 +913,10 @@ static void push_state(LttvTracefileState *tfs, LttvExecutionMode t,
   
   guint cpu = ltt_tracefile_num(tfs->parent.tf);
   LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
+
+#ifdef HASH_TABLE_DEBUG
+  hash_table_check(ts->processes);
+#endif
   LttvProcessState *process = ts->running_process[cpu];
 
   guint depth = process->execution_stack->len;
@@ -1206,6 +1238,7 @@ static gboolean process_fork(void *hook_data, void *call_data)
   guint cpu = ltt_tracefile_num(s->parent.tf);
   LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
   LttvProcessState *process = ts->running_process[cpu];
+  LttvProcessState *child_process;
 
   /* Parent PID */
   f = thf->f1;
@@ -1215,18 +1248,40 @@ static gboolean process_fork(void *hook_data, void *call_data)
   f = thf->f2;
   child_pid = ltt_event_get_unsigned(e, f);
 
+  /* Mathieu : it seems like the process might have been scheduled in before the
+   * fork, and, in a rare case, might be the current process. This might happen
+   * in a SMP case where we don't have enough precision on the clocks */
+#if 0
   zombie_process = lttv_state_find_process(ts, ANY_CPU, child_pid);
 
   if(unlikely(zombie_process != NULL)) {
     /* Reutilisation of PID. Only now we are sure that the old PID
      * has been released. FIXME : should know when release_task happens instead.
      */
+    guint num_cpus = ltt_trace_get_num_cpu(ts->parent.t);
+    guint i;
+    for(i=0; i< num_cpus; i++) {
+      g_assert(process != ts->running_process[i]);
+    }
+
     exit_process(s, zombie_process);
   }
+#endif //0
   g_assert(process->pid != child_pid);
   // FIXME : Add this test in the "known state" section
   // g_assert(process->pid == parent_pid);
-  lttv_state_create_process(ts, process, cpu, child_pid, &s->parent.timestamp);
+  child_process = lttv_state_find_process(ts, ANY_CPU, child_pid);
+  if(child_process == NULL) {
+    lttv_state_create_process(ts, process, cpu,
+                              child_pid, &s->parent.timestamp);
+  } else {
+    /* The process has already been created :  due to time imprecision between
+     * multiple CPUs : it has been scheduled in before creation.
+     *
+     * Simply put a correct parent.
+     */
+    child_process->ppid = process->pid;
+  }
 
   return FALSE;
 }
@@ -1265,18 +1320,47 @@ static gboolean process_free(void *hook_data, void *call_data)
 
   /* PID of the process to release */
   release_pid = ltt_event_get_unsigned(e, thf->f1);
+  
+  g_assert(release_pid != 0);
 
   process = lttv_state_find_process(ts, ANY_CPU, release_pid);
 
   if(likely(process != NULL)) {
     /* release_task is happening at kernel level : we can now safely release
      * the data structure of the process */
+    guint num_cpus = ltt_trace_get_num_cpu(ts->parent.t);
+    guint i;
+    for(i=0; i< num_cpus; i++) {
+      g_assert(process != ts->running_process[i]);
+    }
     exit_process(s, process);
   }
 
   return FALSE;
 }
 
+
+static gboolean process_exec(void *hook_data, void *call_data)
+{
+  LttvTracefileState *s = (LttvTracefileState *)call_data;
+  LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
+  LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
+  LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
+  gchar *name;
+  guint cpu = ltt_tracefile_num(s->parent.tf);
+  LttvProcessState *process = ts->running_process[cpu];
+
+  /* PID of the process to release */
+  name = ltt_event_get_string(e, thf->f1);
+
+  process->name = g_quark_from_string(name);
+
+  return FALSE;
+}
+
+
+
+
 gint lttv_state_hook_add_event_hooks(void *hook_data, void *call_data)
 {
   LttvTracesetState *tss = (LttvTracesetState*)(call_data);
@@ -1313,8 +1397,8 @@ void lttv_state_add_event_hooks(LttvTracesetState *self)
     /* Find the eventtype id for the following events and register the
        associated by id hooks. */
 
-    hooks = g_array_sized_new(FALSE, FALSE, sizeof(LttvTraceHook), 10);
-    hooks = g_array_set_size(hooks, 10);
+    hooks = g_array_sized_new(FALSE, FALSE, sizeof(LttvTraceHook), 11);
+    hooks = g_array_set_size(hooks, 11);
 
     ret = lttv_trace_find_hook(ts->parent.t,
         LTT_FACILITY_KERNEL, LTT_EVENT_SYSCALL_ENTRY,
@@ -1376,6 +1460,13 @@ void lttv_state_add_event_hooks(LttvTracesetState *self)
         process_free, NULL, &g_array_index(hooks, LttvTraceHook, 9));
     g_assert(!ret);
 
+    ret = lttv_trace_find_hook(ts->parent.t,
+        LTT_FACILITY_FS, LTT_EVENT_EXEC,
+        LTT_FIELD_FILENAME, 0, 0,
+        process_exec, NULL, &g_array_index(hooks, LttvTraceHook, 10));
+    g_assert(!ret);
+
+
 
     /* Add these hooks to each event_by_id hooks list */
 
@@ -1463,12 +1554,10 @@ void lttv_state_remove_event_hooks(LttvTracesetState *self)
   }
 }
 
-static guint test_event_count = 0;
 static gboolean state_save_event_hook(void *hook_data, void *call_data)
 {
   guint *event_count = (guint*)hook_data;
 
-  test_event_count++;
   /* Only save at LTTV_STATE_SAVE_INTERVAL */
   if(likely((*event_count)++ < LTTV_STATE_SAVE_INTERVAL))
     return FALSE;
@@ -1735,7 +1824,6 @@ void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
     }
     g_free(event_count);
   }
-  g_info("EVENT COUNT TEST : %u", test_event_count);
 }
 
 gint lttv_state_save_hook_remove_event_hooks(void *hook_data, void *call_data)
@@ -1755,6 +1843,8 @@ void lttv_state_traceset_seek_time_closest(LttvTracesetState *self, LttTime t)
 
   int min_pos, mid_pos, max_pos;
 
+  guint call_rest = 0;
+
   LttvTraceState *tcs;
 
   LttvAttributeValue value;
@@ -1768,6 +1858,8 @@ void lttv_state_traceset_seek_time_closest(LttvTracesetState *self, LttTime t)
   g_tree_destroy(self->parent.pqueue);
   self->parent.pqueue = g_tree_new(compare_tracefile);
   
+  g_info("Entering seek_time_closest for time %lu.%lu", t.tv_sec, t.tv_nsec);
+  
   nb_trace = lttv_traceset_number(traceset);
   for(i = 0 ; i < nb_trace ; i++) {
     tcs = (LttvTraceState *)self->parent.traces[i];
@@ -1800,6 +1892,7 @@ void lttv_state_traceset_seek_time_closest(LttvTracesetState *self, LttTime t)
       /* restore the closest earlier saved state */
       if(min_pos != -1) {
         lttv_state_restore(tcs, closest_tree);
+        call_rest = 1;
       }
 
       /* There is no saved state, yet we want to have it. Restart at T0 */
@@ -1814,6 +1907,7 @@ void lttv_state_traceset_seek_time_closest(LttvTracesetState *self, LttTime t)
       lttv_process_trace_seek_time(&(tcs->parent), t);
     }
   }
+  if(!call_rest) g_info("NOT Calling restore");
 }
 
 
@@ -2001,6 +2095,7 @@ static void module_init()
   
   LTT_FACILITY_KERNEL     = g_quark_from_string("kernel");
   LTT_FACILITY_PROCESS    = g_quark_from_string("process");
+  LTT_FACILITY_FS    = g_quark_from_string("fs");
 
   
   LTT_EVENT_SYSCALL_ENTRY = g_quark_from_string("syscall_entry");
@@ -2013,6 +2108,7 @@ static void module_init()
   LTT_EVENT_FORK          = g_quark_from_string("fork");
   LTT_EVENT_EXIT          = g_quark_from_string("exit");
   LTT_EVENT_FREE          = g_quark_from_string("free");
+  LTT_EVENT_EXEC          = g_quark_from_string("exec");
 
 
   LTT_FIELD_SYSCALL_ID    = g_quark_from_string("syscall_id");
@@ -2024,6 +2120,7 @@ static void module_init()
   LTT_FIELD_PARENT_PID    = g_quark_from_string("parent_pid");
   LTT_FIELD_CHILD_PID     = g_quark_from_string("child_pid");
   LTT_FIELD_PID           = g_quark_from_string("pid");
+  LTT_FIELD_FILENAME      = g_quark_from_string("filename");
   
 }
 
This page took 0.02677 seconds and 4 git commands to generate.