precomputed states almost ok, needs testing
[lttv.git] / ltt / branches / poly / lttv / lttv / state.c
index 85a50e80972cbea841bec0d860048022c1f2bd6d..914ab728b86cc032185a0d4464568b933a0fc03d 100644 (file)
 #include <stdio.h>
 #include <string.h>
 
+/* Comment :
+ * Mathieu Desnoyers
+ * usertrace is there only to be able to update the current CPU of the
+ * usertraces when there is a schedchange. it is a way to link the ProcessState
+ * to the associated usertrace. Link only created upon thread creation.
+ *
+ * The cpu id is necessary : it gives us back the current ProcessState when we
+ * are considering data from the usertrace.
+ */
+
 #define PREALLOCATED_EXECUTION_STACK 10
 
 /* Facilities Quarks */
@@ -143,6 +153,8 @@ static void free_saved_state(LttvTraceState *tcs);
 
 static void lttv_state_free_process_table(GHashTable *processes);
 
+static void lttv_trace_states_read_raw(LttvTraceState *tcs, FILE *fp,
+                       GPtrArray *quarktable);
 
 void lttv_state_save(LttvTraceState *self, LttvAttribute *container)
 {
@@ -231,8 +243,18 @@ restore_init_state(LttvTraceState *self)
   
   /* Put the per cpu running_process to beginning state : process 0. */
   for(i=0; i< nb_cpus; i++) {
+    LttvExecutionState *es;
     self->running_process[i] = lttv_state_create_process(self, NULL, i, 0, 0,
         LTTV_STATE_UNNAMED, &start_time);
+    /* We are not sure is it's a kernel thread or normal thread, put the
+      * bottom stack state to unknown */
+    self->running_process[i]->execution_stack = 
+      g_array_set_size(self->running_process[i]->execution_stack, 1);
+    es = self->running_process[i]->state =
+      &g_array_index(self->running_process[i]->execution_stack,
+        LttvExecutionState, 0);
+    es->t = LTTV_STATE_MODE_UNKNOWN;
+
     self->running_process[i]->state->s = LTTV_STATE_RUN;
     self->running_process[i]->cpu = i;
   }
@@ -270,6 +292,82 @@ static void free_usertrace_key(gpointer data)
   g_free(data);
 }
 
+#define MAX_STRING_LEN 4096
+
+static void
+state_load_saved_states(LttvTraceState *tcs)
+{
+  FILE *fp;
+  GPtrArray *quarktable;
+  char *trace_path;
+  char path[PATH_MAX];
+  guint count;
+  guint i;
+  tcs->has_precomputed_states = FALSE;
+  GQuark q;
+  gchar *string;
+  gint hdr;
+  gchar buf[MAX_STRING_LEN];
+  guint len;
+
+  trace_path = g_quark_to_string(ltt_trace_name(tcs->parent.t));
+  strncpy(path, trace_path, PATH_MAX-1);
+  count = strnlen(trace_path, PATH_MAX-1);
+  // quarktable : open, test
+  strncat(path, "/precomputed/quarktable", PATH_MAX-count-1);
+  fp = fopen(path, "r");
+  if(!fp) return;
+  quarktable = g_ptr_array_sized_new(4096);
+  
+  /* Index 0 is null */
+  hdr = fgetc(fp);
+  if(hdr == EOF) return;
+  g_assert(hdr == HDR_QUARKS);
+  q = 1;
+  do {
+    hdr = fgetc(fp);
+    if(hdr == EOF) break;
+    g_assert(hdr == HDR_QUARK);
+    g_ptr_array_set_size(quarktable, q+1);
+    i=0;
+    while(1) {
+      fread(&buf[i], sizeof(gchar), 1, fp);
+      if(buf[i] == '\0' || feof(fp)) break;
+      i++;
+    }
+    len = strnlen(buf, MAX_STRING_LEN-1);
+    g_ptr_array_index (quarktable, q) = g_new(gchar, len+1);
+    strncpy(g_ptr_array_index (quarktable, q), buf, len+1);
+    q++;
+  } while(1);
+
+  fclose(fp);
+  // saved_states : open, test
+  strncpy(path, trace_path, PATH_MAX-1);
+  count = strnlen(trace_path, PATH_MAX-1);
+  strncat(path, "/precomputed/states", PATH_MAX-count-1);
+  fp = fopen(path, "r");
+  if(!fp) return;
+
+  hdr = fgetc(fp);
+  if(hdr != HDR_TRACE) goto end;
+
+  lttv_trace_states_read_raw(tcs, fp, quarktable);
+
+  tcs->has_precomputed_states = TRUE;
+
+end:
+  fclose(fp);
+
+  /* Free the quarktable */
+  for(i=0; i<quarktable->len; i++) {
+    string = g_ptr_array_index (quarktable, i);
+    g_free(string);
+  }
+  g_ptr_array_free(quarktable, TRUE);
+  return;
+}
+
 static void
 init(LttvTracesetState *self, LttvTraceset *ts)
 {
@@ -314,21 +412,6 @@ init(LttvTracesetState *self, LttvTraceset *ts)
                                           LttvTracefileContext*, j));
       tfcs->tracefile_name = ltt_tracefile_name(tfcs->parent.tf);
       tfcs->cpu = ltt_tracefile_cpu(tfcs->parent.tf);
