X-Git-Url: http://git.liburcu.org/?a=blobdiff_plain;f=lttv%2Flttv%2Fstate.c;h=25af4116000fc457adf4d7eff7f1d11b0f942bbd;hb=9ba166625a51142799f6b9bbf86e8260f712c3a2;hp=70ca8cbe06286f447bd4f7193be8ccca48c51b9e;hpb=f61f4dca50e13aa52b1ca3941c8f420848f4353f;p=lttv.git diff --git a/lttv/lttv/state.c b/lttv/lttv/state.c index 70ca8cbe..25af4116 100644 --- a/lttv/lttv/state.c +++ b/lttv/lttv/state.c @@ -83,6 +83,7 @@ GQuark LTT_EVENT_SOFT_IRQ_ENTRY, LTT_EVENT_SOFT_IRQ_EXIT, LTT_EVENT_SCHED_SCHEDULE, + LTT_EVENT_SCHED_TRY_WAKEUP, LTT_EVENT_PROCESS_FORK, LTT_EVENT_KTHREAD_CREATE, LTT_EVENT_PROCESS_EXIT, @@ -99,7 +100,10 @@ GQuark LTT_EVENT_SYS_CALL_TABLE, LTT_EVENT_SOFTIRQ_VEC, LTT_EVENT_KPROBE_TABLE, - LTT_EVENT_KPROBE; + LTT_EVENT_KPROBE, + LTT_EVENT_OPEN, + LTT_EVENT_READ, + LTT_EVENT_POLL_EVENT; /* Fields Quarks */ @@ -131,7 +135,10 @@ GQuark LTT_FIELD_ID, LTT_FIELD_ADDRESS, LTT_FIELD_SYMBOL, - LTT_FIELD_IP; + LTT_FIELD_IP, + LTT_FIELD_FD, + LTT_FIELD_STATE, + LTT_FIELD_CPU_ID; LttvExecutionMode LTTV_STATE_MODE_UNKNOWN, @@ -227,7 +234,7 @@ static void bdevstate_free_cb(gpointer key, gpointer value, gpointer user_data); static LttvBdevState *bdevstate_copy(LttvBdevState *bds); -#if (__SIZEOF_LONG__ == 4) +#if (__WORDSIZE == 32) guint guint64_hash(gconstpointer key) { guint64 ukey = *(const guint64 *)key; @@ -318,6 +325,7 @@ static void expand_name_table(LttvTraceState *ts, GQuark **table, GQuark *old_table = *table; *table = g_new(GQuark, new_nb); memcpy(*table, old_table, nb * sizeof(GQuark)); + g_free(old_table); } static void fill_name_table(LttvTraceState *ts, GQuark *table, guint nb, @@ -334,84 +342,103 @@ static void fill_name_table(LttvTraceState *ts, GQuark *table, guint nb, static void expand_syscall_table(LttvTraceState *ts, int id) { - guint new_nb = check_expand(ts->nb_syscalls, id); - if(likely(new_nb == ts->nb_syscalls)) + LttvNameTables *nt = ts->name_tables; + guint new_nb; + + new_nb = check_expand(nt->nb_syscalls, id); + if(likely(new_nb == nt->nb_syscalls)) return; - expand_name_table(ts, &ts->syscall_names, ts->nb_syscalls, new_nb); - fill_name_table(ts, ts->syscall_names, ts->nb_syscalls, new_nb, "syscall"); + expand_name_table(ts, &nt->syscall_names, nt->nb_syscalls, new_nb); + fill_name_table(ts, nt->syscall_names, nt->nb_syscalls, new_nb, "syscall"); /* Update the table size */ - ts->nb_syscalls = new_nb; + nt->nb_syscalls = new_nb; } static void expand_kprobe_table(LttvTraceState *ts, guint64 ip, char *symbol) { -#if (__SIZEOF_LONG__ == 4) + LttvNameTables *nt = ts->name_tables; +#if (__WORDSIZE == 32) guint64 *ip_ptr = g_new(guint64, 1); - g_hash_table_insert(ts->kprobe_hash, ip_ptr, + g_hash_table_insert(nt->kprobe_hash, ip_ptr, (gpointer)(glong)g_quark_from_string(symbol)); #else - g_hash_table_insert(ts->kprobe_hash, (gpointer)ip, + g_hash_table_insert(nt->kprobe_hash, (gpointer)ip, (gpointer)(glong)g_quark_from_string(symbol)); #endif } static void expand_trap_table(LttvTraceState *ts, int id) { - guint new_nb = check_expand(ts->nb_traps, id); - guint i; - if(likely(new_nb == ts->nb_traps)) + LttvNameTables *nt = ts->name_tables; + LttvTrapState *old_table; + guint new_nb, i; + + new_nb = check_expand(nt->nb_traps, id); + if(likely(new_nb == nt->nb_traps)) return; - expand_name_table(ts, &ts->trap_names, ts->nb_traps, new_nb); - fill_name_table(ts, ts->trap_names, ts->nb_traps, new_nb, "trap"); - /* Update the table size */ - ts->nb_traps = new_nb; - LttvTrapState *old_table = ts->trap_states; + expand_name_table(ts, &nt->trap_names, nt->nb_traps, new_nb); + fill_name_table(ts, nt->trap_names, nt->nb_traps, new_nb, "trap"); + + old_table = ts->trap_states; ts->trap_states = g_new(LttvTrapState, new_nb); - memcpy(ts->trap_states, old_table, - ts->nb_traps * sizeof(LttvTrapState)); - for(i = ts->nb_traps; i < new_nb; i++) + memcpy(ts->trap_states, old_table, nt->nb_traps * sizeof(LttvTrapState)); + g_free(old_table); + for(i = nt->nb_traps; i < new_nb; i++) ts->trap_states[i].running = 0; + + /* Update the table size */ + nt->nb_traps = new_nb; } static void expand_irq_table(LttvTraceState *ts, int id) { - guint new_nb = check_expand(ts->nb_irqs, id); - guint i; - if(likely(new_nb == ts->nb_irqs)) + LttvNameTables *nt = ts->name_tables; + LttvIRQState *old_table; + guint new_nb, i; + + new_nb = check_expand(nt->nb_irqs, id); + if(likely(new_nb == nt->nb_irqs)) return; - expand_name_table(ts, &ts->irq_names, ts->nb_irqs, new_nb); - fill_name_table(ts, ts->irq_names, ts->nb_irqs, new_nb, "irq"); - LttvIRQState *old_table = ts->irq_states; + expand_name_table(ts, &nt->irq_names, nt->nb_irqs, new_nb); + fill_name_table(ts, nt->irq_names, nt->nb_irqs, new_nb, "irq"); + + old_table = ts->irq_states; ts->irq_states = g_new(LttvIRQState, new_nb); - memcpy(ts->irq_states, old_table, ts->nb_irqs * sizeof(LttvIRQState)); - for(i = ts->nb_irqs; i < new_nb; i++) { - ts->irq_states[i].mode_stack = g_array_new(FALSE, FALSE, sizeof(LttvIRQMode)); - } + memcpy(ts->irq_states, old_table, nt->nb_irqs * sizeof(LttvIRQState)); + g_free(old_table); + for(i = nt->nb_irqs; i < new_nb; i++) + ts->irq_states[i].mode_stack = + g_array_new(FALSE, FALSE, sizeof(LttvIRQMode)); /* Update the table size */ - ts->nb_irqs = new_nb; + nt->nb_irqs = new_nb; } static void expand_soft_irq_table(LttvTraceState *ts, int id) { - guint new_nb = check_expand(ts->nb_soft_irqs, id); - guint i; - if(likely(new_nb == ts->nb_soft_irqs)) + LttvNameTables *nt = ts->name_tables; + LttvSoftIRQState *old_table; + guint new_nb, i; + + new_nb = check_expand(nt->nb_soft_irqs, id); + if(likely(new_nb == nt->nb_soft_irqs)) return; - expand_name_table(ts, &ts->soft_irq_names, ts->nb_soft_irqs, new_nb); - fill_name_table(ts, ts->soft_irq_names, ts->nb_soft_irqs, new_nb, "softirq"); - LttvSoftIRQState *old_table = ts->soft_irq_states; + expand_name_table(ts, &nt->soft_irq_names, nt->nb_soft_irqs, new_nb); + fill_name_table(ts, nt->soft_irq_names, nt->nb_soft_irqs, new_nb, "softirq"); + + old_table = ts->soft_irq_states; ts->soft_irq_states = g_new(LttvSoftIRQState, new_nb); memcpy(ts->soft_irq_states, old_table, - ts->nb_soft_irqs * sizeof(LttvSoftIRQState)); - for(i = ts->nb_soft_irqs; i < new_nb; i++) + nt->nb_soft_irqs * sizeof(LttvSoftIRQState)); + g_free(old_table); + for(i = nt->nb_soft_irqs; i < new_nb; i++) ts->soft_irq_states[i].running = 0; /* Update the table size */ - ts->nb_soft_irqs = new_nb; + nt->nb_soft_irqs = new_nb; } static void @@ -442,9 +469,9 @@ restore_init_state(LttvTraceState *self) //lttv_process_trace_seek_time(&self->parent, ltt_time_zero); nb_cpus = ltt_trace_get_num_cpu(self->parent.t); - nb_irqs = self->nb_irqs; - nb_soft_irqs = self->nb_soft_irqs; - nb_traps = self->nb_traps; + nb_irqs = self->name_tables->nb_irqs; + nb_soft_irqs = self->name_tables->nb_soft_irqs; + nb_traps = self->name_tables->nb_traps; /* Put the per cpu running_process to beginning state : process 0. */ for(i=0; i< nb_cpus; i++) { @@ -643,7 +670,7 @@ init(LttvTracesetState *self, LttvTraceset *ts) nb_tracefile = tc->tracefiles->len; nb_cpu = ltt_trace_get_num_cpu(tc->t); - nb_irq = tcs->nb_irqs; + nb_irq = tcs->name_tables->nb_irqs; tcs->processes = NULL; tcs->usertraces = NULL; tcs->running_process = g_new(LttvProcessState*, nb_cpu); @@ -667,10 +694,10 @@ init(LttvTracesetState *self, LttvTraceset *ts) /* init soft irq stuff */ /* the kernel has a statically fixed max of 32 softirqs */ - tcs->soft_irq_states = g_new(LttvSoftIRQState, tcs->nb_soft_irqs); + tcs->soft_irq_states = g_new(LttvSoftIRQState, tcs->name_tables->nb_soft_irqs); /* init trap stuff */ - tcs->trap_states = g_new(LttvTrapState, tcs->nb_traps); + tcs->trap_states = g_new(LttvTrapState, tcs->name_tables->nb_traps); /* init bdev resource stuff */ tcs->bdev_states = g_hash_table_new(g_int_hash, g_int_equal); @@ -1311,6 +1338,24 @@ static void copy_process_state(gpointer key, gpointer value,gpointer user_data) g_array_index(process->user_stack, guint64, i); } new_process->current_function = process->current_function; + + /* fd hash table stuff */ + { + GHashTableIter it; + gpointer key; + gpointer value; + + /* copy every item in the hash table */ + new_process->fds = g_hash_table_new(g_direct_hash, g_direct_equal); + + g_hash_table_iter_init(&it, process->fds); + while (g_hash_table_iter_next (&it, (void *)&key, (void *)&value)) { + g_hash_table_insert(new_process->fds, key, value); + } + } + + /* When done creating the new process state, insert it in the + * hash table */ g_hash_table_insert(new_processes, new_process, new_process); } @@ -1613,7 +1658,7 @@ static void state_save(LttvTraceState *self, LttvAttribute *container) } /* save the irq state */ - nb_irqs = self->nb_irqs; + nb_irqs = self->name_tables->nb_irqs; { value = lttv_attribute_add(container, LTTV_STATE_RESOURCE_IRQS, LTTV_POINTER); @@ -1621,7 +1666,7 @@ static void state_save(LttvTraceState *self, LttvAttribute *container) } /* save the soft irq state */ - nb_soft_irqs = self->nb_soft_irqs; + nb_soft_irqs = self->name_tables->nb_soft_irqs; { value = lttv_attribute_add(container, LTTV_STATE_RESOURCE_SOFT_IRQS, LTTV_POINTER); @@ -1629,7 +1674,7 @@ static void state_save(LttvTraceState *self, LttvAttribute *container) } /* save the trap state */ - nb_traps = self->nb_traps; + nb_traps = self->name_tables->nb_traps; { value = lttv_attribute_add(container, LTTV_STATE_RESOURCE_TRAPS, LTTV_POINTER); @@ -1664,6 +1709,7 @@ static void state_restore(LttvTraceState *self, LttvAttribute *container) LttEventPosition *ep; LttvTracesetContext *tsc = self->parent.ts_context; + int retval; tracefiles_tree = lttv_attribute_find_subdir(container, LTTV_STATE_TRACEFILES); @@ -1698,21 +1744,21 @@ static void state_restore(LttvTraceState *self, LttvAttribute *container) self->cpu_states = lttv_state_copy_cpu_states(*(value.v_pointer), nb_cpus); /* restore irq resource states */ - nb_irqs = self->nb_irqs; + nb_irqs = self->name_tables->nb_irqs; type = lttv_attribute_get_by_name(container, LTTV_STATE_RESOURCE_IRQS, &value); g_assert(type == LTTV_POINTER); lttv_state_free_irq_states(self->irq_states, nb_irqs); self->irq_states = lttv_state_copy_irq_states(*(value.v_pointer), nb_irqs); /* restore soft irq resource states */ - nb_soft_irqs = self->nb_soft_irqs; + nb_soft_irqs = self->name_tables->nb_soft_irqs; type = lttv_attribute_get_by_name(container, LTTV_STATE_RESOURCE_SOFT_IRQS, &value); g_assert(type == LTTV_POINTER); lttv_state_free_soft_irq_states(self->soft_irq_states, nb_soft_irqs); self->soft_irq_states = lttv_state_copy_soft_irq_states(*(value.v_pointer), nb_soft_irqs); /* restore trap resource states */ - nb_traps = self->nb_traps; + nb_traps = self->name_tables->nb_traps; type = lttv_attribute_get_by_name(container, LTTV_STATE_RESOURCE_TRAPS, &value); g_assert(type == LTTV_POINTER); lttv_state_free_trap_states(self->trap_states, nb_traps); @@ -1751,9 +1797,10 @@ static void state_restore(LttvTraceState *self, LttvAttribute *container) g_tree_remove(tsc->pqueue, tfc); if(ep != NULL) { - g_assert(ltt_tracefile_seek_position(tfc->tf, ep) == 0); + retval= ltt_tracefile_seek_position(tfc->tf, ep); + g_assert_cmpint(retval, ==, 0); tfc->timestamp = ltt_event_time(ltt_tracefile_get_event(tfc->tf)); - g_assert(ltt_time_compare(tfc->timestamp, ltt_time_infinite) != 0); + g_assert_cmpint(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 { @@ -1765,7 +1812,7 @@ static void state_restore(LttvTraceState *self, LttvAttribute *container) static void state_saved_free(LttvTraceState *self, LttvAttribute *container) { - guint i, nb_tracefile, nb_cpus, nb_irqs, nb_softirqs; + guint i, nb_tracefile, nb_cpus, nb_irqs, nb_soft_irqs; LttvTracefileState *tfcs; @@ -1809,16 +1856,16 @@ static void state_saved_free(LttvTraceState *self, LttvAttribute *container) lttv_state_free_cpu_states(*(value.v_pointer), nb_cpus); /* free irq resource states */ - nb_irqs = self->nb_irqs; + nb_irqs = self->name_tables->nb_irqs; type = lttv_attribute_get_by_name(container, LTTV_STATE_RESOURCE_IRQS, &value); g_assert(type == LTTV_POINTER); lttv_state_free_irq_states(*(value.v_pointer), nb_irqs); /* free softirq resource states */ - nb_softirqs = self->nb_irqs; + nb_soft_irqs = self->name_tables->nb_soft_irqs; type = lttv_attribute_get_by_name(container, LTTV_STATE_RESOURCE_SOFT_IRQS, &value); g_assert(type == LTTV_POINTER); - lttv_state_free_soft_irq_states(*(value.v_pointer), nb_softirqs); + lttv_state_free_soft_irq_states(*(value.v_pointer), nb_soft_irqs); /* free the blkdev states */ type = lttv_attribute_get_by_name(container, LTTV_STATE_RESOURCE_BLKDEVS, &value); @@ -1908,21 +1955,6 @@ free_max_time(LttvTraceState *tcs) *(v.v_pointer) = NULL; } - -typedef struct _LttvNameTables { - // FIXME GQuark *eventtype_names; - GQuark *syscall_names; - guint nb_syscalls; - GQuark *trap_names; - guint nb_traps; - GQuark *irq_names; - guint nb_irqs; - GQuark *soft_irq_names; - guint nb_softirqs; - GHashTable *kprobe_hash; -} LttvNameTables; - - static void create_name_tables(LttvTraceState *tcs) { @@ -2025,10 +2057,12 @@ create_name_tables(LttvTraceState *tcs) name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i)); } */ + /* FIXME: LttvIRQState *irq_states should become a g_array */ + /* temp fix: increase from 256 to 512 default size */ - name_tables->nb_irqs = 256; - name_tables->irq_names = g_new(GQuark, 256); - for(i = 0 ; i < 256 ; i++) { + name_tables->nb_irqs = 512; + name_tables->irq_names = g_new(GQuark, 512); + for(i = 0 ; i < 512 ; i++) { g_string_printf(fe_name, "irq %d", i); name_tables->irq_names[i] = g_quark_from_string(fe_name->str); } @@ -2045,9 +2079,9 @@ create_name_tables(LttvTraceState *tcs) */ /* the kernel is limited to 32 statically defined softirqs */ - name_tables->nb_softirqs = 32; - name_tables->soft_irq_names = g_new(GQuark, name_tables->nb_softirqs); - for(i = 0 ; i < name_tables->nb_softirqs ; i++) { + name_tables->nb_soft_irqs = 32; + name_tables->soft_irq_names = g_new(GQuark, name_tables->nb_soft_irqs); + for(i = 0 ; i < name_tables->nb_soft_irqs ; i++) { g_string_printf(fe_name, "softirq %d", i); name_tables->soft_irq_names[i] = g_quark_from_string(fe_name->str); } @@ -2055,7 +2089,7 @@ create_name_tables(LttvTraceState *tcs) g_string_free(fe_name, TRUE); -#if (__SIZEOF_LONG__ == 4) +#if (__WORDSIZE == 32) name_tables->kprobe_hash = g_hash_table_new_full(guint64_hash, guint64_equal, g_free, NULL); #else @@ -2067,24 +2101,12 @@ create_name_tables(LttvTraceState *tcs) static void get_name_tables(LttvTraceState *tcs) { - LttvNameTables *name_tables; - LttvAttributeValue v; lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_NAME_TABLES, LTTV_POINTER, &v); g_assert(*(v.v_pointer) != NULL); - name_tables = (LttvNameTables *)*(v.v_pointer); - //tcs->eventtype_names = name_tables->eventtype_names; - tcs->syscall_names = name_tables->syscall_names; - tcs->nb_syscalls = name_tables->nb_syscalls; - tcs->trap_names = name_tables->trap_names; - tcs->nb_traps = name_tables->nb_traps; - tcs->irq_names = name_tables->irq_names; - tcs->soft_irq_names = name_tables->soft_irq_names; - tcs->nb_irqs = name_tables->nb_irqs; - tcs->nb_soft_irqs = name_tables->nb_softirqs; - tcs->kprobe_hash = name_tables->kprobe_hash; + tcs->name_tables = (LttvNameTables *)*(v.v_pointer); } @@ -2105,8 +2127,8 @@ free_name_tables(LttvTraceState *tcs) if(name_tables->trap_names) g_free(name_tables->trap_names); if(name_tables->irq_names) g_free(name_tables->irq_names); if(name_tables->soft_irq_names) g_free(name_tables->soft_irq_names); - if(name_tables) g_free(name_tables); - if(name_tables) g_hash_table_destroy(name_tables->kprobe_hash); + g_hash_table_destroy(name_tables->kprobe_hash); + g_free(name_tables); } #ifdef HASH_TABLE_DEBUG @@ -2327,6 +2349,7 @@ static LttvTracefileState *ltt_state_usertrace_find(LttvTraceState *tcs, return tfs; } +/* Return a new and initialized LttvProcessState structure */ LttvProcessState * lttv_state_create_process(LttvTraceState *tcs, LttvProcessState *parent, @@ -2400,6 +2423,8 @@ lttv_state_create_process(LttvTraceState *tcs, LttvProcessState *parent, /* Allocate an empty function call stack. If it's empty, use 0x0. */ process->user_stack = g_array_sized_new(FALSE, FALSE, sizeof(guint64), 0); + + process->fds = g_hash_table_new(g_direct_hash, g_direct_equal); return process; } @@ -2441,7 +2466,7 @@ lttv_state_find_process_or_create(LttvTraceState *ts, guint cpu, guint pid, /* 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 + * the parent waits for its child termination, but may also happens 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 group, but isn't the leader. @@ -2461,6 +2486,10 @@ static int exit_process(LttvTracefileState *tfs, LttvProcessState *process) g_hash_table_remove(ts->processes, &key); g_array_free(process->execution_stack, TRUE); g_array_free(process->user_stack, TRUE); + + /* the following also clears the content */ + g_hash_table_destroy(process->fds); + g_free(process); return 1; } @@ -2470,6 +2499,10 @@ 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); + + /* the following also clears the content */ + g_hash_table_destroy(((LttvProcessState *)value)->fds); + g_free(value); } @@ -2491,10 +2524,11 @@ static gboolean syscall_entry(void *hook_data, void *call_data) LttvTraceHook *th = (LttvTraceHook *)hook_data; struct marker_field *f = lttv_trace_get_hook_field(th, 0); LttvExecutionSubmode submode; + LttvNameTables *nt = ((LttvTraceState *)(s->parent.t_context))->name_tables; guint syscall = ltt_event_get_unsigned(e, f); expand_syscall_table(ts, syscall); - submode = ((LttvTraceState *)(s->parent.t_context))->syscall_names[syscall]; + submode = nt->syscall_names[syscall]; /* There can be no system call from PID 0 : unknown state */ if(process->pid != 0) push_state(s, LTTV_STATE_SYSCALL, submode); @@ -2523,6 +2557,7 @@ static gboolean trap_entry(void *hook_data, void *call_data) LttEvent *e = ltt_tracefile_get_event(s->parent.tf); LttvTraceHook *th = (LttvTraceHook *)hook_data; struct marker_field *f = lttv_trace_get_hook_field(th, 0); + LttvNameTables *nt = ((LttvTraceState *)(s->parent.t_context))->name_tables; LttvExecutionSubmode submode; @@ -2530,7 +2565,7 @@ static gboolean trap_entry(void *hook_data, void *call_data) expand_trap_table(ts, trap); - submode = ((LttvTraceState *)(s->parent.t_context))->trap_names[trap]; + submode = nt->trap_names[trap]; push_state(s, LTTV_STATE_TRAP, submode); @@ -2572,13 +2607,14 @@ static gboolean irq_entry(void *hook_data, void *call_data) //guint8 ev_id = ltt_event_eventtype_id(e); LttvTraceHook *th = (LttvTraceHook *)hook_data; struct marker_field *f = lttv_trace_get_hook_field(th, 0); + LttvNameTables *nt = ((LttvTraceState *)(s->parent.t_context))->name_tables; LttvExecutionSubmode submode; guint64 irq = ltt_event_get_long_unsigned(e, f); expand_irq_table(ts, irq); - submode = ((LttvTraceState *)(s->parent.t_context))->irq_names[irq]; + submode = nt->irq_names[irq]; /* Do something with the info about being in user or system mode when int? */ push_state(s, LTTV_STATE_IRQ, submode); @@ -2641,13 +2677,14 @@ static gboolean soft_irq_raise(void *hook_data, void *call_data) //guint8 ev_id = ltt_event_eventtype_id(e); LttvTraceHook *th = (LttvTraceHook *)hook_data; struct marker_field *f = lttv_trace_get_hook_field(th, 0); + LttvNameTables *nt = ((LttvTraceState *)(s->parent.t_context))->name_tables; LttvExecutionSubmode submode; guint64 softirq = ltt_event_get_long_unsigned(e, f); - guint64 nb_softirqs = ((LttvTraceState *)(s->parent.t_context))->nb_soft_irqs; + guint64 nb_softirqs = nt->nb_soft_irqs; if(softirq < nb_softirqs) { - submode = ((LttvTraceState *)(s->parent.t_context))->soft_irq_names[softirq]; + submode = nt->soft_irq_names[softirq]; } else { /* Fixup an incomplete irq table */ GString *string = g_string_new(""); @@ -2674,7 +2711,8 @@ static gboolean soft_irq_entry(void *hook_data, void *call_data) LttvExecutionSubmode submode; guint64 softirq = ltt_event_get_long_unsigned(e, f); expand_soft_irq_table(ts, softirq); - submode = ((LttvTraceState *)(s->parent.t_context))->soft_irq_names[softirq]; + LttvNameTables *nt = ((LttvTraceState *)(s->parent.t_context))->name_tables; + submode = nt->soft_irq_names[softirq]; /* Do something with the info about being in user or system mode when int? */ push_state(s, LTTV_STATE_SOFT_IRQ, submode); @@ -2695,6 +2733,7 @@ static gboolean enum_interrupt(void *hook_data, void *call_data) { LttvTracefileState *s = (LttvTracefileState *)call_data; LttvTraceState *ts = (LttvTraceState *)s->parent.t_context; + LttvNameTables *nt = ts->name_tables; LttEvent *e = ltt_tracefile_get_event(s->parent.tf); //guint8 ev_id = ltt_event_eventtype_id(e); LttvTraceHook *th = (LttvTraceHook *)hook_data; @@ -2704,7 +2743,7 @@ static gboolean enum_interrupt(void *hook_data, void *call_data) guint irq = ltt_event_get_long_unsigned(e, lttv_trace_get_hook_field(th, 1)); expand_irq_table(ts, irq); - ts->irq_names[irq] = action; + nt->irq_names[irq] = action; return FALSE; } @@ -2843,6 +2882,7 @@ static gboolean dump_syscall(void *hook_data, void *call_data) { LttvTracefileState *s = (LttvTracefileState *)call_data; LttvTraceState *ts = (LttvTraceState*)s->parent.t_context; + LttvNameTables *nt = ts->name_tables; LttEvent *e = ltt_tracefile_get_event(s->parent.tf); LttvTraceHook *th = (LttvTraceHook *)hook_data; guint id; @@ -2854,7 +2894,7 @@ static gboolean dump_syscall(void *hook_data, void *call_data) symbol = ltt_event_get_string(e, lttv_trace_get_hook_field(th, 2)); expand_syscall_table(ts, id); - ts->syscall_names[id] = g_quark_from_string(symbol); + nt->syscall_names[id] = g_quark_from_string(symbol); return FALSE; } @@ -2880,6 +2920,7 @@ static gboolean dump_softirq(void *hook_data, void *call_data) { LttvTracefileState *s = (LttvTracefileState *)call_data; LttvTraceState *ts = (LttvTraceState*)s->parent.t_context; + LttvNameTables *nt = ts->name_tables; LttEvent *e = ltt_tracefile_get_event(s->parent.tf); LttvTraceHook *th = (LttvTraceHook *)hook_data; guint id; @@ -2891,7 +2932,31 @@ static gboolean dump_softirq(void *hook_data, void *call_data) symbol = ltt_event_get_string(e, lttv_trace_get_hook_field(th, 2)); expand_soft_irq_table(ts, id); - ts->soft_irq_names[id] = g_quark_from_string(symbol); + nt->soft_irq_names[id] = g_quark_from_string(symbol); + + return FALSE; +} + +static gboolean sched_try_wakeup(void *hook_data, void *call_data) +{ + LttvTracefileState *s = (LttvTracefileState *)call_data; + LttEvent *e = ltt_tracefile_get_event(s->parent.tf); + LttvTraceHook *th = (LttvTraceHook *)hook_data; + LttvProcessState *process; + gint woken_pid; + guint woken_cpu; + + woken_pid = ltt_event_get_int(e, lttv_trace_get_hook_field(th, 0)); + woken_cpu = ltt_event_get_unsigned(e, lttv_trace_get_hook_field(th, 1)); + + process = lttv_state_find_process_or_create( + (LttvTraceState*)s->parent.t_context, + woken_cpu, woken_pid, + &s->parent.timestamp); + process->state->s = LTTV_STATE_WAIT_CPU; + process->state->change = s->parent.timestamp; + + g_debug("Wakeup: process %d on CPU %u\n", woken_pid, woken_cpu); return FALSE; } @@ -3224,6 +3289,49 @@ static gboolean thread_brand(void *hook_data, void *call_data) return FALSE; } +static gboolean fs_open(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); + LttvTraceHook *th = (LttvTraceHook *)hook_data; + struct marker_field *f; + guint cpu = s->cpu; + int fd; + char *filename; + LttvProcessState *process = ts->running_process[cpu]; + + f = lttv_trace_get_hook_field(th, 0); + fd = ltt_event_get_int(e, f); + + f = lttv_trace_get_hook_field(th, 1); + filename = ltt_event_get_string(e, f); + + g_hash_table_insert(process->fds, (gpointer)(long)fd, + (gpointer)(unsigned long)g_quark_from_string(filename)); + + return FALSE; +} + +static void print_stack(LttvProcessState *process) +{ + LttvExecutionState *es; + int i; + + g_debug("Execution stack for process %u %s:\n", + process->pid, g_quark_to_string(process->name)); + + for (i = 0; i < process->execution_stack->len; i++) { + es = &g_array_index(process->execution_stack, + LttvExecutionState, i); + g_debug("Depth %d mode %s submode %s status %s\n", + i, g_quark_to_string(es->t), + g_quark_to_string(es->n), + g_quark_to_string(es->s)); + } + +} + static void fix_process(gpointer key, gpointer value, gpointer user_data) { @@ -3232,6 +3340,8 @@ static void fix_process(gpointer key, gpointer value, process = (LttvProcessState *)value; LttTime *timestamp = (LttTime*)user_data; + print_stack(process); + if(process->type == LTTV_STATE_KERNEL_THREAD) { es = &g_array_index(process->execution_stack, LttvExecutionState, 0); if(es->t == LTTV_STATE_MODE_UNKNOWN) { @@ -3256,21 +3366,28 @@ static void fix_process(gpointer key, gpointer value, es->s = LTTV_STATE_RUN; if(process->execution_stack->len == 1) { - /* Still in bottom unknown mode, means never did a system call + /* Still in bottom unknown mode, means we either: + * - never did a system call + * - are scheduled out from user mode. * May be either in user mode, syscall mode, running or waiting.*/ - /* FIXME : we may be tagging syscall mode when being user mode */ - process->execution_stack = - g_array_set_size(process->execution_stack, 2); - 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->cum_cpu_time = ltt_time_zero; - if(es->s == LTTV_STATE_WAIT_FORK) - es->s = LTTV_STATE_WAIT; + /* CHECK : we may be tagging syscall mode when being user mode + * (should be fixed now) */ + if (es->s == LTTV_STATE_WAIT_CPU) { + /* nothing to do: scheduled out from userspace */ + } else { + process->execution_stack = + g_array_set_size(process->execution_stack, 2); + 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->cum_cpu_time = ltt_time_zero; + if(es->s == LTTV_STATE_WAIT_FORK) + es->s = LTTV_STATE_WAIT; + } } } } @@ -3577,6 +3694,12 @@ void lttv_state_add_event_hooks(LttvTracesetState *self) LTT_FIELD_PREV_STATE), schedchange, NULL, &hooks); + lttv_trace_find_hook(ts->parent.t, + LTT_CHANNEL_KERNEL, + LTT_EVENT_SCHED_TRY_WAKEUP, + FIELD_ARRAY(LTT_FIELD_PID, LTT_FIELD_CPU_ID, LTT_FIELD_STATE), + sched_try_wakeup, NULL, &hooks); + lttv_trace_find_hook(ts->parent.t, LTT_CHANNEL_KERNEL, LTT_EVENT_PROCESS_FORK, @@ -3677,6 +3800,12 @@ void lttv_state_add_event_hooks(LttvTracesetState *self) FIELD_ARRAY(LTT_FIELD_ID, LTT_FIELD_ADDRESS, LTT_FIELD_SYMBOL), dump_softirq, NULL, &hooks); + lttv_trace_find_hook(ts->parent.t, + LTT_CHANNEL_FS, + LTT_EVENT_OPEN, + FIELD_ARRAY(LTT_FIELD_FD, LTT_FIELD_FILENAME), + fs_open, NULL, &hooks); + /* Add these hooks to each event_by_id hooks list */ nb_tracefile = ts->parent.tracefiles->len; @@ -4366,6 +4495,7 @@ static void module_init() LTT_EVENT_SOFT_IRQ_ENTRY = g_quark_from_string("softirq_entry"); LTT_EVENT_SOFT_IRQ_EXIT = g_quark_from_string("softirq_exit"); LTT_EVENT_SCHED_SCHEDULE = g_quark_from_string("sched_schedule"); + LTT_EVENT_SCHED_TRY_WAKEUP = g_quark_from_string("sched_try_wakeup"); LTT_EVENT_PROCESS_FORK = g_quark_from_string("process_fork"); LTT_EVENT_KTHREAD_CREATE = g_quark_from_string("kthread_create"); LTT_EVENT_PROCESS_EXIT = g_quark_from_string("process_exit"); @@ -4383,6 +4513,9 @@ static void module_init() LTT_EVENT_SOFTIRQ_VEC = g_quark_from_string("softirq_vec"); LTT_EVENT_KPROBE_TABLE = g_quark_from_string("kprobe_table"); LTT_EVENT_KPROBE = g_quark_from_string("kprobe"); + LTT_EVENT_OPEN = g_quark_from_string("open"); + LTT_EVENT_READ = g_quark_from_string("read"); + LTT_EVENT_POLL_EVENT = g_quark_from_string("poll_event"); LTT_FIELD_SYSCALL_ID = g_quark_from_string("syscall_id"); LTT_FIELD_TRAP_ID = g_quark_from_string("trap_id"); @@ -4412,6 +4545,9 @@ static void module_init() LTT_FIELD_ADDRESS = g_quark_from_string("address"); LTT_FIELD_SYMBOL = g_quark_from_string("symbol"); LTT_FIELD_IP = g_quark_from_string("ip"); + LTT_FIELD_FD = g_quark_from_string("fd"); + LTT_FIELD_STATE = g_quark_from_string("state"); + LTT_FIELD_CPU_ID = g_quark_from_string("cpu_id"); LTTV_CPU_UNKNOWN = g_quark_from_string("unknown"); LTTV_CPU_IDLE = g_quark_from_string("idle");