trying to introduce cumulative time
[lttv.git] / ltt / branches / poly / lttv / lttv / state.c
index a9d371a50924ff20237b4b75f3489673f1ef72fe..8e80c943f462d48a11370f36af8949ab82919aa9 100644 (file)
@@ -39,7 +39,8 @@ GQuark
     LTT_FACILITY_KERNEL_ARCH,
     LTT_FACILITY_PROCESS,
     LTT_FACILITY_FS,
-    LTT_FACILITY_STATEDUMP;
+    LTT_FACILITY_STATEDUMP,
+               LTT_FACILITY_USER_GENERIC;
 
 /* Events Quarks */
 
@@ -58,7 +59,9 @@ GQuark
     LTT_EVENT_EXIT,
     LTT_EVENT_FREE,
     LTT_EVENT_EXEC,
-    LTT_EVENT_ENUM_PROCESS_STATE;
+    LTT_EVENT_ENUM_PROCESS_STATE,
+               LTT_EVENT_FUNCTION_ENTRY,
+               LTT_EVENT_FUNCTION_EXIT;
 
 /* Fields Quarks */
 
@@ -77,7 +80,9 @@ GQuark
     LTT_FIELD_NAME,
     LTT_FIELD_MODE,
     LTT_FIELD_SUBMODE,
-    LTT_FIELD_STATUS;
+    LTT_FIELD_STATUS,
+               LTT_FIELD_THIS_FN,
+               LTT_FIELD_CALL_SITE;
 
 LttvExecutionMode
   LTTV_STATE_MODE_UNKNOWN,
@@ -496,6 +501,16 @@ static void copy_process_state(gpointer key, gpointer value,gpointer user_data)
   }
   new_process->state = &g_array_index(new_process->execution_stack, 
       LttvExecutionState, new_process->execution_stack->len - 1);
+  new_process->user_stack = g_array_sized_new(FALSE, FALSE, 
+      sizeof(guint64), 0);
+  new_process->user_stack = 
+              g_array_set_size(new_process->user_stack,
+                  process->user_stack->len);
+  for(i = 0 ; i < process->user_stack->len; i++) {
+    g_array_index(new_process->user_stack, guint64, i) =
+        g_array_index(process->user_stack, guint64, i);
+  }
+  new_process->current_function = process->current_function;
   g_hash_table_insert(new_processes, new_process, new_process);
 }
 
@@ -608,6 +623,8 @@ static void state_restore(LttvTraceState *self, LttvAttribute *container)
 
   LttvAttributeName name;
 
+       gboolean is_named;
+
   LttEventPosition *ep;
 
   LttvTracesetContext *tsc = self->parent.ts_context;
@@ -643,7 +660,7 @@ static void state_restore(LttvTraceState *self, LttvAttribute *container)
     tfcs = 
           LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
                                           LttvTracefileContext*, i));
-    type = lttv_attribute_get(tracefiles_tree, i, &name, &value);
+    type = lttv_attribute_get(tracefiles_tree, i, &name, &value, &is_named);
     g_assert(type == LTTV_GOBJECT);
     tracefile_tree = *((LttvAttribute **)(value.v_gobject));
 #if 0
@@ -692,6 +709,8 @@ static void state_saved_free(LttvTraceState *self, LttvAttribute *container)
 
   LttvAttributeName name;
 
+       gboolean is_named;
+
   LttEventPosition *ep;
 
   tracefiles_tree = lttv_attribute_find_subdir(container, 
@@ -720,7 +739,7 @@ static void state_saved_free(LttvTraceState *self, LttvAttribute *container)
     tfcs = 
           LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
                                           LttvTracefileContext*, i));
-    type = lttv_attribute_get(tracefiles_tree, i, &name, &value);
+    type = lttv_attribute_get(tracefiles_tree, i, &name, &value, &is_named);
     g_assert(type == LTTV_GOBJECT);
     tracefile_tree = *((LttvAttribute **)(value.v_gobject));
 
@@ -743,6 +762,8 @@ static void free_saved_state(LttvTraceState *self)
 
   LttvAttributeName name;
 