-#if 0    
-      if(ltt_tracefile_tid(tfcs->parent.tf) != 0) {
-        /* It's a Usertrace */
-        LttvProcessState *process;
-        LttTime timestamp = 
-          ltt_interpolate_time_from_tsc(tfcs->parent.tf,
-              ltt_tracefile_creation(tfcs->parent.tf));
-        process = lttv_state_find_process_or_create(
-                        tcs,
-                        0, ltt_tracefile_tid(tfcs->parent.tf),
-                        &timestamp);
-        process->usertrace = tfcs;
-      }
-    }
-#endif //0
       if(ltt_tracefile_tid(tfcs->parent.tf) != 0) {
         /* It's a Usertrace */
         guint tid = ltt_tracefile_tid(tfcs->parent.tf);
@@ -347,6 +430,8 @@ init(LttvTracesetState *self, LttvTraceset *ts)
       }
     }
 
+    /* See if the trace has saved states */
+    state_load_saved_states(tcs);
   }
 }
 
@@ -424,7 +509,7 @@ static void write_process_state(gpointer key, gpointer value,
 
   process = (LttvProcessState *)value;
   fprintf(fp,
-"  <PROCESS CORE=%p PID=%u TGID=%u PPID=%u TYPE=\"%s\" CTIME_S=%lu CTIME_NS=%lu ITIME_S=%lu ITIME_NS=%lu NAME=\"%s\" BRAND=\"%s\" CPU=\"%u\" PROCESS_TYPE=%u>\n",
+"  <PROCESS CORE=%p PID=%u TGID=%u PPID=%u TYPE=\"%s\" CTIME_S=%lu CTIME_NS=%lu ITIME_S=%lu ITIME_NS=%lu NAME=\"%s\" BRAND=\"%s\" CPU=\"%u\">\n",
       process, process->pid, process->tgid, process->ppid,
       g_quark_to_string(process->type),
       process->creation_time.tv_sec,
@@ -569,6 +654,7 @@ static void write_process_state_raw(gpointer key, gpointer value,
     fwrite(&es->s, sizeof(es->s), 1, fp);
     fwrite(&es->entry, sizeof(es->entry), 1, fp);
     fwrite(&es->change, sizeof(es->change), 1, fp);
+    fwrite(&es->cum_cpu_time, sizeof(es->cum_cpu_time), 1, fp);
 #if 0
     fprintf(fp, "    <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
       g_quark_to_string(es->t), g_quark_to_string(es->n),
@@ -667,19 +753,19 @@ void lttv_state_write_raw(LttvTraceState *self, LttTime t, FILE *fp)
 /* Read process state from a file */
 
 /* Called because a HDR_PROCESS was found */
-static void read_process_state_raw(LttvTraceState *self, FILE *fp)
+static void read_process_state_raw(LttvTraceState *self, FILE *fp,
+                       GPtrArray *quarktable)
 {
   LttvExecutionState *es;
   LttvProcessState *process, *parent_process;
   LttvProcessState tmp;
-
-  FILE *fp = (FILE *)user_data;
+  GQuark tmpq;
 
   guint i;
-  guint64 address;
+  guint64 *address;
   guint cpu;
 
-  /* TOOD : check return value */
+  /* TODO : check return value */
   fread(&tmp.type, sizeof(tmp.type), 1, fp);
   fread(&tmp.name, sizeof(tmp.name), 1, fp);
   fread(&tmp.brand, sizeof(tmp.brand), 1, fp);
@@ -691,34 +777,63 @@ static void read_process_state_raw(LttvTraceState *self, FILE *fp)
   fread(&tmp.insertion_time, sizeof(tmp.insertion_time), 1, fp);
 
   if(tmp.pid == 0) {
-    process = lttv_state_find_process(self, tmp.cpu, tmp.pid,
-        tmp.insertion_time);
+    process = lttv_state_find_process(self, tmp.cpu, tmp.pid);
   } else {
     /* We must link to the parent */
     parent_process = lttv_state_find_process_or_create(self, ANY_CPU, tmp.ppid,
-        LTT_TIME_ZERO);
-    process = lttv_state_find_process_or_create(self, ANY_CPU, tmp.pid,
-        tmp.insertion_time);
+        &ltt_time_zero);
+    process = lttv_state_find_process_or_create(self, tmp.cpu, tmp.pid,
+        &tmp.creation_time);
   }
+  process->insertion_time = tmp.insertion_time;
   process->creation_time = tmp.creation_time;
-  process->type = tmp.type;
-  process->brand = tmp.brand;
+  process->type = g_quark_from_string(
+    (gchar*)g_ptr_array_index(quarktable, tmp.type));
   process->tgid = tmp.tgid;
-  process->cpu = tmp.cpu;
+  process->ppid = tmp.ppid;
+  process->brand = g_quark_from_string(
+    (gchar*)g_ptr_array_index(quarktable, tmp.brand));
+  process->name = 
+    g_quark_from_string((gchar*)g_ptr_array_index(quarktable, tmp.name));
 
   do {
     if(feof(fp) || ferror(fp)) goto end_loop;
 
-    hdr = fgetc(fp);
+    gint hdr = fgetc(fp);
+    if(hdr == EOF) goto end_loop;
 
     switch(hdr) {
       case HDR_ES:
+        process->execution_stack =
+          g_array_set_size(process->execution_stack,
+                           process->execution_stack->len + 1);
+        es = &g_array_index(process->execution_stack, LttvExecutionState,
+                process->execution_stack->len-1);
+
+        fread(&es->t, sizeof(es->t), 1, fp);
+        es->t = g_quark_from_string(
+           (gchar*)g_ptr_array_index(quarktable, es->t));
+        fread(&es->n, sizeof(es->n), 1, fp);
+        es->n = g_quark_from_string(
+           (gchar*)g_ptr_array_index(quarktable, es->n));
+        fread(&es->s, sizeof(es->s), 1, fp);
+        es->s = g_quark_from_string(
+           (gchar*)g_ptr_array_index(quarktable, es->s));
+        fread(&es->entry, sizeof(es->entry), 1, fp);
+        fread(&es->change, sizeof(es->change), 1, fp);
+        fread(&es->cum_cpu_time, sizeof(es->cum_cpu_time), 1, fp);
         break;
       case HDR_USER_STACK:
+        process->user_stack = g_array_set_size(process->user_stack,
+                              process->user_stack->len + 1);
+        address = &g_array_index(process->user_stack, guint64,
+                                 process->user_stack->len-1);
+        fread(address, sizeof(address), 1, fp);
+       process->current_function = *address;
         break;
       case HDR_USERTRACE:
-        break;
-      case HDR_PROCESS_STATE:
+        fread(&tmpq, sizeof(tmpq), 1, fp);
+        fread(&process->usertrace->cpu, sizeof(process->usertrace->cpu), 1, fp);
         break;
       default:
         ungetc(hdr, fp);
@@ -726,17 +841,17 @@ static void read_process_state_raw(LttvTraceState *self, FILE *fp)
     };
   } while(1);
 end_loop:
-
+  return;
 }
 
 
 /* Called because a HDR_PROCESS_STATE was found */
 /* Append a saved state to the trace states */
-void lttv_state_read_raw(LttvTraceState *self, FILE *fp)
+void lttv_state_read_raw(LttvTraceState *self, FILE *fp, GPtrArray *quarktable)
 {
   guint i, nb_tracefile, nb_block, offset;
   guint64 tsc;
-  LttTracefile *tf;
+  LttvTracefileState *tfcs;
 
   LttEventPosition *ep;
 
@@ -758,11 +873,12 @@ void lttv_state_read_raw(LttvTraceState *self, FILE *fp)
   do {
     if(feof(fp) || ferror(fp)) goto end_loop;
     hdr = fgetc(fp);
+    if(hdr == EOF) goto end_loop;
 
     switch(hdr) {
       case HDR_PROCESS:
         /* Call read_process_state_raw */
-        read_process_state_raw(self, fp);
+        read_process_state_raw(self, fp, quarktable);
         break;
       case HDR_TRACEFILE:
       case HDR_TRACESET:
@@ -774,9 +890,8 @@ void lttv_state_read_raw(LttvTraceState *self, FILE *fp)
       case HDR_USERTRACE:
       case HDR_PROCESS_STATE:
       case HDR_CPU:
-        g_error("Error while parsing saved state file :"
-            " unexpected data header %d",
-            hdr);
+        ungetc(hdr, fp);
+       goto end_loop;
         break;
       default:
         g_error("Error while parsing saved state file : unknown data header %d",
@@ -810,17 +925,18 @@ end_loop:
     fread(&tfcs->parent.timestamp, sizeof(tfcs->parent.timestamp), 1, fp);
     /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
      * position following : end of trace */
-    if(ltt_time_compare(tfcs->parent.timestamp, LTT_TIME_INFINITE) != 0) {
+    if(ltt_time_compare(tfcs->parent.timestamp, ltt_time_infinite) != 0) {
       fread(&nb_block, sizeof(nb_block), 1, fp);
       fread(&offset, sizeof(offset), 1, fp);
       fread(&tsc, sizeof(tsc), 1, fp);
-      ltt_event_position_set(ep, tf, nb_block, offset, tsc);
-      g_assert(ltt_tracefile_seek_position(tfc->tf, ep) == 0);
+      ltt_event_position_set(ep, tfcs->parent.tf, nb_block, offset, tsc);
+      gint ret = ltt_tracefile_seek_position(tfcs->parent.tf, ep);
+      g_assert(ret == 0);
     }
   }
   g_free(ep);
 
-  saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a, 
+  saved_states_tree = lttv_attribute_find_subdir(self->parent.t_a, 
       LTTV_STATE_SAVED_STATES);
   saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
   value = lttv_attribute_add(saved_states_tree, 
@@ -828,26 +944,28 @@ end_loop:
   *(value.v_gobject) = (GObject *)saved_state_tree;
   value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
   *(value.v_time) = t;
-  lttv_state_save(tcs, saved_state_tree);
+  lttv_state_save(self, saved_state_tree);
   g_debug("Saving state at time %lu.%lu", t.tv_sec,
-    self->parent.timestamp.tv_nsec);
+    t.tv_nsec);
 
   *(self->max_time_state_recomputed_in_seek) = t;
 }
 
 /* Called when a HDR_TRACE is found */
-void lttv_trace_states_read_raw(LttvTraceState *tcs, FILE *fp)
+void lttv_trace_states_read_raw(LttvTraceState *tcs, FILE *fp,
+                       GPtrArray *quarktable)
 {
   int hdr;
 
   do {
     if(feof(fp) || ferror(fp)) goto end_loop;
     hdr = fgetc(fp);
+    if(hdr == EOF) goto end_loop;
 
     switch(hdr) {
       case HDR_PROCESS_STATE:
         /* Call read_process_state_raw */
-        lttv_state_read_raw(tcs, fp);
+        lttv_state_read_raw(tcs, fp, quarktable);
         break;
       case HDR_TRACEFILE:
       case HDR_TRACESET:
@@ -1659,7 +1777,7 @@ LttvProcessState *lttv_state_find_process(LttvTraceState *ts, guint cpu,
 
 LttvProcessState *
 lttv_state_find_process_or_create(LttvTraceState *ts, guint cpu, guint pid,
-    LttTime *timestamp)
+    const LttTime *timestamp)
 {
   LttvProcessState *process = lttv_state_find_process(ts, cpu, pid);
   LttvExecutionState *es;
@@ -1715,6 +1833,9 @@ static void lttv_state_free_process_table(GHashTable *processes)
 static gboolean syscall_entry(void *hook_data, void *call_data)
 {
   LttvTracefileState *s = (LttvTracefileState *)call_data;
+  guint cpu = s->cpu;
+  LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
+  LttvProcessState *process = ts->running_process[cpu];
   LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
   LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
   LttField *f = thf->f1;
@@ -1734,7 +1855,9 @@ static gboolean syscall_entry(void *hook_data, void *call_data)
     submode = g_quark_from_string(string->str);
     g_string_free(string, TRUE);
   }
-  push_state(s, LTTV_STATE_SYSCALL, submode);
+  /* There can be no system call from PID 0 : unknown state */
+  if(process->pid != 0)
+    push_state(s, LTTV_STATE_SYSCALL, submode);
   return FALSE;
 }
 
@@ -1742,8 +1865,13 @@ static gboolean syscall_entry(void *hook_data, void *call_data)
 static gboolean syscall_exit(void *hook_data, void *call_data)
 {
   LttvTracefileState *s = (LttvTracefileState *)call_data;
+  guint cpu = s->cpu;
+  LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
+  LttvProcessState *process = ts->running_process[cpu];
 
-  pop_state(s, LTTV_STATE_SYSCALL);
+  /* There can be no system call from PID 0 : unknown state */
+  if(process->pid != 0)
+    pop_state(s, LTTV_STATE_SYSCALL);
   return FALSE;
 }
 
@@ -1961,7 +2089,12 @@ static gboolean schedchange(void *hook_data, void *call_data)
     //if(unlikely(process->pid != pid_out)) {
     //  g_assert(process->pid == 0);
     //}
-
+    if(process->pid == 0 && process->state->t == LTTV_STATE_MODE_UNKNOWN) {
+      /* Scheduling out of pid 0 at beginning of the trace :
+       * we know for sure it is in syscall mode at this point. */
+      g_assert(process->execution_stack->len == 1);
+      process->state->t = LTTV_STATE_SYSCALL;
+    }
     if(unlikely(process->state->s == LTTV_STATE_EXIT)) {
       process->state->s = LTTV_STATE_ZOMBIE;
       process->state->change = s->parent.timestamp;
@@ -2344,6 +2477,8 @@ void lttv_state_add_event_hooks(LttvTracesetState *self)
   for(i = 0 ; i < nb_trace ; i++) {
     ts = (LttvTraceState *)self->parent.traces[i];
 
+    if(ts->has_precomputed_states) continue;
+
     /* Find the eventtype id for the following events and register the
        associated by id hooks. */
 
@@ -2519,6 +2654,9 @@ void lttv_state_remove_event_hooks(LttvTracesetState *self)
   nb_trace = lttv_traceset_number(traceset);
   for(i = 0 ; i < nb_trace ; i++) {
     ts = LTTV_TRACE_STATE(self->parent.traces[i]);
+
+    if(ts->has_precomputed_states) continue;
+
     lttv_attribute_find(ts->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
     hooks = *(val.v_pointer);
 
This page took 0.027525 seconds and 4 git commands to generate.