<facility name=statedump>
<description>The statedump facility contains the events generated at trace startup</description>
+ <type name=execution_mode>
+ <enum>
+ <label name=USER_MODE value=0/> <description>Task is executing user code</description>
+ <label name=SYSCALL value=1/> <description>Task is in a system call</description>
+ <label name=TRAP value=2/> <description>Task is in a trap</description>
+ <label name=IRQ value=3/> <description></description>
+ <label name=SOFTIRQ value=4/> <description></description>
+ <label name=MODE_UNKNOWN value=5/> <description>Execution mode cannot be determined for this task</description>
+ </enum>
+ </type>
+
+ <type name=execution_submode>
+ <enum>
+ <label name=NONE value=0/> <description>No execution submode to report</description>
+ <label name=UNKNOWN value=1/> <description>Task execution submode cannot be determined</description>
+ </enum>
+ </type>
+
+ <type name=process_status>
+ <enum>
+ <label name=UNNAMED value=0/> <description></description>
+ <label name=WAIT_FORK value=1/> <description></description>
+ <label name=WAIT_CPU value=2/> <description></description>
+ <label name=EXIT value=3/> <description></description>
+ <label name=ZOMBIE value=4/> <description></description>
+ <label name=WAIT value=5/> <description></description>
+ <label name=RUN value=6/> <description></description>
+ <label name=DEAD value=7/> <description></description>
+ </enum>
+ </type>
+
<event name=enumerate_file_descriptors>
<description>List of open file descriptors</description>
<field name="name"><description>File name</description><string/></field>
<event name=enumerate_vm_maps>
<description>List of active vm maps</description>
+ <field name="PID"><description>Process identifier</description><uint size=4/></field>
<field name="start"> <description>VM's start address</description> <pointer/> </field>
<field name="end"> <description>VM's end address</description> <pointer/> </field>
<field name="flags"> <description>VM area flags</description> <uint size=1/> </field>
<field name="num"> <description>Interrupt number</description> <uint size=4/> </field>
</event>
+ <event name=enumerate_process_state>
+ <description>State of each process when statedump is performed</description>
+ <field name="pid"><description>Process identifier</description><uint size=4/></field>
+ <field name="parent_pid"><description>Parent process identifier</description><uint size=4/></field>
+ <field name="name"> <description>Process name</description><string/></field>
+ <field name="mode"> <description>Execution mode</description> <typeref name=execution_mode/> </field>
+ <field name="submode"> <description>Execution submode</description> <typeref name=execution_submode/> </field>
+ <field name="status"> <description>Process status</description> <typeref name=process_status/> </field>
+ </event>
+
<event name=statedump_end>
<description>Kernel state dump complete</description>
</event>
#include <ltt/event.h>
#include <ltt/type.h>
#include <stdio.h>
+#include <string.h>
#define PREALLOCATED_EXECUTION_STACK 10
LTT_FACILITY_KERNEL,
LTT_FACILITY_KERNEL_ARCH,
LTT_FACILITY_PROCESS,
- LTT_FACILITY_FS;
+ LTT_FACILITY_FS,
+ LTT_FACILITY_STATEDUMP;
/* Events Quarks */
LTT_EVENT_FORK,
LTT_EVENT_EXIT,
LTT_EVENT_FREE,
- LTT_EVENT_EXEC;
+ LTT_EVENT_EXEC,
+ LTT_EVENT_ENUM_PROCESS_STATE;
/* Fields Quarks */
LTT_FIELD_PARENT_PID,
LTT_FIELD_CHILD_PID,
LTT_FIELD_PID,
- LTT_FIELD_FILENAME;
+ LTT_FIELD_FILENAME,
+ LTT_FIELD_NAME,
+ LTT_FIELD_MODE,
+ LTT_FIELD_SUBMODE,
+ LTT_FIELD_STATUS;
LttvExecutionMode
LTTV_STATE_MODE_UNKNOWN,
/* Put the per cpu running_process to beginning state : process 0. */
for(i=0; i< nb_cpus; i++) {
self->running_process[i] = lttv_state_create_process(self, NULL, i, 0,
- <t_time_zero);
+ LTTV_STATE_UNNAMED, <t_time_zero);
self->running_process[i]->state->s = LTTV_STATE_RUN;
self->running_process[i]->cpu = i;
}
LttvProcessState *
lttv_state_create_process(LttvTraceState *tcs, LttvProcessState *parent,
- guint cpu, guint pid, const LttTime *timestamp)
+ guint cpu, guint pid, GQuark name, const LttTime *timestamp)
{
LttvProcessState *process = g_new(LttvProcessState, 1);
process->pid = pid;
process->cpu = cpu;
+ process->name = name;
//process->last_cpu = tfs->cpu_name;
//process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
g_info("Process %u, core %p", process->pid, process);
if(parent) {
process->ppid = parent->pid;
- process->name = parent->name;
process->creation_time = *timestamp;
}
else {
process->ppid = 0;
- process->name = LTTV_STATE_UNNAMED;
process->creation_time = ltt_time_zero;
}
/* Put ltt_time_zero creation time for unexisting processes */
if(unlikely(process == NULL)) process = lttv_state_create_process(ts,
- NULL, cpu, pid, timestamp);
+ NULL, cpu, pid, LTTV_STATE_UNNAMED, timestamp);
return process;
}
LttvTracefileState *s = (LttvTracefileState *)call_data;
LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
- LttField *f;
guint parent_pid;
guint child_pid;
LttvProcessState *zombie_process;
LttvProcessState *child_process;
/* Parent PID */
- f = thf->f1;
- parent_pid = ltt_event_get_unsigned(e, f);
+ parent_pid = ltt_event_get_unsigned(e, thf->f1);
/* Child PID */
- f = thf->f2;
- child_pid = ltt_event_get_unsigned(e, f);
+ child_pid = ltt_event_get_unsigned(e, thf->f2);
/* 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
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);
+ child_pid, LTTV_STATE_UNNAMED, &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
return FALSE;
}
+static gboolean enum_process_state(void *hook_data, void *call_data)
+{
+ LttvTracefileState *s = (LttvTracefileState *)call_data;
+ LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
+ //It's slow : optimise later by doing this before reading trace.
+ LttEventType *et = ltt_event_eventtype(e);
+ //
+ LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
+ guint parent_pid;
+ guint pid;
+ gchar * command;
+ guint cpu = ltt_tracefile_num(s->parent.tf);
+ LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
+ LttvProcessState *process = ts->running_process[cpu];
+ LttvProcessState *parent_process;
+ LttField *f4, *f5, *f6;
+ GQuark mode, submode, status;
+ /* PID */
+ pid = ltt_event_get_unsigned(e, thf->f1);
+ /* Parent PID */
+ parent_pid = ltt_event_get_unsigned(e, thf->f2);
+
+ /* Command name */
+ command = ltt_event_get_string(e, thf->f3);
+
+ /* mode */
+ f4 = ltt_eventtype_field_by_name(et, LTT_FIELD_MODE);
+ mode = ltt_enum_string_get(ltt_field_type(f4),
+ ltt_event_get_unsigned(e, f4));
+
+ /* submode */
+ f5 = ltt_eventtype_field_by_name(et, LTT_FIELD_SUBMODE);
+ submode = ltt_enum_string_get(ltt_field_type(f5),
+ ltt_event_get_unsigned(e, f5));
+
+ /* status */
+ f6 = ltt_eventtype_field_by_name(et, LTT_FIELD_STATUS);
+ status = ltt_enum_string_get(ltt_field_type(f6),
+ ltt_event_get_unsigned(e, f6));
+
+ /* The process might exist if a process was forked while performing the sate dump. */
+ process = lttv_state_find_process(ts, ANY_CPU, pid);
+ if(process == NULL) {
+ parent_process = lttv_state_find_process(ts, ANY_CPU, parent_pid);
+ process = lttv_state_create_process(ts, parent_process, cpu,
+ pid, g_quark_from_string(command),
+ &s->parent.timestamp);
+
+ /* Keep the stack bottom : a running user mode */
+
+ if(mode == LTTV_STATE_USER_MODE) {
+ /* Only keep the bottom */
+ process->execution_stack = g_array_set_size(process->execution_stack, 1);
+ } else {
+ /* On top of it : */
+ LttvExecutionState *es;
+ es = process->state = &g_array_index(process->execution_stack,
+ LttvExecutionState, 1);
+ es->t = mode;
+ es->s = status;
+ es->n = submode;
+ }
+
+ } else {
+ /* The process has already been created :
+ * Probably was forked while dumping the process state or
+ * was simply scheduled in prior to get the state dump event.
+ */
+ process->ppid = parent_pid;
+ process->name = g_quark_from_string(command);
+ /* Don't mess around with the stack, it will eventually become
+ * ok after the end of state dump. */
+ }
+
+ return FALSE;
+}
gint lttv_state_hook_add_event_hooks(void *hook_data, void *call_data)
{
/* Find the eventtype id for the following events and register the
associated by id hooks. */
- hooks = g_array_sized_new(FALSE, FALSE, sizeof(LttvTraceHook), 13);
- hooks = g_array_set_size(hooks, 13);
+ hooks = g_array_sized_new(FALSE, FALSE, sizeof(LttvTraceHook), 14);
+ hooks = g_array_set_size(hooks, 14);
ret = lttv_trace_find_hook(ts->parent.t,
LTT_FACILITY_KERNEL_ARCH, LTT_EVENT_SYSCALL_ENTRY,
process_exec, NULL, &g_array_index(hooks, LttvTraceHook, 12));
g_assert(!ret);
+ /* statedump-related hooks */
+ ret = lttv_trace_find_hook(ts->parent.t,
+ LTT_FACILITY_STATEDUMP, LTT_EVENT_ENUM_PROCESS_STATE,
+ LTT_FIELD_PID, LTT_FIELD_PARENT_PID, LTT_FIELD_NAME,
+ enum_process_state, NULL, &g_array_index(hooks, LttvTraceHook, 13));
+ g_assert(!ret);
-
+
/* Add these hooks to each event_by_id hooks list */
nb_tracefile = ts->parent.tracefiles->len;
static void module_init()
{
LTTV_STATE_UNNAMED = g_quark_from_string("unnamed");
- LTTV_STATE_MODE_UNKNOWN = g_quark_from_string("unknown execution mode");
- LTTV_STATE_USER_MODE = g_quark_from_string("user mode");
- LTTV_STATE_WAIT_FORK = g_quark_from_string("wait fork");
- 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_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_DEAD = g_quark_from_string("dead");
+ LTTV_STATE_MODE_UNKNOWN = g_quark_from_string("MODE_UNKNOWN");
+ LTTV_STATE_USER_MODE = g_quark_from_string("USER_MODE");
+ LTTV_STATE_SYSCALL = g_quark_from_string("SYSCALL");
+ 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");
+ LTTV_STATE_SUBMODE_NONE = g_quark_from_string("NONE");
+ LTTV_STATE_WAIT_FORK = g_quark_from_string("WAIT_FORK");
+ LTTV_STATE_WAIT_CPU = g_quark_from_string("WAIT_CPU");
+ LTTV_STATE_EXIT = g_quark_from_string("EXIT");
+ LTTV_STATE_ZOMBIE = g_quark_from_string("ZOMBIE");
+ LTTV_STATE_WAIT = g_quark_from_string("WAIT");
+ LTTV_STATE_RUN = g_quark_from_string("RUN");
+ 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_ARCH = g_quark_from_string("kernel_arch");
LTT_FACILITY_PROCESS = g_quark_from_string("process");
LTT_FACILITY_FS = g_quark_from_string("fs");
+ LTT_FACILITY_STATEDUMP = g_quark_from_string("statedump");
LTT_EVENT_SYSCALL_ENTRY = g_quark_from_string("syscall_entry");
LTT_EVENT_EXIT = g_quark_from_string("exit");
LTT_EVENT_FREE = g_quark_from_string("free");
LTT_EVENT_EXEC = g_quark_from_string("exec");
+ LTT_EVENT_ENUM_PROCESS_STATE = g_quark_from_string("enumerate_process_state");
LTT_FIELD_SYSCALL_ID = g_quark_from_string("syscall_id");
LTT_FIELD_CHILD_PID = g_quark_from_string("child_pid");
LTT_FIELD_PID = g_quark_from_string("pid");
LTT_FIELD_FILENAME = g_quark_from_string("filename");
+ LTT_FIELD_NAME = g_quark_from_string("name");
+ LTT_FIELD_MODE = g_quark_from_string("mode");
+ LTT_FIELD_SUBMODE = g_quark_from_string("submode");
+ LTT_FIELD_STATUS = g_quark_from_string("status");
}
prop_line.color = drawing_colors[COL_EXIT];
} else if(process->state->s == LTTV_STATE_UNNAMED) {
prop_line.color = drawing_colors[COL_UNNAMED];
- } else
+ } else {
+ g_critical("unknown state : %s", g_quark_to_string(process->state->s));
g_assert(FALSE); /* UNKNOWN STATE */
+ }
return prop_line;
}
+/* after_event_enum_process_hook
+ *
+ * DOES EXACTLY THE SAME AS after_schedchange_hook, for the "in" process.
+ * Create the processlist entry for the child process. Put the last
+ * position in x at the current time value.
+ *
+ * @param hook_data ControlFlowData structure of the viewer.
+ * @param call_data Event context.
+ *
+ * This function adds items to be drawn in a queue for each process.
+ *
+ */
+int after_event_enum_process_hook(void *hook_data, void *call_data)
+{
+ LttvTraceHookByFacility *thf = (LttvTraceHookByFacility*)hook_data;
+ EventsRequest *events_request = (EventsRequest*)thf->hook_data;
+ ControlFlowData *control_flow_data = events_request->viewer_data;
+
+ LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
+
+ LttvTracefileState *tfs = (LttvTracefileState *)call_data;
+
+ LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
+
+ LttEvent *e;
+ e = ltt_tracefile_get_event(tfc->tf);
+
+ LttTime evtime = ltt_event_time(e);
+
+ /* Add process to process list (if not present) */
+ LttvProcessState *process_in;
+ LttTime birth;
+ guint pl_height = 0;
+ HashedProcessData *hashed_process_data_in = NULL;
+
+ ProcessList *process_list = control_flow_data->process_list;
+
+ guint pid_in;
+ {
+ pid_in = ltt_event_get_long_unsigned(e, thf->f1);
+ }
+
+
+ /* Find process pid_in in the list... */
+ process_in = lttv_state_find_process(ts, ANY_CPU, pid_in);
+ //process_in = tfs->process;
+ //guint cpu = ltt_tracefile_num(tfc->tf);
+ //process_in = ts->running_process[cpu];
+ /* It should exist, because we are after the state update. */
+#ifdef EXTRA_CHECK
+ //g_assert(process_in != NULL);
+#endif //EXTRA_CHECK
+ birth = process_in->creation_time;
+
+ hashed_process_data_in = processlist_get_process_data(process_list,
+ pid_in,
+ process_in->cpu,
+ &birth,
+ tfc->t_context->index);
+ if(hashed_process_data_in == NULL)
+ {
+ if(pid_in != 0 && pid_in == process_in->ppid)
+ g_critical("TEST %u , %u", pid_in, process_in->ppid);
+ g_assert(pid_in == 0 || pid_in != process_in->ppid);
+ ProcessInfo *process_info;
+ Drawing_t *drawing = control_flow_data->drawing;
+ /* Process not present */
+ processlist_add(process_list,
+ drawing,
+ pid_in,
+ process_in->cpu,
+ process_in->ppid,
+ &birth,
+ tfc->t_context->index,
+ process_in->name,
+ &pl_height,
+ &process_info,
+ &hashed_process_data_in);
+ gtk_widget_set_size_request(drawing->drawing_area,
+ -1,
+ pl_height);
+ gtk_widget_queue_draw(drawing->drawing_area);
+ }
+ /* Set the current process */
+ process_list->current_hash_data[process_in->cpu] =
+ hashed_process_data_in;
+
+ if(ltt_time_compare(hashed_process_data_in->next_good_time,
+ evtime) <= 0)
+ {
+ TimeWindow time_window =
+ lttvwindow_get_time_window(control_flow_data->tab);
+
+#ifdef EXTRA_CHECK
+ if(ltt_time_compare(evtime, time_window.start_time) == -1
+ || ltt_time_compare(evtime, time_window.end_time) == 1)
+ return;
+#endif //EXTRA_CHECK
+ Drawing_t *drawing = control_flow_data->drawing;
+ guint width = drawing->width;
+ guint new_x;
+
+ convert_time_to_pixels(
+ time_window,
+ evtime,
+ width,
+ &new_x);
+ if(hashed_process_data_in->x.middle != new_x) {
+ hashed_process_data_in->x.middle = new_x;
+ hashed_process_data_in->x.middle_used = FALSE;
+ hashed_process_data_in->x.middle_marked = FALSE;
+ }
+ }
+ return 0;
+}
gint update_time_window_hook(void *hook_data, void *call_data)