return ret;
}
+static void delete_usertrace(gpointer key, gpointer value, gpointer user_data)
+{
+ g_tree_destroy((GTree*)value);
+}
+
+static void lttv_state_free_usertraces(GHashTable *usertraces)
+{
+ g_hash_table_foreach(usertraces, delete_usertrace, NULL);
+ g_hash_table_destroy(usertraces);
+}
+
+
static void
restore_init_state(LttvTraceState *self)
/* Free the process tables */
if(self->processes != NULL) lttv_state_free_process_table(self->processes);
+ if(self->usertraces != NULL) lttv_state_free_usertraces(self->usertraces);
self->processes = g_hash_table_new(process_hash, process_equal);
+ self->usertraces = g_hash_table_new(g_direct_hash, g_direct_equal);
self->nb_event = 0;
/* Seek time to beginning */
//static LttTime time_zero = {0,0};
+static gint compare_usertraces(gconstpointer a, gconstpointer b,
+ gpointer user_data)
+{
+ const LttTime *t1 = (const LttTime *)a;
+ const LttTime *t2 = (const LttTime *)b;
+
+ return ltt_time_compare(*t1, *t2);
+}
+
+static void free_usertrace_key(gpointer data)
+{
+ g_free(data);
+}
+
static void
init(LttvTracesetState *self, LttvTraceset *ts)
{
get_max_time(tcs);
nb_tracefile = tc->tracefiles->len;
-#if 0
+ tcs->processes = NULL;
+ tcs->usertraces = NULL;
+ tcs->running_process = g_new(LttvProcessState*,
+ ltt_trace_get_num_cpu(tc->t));
+ restore_init_state(tcs);
for(j = 0 ; j < nb_tracefile ; j++) {
tfcs =
LTTV_TRACEFILE_STATE(g_array_index(tc->tracefiles,
LttvTracefileContext*, j));
tfcs->tracefile_name = ltt_tracefile_name(tfcs->parent.tf);
+ tfcs->cpu = ltt_tracefile_cpu(tfcs->parent.tf);
+#if 0
+ if(ltt_tracefile_tid(tfcs->parent.tf) != 0) {
+ /* It's a Usertrace */
+ LttvProcessState *process;
+ LttTime timestamp =
+ ltt_interpolate_time_from_tsc(tfcs->parent.tf,
+ ltt_tracefile_creation(tfcs->parent.tf));
+ process = lttv_state_find_process_or_create(
+ tcs,
+ 0, ltt_tracefile_tid(tfcs->parent.tf),
+ ×tamp);
+ process->usertrace = tfcs;
+ }
}
#endif //0
- tcs->processes = NULL;
- tcs->running_process = g_new(LttvProcessState*,
- ltt_trace_get_num_cpu(tc->t));
- restore_init_state(tcs);
+ if(ltt_tracefile_tid(tfcs->parent.tf) != 0) {
+ /* It's a Usertrace */
+ guint tid = ltt_tracefile_tid(tfcs->parent.tf);
+ GTree *usertrace_tree = (GTree*)g_hash_table_lookup(tcs->usertraces,
+ (gconstpointer)tid);
+ if(!usertrace_tree) {
+ usertrace_tree = g_tree_new_full(compare_usertraces,
+ NULL, free_usertrace_key, NULL);
+ g_hash_table_insert(tcs->usertraces,
+ (gpointer)tid, usertrace_tree);
+ }
+ LttTime *timestamp = g_new(LttTime, 1);
+ *timestamp = ltt_interpolate_time_from_tsc(tfcs->parent.tf,
+ ltt_tracefile_creation(tfcs->parent.tf));
+ g_tree_insert(usertrace_tree, timestamp, tfcs);
+ }
+ }
+
}
}
-
static void
fini(LttvTracesetState *self)
{
g_free(tcs->running_process);
tcs->running_process = NULL;
lttv_state_free_process_table(tcs->processes);
+ lttv_state_free_usertraces(tcs->usertraces);
tcs->processes = NULL;
+ tcs->usertraces = NULL;
}
LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))->
fini((LttvTracesetContext *)self);
typedef struct _LttvNameTables {
// FIXME GQuark *eventtype_names;
GQuark *syscall_names;
+ guint nb_syscalls;
GQuark *trap_names;
GQuark *irq_names;
GQuark *soft_irq_names;
lttv_trace_hook_destroy(&h);
name_tables->syscall_names = g_new(GQuark, nb);
+ name_tables->nb_syscalls = nb;
for(i = 0 ; i < nb ; i++) {
name_tables->syscall_names[i] = ltt_enum_string_get(t, i);
name_tables = (LttvNameTables *)*(v.v_pointer);
//tcs->eventtype_names = name_tables->eventtype_names;
tcs->syscall_names = name_tables->syscall_names;
+ tcs->nb_syscalls = name_tables->nb_syscalls;
tcs->trap_names = name_tables->trap_names;
tcs->irq_names = name_tables->irq_names;
tcs->soft_irq_names = name_tables->soft_irq_names;
{
LttvExecutionState *es;
- guint cpu = ltt_tracefile_num(tfs->parent.tf);
LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
+ guint cpu = tfs->cpu;
#ifdef HASH_TABLE_DEBUG
hash_table_check(ts->processes);
static void pop_state(LttvTracefileState *tfs, LttvExecutionMode t)
{
- guint cpu = ltt_tracefile_num(tfs->parent.tf);
+ guint cpu = tfs->cpu;
LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
LttvProcessState *process = ts->running_process[cpu];
process->state->change = tfs->parent.timestamp;
}
+struct search_result {
+ const LttTime *time; /* Requested time */
+ LttTime *best; /* Best result */
+};
+
+static gint search_usertrace(gconstpointer a, gconstpointer b)
+{
+ const LttTime *elem_time = (const LttTime*)a;
+ /* Explicit non const cast */
+ struct search_result *res = (struct search_result *)b;
+
+ if(ltt_time_compare(*elem_time, *(res->time)) < 0) {
+ /* The usertrace was created before the schedchange */
+ /* Get larger keys */
+ return 1;
+ } else if(ltt_time_compare(*elem_time, *(res->time)) >= 0) {
+ /* The usertrace was created after the schedchange time */
+ /* Get smaller keys */
+ if(res->best) {
+ if(ltt_time_compare(*elem_time, *res->best) < 0) {
+ res->best = elem_time;
+ }
+ } else {
+ res->best = elem_time;
+ }
+ return -1;
+ }
+}
+
+static LttvTracefileState *ltt_state_usertrace_find(LttvTraceState *tcs,
+ guint pid, const LttTime *timestamp)
+{
+ LttvTracefileState *tfs = NULL;
+ struct search_result res;
+ /* Find the usertrace associated with a pid and time interval.
+ * Search in the usertraces by PID (within a hash) and then, for each
+ * corresponding element of the array, find the first one with creation
+ * timestamp the lowest, but higher or equal to "timestamp". */
+ res.time = timestamp;
+ res.best = NULL;
+ GTree *usertrace_tree = g_hash_table_lookup(tcs->usertraces, (gpointer)pid);
+ if(usertrace_tree) {
+ g_tree_search(usertrace_tree, search_usertrace, &res);
+ if(res.best)
+ tfs = g_tree_lookup(usertrace_tree, res.best);
+ }
+
+ return tfs;
+}
+
LttvProcessState *
lttv_state_create_process(LttvTraceState *tcs, LttvProcessState *parent,
//process->last_cpu = tfs->cpu_name;
//process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
process->kernel_thread = 0;
+ process->usertrace = ltt_state_usertrace_find(tcs, pid, timestamp);
g_info("Process %u, core %p", process->pid, process);
g_hash_table_insert(tcs->processes, process, process);
LttvExecutionSubmode submode;
- submode = ((LttvTraceState *)(s->parent.t_context))->syscall_names[
- ltt_event_get_unsigned(e, f)];
+ 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);
+ }
push_state(s, LTTV_STATE_SYSCALL, submode);
return FALSE;
}
static gboolean schedchange(void *hook_data, void *call_data)
{
LttvTracefileState *s = (LttvTracefileState *)call_data;
- guint cpu = ltt_tracefile_num(s->parent.tf);
+ guint cpu = s->cpu;
LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
LttvProcessState *process = ts->running_process[cpu];
+ LttvProcessState *old_process = ts->running_process[cpu];
LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
the wrongly attributed statistics. */
//This test only makes sense once the state is known and if there is no
- //missing events.
+ //missing events. We need to silently ignore schedchange coming after a
+ //process_free, or it causes glitches. (FIXME)
//if(unlikely(process->pid != pid_out)) {
// g_assert(process->pid == 0);
//}
else process->state->s = LTTV_STATE_WAIT;
process->state->change = s->parent.timestamp;
}
-
- if(state_out == 32)
+
+ if(state_out == 32)
exit_process(s, process); /* EXIT_DEAD */
/* see sched.h for states */
}
&s->parent.timestamp);
process->state->s = LTTV_STATE_RUN;
process->cpu = cpu;
+ if(process->usertrace)
+ process->usertrace->cpu = cpu;
// process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
process->state->change = s->parent.timestamp;
return FALSE;
guint parent_pid;
guint child_pid;
LttvProcessState *zombie_process;
- guint cpu = ltt_tracefile_num(s->parent.tf);
+ guint cpu = s->cpu;
LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
LttvProcessState *process = ts->running_process[cpu];
LttvProcessState *child_process;
LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
guint pid;
- guint cpu = ltt_tracefile_num(s->parent.tf);
+ guint cpu = s->cpu;
LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
LttvProcessState *process;
LttvExecutionState *es;
LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
LttField *f;
guint pid;
- guint cpu = ltt_tracefile_num(s->parent.tf);
+ guint cpu = s->cpu;
LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
LttvProcessState *process = ts->running_process[cpu];
break;
}
}
- if(i == num_cpus) /* process is not scheduled */
- exit_process(s, process);
+ //if(i == num_cpus) /* process is not scheduled */
+ //exit_process(s, process); // do nothing : wait for the schedchange to
+ //delete the process.
}
return FALSE;
LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
//gchar *name;
- guint cpu = ltt_tracefile_num(s->parent.tf);
+ guint cpu = s->cpu;
LttvProcessState *process = ts->running_process[cpu];
/* PID of the process to release */
guint parent_pid;
guint pid;
gchar * command;
- guint cpu = ltt_tracefile_num(s->parent.tf);
+ guint cpu = s->cpu;
LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
LttvProcessState *process = ts->running_process[cpu];
LttvProcessState *parent_process;
return FALSE;
}
+guint lttv_state_current_cpu(LttvTracefileState *tfs)
+{
+ return tfs->cpu;
+}
+
+
+
#if 0
static gboolean block_start(void *hook_data, void *call_data)
{