draw closure in cfv optimisation
[lttv.git] / ltt / branches / poly / lttv / lttv / state.c
index d8cbe8c63c2c4a83f1e018981e231bc2ce66a649..d60b4588a3d3f428ac39c8d3951e5129d598710b 100644 (file)
@@ -26,6 +26,8 @@
 #include <ltt/type.h>
 #include <stdio.h>
 
+#define PREALLOCATED_EXECUTION_STACK 10
+
 LttvExecutionMode
   LTTV_STATE_MODE_UNKNOWN,
   LTTV_STATE_USER_MODE,
@@ -42,6 +44,7 @@ LttvProcessStatus
   LTTV_STATE_WAIT_FORK,
   LTTV_STATE_WAIT_CPU,
   LTTV_STATE_EXIT,
+  LTTV_STATE_ZOMBIE,
   LTTV_STATE_WAIT,
   LTTV_STATE_RUN;
 
@@ -96,16 +99,17 @@ void lttv_state_state_saved_free(LttvTraceState *self,
 
 guint process_hash(gconstpointer key) 
 {
-  return ((LttvProcessState *)key)->pid;
+  guint pid = ((const LttvProcessState *)key)->pid;
+  return (pid>>8 ^ pid>>4 ^ pid>>2 ^ pid) ;
 }
 
 
 gboolean process_equal(gconstpointer a, gconstpointer b)
 {
-  LttvProcessState *process_a, *process_b;
+  const LttvProcessState *process_a, *process_b;
 
-  process_a = (LttvProcessState *)a;
-  process_b = (LttvProcessState *)b;
+  process_a = (const LttvProcessState *)a;
+  process_b = (const LttvProcessState *)b;
 
   if(process_a->pid != process_b->pid) return FALSE;
   if(process_a->pid == 0 && 
@@ -121,8 +125,6 @@ restore_init_state(LttvTraceState *self)
 
   LttvTracefileState *tfcs;
   
-  LttTime null_time = {0,0};
-
   if(self->processes != NULL) lttv_state_free_process_table(self->processes);
   self->processes = g_hash_table_new(process_hash, process_equal);
   self->nb_event = 0;
@@ -132,11 +134,12 @@ restore_init_state(LttvTraceState *self)
 
   for(i = 0 ; i < nb_tracefile ; i++) {
     tfcs = LTTV_TRACEFILE_STATE(self->parent.tracefiles[i]);
-    tfcs->parent.timestamp = null_time;
+    ltt_trace_time_span_get(self->parent.t, &tfcs->parent.timestamp, NULL);
     tfcs->saved_position = 0;
     tfcs->process = lttv_state_create_process(tfcs, NULL,0);
     tfcs->process->state->s = LTTV_STATE_RUN;
     tfcs->process->last_cpu = tfcs->cpu_name;
+    tfcs->process->last_cpu_index = ((LttvTracefileContext*)tfcs)->index;
   }
 }
 
@@ -190,7 +193,7 @@ init(LttvTracesetState *self, LttvTraceset *ts)
 static void
 fini(LttvTracesetState *self)
 {
-  guint i, j, nb_trace;
+  guint i, nb_trace;
 
   LttvTraceState *tcs;
 
@@ -203,9 +206,10 @@ fini(LttvTracesetState *self)
     tcs = (LttvTraceState *)(LTTV_TRACESET_CONTEXT(self)->traces[i]);
     lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_TRACE_STATE_USE_COUNT, 
         LTTV_UINT, &v);
+
+    g_assert(*(v.v_uint) != 0);
     (*v.v_uint)--;
 
-    g_assert(*(v.v_uint) >= 0);
     if(*(v.v_uint) == 0) {
       free_name_tables(tcs);
       free_max_time(tcs);
@@ -321,8 +325,8 @@ static void copy_process_state(gpointer key, gpointer value,gpointer user_data)
   process = (LttvProcessState *)value;
   new_process = g_new(LttvProcessState, 1);
   *new_process = *process;
-  new_process->execution_stack = g_array_new(FALSE, FALSE, 
-      sizeof(LttvExecutionState));
+  new_process->execution_stack = g_array_sized_new(FALSE, FALSE, 
+      sizeof(LttvExecutionState), PREALLOCATED_EXECUTION_STACK);
   g_array_set_size(new_process->execution_stack,process->execution_stack->len);
   for(i = 0 ; i < process->execution_stack->len; i++) {
     g_array_index(new_process->execution_stack, LttvExecutionState, i) =
@@ -448,7 +452,8 @@ static void state_restore(LttvTraceState *self, LttvAttribute *container)
     if(*(value.v_pointer) == NULL) tfcs->parent.e = NULL;
     else {
       ep = *(value.v_pointer);
-      lttv_process_tracefile_seek_position(tfcs->parent, ep);
+      g_assert(tfcs->parent.t_context != NULL);
+      lttv_process_tracefile_seek_position(LTTV_TRACEFILE_CONTEXT(tfcs), ep);
     }
   }
 }
@@ -730,7 +735,7 @@ static void pop_state(LttvTracefileState *tfs, LttvExecutionMode t)
   guint depth = process->execution_stack->len;
 
   if(process->state->t != t){
-    g_info("Different execution mode type (%d.%09d): ignore it\n",
+    g_info("Different execution mode type (%lu.%09lu): ignore it\n",
         tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
     g_info("process state has %s when pop_int is %s\n",
                    g_quark_to_string(process->state->t),
@@ -744,7 +749,7 @@ static void pop_state(LttvTracefileState *tfs, LttvExecutionMode t)
   }
 
   if(depth == 1){
-    g_info("Trying to pop last state on stack (%d.%09d): ignore it\n",
+    g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
         tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
     return;
   }
@@ -775,6 +780,7 @@ lttv_state_create_process(LttvTracefileState *tfs, LttvProcessState *parent,
        
   process->pid = pid;
   process->last_cpu = tfs->cpu_name;
+  process->last_cpu_index = ((LttvTracefileContext*)tfs)->index;
   g_warning("Process %u, core %p", process->pid, process);
   g_hash_table_insert(tcs->processes, process, process);
 
@@ -799,42 +805,36 @@ lttv_state_create_process(LttvTracefileState *tfs, LttvProcessState *parent,
          process->creation_time.tv_nsec);
   process->pid_time = g_quark_from_string(buffer);
   process->last_cpu = tfs->cpu_name;
-  process->execution_stack = g_array_new(FALSE, FALSE, 
-      sizeof(LttvExecutionState));
+  process->last_cpu_index = ((LttvTracefileContext*)tfs)->index;
+  process->execution_stack = g_array_sized_new(FALSE, FALSE, 
+      sizeof(LttvExecutionState), PREALLOCATED_EXECUTION_STACK);
   g_array_set_size(process->execution_stack, 1);
   es = process->state = &g_array_index(process->execution_stack, 
       LttvExecutionState, 0);
   es->t = LTTV_STATE_USER_MODE;
   es->n = LTTV_STATE_SUBMODE_NONE;
   es->entry = tfs->parent.timestamp;
+  g_assert(tfs->parent.timestamp.tv_sec != 0);
   es->change = tfs->parent.timestamp;
   es->s = LTTV_STATE_WAIT_FORK;
 
   return process;
 }
 
-
-LttvProcessState *
-lttv_state_find_process_from_trace(LttvTraceState *ts, GQuark cpu, guint pid)
+LttvProcessState *lttv_state_find_process(LttvTracefileState *tfs, 
+    guint pid)
 {
   LttvProcessState key;
   LttvProcessState *process;
 
+  LttvTraceState* ts = (LttvTraceState*)tfs->parent.t_context;
+
   key.pid = pid;
-  key.last_cpu = cpu;
+  key.last_cpu = tfs->cpu_name;
   process = g_hash_table_lookup(ts->processes, &key);
   return process;
 }
 
-
-LttvProcessState *lttv_state_find_process(LttvTracefileState *tfs, 
-    guint pid)
-{
-  LttvTraceState *ts =(LttvTraceState *)tfs->parent.t_context;
-  return lttv_state_find_process_from_trace(ts, tfs->cpu_name, pid);
-}
-
-
 LttvProcessState *
 lttv_state_find_process_or_create(LttvTracefileState *tfs, guint pid)
 {
@@ -844,7 +844,13 @@ lttv_state_find_process_or_create(LttvTracefileState *tfs, guint pid)
   return process;
 }
 
-
+/* FIXME : this function should be called when we receive an event telling that
+ * release_task has been called in the kernel. In happens generally when
+ * the parent waits for its child terminaison, but may also happen in special
+ * cases in the child's exit : when the parent ignores its children SIGCCHLD or
+ * has the flag SA_NOCLDWAIT. It can also happen when the child is part
+ * of a killed thread ground, but isn't the leader.
+ */
 static void exit_process(LttvTracefileState *tfs, LttvProcessState *process) 
 {
   LttvTraceState *ts = LTTV_TRACE_STATE(tfs->parent.t_context);
@@ -970,45 +976,89 @@ static gboolean schedchange(void *hook_data, void *call_data)
       g_assert(s->process->pid == 0);
     }
 
-    if(state_out == 0) s->process->state->s = LTTV_STATE_WAIT_CPU;
-    else if(s->process->state->s == LTTV_STATE_EXIT) 
-        exit_process(s, s->process);
-    else s->process->state->s = LTTV_STATE_WAIT;
+    if(s->process->state->s == LTTV_STATE_EXIT) {
+      s->process->state->s = LTTV_STATE_ZOMBIE;
+    } else {
+      if(state_out == 0) s->process->state->s = LTTV_STATE_WAIT_CPU;
+      else s->process->state->s = LTTV_STATE_WAIT;
+    } /* FIXME : we do not remove process here, because the kernel
+       * still has them : they may be zombies. We need to know
+       * exactly when release_task is executed on the PID to 
+       * know when the zombie is destroyed.
+       */
+    //else
+    //  exit_process(s, s->process);
 
     s->process->state->change = s->parent.timestamp;
   }
   s->process = lttv_state_find_process_or_create(s, pid_in);
   s->process->state->s = LTTV_STATE_RUN;
   s->process->last_cpu = s->cpu_name;
+  s->process->last_cpu_index = ((LttvTracefileContext*)s)->index;
   s->process->state->change = s->parent.timestamp;
   return FALSE;
 }
 
 
-static gboolean process_fork(void *hook_data, void *call_data)
+static gboolean process_fork(LttvTraceHook *trace_hook, LttvTracefileState *s)
 {
-  LttField *f = ((LttvTraceHook *)hook_data)->f1;
-
-  LttvTracefileState *s = (LttvTracefileState *)call_data;
-
+  LttField *f;
   guint child_pid;
+  LttvProcessState *zombie_process;
 
+  /* Child PID */
+  f = trace_hook->f2;
   child_pid = ltt_event_get_unsigned(s->parent.e, f);
+
+  zombie_process = lttv_state_find_process(s, child_pid);
+
+  if(zombie_process != NULL) {
+    /* Reutilisation of PID. Only now we are sure that the old PID
+     * has been released. FIXME : sould know when release_task happens instead.
+     */
+    exit_process(s, zombie_process);
+  }
+  g_assert(s->process->pid != child_pid);
   lttv_state_create_process(s, s->process, child_pid);
+
   return FALSE;
 }
 
 
-static gboolean process_exit(void *hook_data, void *call_data)
+static gboolean process_exit(LttvTraceHook *trace_hook, LttvTracefileState *s)
 {
-  LttvTracefileState *s = (LttvTracefileState *)call_data;
-
   if(s->process != NULL) {
     s->process->state->s = LTTV_STATE_EXIT;
   }
   return FALSE;
 }
 
+gboolean process(void *hook_data, void *call_data)
+{
+  LttvTraceHook *trace_hook = (LttvTraceHook *)hook_data;
+  LttField *f = trace_hook->f1;
+
+  LttvTracefileState *s = (LttvTracefileState *)call_data;
+  
+  guint sub_id = ltt_event_get_unsigned(s->parent.e, f);
+
+  /* CHECK : do not hardcode the sub_id values here ? */
+  if(sub_id == 2) {
+    return process_fork(trace_hook, s);
+  } else if(sub_id == 3) {
+    return process_exit(trace_hook, s);
+  }
+  return 0;
+}
+
+gint lttv_state_hook_add_event_hooks(void *hook_data, void *call_data)
+{
+  LttvTracesetState *tss = (LttvTracesetState*)(call_data);
+
+  lttv_state_add_event_hooks(tss);
+
+  return 0;
+}
 
 void lttv_state_add_event_hooks(LttvTracesetState *self)
 {
@@ -1034,7 +1084,7 @@ void lttv_state_add_event_hooks(LttvTracesetState *self)
        associated by id hooks. */
 
     hooks = g_array_new(FALSE, FALSE, sizeof(LttvTraceHook));
-    g_array_set_size(hooks, 9);
+    g_array_set_size(hooks, 8);
 
     lttv_trace_find_hook(ts->parent.t, "core","syscall_entry","syscall_id", 
        NULL, NULL, syscall_entry, &g_array_index(hooks, LttvTraceHook, 0));
@@ -1057,12 +1107,17 @@ void lttv_state_add_event_hooks(LttvTracesetState *self)
     lttv_trace_find_hook(ts->parent.t, "core", "schedchange", "in", "out", 
         "out_state", schedchange, &g_array_index(hooks, LttvTraceHook, 6));
 
+    lttv_trace_find_hook(ts->parent.t, "core", "process", "event_sub_id", 
+        "event_data1", "event_data2", process,
+        &g_array_index(hooks, LttvTraceHook, 7));
+
+#if 0
     lttv_trace_find_hook(ts->parent.t, "core", "process_fork", "child_pid", 
         NULL, NULL, process_fork, &g_array_index(hooks, LttvTraceHook, 7));
 
     lttv_trace_find_hook(ts->parent.t, "core", "process_exit", NULL, NULL, 
         NULL, process_exit, &g_array_index(hooks, LttvTraceHook, 8));
-
+#endif //0
     /* Add these hooks to each event_by_id hooks list */
 
     nb_tracefile = ltt_trace_control_tracefile_number(ts->parent.t) +
@@ -1082,6 +1137,14 @@ void lttv_state_add_event_hooks(LttvTracesetState *self)
   }
 }
 
+gint lttv_state_hook_remove_event_hooks(void *hook_data, void *call_data)
+{
+  LttvTracesetState *tss = (LttvTracesetState*)(call_data);
+
+  lttv_state_remove_event_hooks(tss);
+
+  return 0;
+}
 
 void lttv_state_remove_event_hooks(LttvTracesetState *self)
 {
@@ -1197,6 +1260,8 @@ static gboolean block_end(void *hook_data, void *call_data)
   self->saved_position = 0;
   *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
   g_free(ep);
+
+  return FALSE;
 }
 
 
@@ -1204,7 +1269,7 @@ void lttv_state_save_add_event_hooks(LttvTracesetState *self)
 {
   LttvTraceset *traceset = self->parent.ts;
 
-  guint i, j, k, nb_trace, nb_tracefile;
+  guint i, j, nb_trace, nb_tracefile;
 
   LttvTraceState *ts;
 
@@ -1233,12 +1298,21 @@ void lttv_state_save_add_event_hooks(LttvTracesetState *self)
   }
 }
 
+gint lttv_state_save_hook_add_event_hooks(void *hook_data, void *call_data)
+{
+  LttvTracesetState *tss = (LttvTracesetState*)(call_data);
+
+  lttv_state_save_add_event_hooks(tss);
+
+  return 0;
+}
+
 
 void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
 {
   LttvTraceset *traceset = self->parent.ts;
 
-  guint i, j, k, nb_trace, nb_tracefile;
+  guint i, j, nb_trace, nb_tracefile;
 
   LttvTraceState *ts;
 
@@ -1268,12 +1342,20 @@ void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
   }
 }
 
+gint lttv_state_save_hook_remove_event_hooks(void *hook_data, void *call_data)
+{
+  LttvTracesetState *tss = (LttvTracesetState*)(call_data);
+
+  lttv_state_save_remove_event_hooks(tss);
+
+  return 0;
+}
 
 void lttv_state_traceset_seek_time_closest(LttvTracesetState *self, LttTime t)
 {
   LttvTraceset *traceset = self->parent.ts;
 
-  guint i, j, nb_trace, nb_saved_state;
+  guint i, nb_trace;
 
   int min_pos, mid_pos, max_pos;
 
@@ -1378,7 +1460,8 @@ lttv_traceset_state_get_type(void)
       NULL,   /* class_data */
       sizeof (LttvTracesetState),
       0,      /* n_preallocs */
-      (GInstanceInitFunc) traceset_state_instance_init    /* instance_init */
+      (GInstanceInitFunc) traceset_state_instance_init,    /* instance_init */
+      NULL    /* value handling */
     };
 
     type = g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE, "LttvTracesetStateType", 
@@ -1428,7 +1511,8 @@ lttv_trace_state_get_type(void)
       NULL,   /* class_data */
       sizeof (LttvTraceState),
       0,      /* n_preallocs */
-      (GInstanceInitFunc) trace_state_instance_init    /* instance_init */
+      (GInstanceInitFunc) trace_state_instance_init,    /* instance_init */
+      NULL    /* value handling */
     };
 
     type = g_type_register_static (LTTV_TRACE_CONTEXT_TYPE, 
@@ -1475,7 +1559,8 @@ lttv_tracefile_state_get_type(void)
       NULL,   /* class_data */
       sizeof (LttvTracefileState),
       0,      /* n_preallocs */
-      (GInstanceInitFunc) tracefile_state_instance_init    /* instance_init */
+      (GInstanceInitFunc) tracefile_state_instance_init,    /* instance_init */
+      NULL    /* value handling */
     };
 
     type = g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE, 
@@ -1498,6 +1583,7 @@ static void module_init()
   LTTV_STATE_SUBMODE_NONE = g_quark_from_string("(no submode)");
   LTTV_STATE_WAIT_CPU = g_quark_from_string("wait for cpu");
   LTTV_STATE_EXIT = g_quark_from_string("exiting");
+  LTTV_STATE_ZOMBIE = g_quark_from_string("zombie");
   LTTV_STATE_WAIT = g_quark_from_string("wait for I/O");
   LTTV_STATE_RUN = g_quark_from_string("running");
   LTTV_STATE_TRACEFILES = g_quark_from_string("tracefiles");
This page took 0.028624 seconds and 4 git commands to generate.