#include <ltt/type.h>
#include <stdio.h>
+#define PREALLOCATED_EXECUTION_STACK 10
+
LttvExecutionMode
LTTV_STATE_MODE_UNKNOWN,
LTTV_STATE_USER_MODE,
LTTV_STATE_WAIT_FORK,
LTTV_STATE_WAIT_CPU,
LTTV_STATE_EXIT,
+ LTTV_STATE_ZOMBIE,
LTTV_STATE_WAIT,
LTTV_STATE_RUN;
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;
}
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;
}
}
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) =
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);
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);
{
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;
}
* 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)
{
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
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);
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;
}
{
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)
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;
}
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");