#include <ltt/marker-desc.h>
#include <stdio.h>
#include <string.h>
+#include <ltt/ltt-private.h>
/* Comment :
* Mathieu Desnoyers
LTT_FACILITY_LIST,
LTT_FACILITY_FS,
LTT_FACILITY_USER_GENERIC,
- LTT_FACILITY_BLOCK;
+ LTT_FACILITY_BLOCK,
+ LTT_FACILITY_STATEDUMP;
/* Events Quarks */
LTT_EVENT_TRAP_EXIT,
LTT_EVENT_IRQ_ENTRY,
LTT_EVENT_IRQ_EXIT,
+ LTT_EVENT_SOFT_IRQ_RAISE,
LTT_EVENT_SOFT_IRQ_ENTRY,
LTT_EVENT_SOFT_IRQ_EXIT,
LTT_EVENT_SCHED_SCHEDULE,
LTT_EVENT_THREAD_BRAND,
LTT_EVENT_REQUEST_ISSUE,
LTT_EVENT_REQUEST_COMPLETE,
- LTT_EVENT_LIST_INTERRUPT;
+ LTT_EVENT_LIST_INTERRUPT,
+ LTT_EVENT_SYS_CALL_TABLE,
+ LTT_EVENT_SOFTIRQ_VEC;
/* Fields Quarks */
LTT_FIELD_MINOR,
LTT_FIELD_MAJOR,
LTT_FIELD_OPERATION,
- LTT_FIELD_ACTION;
+ LTT_FIELD_ACTION,
+ LTT_FIELD_ID,
+ LTT_FIELD_ADDRESS,
+ LTT_FIELD_SYMBOL;
LttvExecutionMode
LTTV_STATE_MODE_UNKNOWN,
return TRUE;
}
+static guint check_expand(nb, id)
+{
+ if(likely(nb > id))
+ return nb;
+ else
+ return max(id + 1, nb * 2);
+}
+
+static void expand_name_table(LttvTraceState *ts, GQuark **table,
+ guint nb, guint new_nb)
+{
+ /* Expand an incomplete table */
+ GQuark *old_table = *table;
+ *table = g_new(GQuark, new_nb);
+ memcpy(*table, old_table, nb * sizeof(GQuark));
+}
+
+static void fill_name_table(LttvTraceState *ts, GQuark *table, guint nb,
+ guint new_nb, const char *def_string)
+{
+ guint i;
+ GString *fe_name = g_string_new("");
+ for(i = nb; i < new_nb; i++) {
+ g_string_printf(fe_name, "%s %d", def_string, i);
+ table[i] = g_quark_from_string(fe_name->str);
+ }
+ g_string_free(fe_name, TRUE);
+}
+
+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))
+ 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");
+ /* Update the table size */
+ ts->nb_syscalls = new_nb;
+}
+
+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))
+ 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;
+ 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++)
+ ts->trap_states[i].running = 0;
+}
+
+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))
+ 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;
+ 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));
+ }
+
+ /* Update the table size */
+ ts->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))
+ 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;
+ 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++)
+ ts->soft_irq_states[i].running = 0;
+
+ /* Update the table size */
+ ts->nb_soft_irqs = new_nb;
+}
+
static void
restore_init_state(LttvTraceState *self)
{
/* reset softirq states */
for(i=0; i<nb_soft_irqs; i++) {
+ self->soft_irq_states[i].pending = 0;
self->soft_irq_states[i].running = 0;
}
guint i,j;
LttvCPUState *retval;
- retval = g_malloc(n*sizeof(LttvCPUState));
+ retval = g_new(LttvCPUState, n);
for(i=0; i<n; i++) {
retval[i].mode_stack = g_array_new(FALSE, FALSE, sizeof(LttvCPUMode));
guint i,j;
LttvIRQState *retval;
- retval = g_malloc(n*sizeof(LttvIRQState));
+ retval = g_new(LttvIRQState, n);
for(i=0; i<n; i++) {
retval[i].mode_stack = g_array_new(FALSE, FALSE, sizeof(LttvIRQMode));
guint i;
LttvSoftIRQState *retval;
- retval = g_malloc(n*sizeof(LttvSoftIRQState));
+ retval = g_new(LttvSoftIRQState, n);
for(i=0; i<n; i++) {
+ retval[i].pending = states[i].pending;
retval[i].running = states[i].running;
}
guint i;
LttvTrapState *retval;
- retval = g_malloc(n*sizeof(LttvTrapState));
+ retval = g_new(LttvTrapState, n);
for(i=0; i<n; i++) {
retval[i].running = states[i].running;
gint devcode_gint = devcode;
gpointer bdev = g_hash_table_lookup(ts->bdev_states, &devcode_gint);
if(bdev == NULL) {
- LttvBdevState *bdevstate = g_malloc(sizeof(LttvBdevState));
+ LttvBdevState *bdevstate = g_new(LttvBdevState, 1);
bdevstate->mode_stack = g_array_new(FALSE, FALSE, sizeof(GQuark));
- gint * key = g_malloc(sizeof(gint));
+ gint * key = g_new(gint, 1);
*key = devcode;
g_hash_table_insert(ts->bdev_states, key, bdevstate);
static LttvBdevState *bdevstate_new(void)
{
LttvBdevState *retval;
- retval = g_malloc(sizeof(LttvBdevState));
+ retval = g_new(LttvBdevState, 1);
retval->mode_stack = g_array_new(FALSE, FALSE, sizeof(GQuark));
return retval;
static void state_saved_free(LttvTraceState *self, LttvAttribute *container)
{
- guint i, nb_tracefile, nb_cpus, nb_irqs;
+ guint i, nb_tracefile, nb_cpus, nb_irqs, nb_softirqs;
LttvTracefileState *tfcs;
g_assert(type == LTTV_POINTER);
lttv_state_free_irq_states(*(value.v_pointer), nb_irqs);
+ /* free softirq resource states */
+ nb_softirqs = self->nb_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);
+
/* free the blkdev states */
type = lttv_attribute_get_by_name(container, LTTV_STATE_RESOURCE_BLKDEVS, &value);
g_assert(type == LTTV_POINTER);
* has the flag SA_NOCLDWAIT. It can also happen when the child is part
* of a killed thread group, but isn't the leader.
*/
-static void exit_process(LttvTracefileState *tfs, LttvProcessState *process)
+static int exit_process(LttvTracefileState *tfs, LttvProcessState *process)
{
LttvTraceState *ts = LTTV_TRACE_STATE(tfs->parent.t_context);
LttvProcessState key;
+ /* Wait for both schedule with exit dead and process free to happen.
+ * They can happen in any order. */
+ if (++(process->free_events) < 2)
+ return 0;
+
key.pid = process->pid;
key.cpu = process->cpu;
g_hash_table_remove(ts->processes, &key);
g_array_free(process->execution_stack, TRUE);
g_array_free(process->user_stack, TRUE);
g_free(process);
+ return 1;
}
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);
-
LttvExecutionSubmode submode;
- guint nb_syscalls = ((LttvTraceState *)(s->parent.t_context))->nb_syscalls;
guint syscall = ltt_event_get_unsigned(e, f);
-
- if(syscall < nb_syscalls) {
- submode = ((LttvTraceState *)(s->parent.t_context))->syscall_names[
- syscall];
- } else {
- /* Fixup an incomplete syscall table */
- GString *string = g_string_new("");
- g_string_printf(string, "syscall %u", syscall);
- submode = g_quark_from_string(string->str);
- g_string_free(string, TRUE);
- }
+ expand_syscall_table(ts, syscall);
+ submode = ((LttvTraceState *)(s->parent.t_context))->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);
LttvExecutionSubmode submode;
- guint64 nb_traps = ((LttvTraceState *)(s->parent.t_context))->nb_traps;
guint64 trap = ltt_event_get_long_unsigned(e, f);
- if(trap < nb_traps) {
- submode = ((LttvTraceState *)(s->parent.t_context))->trap_names[trap];
- } else {
- /* Fixup an incomplete trap table */
- GString *string = g_string_new("");
- g_string_printf(string, "trap %llu", trap);
- submode = g_quark_from_string(string->str);
- g_string_free(string, TRUE);
- }
+ expand_trap_table(ts, trap);
+
+ submode = ((LttvTraceState *)(s->parent.t_context))->trap_names[trap];
push_state(s, LTTV_STATE_TRAP, submode);
LttvExecutionSubmode submode;
guint64 irq = ltt_event_get_long_unsigned(e, f);
- guint64 nb_irqs = ((LttvTraceState *)(s->parent.t_context))->nb_irqs;
- if(irq < nb_irqs) {
- submode = ((LttvTraceState *)(s->parent.t_context))->irq_names[irq];
- } else {
- /* Fixup an incomplete irq table */
- GString *string = g_string_new("");
- g_string_printf(string, "irq %llu", irq);
- submode = g_quark_from_string(string->str);
- g_string_free(string, TRUE);
- }
+ expand_irq_table(ts, irq);
+
+ submode = ((LttvTraceState *)(s->parent.t_context))->irq_names[irq];
/* Do something with the info about being in user or system mode when int? */
push_state(s, LTTV_STATE_IRQ, submode);
return FALSE;
}
-static gboolean soft_irq_entry(void *hook_data, void *call_data)
+static gboolean soft_irq_raise(void *hook_data, void *call_data)
{
LttvTracefileState *s = (LttvTracefileState *)call_data;
LttvTraceState *ts = (LttvTraceState *)s->parent.t_context;
g_string_free(string, TRUE);
}
+ /* update softirq status */
+ ts->soft_irq_states[softirq].pending++;
+
+ return FALSE;
+}
+
+static gboolean soft_irq_entry(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);
+ //guint8 ev_id = ltt_event_eventtype_id(e);
+ LttvTraceHook *th = (LttvTraceHook *)hook_data;
+ struct marker_field *f = lttv_trace_get_hook_field(th, 0);
+ 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];
+
/* Do something with the info about being in user or system mode when int? */
push_state(s, LTTV_STATE_SOFT_IRQ, submode);
/* update softirq status */
s->cpu_state->last_soft_irq = softirq;
+ if(ts->soft_irq_states[softirq].pending)
+ ts->soft_irq_states[softirq].pending--;
ts->soft_irq_states[softirq].running++;
return FALSE;
lttv_trace_get_hook_field(th, 0)));
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;
return FALSE;
return FALSE;
}
+static gboolean dump_syscall(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;
+ guint id;
+ guint64 address;
+ char *symbol;
+
+ id = ltt_event_get_unsigned(e, lttv_trace_get_hook_field(th, 0));
+ address = ltt_event_get_long_unsigned(e, lttv_trace_get_hook_field(th, 1));
+ 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);
+
+ return FALSE;
+}
+
+static gboolean dump_softirq(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;
+ guint id;
+ guint64 address;
+ char *symbol;
+
+ id = ltt_event_get_unsigned(e, lttv_trace_get_hook_field(th, 0));
+ address = ltt_event_get_long_unsigned(e, lttv_trace_get_hook_field(th, 1));
+ 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);
+
+ return FALSE;
+}
+
static gboolean schedchange(void *hook_data, void *call_data)
{
LttvTracefileState *s = (LttvTracefileState *)call_data;
if(state_out == 32 || state_out == 64) { /* EXIT_DEAD || TASK_DEAD */
/* see sched.h for states */
- process->state->s = LTTV_STATE_DEAD;
- process->state->change = s->parent.timestamp;
+ if (!exit_process(s, process)) {
+ process->state->s = LTTV_STATE_DEAD;
+ process->state->change = s->parent.timestamp;
+ }
}
}
}
process = lttv_state_find_process(ts, ANY_CPU, release_pid);
if(likely(process != NULL))
exit_process(s, process);
+ return FALSE;
+//DISABLED
+ if(likely(process != NULL)) {
+ /* release_task is happening at kernel level : we can now safely release
+ * the data structure of the process */
+ //This test is fun, though, as it may happen that
+ //at time t : CPU 0 : process_free
+ //at time t+150ns : CPU 1 : schedule out
+ //Clearly due to time imprecision, we disable it. (Mathieu)
+ //If this weird case happen, we have no choice but to put the
+ //Currently running process on the cpu to 0.
+ //I re-enable it following time precision fixes. (Mathieu)
+ //Well, in the case where an process is freed by a process on another CPU
+ //and still scheduled, it happens that this is the schedchange that will
+ //drop the last reference count. Do not free it here!
+ guint num_cpus = ltt_trace_get_num_cpu(ts->parent.t);
+ guint i;
+ for(i=0; i< num_cpus; i++) {
+ //g_assert(process != ts->running_process[i]);
+ if(process == ts->running_process[i]) {
+ //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
+ break;
+ }
+ }
+ if(i == num_cpus) /* process is not scheduled */
+ exit_process(s, process);
+ }
return FALSE;
}
NULL,
irq_exit, NULL, &hooks);
+ lttv_trace_find_hook(ts->parent.t,
+ LTT_FACILITY_KERNEL,
+ LTT_EVENT_SOFT_IRQ_RAISE,
+ FIELD_ARRAY(LTT_FIELD_SOFT_IRQ_ID),
+ soft_irq_raise, NULL, &hooks);
+
lttv_trace_find_hook(ts->parent.t,
LTT_FACILITY_KERNEL,
LTT_EVENT_SOFT_IRQ_ENTRY,
FIELD_ARRAY(LTT_FIELD_THIS_FN, LTT_FIELD_CALL_SITE),
function_exit, NULL, &hooks);
+ lttv_trace_find_hook(ts->parent.t,
+ LTT_FACILITY_STATEDUMP,
+ LTT_EVENT_SYS_CALL_TABLE,
+ FIELD_ARRAY(LTT_FIELD_ID, LTT_FIELD_ADDRESS, LTT_FIELD_SYMBOL),
+ dump_syscall, NULL, &hooks);
+
+ lttv_trace_find_hook(ts->parent.t,
+ LTT_FACILITY_STATEDUMP,
+ LTT_EVENT_SOFTIRQ_VEC,
+ FIELD_ARRAY(LTT_FIELD_ID, LTT_FIELD_ADDRESS, LTT_FIELD_SYMBOL),
+ dump_softirq, NULL, &hooks);
+
/* Add these hooks to each event_by_id hooks list */
nb_tracefile = ts->parent.tracefiles->len;
LTT_FACILITY_LIST = g_quark_from_string("list");
LTT_FACILITY_USER_GENERIC = g_quark_from_string("user_generic");
LTT_FACILITY_BLOCK = g_quark_from_string("block");
-
-
+ LTT_FACILITY_STATEDUMP = g_quark_from_string("statedump");
+
LTT_EVENT_SYSCALL_ENTRY = g_quark_from_string("syscall_entry");
LTT_EVENT_SYSCALL_EXIT = g_quark_from_string("syscall_exit");
LTT_EVENT_TRAP_ENTRY = g_quark_from_string("trap_entry");
LTT_EVENT_TRAP_EXIT = g_quark_from_string("trap_exit");
LTT_EVENT_IRQ_ENTRY = g_quark_from_string("irq_entry");
LTT_EVENT_IRQ_EXIT = g_quark_from_string("irq_exit");
+ LTT_EVENT_SOFT_IRQ_RAISE = g_quark_from_string("softirq_raise");
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_THREAD_BRAND = g_quark_from_string("thread_brand");
LTT_EVENT_REQUEST_ISSUE = g_quark_from_string("_blk_request_issue");
LTT_EVENT_REQUEST_COMPLETE = g_quark_from_string("_blk_request_complete");
- LTT_EVENT_LIST_INTERRUPT = g_quark_from_string("interrupt");;
-
+ LTT_EVENT_LIST_INTERRUPT = g_quark_from_string("interrupt");
+ LTT_EVENT_SYS_CALL_TABLE = g_quark_from_string("sys_call_table");
+ LTT_EVENT_SOFTIRQ_VEC = g_quark_from_string("softirq_vec");
LTT_FIELD_SYSCALL_ID = g_quark_from_string("syscall_id");
LTT_FIELD_TRAP_ID = g_quark_from_string("trap_id");
LTT_FIELD_MINOR = g_quark_from_string("minor");
LTT_FIELD_OPERATION = g_quark_from_string("direction");
LTT_FIELD_ACTION = g_quark_from_string("action");
+ LTT_FIELD_ID = g_quark_from_string("id");
+ LTT_FIELD_ADDRESS = g_quark_from_string("address");
+ LTT_FIELD_SYMBOL = g_quark_from_string("symbol");
LTTV_CPU_UNKNOWN = g_quark_from_string("unknown");
LTTV_CPU_IDLE = g_quark_from_string("idle");