GQuark
LTT_FACILITY_KERNEL,
+ LTT_FACILITY_KERNEL_ARCH,
LTT_FACILITY_PROCESS,
LTT_FACILITY_FS;
LTT_EVENT_TRAP_EXIT,
LTT_EVENT_IRQ_ENTRY,
LTT_EVENT_IRQ_EXIT,
+ LTT_EVENT_SOFT_IRQ_ENTRY,
+ LTT_EVENT_SOFT_IRQ_EXIT,
LTT_EVENT_SCHEDCHANGE,
LTT_EVENT_FORK,
LTT_EVENT_EXIT,
LTT_FIELD_SYSCALL_ID,
LTT_FIELD_TRAP_ID,
LTT_FIELD_IRQ_ID,
+ LTT_FIELD_SOFT_IRQ_ID,
LTT_FIELD_OUT,
LTT_FIELD_IN,
LTT_FIELD_OUT_STATE,
LTTV_STATE_USER_MODE,
LTTV_STATE_SYSCALL,
LTTV_STATE_TRAP,
- LTTV_STATE_IRQ;
+ LTTV_STATE_IRQ,
+ LTTV_STATE_SOFT_IRQ;
LttvExecutionSubmode
LTTV_STATE_SUBMODE_UNKNOWN,
LTTV_STATE_EXIT,
LTTV_STATE_ZOMBIE,
LTTV_STATE_WAIT,
- LTTV_STATE_RUN;
+ LTTV_STATE_RUN,
+ LTTV_STATE_DEAD;
static GQuark
LTTV_STATE_TRACEFILES,
nb_tracefile = self->parent.tracefiles->len;
- g_tree_destroy(tsc->pqueue);
- tsc->pqueue = g_tree_new(compare_tracefile);
+ //g_tree_destroy(tsc->pqueue);
+ //tsc->pqueue = g_tree_new(compare_tracefile);
for(i = 0 ; i < nb_tracefile ; i++) {
tfcs =
g_assert(tfcs->parent.t_context != NULL);
LttvTracefileContext *tfc = LTTV_TRACEFILE_CONTEXT(tfcs);
+ g_tree_remove(tsc->pqueue, tfc);
if(ep != NULL) {
g_assert(ltt_tracefile_seek_position(tfc->tf, ep) == 0);
GQuark *syscall_names;
GQuark *trap_names;
GQuark *irq_names;
+ GQuark *soft_irq_names;
} LttvNameTables;
}
#endif //0
if(lttv_trace_find_hook(tcs->parent.t,
- LTT_FACILITY_KERNEL, LTT_EVENT_SYSCALL_ENTRY,
+ LTT_FACILITY_KERNEL_ARCH, LTT_EVENT_SYSCALL_ENTRY,
LTT_FIELD_SYSCALL_ID, 0, 0,
NULL, NULL, &h))
return;
lttv_trace_hook_destroy(&h);
- /* CHECK syscalls should be an enum but currently are not!
name_tables->syscall_names = g_new(GQuark, nb);
for(i = 0 ; i < nb ; i++) {
- name_tables->syscall_names[i] = g_quark_from_string(
- ltt_enum_string_get(t, i));
+ name_tables->syscall_names[i] = ltt_enum_string_get(t, i);
}
- */
- name_tables->syscall_names = g_new(GQuark, 256);
- for(i = 0 ; i < 256 ; i++) {
- g_string_printf(fe_name, "syscall %d", i);
- name_tables->syscall_names[i] = g_quark_from_string(fe_name->str);
- }
+ //name_tables->syscall_names = g_new(GQuark, 256);
+ //for(i = 0 ; i < 256 ; i++) {
+ // g_string_printf(fe_name, "syscall %d", i);
+ // name_tables->syscall_names[i] = g_quark_from_string(fe_name->str);
+ //}
if(lttv_trace_find_hook(tcs->parent.t, LTT_FACILITY_KERNEL,
LTT_EVENT_TRAP_ENTRY,
thf = lttv_trace_hook_get_first(&h);
t = ltt_field_type(thf->f1);
- nb = ltt_type_element_number(t);
+ //nb = ltt_type_element_number(t);
lttv_trace_hook_destroy(&h);
thf = lttv_trace_hook_get_first(&h);
t = ltt_field_type(thf->f1);
- nb = ltt_type_element_number(t);
+ //nb = ltt_type_element_number(t);
lttv_trace_hook_destroy(&h);
name_tables->irq_names[i] = g_quark_from_string(fe_name->str);
}
+ /*
+ name_tables->soft_irq_names = g_new(GQuark, nb);
+ for(i = 0 ; i < nb ; i++) {
+ name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
+ }
+ */
+
+ name_tables->soft_irq_names = g_new(GQuark, 256);
+ for(i = 0 ; i < 256 ; i++) {
+ g_string_printf(fe_name, "softirq %d", i);
+ name_tables->soft_irq_names[i] = g_quark_from_string(fe_name->str);
+ }
+
+
g_string_free(fe_name, TRUE);
}
tcs->syscall_names = name_tables->syscall_names;
tcs->trap_names = name_tables->trap_names;
tcs->irq_names = name_tables->irq_names;
+ tcs->soft_irq_names = name_tables->soft_irq_names;
}
g_free(name_tables->syscall_names);
g_free(name_tables->trap_names);
g_free(name_tables->irq_names);
+ g_free(name_tables->soft_irq_names);
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)
{
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;
//process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
process->execution_stack = g_array_sized_new(FALSE, FALSE,
sizeof(LttvExecutionState), PREALLOCATED_EXECUTION_STACK);
- process->execution_stack = g_array_set_size(process->execution_stack, 1);
+ process->execution_stack = g_array_set_size(process->execution_stack, 2);
es = process->state = &g_array_index(process->execution_stack,
LttvExecutionState, 0);
es->t = LTTV_STATE_USER_MODE;
es->entry = *timestamp;
//g_assert(timestamp->tv_sec != 0);
es->change = *timestamp;
+ es->s = LTTV_STATE_RUN;
+
+ es = process->state = &g_array_index(process->execution_stack,
+ LttvExecutionState, 1);
+ es->t = LTTV_STATE_SYSCALL;
+ es->n = LTTV_STATE_SUBMODE_NONE;
+ es->entry = *timestamp;
+ //g_assert(timestamp->tv_sec != 0);
+ es->change = *timestamp;
es->s = LTTV_STATE_WAIT_FORK;
return process;
return FALSE;
}
+static gboolean soft_irq_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(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
+ g_assert(thf->f1 != NULL);
+ // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
+ LttField *f = thf->f1;
+
+ LttvExecutionSubmode submode;
+
+ submode = ((LttvTraceState *)(s->parent.t_context))->soft_irq_names[
+ ltt_event_get_unsigned(e, f)];
+
+ /* Do something with the info about being in user or system mode when int? */
+ push_state(s, LTTV_STATE_SOFT_IRQ, submode);
+ 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 schedchange(void *hook_data, void *call_data)
{
if(unlikely(process->state->s == LTTV_STATE_EXIT)) {
process->state->s = LTTV_STATE_ZOMBIE;
+ process->state->change = s->parent.timestamp;
} else {
if(unlikely(state_out == 0)) process->state->s = LTTV_STATE_WAIT_CPU;
else 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, process);
-
- process->state->change = s->parent.timestamp;
+ process->state->change = s->parent.timestamp;
+ }
+
+ if(state_out == 32)
+ exit_process(s, process); /* EXIT_DEAD */
+ /* see sched.h for states */
}
process = ts->running_process[cpu] =
lttv_state_find_process_or_create(
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;
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.
+ *
+ * Test reenabled after precision fixes on time. (Mathieu) */
+#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(zombie_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. Note that we
+ * shouldn't have this kind of imprecision.
+ *
+ * Simply put a correct parent.
+ */
+ g_assert(0); /* This is a problematic case : the process has been created
+ before the fork event */
+ child_process->ppid = process->pid;
+ }
return FALSE;
}
/* 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 */
+ //This test is fun, though, as it may happen that
+ //at time t : CPU 0 : process_free
+ //at time t+150ns : CPU 1 : schedule out
+ //Clearly due to time imprecision, we disable it. (Mathieu)
+ //If this weird case happen, we have no choice but to put the
+ //Currently running process on the cpu to 0.
+ //I re-enable it following time precision fixes. (Mathieu)
+ //Well, in the case where an process is freed by a process on another CPU
+ //and still scheduled, it happens that this is the schedchange that will
+ //drop the last reference count. Do not free it here!
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]);
+ //g_assert(process != ts->running_process[i]);
+ if(process == ts->running_process[i]) {
+ //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
+ break;
+ }
}
- exit_process(s, process);
+ if(i == num_cpus) /* process is not scheduled */
+ exit_process(s, process);
}
return FALSE;
LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
- gchar *name;
+ //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);
-
+ guint64 name_len = ltt_event_field_element_number(e, thf->f1);
+ //name = ltt_event_get_string(e, thf->f1);
+ LttField *child = ltt_event_field_element_select(e, thf->f1, 0);
+ gchar *name_begin =
+ (gchar*)(ltt_event_data(e)+ltt_event_field_offset(e, child));
+ gchar *null_term_name = g_new(gchar, name_len+1);
+ memcpy(null_term_name, name_begin, name_len);
+ null_term_name[name_len] = '\0';
+
+ process->name = g_quark_from_string(null_term_name);
+ g_free(null_term_name);
return FALSE;
}
/* Find the eventtype id for the following events and register the
associated by id hooks. */
- hooks = g_array_sized_new(FALSE, FALSE, sizeof(LttvTraceHook), 11);
- hooks = g_array_set_size(hooks, 11);
+ hooks = g_array_sized_new(FALSE, FALSE, sizeof(LttvTraceHook), 13);
+ hooks = g_array_set_size(hooks, 13);
ret = lttv_trace_find_hook(ts->parent.t,
- LTT_FACILITY_KERNEL, LTT_EVENT_SYSCALL_ENTRY,
+ 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);
ret = lttv_trace_find_hook(ts->parent.t,
- LTT_FACILITY_KERNEL, LTT_EVENT_SYSCALL_EXIT,
+ LTT_FACILITY_KERNEL_ARCH, LTT_EVENT_SYSCALL_EXIT,
0, 0, 0,
syscall_exit, NULL, &g_array_index(hooks, LttvTraceHook, 1));
g_assert(!ret);
irq_exit, NULL, &g_array_index(hooks, LttvTraceHook, 5));
g_assert(!ret);
+ 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);
+
+ 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);
+
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, 6));
+ schedchange, NULL, &g_array_index(hooks, LttvTraceHook, 8));
g_assert(!ret);
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, 7));
+ process_fork, NULL, &g_array_index(hooks, LttvTraceHook, 9));
g_assert(!ret);
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, 8));
+ process_exit, NULL, &g_array_index(hooks, LttvTraceHook, 10));
g_assert(!ret);
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, 9));
+ process_free, NULL, &g_array_index(hooks, LttvTraceHook, 11));
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));
+ process_exec, NULL, &g_array_index(hooks, LttvTraceHook, 12));
g_assert(!ret);
return FALSE;
}
+static gboolean state_save_after_trace_hook(void *hook_data, void *call_data)
+{
+ LttvTraceState *tcs = (LttvTraceState *)(call_data);
+
+ *(tcs->max_time_state_recomputed_in_seek) = tcs->parent.time_span.end_time;
+
+ return FALSE;
+}
+
#if 0
static gboolean block_start(void *hook_data, void *call_data)
{
}
}
+
+ lttv_process_traceset_begin(&self->parent,
+ NULL, NULL, NULL, NULL, NULL);
+
}
gint lttv_state_save_hook_add_event_hooks(void *hook_data, void *call_data)
LttvTracefileState *tfs;
+ LttvHooks *after_trace = lttv_hooks_new();
+
+ lttv_hooks_add(after_trace,
+ state_save_after_trace_hook,
+ NULL,
+ LTTV_PRIO_STATE);
+
+
+ lttv_process_traceset_end(&self->parent,
+ NULL, after_trace, NULL, NULL, NULL);
+ lttv_hooks_destroy(after_trace);
+
nb_trace = lttv_traceset_number(traceset);
for(i = 0 ; i < nb_trace ; i++) {
ts = (LttvTraceState *)self->parent.traces[i];
nb_tracefile = ts->parent.tracefiles->len;
- guint *event_count;
+ guint *event_count = NULL;
for(j = 0 ; j < nb_tracefile ; j++) {
tfs =
LttvTracefileContext*, j));
event_count = lttv_hooks_remove(tfs->parent.event,
state_save_event_hook);
-
}
- g_free(event_count);
+ if(event_count) g_free(event_count);
}
}
LttvAttribute *saved_states_tree, *saved_state_tree, *closest_tree;
- g_tree_destroy(self->parent.pqueue);
- self->parent.pqueue = g_tree_new(compare_tracefile);
+ //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);
LTTV_STATE_SYSCALL = g_quark_from_string("system call");
LTTV_STATE_TRAP = g_quark_from_string("trap");
LTTV_STATE_IRQ = g_quark_from_string("irq");
+ LTTV_STATE_SOFT_IRQ = g_quark_from_string("softirq");
LTTV_STATE_SUBMODE_UNKNOWN = g_quark_from_string("unknown submode");
LTTV_STATE_SUBMODE_NONE = g_quark_from_string("(no submode)");
LTTV_STATE_WAIT_CPU = g_quark_from_string("wait for cpu");
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_DEAD = g_quark_from_string("dead");
LTTV_STATE_TRACEFILES = g_quark_from_string("tracefiles");
LTTV_STATE_PROCESSES = g_quark_from_string("processes");
LTTV_STATE_PROCESS = g_quark_from_string("process");
LTT_FACILITY_KERNEL = g_quark_from_string("kernel");
+ LTT_FACILITY_KERNEL_ARCH = g_quark_from_string("kernel_arch");
LTT_FACILITY_PROCESS = g_quark_from_string("process");
LTT_FACILITY_FS = g_quark_from_string("fs");
LTT_EVENT_TRAP_EXIT = g_quark_from_string("trap_exit");
LTT_EVENT_IRQ_ENTRY = g_quark_from_string("irq_entry");
LTT_EVENT_IRQ_EXIT = g_quark_from_string("irq_exit");
+ LTT_EVENT_SOFT_IRQ_ENTRY = g_quark_from_string("soft_irq_entry");
+ LTT_EVENT_SOFT_IRQ_EXIT = g_quark_from_string("soft_irq_exit");
LTT_EVENT_SCHEDCHANGE = g_quark_from_string("schedchange");
LTT_EVENT_FORK = g_quark_from_string("fork");
LTT_EVENT_EXIT = g_quark_from_string("exit");
LTT_FIELD_SYSCALL_ID = g_quark_from_string("syscall_id");
LTT_FIELD_TRAP_ID = g_quark_from_string("trap_id");
LTT_FIELD_IRQ_ID = g_quark_from_string("irq_id");
+ LTT_FIELD_SOFT_IRQ_ID = g_quark_from_string("softirq_id");
LTT_FIELD_OUT = g_quark_from_string("out");
LTT_FIELD_IN = g_quark_from_string("in");
LTT_FIELD_OUT_STATE = g_quark_from_string("out_state");