X-Git-Url: http://git.lttng.org./?a=blobdiff_plain;f=ltt%2Fbranches%2Fpoly%2Flttv%2Flttv%2Fstate.c;h=dc5c9806bfcadd63270d47828e2c7c8606b97f30;hb=389ba50ee4e6f47c3e5d118ca8b62cf701e843af;hp=0624fe4b01e17ed3b9180162c15763f6bc54fa1b;hpb=d8f124de0295aea546b6debf5945bfeea2bbeb2a;p=lttv.git diff --git a/ltt/branches/poly/lttv/lttv/state.c b/ltt/branches/poly/lttv/lttv/state.c index 0624fe4b..dc5c9806 100644 --- a/ltt/branches/poly/lttv/lttv/state.c +++ b/ltt/branches/poly/lttv/lttv/state.c @@ -26,6 +26,8 @@ #include #include +#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; @@ -87,7 +90,7 @@ void lttv_state_restore(LttvTraceState *self, LttvAttribute *container) } -void lttv_state__state_saved_free(LttvTraceState *self, +void lttv_state_state_saved_free(LttvTraceState *self, LttvAttribute *container) { LTTV_TRACE_STATE_GET_CLASS(self)->state_saved_free(self, container); @@ -96,21 +99,26 @@ 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) ; } +/* If the hash table hash function is well distributed, + * the process_equal should compare different pid */ gboolean process_equal(gconstpointer a, gconstpointer b) { - LttvProcessState *process_a, *process_b; - - process_a = (LttvProcessState *)a; - process_b = (LttvProcessState *)b; + const LttvProcessState *process_a, *process_b; + gboolean ret = TRUE; + + process_a = (const LttvProcessState *)a; + process_b = (const LttvProcessState *)b; + + if(likely(process_a->pid != process_b->pid)) ret = FALSE; + else if(likely(process_a->pid == 0 && + process_a->last_cpu != process_b->last_cpu)) ret = FALSE; - if(process_a->pid != process_b->pid) return FALSE; - if(process_a->pid == 0 && - process_a->last_cpu != process_b->last_cpu) return FALSE; - return TRUE; + return ret; } @@ -121,8 +129,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 +138,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 +197,7 @@ init(LttvTracesetState *self, LttvTraceset *ts) static void fini(LttvTracesetState *self) { - guint i, j, nb_trace; + guint i, nb_trace; LttvTraceState *tcs; @@ -203,9 +210,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 +329,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,9 +456,8 @@ static void state_restore(LttvTraceState *self, LttvAttribute *container) if(*(value.v_pointer) == NULL) tfcs->parent.e = NULL; else { ep = *(value.v_pointer); - ltt_tracefile_seek_position(tfcs->parent.tf, ep); - tfcs->parent.e = ltt_tracefile_read(tfcs->parent.tf); - tfcs->parent.timestamp = ltt_event_time(tfcs->parent.e); + g_assert(tfcs->parent.t_context != NULL); + lttv_process_tracefile_seek_position(LTTV_TRACEFILE_CONTEXT(tfcs), ep); } } } @@ -474,6 +481,7 @@ static void state_saved_free(LttvTraceState *self, LttvAttribute *container) tracefiles_tree = lttv_attribute_find_subdir(container, LTTV_STATE_TRACEFILES); + g_object_ref(G_OBJECT(tracefiles_tree)); lttv_attribute_remove_by_name(container, LTTV_STATE_TRACEFILES); type = lttv_attribute_get_by_name(container, LTTV_STATE_PROCESSES, @@ -497,7 +505,7 @@ static void state_saved_free(LttvTraceState *self, LttvAttribute *container) g_assert(type == LTTV_POINTER); if(*(value.v_pointer) != NULL) g_free(*(value.v_pointer)); } - lttv_attribute_recursive_free(tracefiles_tree); + g_object_unref(G_OBJECT(tracefiles_tree)); } @@ -524,7 +532,6 @@ static void free_saved_state(LttvTraceState *self) } lttv_attribute_remove_by_name(self->parent.t_a, LTTV_STATE_SAVED_STATES); - lttv_attribute_recursive_free(saved_states); } @@ -732,7 +739,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), @@ -746,7 +753,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; } @@ -772,10 +779,12 @@ lttv_state_create_process(LttvTracefileState *tfs, LttvProcessState *parent, char buffer[128]; - tcs = ((LttvTraceState *)tc = tfs->parent.t_context); + tc = tfs->parent.t_context; + tcs = (LttvTraceState *)tc; 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); @@ -800,52 +809,52 @@ 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) { LttvProcessState *process = lttv_state_find_process(tfs, pid); - if(process == NULL) process = lttv_state_create_process(tfs, NULL, pid); + if(unlikely(process == NULL)) process = lttv_state_create_process(tfs, NULL, 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); @@ -959,7 +968,7 @@ static gboolean schedchange(void *hook_data, void *call_data) pid_out = ltt_event_get_unsigned(s->parent.e, h->f2); state_out = ltt_event_get_unsigned(s->parent.e, h->f3); - if(s->process != NULL) { + if(likely(s->process != NULL)) { /* We could not know but it was not the idle process executing. This should only happen at the beginning, before the first schedule @@ -967,49 +976,117 @@ static gboolean schedchange(void *hook_data, void *call_data) is missing. It is not obvious how we could, after the fact, compensate the wrongly attributed statistics. */ - if(s->process->pid != pid_out) { + if(unlikely(s->process->pid != pid_out)) { 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(unlikely(s->process->state->s == LTTV_STATE_EXIT)) { + s->process->state->s = LTTV_STATE_ZOMBIE; + } else { + if(unlikely(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(unlikely(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) { + if(likely(s->process != NULL)) { s->process->state->s = LTTV_STATE_EXIT; } return FALSE; } +static gboolean process_release(LttvTraceHook *trace_hook, + LttvTracefileState *s) +{ + LttField *f; + guint release_pid; + LttvProcessState *process; + + /* PID of the process to release */ + f = trace_hook->f2; + release_pid = ltt_event_get_unsigned(s->parent.e, f); + + process = lttv_state_find_process(s, release_pid); + + if(likely(process != NULL)) { + /* release_task is happening at kernel level : we can now safely release + * the data structure of the process */ + exit_process(s, process); + } + + 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); + } else if(sub_id == 7) { + return process_release(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) { @@ -1035,7 +1112,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)); @@ -1058,13 +1135,18 @@ 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)); - - /* Add these hooks to each before_event_by_id hooks list */ +#endif //0 + /* Add these hooks to each event_by_id hooks list */ nb_tracefile = ltt_trace_control_tracefile_number(ts->parent.t) + ltt_trace_per_cpu_tracefile_number(ts->parent.t); @@ -1074,8 +1156,8 @@ void lttv_state_add_event_hooks(LttvTracesetState *self) for(k = 0 ; k < hooks->len ; k++) { hook = g_array_index(hooks, LttvTraceHook, k); - lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.after_event_by_id, - hook.id), hook.h, &g_array_index(hooks, LttvTraceHook, k)); + lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id, + hook.id), hook.h, &g_array_index(hooks, LttvTraceHook, k), LTTV_PRIO_STATE); } } lttv_attribute_find(self->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val); @@ -1083,6 +1165,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) { @@ -1106,7 +1196,7 @@ void lttv_state_remove_event_hooks(LttvTracesetState *self) lttv_attribute_find(self->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val); hooks = *(val.v_pointer); - /* Add these hooks to each before_event_by_id hooks list */ + /* Remove these hooks from each event_by_id hooks list */ nb_tracefile = ltt_trace_control_tracefile_number(ts->parent.t) + ltt_trace_per_cpu_tracefile_number(ts->parent.t); @@ -1117,7 +1207,7 @@ void lttv_state_remove_event_hooks(LttvTracesetState *self) for(k = 0 ; k < hooks->len ; k++) { hook = g_array_index(hooks, LttvTraceHook, k); lttv_hooks_remove_data( - lttv_hooks_by_id_find(tfs->parent.after_event_by_id, + lttv_hooks_by_id_find(tfs->parent.event_by_id, hook.id), hook.h, &g_array_index(hooks, LttvTraceHook, k)); } } @@ -1198,6 +1288,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; } @@ -1205,7 +1297,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; @@ -1226,20 +1318,29 @@ void lttv_state_save_add_event_hooks(LttvTracesetState *self) for(j = 0 ; j < nb_tracefile ; j++) { tfs = LTTV_TRACEFILE_STATE(ts->parent.tracefiles[j]); - lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.after_event_by_id, - hook_start.id), hook_start.h, NULL); - lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.after_event_by_id, - hook_end.id), hook_end.h, NULL); + lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id, + hook_start.id), hook_start.h, NULL, LTTV_PRIO_STATE); + lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id, + hook_end.id), hook_end.h, NULL, LTTV_PRIO_STATE); } } } +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; @@ -1262,19 +1363,27 @@ void lttv_state_save_remove_event_hooks(LttvTracesetState *self) for(j = 0 ; j < nb_tracefile ; j++) { tfs = LTTV_TRACEFILE_STATE(ts->parent.tracefiles[j]); lttv_hooks_remove_data(lttv_hooks_by_id_find( - tfs->parent.after_event_by_id, hook_start.id), hook_start.h, NULL); + tfs->parent.event_by_id, hook_start.id), hook_start.h, NULL); lttv_hooks_remove_data(lttv_hooks_by_id_find( - tfs->parent.after_event_by_id, hook_end.id), hook_end.h, NULL); + tfs->parent.event_by_id, hook_end.id), hook_end.h, NULL); } } } +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; @@ -1379,7 +1488,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", @@ -1429,7 +1539,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, @@ -1476,7 +1587,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, @@ -1499,6 +1611,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");