+       gboolean is_named;
+
   LttvAttribute *saved_states;
 
   saved_states = lttv_attribute_find_subdir(self->parent.t_a,
@@ -750,7 +771,7 @@ static void free_saved_state(LttvTraceState *self)
 
   nb = lttv_attribute_get_number(saved_states);
   for(i = 0 ; i < nb ; i++) {
-    type = lttv_attribute_get(saved_states, i, &name, &value);
+    type = lttv_attribute_get(saved_states, i, &name, &value, &is_named);
     g_assert(type == LTTV_GOBJECT);
     state_saved_free(self, *((LttvAttribute **)value.v_gobject));
   }
@@ -1024,10 +1045,33 @@ static void push_state(LttvTracefileState *tfs, LttvExecutionMode t,
   es->t = t;
   es->n = state_id;
   es->entry = es->change = tfs->parent.timestamp;
+       es->cum_cpu_time = ltt_time_zero;
   es->s = process->state->s;
   process->state = es;
 }
 
+/* pop state
+ * return 1 when empty, else 0 */
+int lttv_state_pop_state_cleanup(LttvProcessState *process, 
+               LttvTracefileState *tfs)
+{ 
+       guint cpu = tfs->cpu;
+  LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
+
+  guint depth = process->execution_stack->len;
+
+  if(depth == 1){
+    return 1;
+  }
+
+  process->execution_stack = 
+    g_array_set_size(process->execution_stack, depth - 1);
+  process->state = &g_array_index(process->execution_stack, LttvExecutionState,
+      depth - 2);
+  process->state->change = tfs->parent.timestamp;
+       
+       return 0;
+}
 
 static void pop_state(LttvTracefileState *tfs, LttvExecutionMode t)
 {
@@ -1091,6 +1135,7 @@ static gint search_usertrace(gconstpointer a, gconstpointer b)
                }
                return -1;
        }
