X-Git-Url: http://git.lttng.org./?a=blobdiff_plain;f=ltt%2Fbranches%2Fpoly%2Flttv%2Flttv%2Fstate.c;h=dc5c9806bfcadd63270d47828e2c7c8606b97f30;hb=389ba50ee4e6f47c3e5d118ca8b62cf701e843af;hp=ec5298482d420522dca7e3359730c02714882692;hpb=41c7f80337bb477215ee93d777455ff2757ca0cb;p=lttv.git diff --git a/ltt/branches/poly/lttv/lttv/state.c b/ltt/branches/poly/lttv/lttv/state.c index ec529848..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; @@ -96,21 +99,26 @@ void lttv_state_state_saved_free(LttvTraceState *self, guint process_hash(gconstpointer key) { - return ((const 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) { 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; } @@ -135,6 +143,7 @@ restore_init_state(LttvTraceState *self) 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; } } @@ -320,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) = @@ -775,6 +784,7 @@ lttv_state_create_process(LttvTracefileState *tfs, LttvProcessState *parent, 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); @@ -799,8 +809,9 @@ 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); @@ -833,7 +844,7 @@ 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; } @@ -843,9 +854,6 @@ lttv_state_find_process_or_create(LttvTracefileState *tfs, guint pid) * 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. - * - * This function is important : it removes the dead PID entry in the hash - * table so there is no collision when the OS reuses PID. */ static void exit_process(LttvTracefileState *tfs, LttvProcessState *process) { @@ -960,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 @@ -968,18 +976,19 @@ 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(s->process->state->s != LTTV_STATE_EXIT) { - if(state_out == 0) s->process->state->s = LTTV_STATE_WAIT_CPU; + 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. We should rename STATE_EXIT - * for STATE_ZOMBIE. + * know when the zombie is destroyed. */ //else // exit_process(s, s->process); @@ -989,6 +998,7 @@ static gboolean schedchange(void *hook_data, void *call_data) 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; } @@ -998,43 +1008,55 @@ static gboolean process_fork(LttvTraceHook *trace_hook, LttvTracefileState *s) { LttField *f; guint child_pid; + LttvProcessState *zombie_process; /* Child PID */ f = trace_hook->f2; child_pid = ltt_event_get_unsigned(s->parent.e, f); - lttv_state_create_process(s, s->process, child_pid); - - return FALSE; -#if 0 - LttField *f = ((LttvTraceHook *)hook_data)->f1; - - LttvTracefileState *s = (LttvTracefileState *)call_data; - - guint child_pid; + zombie_process = lttv_state_find_process(s, child_pid); - child_pid = ltt_event_get_unsigned(s->parent.e, f); + 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; -#endif //0 } static gboolean process_exit(LttvTraceHook *trace_hook, LttvTracefileState *s) { - if(s->process != NULL) { + if(likely(s->process != NULL)) { s->process->state->s = LTTV_STATE_EXIT; } return FALSE; - -#if 0 - LttvTracefileState *s = (LttvTracefileState *)call_data; +} - if(s->process != NULL) { - s->process->state->s = LTTV_STATE_EXIT; +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; -#endif //0 } gboolean process(void *hook_data, void *call_data) @@ -1051,6 +1073,8 @@ gboolean process(void *hook_data, void *call_data) 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; } @@ -1587,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");