+       return 0;
 }
 
 static LttvTracefileState *ltt_state_usertrace_find(LttvTraceState *tcs,
@@ -1134,6 +1179,7 @@ lttv_state_create_process(LttvTraceState *tcs, LttvProcessState *parent,
   //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
        process->kernel_thread = 0;
        process->usertrace = ltt_state_usertrace_find(tcs, pid, timestamp);
+       process->current_function = 0; //function 0x0 by default.
 
   g_info("Process %u, core %p", process->pid, process);
   g_hash_table_insert(tcs->processes, process, process);
@@ -1169,6 +1215,7 @@ lttv_state_create_process(LttvTraceState *tcs, LttvProcessState *parent,
   es->entry = *timestamp;
   //g_assert(timestamp->tv_sec != 0);
   es->change = *timestamp;
+       es->cum_cpu_time = ltt_time_zero;
   es->s = LTTV_STATE_RUN;
 
   es = process->state = &g_array_index(process->execution_stack, 
@@ -1178,8 +1225,13 @@ lttv_state_create_process(LttvTraceState *tcs, LttvProcessState *parent,
   es->entry = *timestamp;
   //g_assert(timestamp->tv_sec != 0);
   es->change = *timestamp;
+       es->cum_cpu_time = ltt_time_zero;
   es->s = LTTV_STATE_WAIT_FORK;
-
+       
+       /* Allocate an empty function call stack. If it's empty, use 0x0. */
+       process->user_stack = g_array_sized_new(FALSE, FALSE,
+                       sizeof(guint64), 0);
+       
   return process;
 }
 
@@ -1230,6 +1282,7 @@ static void exit_process(LttvTracefileState *tfs, LttvProcessState *process)
   key.cpu = process->cpu;
   g_hash_table_remove(ts->processes, &key);
   g_array_free(process->execution_stack, TRUE);
+  g_array_free(process->user_stack, TRUE);
   g_free(process);
 }
 
@@ -1237,6 +1290,7 @@ static void exit_process(LttvTracefileState *tfs, LttvProcessState *process)
 static void free_process_state(gpointer key, gpointer value,gpointer user_data)
 {
   g_array_free(((LttvProcessState *)value)->execution_stack, TRUE);
+  g_array_free(((LttvProcessState *)value)->user_stack, TRUE);
   g_free(value);
 }
 
@@ -1331,6 +1385,15 @@ static gboolean irq_entry(void *hook_data, void *call_data)
   return FALSE;
 }
 
+static gboolean soft_irq_exit(void *hook_data, void *call_data)
+{
+  LttvTracefileState *s = (LttvTracefileState *)call_data;
+
+  pop_state(s, LTTV_STATE_SOFT_IRQ);
+  return FALSE;
+}
+
+
 
 static gboolean irq_exit(void *hook_data, void *call_data)
 {
@@ -1362,15 +1425,88 @@ static gboolean soft_irq_entry(void *hook_data, void *call_data)
   return FALSE;
 }
 
+static void push_function(LttvTracefileState *tfs, guint64 funcptr)
+{
+  guint64 *new_func;
+  
+  LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
+  guint cpu = tfs->cpu;
+  LttvProcessState *process = ts->running_process[cpu];
+
+  guint depth = process->user_stack->len;
 
-static gboolean soft_irq_exit(void *hook_data, void *call_data)
+  process->user_stack = 
+    g_array_set_size(process->user_stack, depth + 1);
+    
+  new_func = &g_array_index(process->user_stack, guint64, depth);
+       *new_func = funcptr;
+  process->current_function = funcptr;
+}
+
+static void pop_function(LttvTracefileState *tfs, guint64 funcptr)
+{
+  guint cpu = tfs->cpu;
+  LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
+  LttvProcessState *process = ts->running_process[cpu];
+
+  if(process->current_function != funcptr){
+    g_info("Different functions (%lu.%09lu): ignore it\n",
+        tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
+    g_info("process state has %llu when pop_function is %llu\n",
+                   process->current_function, funcptr);
+    g_info("{ %u, %u, %s, %s }\n",
+                   process->pid,
+                   process->ppid,
+                   g_quark_to_string(process->name),
+                   g_quark_to_string(process->state->s));
+    return;
+  }
+  guint depth = process->user_stack->len;
+
+  if(depth == 0){
+    g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
+        tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
+    return;
+  }
+
+  process->user_stack = 
+    g_array_set_size(process->user_stack, depth - 1);
+  process->current_function =
+               g_array_index(process->user_stack, guint64, depth - 2);
+}
+
+
+static gboolean function_entry(void *hook_data, void *call_data)
 {
   LttvTracefileState *s = (LttvTracefileState *)call_data;
+  LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
+  guint8 fac_id = ltt_event_facility_id(e);
+  guint8 ev_id = ltt_event_eventtype_id(e);
+  LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
+  g_assert(thf->f1 != NULL);
+  LttField *f = thf->f1;
+       guint64 funcptr = ltt_event_get_long_unsigned(e, f);
 
-  pop_state(s, LTTV_STATE_SOFT_IRQ);
+  push_function(s, funcptr);
   return FALSE;
 }
 
+static gboolean function_exit(void *hook_data, void *call_data)
+{
+  LttvTracefileState *s = (LttvTracefileState *)call_data;
+  LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
+  guint8 fac_id = ltt_event_facility_id(e);
+  guint8 ev_id = ltt_event_eventtype_id(e);
+  LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
+  g_assert(thf->f1 != NULL);
+  LttField *f = thf->f1;
+       guint64 funcptr = ltt_event_get_long_unsigned(e, f);
+
+  LttvExecutionSubmode submode;
+
+  pop_function(s, funcptr);
+  return FALSE;
+}
 
 static gboolean schedchange(void *hook_data, void *call_data)
 {
@@ -1730,6 +1866,7 @@ void lttv_state_add_event_hooks(LttvTracesetState *self)
   LttvAttributeValue val;
 
   gint ret;
+       gint hn;
 
   nb_trace = lttv_traceset_number(traceset);
   for(i = 0 ; i < nb_trace ; i++) {
@@ -1738,101 +1875,116 @@ 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), 15);
-    hooks = g_array_set_size(hooks, 15);
+    hooks = g_array_sized_new(FALSE, FALSE, sizeof(LttvTraceHook), 17);
+    hooks = g_array_set_size(hooks, 17); // Max possible number of hooks.
+               hn = 0;
 
     ret = lttv_trace_find_hook(ts->parent.t,
         LTT_FACILITY_KERNEL_ARCH, LTT_EVENT_SYSCALL_ENTRY,
         LTT_FIELD_SYSCALL_ID, 0, 0,
-        syscall_entry, NULL, &g_array_index(hooks, LttvTraceHook, 0));
-    g_assert(!ret);
+        syscall_entry, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
+               if(ret) hn--;
 
     ret = lttv_trace_find_hook(ts->parent.t,
         LTT_FACILITY_KERNEL_ARCH, LTT_EVENT_SYSCALL_EXIT,
         0, 0, 0,
-        syscall_exit, NULL, &g_array_index(hooks, LttvTraceHook, 1));
-    g_assert(!ret);
+        syscall_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
+               if(ret) hn--;
 
     ret = lttv_trace_find_hook(ts->parent.t,
         LTT_FACILITY_KERNEL, LTT_EVENT_TRAP_ENTRY,
         LTT_FIELD_TRAP_ID, 0, 0,
-        trap_entry, NULL, &g_array_index(hooks, LttvTraceHook, 2));
-    g_assert(!ret);
+        trap_entry, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
+               if(ret) hn--;
 
     ret = lttv_trace_find_hook(ts->parent.t,
         LTT_FACILITY_KERNEL, LTT_EVENT_TRAP_EXIT,
         0, 0, 0, 
-        trap_exit, NULL, &g_array_index(hooks, LttvTraceHook, 3));
-    g_assert(!ret);
+        trap_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
+               if(ret) hn--;
 
     ret = lttv_trace_find_hook(ts->parent.t,
         LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_ENTRY,
         LTT_FIELD_IRQ_ID, 0, 0,
-        irq_entry, NULL, &g_array_index(hooks, LttvTraceHook, 4));
-    g_assert(!ret);
+        irq_entry, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
+               if(ret) hn--;
 
     ret = lttv_trace_find_hook(ts->parent.t,
         LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_EXIT,
         0, 0, 0, 
-        irq_exit, NULL, &g_array_index(hooks, LttvTraceHook, 5));
-    g_assert(!ret);
+        irq_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
+               if(ret) hn--;
 
     ret = lttv_trace_find_hook(ts->parent.t,
         LTT_FACILITY_KERNEL, LTT_EVENT_SOFT_IRQ_ENTRY,
         LTT_FIELD_SOFT_IRQ_ID, 0, 0,
-        soft_irq_entry, NULL, &g_array_index(hooks, LttvTraceHook, 6));
-    g_assert(!ret);
+        soft_irq_entry, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
+               if(ret) hn--;
 
     ret = lttv_trace_find_hook(ts->parent.t,
         LTT_FACILITY_KERNEL, LTT_EVENT_SOFT_IRQ_EXIT,
         0, 0, 0, 
-        soft_irq_exit, NULL, &g_array_index(hooks, LttvTraceHook, 7));
-    g_assert(!ret);
+        soft_irq_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
+               if(ret) hn--;
 
     ret = lttv_trace_find_hook(ts->parent.t,
         LTT_FACILITY_PROCESS, LTT_EVENT_SCHEDCHANGE,
         LTT_FIELD_OUT, LTT_FIELD_IN, LTT_FIELD_OUT_STATE,
-        schedchange, NULL, &g_array_index(hooks, LttvTraceHook, 8));
-    g_assert(!ret);
+        schedchange, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
+               if(ret) hn--;
 
     ret = lttv_trace_find_hook(ts->parent.t,
         LTT_FACILITY_PROCESS, LTT_EVENT_FORK,
         LTT_FIELD_PARENT_PID, LTT_FIELD_CHILD_PID, 0,
-        process_fork, NULL, &g_array_index(hooks, LttvTraceHook, 9));
-    g_assert(!ret);
+        process_fork, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
+               if(ret) hn--;
 
     ret = lttv_trace_find_hook(ts->parent.t,
         LTT_FACILITY_PROCESS, LTT_EVENT_KERNEL_THREAD,
         LTT_FIELD_PID, 0, 0,
-        process_kernel_thread, NULL, &g_array_index(hooks, LttvTraceHook, 10));
-    g_assert(!ret);
+        process_kernel_thread, NULL, &g_array_index(hooks, LttvTraceHook,
+                                       hn++));
+               if(ret) hn--;
 
     ret = lttv_trace_find_hook(ts->parent.t,
         LTT_FACILITY_PROCESS, LTT_EVENT_EXIT,
         LTT_FIELD_PID, 0, 0,
-        process_exit, NULL, &g_array_index(hooks, LttvTraceHook, 11));
-    g_assert(!ret);
+        process_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
+               if(ret) hn--;
     
     ret = lttv_trace_find_hook(ts->parent.t,
         LTT_FACILITY_PROCESS, LTT_EVENT_FREE,
         LTT_FIELD_PID, 0, 0,
-        process_free, NULL, &g_array_index(hooks, LttvTraceHook, 12));
-    g_assert(!ret);
+        process_free, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
+               if(ret) hn--;
 
     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, 13));
-    g_assert(!ret);
+        process_exec, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
+               if(ret) hn--;
 
      /* statedump-related hooks */
     ret = lttv_trace_find_hook(ts->parent.t,
         LTT_FACILITY_STATEDUMP, LTT_EVENT_ENUM_PROCESS_STATE,
         LTT_FIELD_PID, LTT_FIELD_PARENT_PID, LTT_FIELD_NAME,
-        enum_process_state, NULL, &g_array_index(hooks, LttvTraceHook, 14));
-    g_assert(!ret);
+        enum_process_state, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
+               if(ret) hn--;
 
-    
+    ret = lttv_trace_find_hook(ts->parent.t,
+        LTT_FACILITY_USER_GENERIC, LTT_EVENT_FUNCTION_ENTRY,
+        LTT_FIELD_THIS_FN, LTT_FIELD_CALL_SITE, 0,
+        function_entry, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
+               if(ret) hn--;
+
+    ret = lttv_trace_find_hook(ts->parent.t,
+        LTT_FACILITY_USER_GENERIC, LTT_EVENT_FUNCTION_EXIT,
+        LTT_FIELD_THIS_FN, LTT_FIELD_CALL_SITE, 0,
+        function_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
+               if(ret) hn--;
+
+    hooks = g_array_set_size(hooks, hn);
+  
     /* Add these hooks to each event_by_id hooks list */
 
     nb_tracefile = ts->parent.tracefiles->len;
@@ -2249,6 +2401,8 @@ void lttv_state_traceset_seek_time_closest(LttvTracesetState *self, LttTime t)
 
   LttvAttributeName name;
 
+       gboolean is_named;
+
   LttvAttribute *saved_states_tree, *saved_state_tree, *closest_tree;
 
   //g_tree_destroy(self->parent.pqueue);
@@ -2269,7 +2423,8 @@ void lttv_state_traceset_seek_time_closest(LttvTracesetState *self, LttTime t)
         max_pos = lttv_attribute_get_number(saved_states_tree) - 1;
         mid_pos = max_pos / 2;
         while(min_pos < max_pos) {
-          type = lttv_attribute_get(saved_states_tree, mid_pos, &name, &value);
+          type = lttv_attribute_get(saved_states_tree, mid_pos, &name, &value,
+                                                       &is_named);
           g_assert(type == LTTV_GOBJECT);
           saved_state_tree = *((LttvAttribute **)(value.v_gobject));
           type = lttv_attribute_get_by_name(saved_state_tree, LTTV_STATE_TIME, 
@@ -2496,6 +2651,7 @@ static void module_init()
   LTT_FACILITY_PROCESS    = g_quark_from_string("process");
   LTT_FACILITY_FS    = g_quark_from_string("fs");
   LTT_FACILITY_STATEDUMP    = g_quark_from_string("statedump");
+  LTT_FACILITY_USER_GENERIC    = g_quark_from_string("user_generic");
 
   
   LTT_EVENT_SYSCALL_ENTRY = g_quark_from_string("syscall_entry");
@@ -2513,6 +2669,8 @@ static void module_init()
   LTT_EVENT_FREE          = g_quark_from_string("free");
   LTT_EVENT_EXEC          = g_quark_from_string("exec");
   LTT_EVENT_ENUM_PROCESS_STATE  = g_quark_from_string("enumerate_process_state");
+  LTT_EVENT_FUNCTION_ENTRY  = g_quark_from_string("function_entry");
+  LTT_EVENT_FUNCTION_EXIT  = g_quark_from_string("function_exit");
 
 
   LTT_FIELD_SYSCALL_ID    = g_quark_from_string("syscall_id");
@@ -2530,6 +2688,8 @@ static void module_init()
   LTT_FIELD_MODE          = g_quark_from_string("mode");
   LTT_FIELD_SUBMODE       = g_quark_from_string("submode");
   LTT_FIELD_STATUS        = g_quark_from_string("status");
+  LTT_FIELD_THIS_FN       = g_quark_from_string("this_fn");
+  LTT_FIELD_CALL_SITE     = g_quark_from_string("call_site");
   
 }
 
This page took 0.044871 seconds and 4 git commands to generate.