#include <stdio.h>
#include <string.h>
+/* Comment :
+ * Mathieu Desnoyers
+ * usertrace is there only to be able to update the current CPU of the
+ * usertraces when there is a schedchange. it is a way to link the ProcessState
+ * to the associated usertrace. Link only created upon thread creation.
+ *
+ * The cpu id is necessary : it gives us back the current ProcessState when we
+ * are considering data from the usertrace.
+ */
+
#define PREALLOCATED_EXECUTION_STACK 10
/* Facilities Quarks */
static void lttv_state_free_process_table(GHashTable *processes);
+static void lttv_trace_states_read_raw(LttvTraceState *tcs, FILE *fp,
+ GPtrArray *quarktable);
void lttv_state_save(LttvTraceState *self, LttvAttribute *container)
{
/* Put the per cpu running_process to beginning state : process 0. */
for(i=0; i< nb_cpus; i++) {
+ LttvExecutionState *es;
self->running_process[i] = lttv_state_create_process(self, NULL, i, 0, 0,
LTTV_STATE_UNNAMED, &start_time);
+ /* We are not sure is it's a kernel thread or normal thread, put the
+ * bottom stack state to unknown */
+ self->running_process[i]->execution_stack =
+ g_array_set_size(self->running_process[i]->execution_stack, 1);
+ es = self->running_process[i]->state =
+ &g_array_index(self->running_process[i]->execution_stack,
+ LttvExecutionState, 0);
+ es->t = LTTV_STATE_MODE_UNKNOWN;
+
self->running_process[i]->state->s = LTTV_STATE_RUN;
self->running_process[i]->cpu = i;
}
g_free(data);
}
+#define MAX_STRING_LEN 4096
+
+static void
+state_load_saved_states(LttvTraceState *tcs)
+{
+ FILE *fp;
+ GPtrArray *quarktable;
+ char *trace_path;
+ char path[PATH_MAX];
+ guint count;
+ guint i;
+ tcs->has_precomputed_states = FALSE;
+ GQuark q;
+ gchar *string;
+ gint hdr;
+ gchar buf[MAX_STRING_LEN];
+ guint len;
+
+ trace_path = g_quark_to_string(ltt_trace_name(tcs->parent.t));
+ strncpy(path, trace_path, PATH_MAX-1);
+ count = strnlen(trace_path, PATH_MAX-1);
+ // quarktable : open, test
+ strncat(path, "/precomputed/quarktable", PATH_MAX-count-1);
+ fp = fopen(path, "r");
+ if(!fp) return;
+ quarktable = g_ptr_array_sized_new(4096);
+
+ /* Index 0 is null */
+ hdr = fgetc(fp);
+ if(hdr == EOF) return;
+ g_assert(hdr == HDR_QUARKS);
+ q = 1;
+ do {
+ hdr = fgetc(fp);
+ if(hdr == EOF) break;
+ g_assert(hdr == HDR_QUARK);
+ g_ptr_array_set_size(quarktable, q+1);
+ i=0;
+ while(1) {
+ fread(&buf[i], sizeof(gchar), 1, fp);
+ if(buf[i] == '\0' || feof(fp)) break;
+ i++;
+ }
+ len = strnlen(buf, MAX_STRING_LEN-1);
+ g_ptr_array_index (quarktable, q) = g_new(gchar, len+1);
+ strncpy(g_ptr_array_index (quarktable, q), buf, len+1);
+ q++;
+ } while(1);
+
+ fclose(fp);
+
+ // saved_states : open, test
+ strncpy(path, trace_path, PATH_MAX-1);
+ count = strnlen(trace_path, PATH_MAX-1);
+ strncat(path, "/precomputed/states", PATH_MAX-count-1);
+ fp = fopen(path, "r");
+ if(!fp) return;
+
+ hdr = fgetc(fp);
+ if(hdr != HDR_TRACE) goto end;
+
+ lttv_trace_states_read_raw(tcs, fp, quarktable);
+
+ tcs->has_precomputed_states = TRUE;
+
+end:
+ fclose(fp);
+
+ /* Free the quarktable */
+ for(i=0; i<quarktable->len; i++) {
+ string = g_ptr_array_index (quarktable, i);
+ g_free(string);
+ }
+ g_ptr_array_free(quarktable, TRUE);
+ return;
+}
+
static void
init(LttvTracesetState *self, LttvTraceset *ts)
{
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
if(ltt_tracefile_tid(tfcs->parent.tf) != 0) {
/* It's a Usertrace */
guint tid = ltt_tracefile_tid(tfcs->parent.tf);
}
}
+ /* See if the trace has saved states */
+ state_load_saved_states(tcs);
}
}
process = (LttvProcessState *)value;
fprintf(fp,
-" <PROCESS CORE=%p PID=%u TGID=%u PPID=%u TYPE=\"%s\" CTIME_S=%lu CTIME_NS=%lu ITIME_S=%lu ITIME_NS=%lu NAME=\"%s\" BRAND=\"%s\" CPU=\"%u\" PROCESS_TYPE=%u>\n",
+" <PROCESS CORE=%p PID=%u TGID=%u PPID=%u TYPE=\"%s\" CTIME_S=%lu CTIME_NS=%lu ITIME_S=%lu ITIME_NS=%lu NAME=\"%s\" BRAND=\"%s\" CPU=\"%u\">\n",
process, process->pid, process->tgid, process->ppid,
g_quark_to_string(process->type),
process->creation_time.tv_sec,
fwrite(&es->s, sizeof(es->s), 1, fp);
fwrite(&es->entry, sizeof(es->entry), 1, fp);
fwrite(&es->change, sizeof(es->change), 1, fp);
+ fwrite(&es->cum_cpu_time, sizeof(es->cum_cpu_time), 1, fp);
#if 0
fprintf(fp, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
g_quark_to_string(es->t), g_quark_to_string(es->n),
/* Read process state from a file */
/* Called because a HDR_PROCESS was found */
-static void read_process_state_raw(LttvTraceState *self, FILE *fp)
+static void read_process_state_raw(LttvTraceState *self, FILE *fp,
+ GPtrArray *quarktable)
{
LttvExecutionState *es;
LttvProcessState *process, *parent_process;
LttvProcessState tmp;
-
- FILE *fp = (FILE *)user_data;
+ GQuark tmpq;
guint i;
- guint64 address;
+ guint64 *address;
guint cpu;
- /* TOOD : check return value */
+ /* TODO : check return value */
fread(&tmp.type, sizeof(tmp.type), 1, fp);
fread(&tmp.name, sizeof(tmp.name), 1, fp);
fread(&tmp.brand, sizeof(tmp.brand), 1, fp);
fread(&tmp.insertion_time, sizeof(tmp.insertion_time), 1, fp);
if(tmp.pid == 0) {
- process = lttv_state_find_process(self, tmp.cpu, tmp.pid,
- tmp.insertion_time);
+ process = lttv_state_find_process(self, tmp.cpu, tmp.pid);
} else {
/* We must link to the parent */
parent_process = lttv_state_find_process_or_create(self, ANY_CPU, tmp.ppid,
- LTT_TIME_ZERO);
- process = lttv_state_find_process_or_create(self, ANY_CPU, tmp.pid,
- tmp.insertion_time);
+ <t_time_zero);
+ process = lttv_state_find_process(self, ANY_CPU, tmp.pid);
+ if(process == NULL) {
+ process = lttv_state_create_process(self, parent_process, tmp.cpu,
+ tmp.pid, tmp.tgid,
+ g_quark_from_string((gchar*)g_ptr_array_index(quarktable, tmp.name)),
+ &tmp.creation_time);
+ }
}
+ process->insertion_time = tmp.insertion_time;
process->creation_time = tmp.creation_time;
- process->type = tmp.type;
- process->brand = tmp.brand;
+ process->type = g_quark_from_string(
+ (gchar*)g_ptr_array_index(quarktable, tmp.type));
process->tgid = tmp.tgid;
- process->cpu = tmp.cpu;
+ process->ppid = tmp.ppid;
+ process->brand = g_quark_from_string(
+ (gchar*)g_ptr_array_index(quarktable, tmp.brand));
+ process->name =
+ g_quark_from_string((gchar*)g_ptr_array_index(quarktable, tmp.name));
+
do {
if(feof(fp) || ferror(fp)) goto end_loop;
- hdr = fgetc(fp);
+ gint hdr = fgetc(fp);
+ if(hdr == EOF) goto end_loop;
switch(hdr) {
case HDR_ES:
+ process->execution_stack =
+ g_array_set_size(process->execution_stack,
+ process->execution_stack->len + 1);
+ es = &g_array_index(process->execution_stack, LttvExecutionState,
+ process->execution_stack->len-1);
+ process->state = es;
+
+ fread(&es->t, sizeof(es->t), 1, fp);
+ es->t = g_quark_from_string(
+ (gchar*)g_ptr_array_index(quarktable, es->t));
+ fread(&es->n, sizeof(es->n), 1, fp);
+ es->n = g_quark_from_string(
+ (gchar*)g_ptr_array_index(quarktable, es->n));
+ fread(&es->s, sizeof(es->s), 1, fp);
+ es->s = g_quark_from_string(
+ (gchar*)g_ptr_array_index(quarktable, es->s));
+ fread(&es->entry, sizeof(es->entry), 1, fp);
+ fread(&es->change, sizeof(es->change), 1, fp);
+ fread(&es->cum_cpu_time, sizeof(es->cum_cpu_time), 1, fp);
break;
case HDR_USER_STACK:
+ process->user_stack = g_array_set_size(process->user_stack,
+ process->user_stack->len + 1);
+ address = &g_array_index(process->user_stack, guint64,
+ process->user_stack->len-1);
+ fread(address, sizeof(address), 1, fp);
+ process->current_function = *address;
break;
case HDR_USERTRACE:
- break;
- case HDR_PROCESS_STATE:
+ fread(&tmpq, sizeof(tmpq), 1, fp);
+ fread(&process->usertrace->cpu, sizeof(process->usertrace->cpu), 1, fp);
break;
default:
ungetc(hdr, fp);
};
} while(1);
end_loop:
-
+ return;
}
/* Called because a HDR_PROCESS_STATE was found */
/* Append a saved state to the trace states */
-void lttv_state_read_raw(LttvTraceState *self, FILE *fp)
+void lttv_state_read_raw(LttvTraceState *self, FILE *fp, GPtrArray *quarktable)
{
guint i, nb_tracefile, nb_block, offset;
guint64 tsc;
- LttTracefile *tf;
+ LttvTracefileState *tfcs;
LttEventPosition *ep;
LttvAttribute *saved_states_tree, *saved_state_tree;
LttvAttributeValue value;
+ GTree *pqueue = self->parent.ts_context->pqueue;
ep = ltt_event_position_new();
restore_init_state(self);
do {
if(feof(fp) || ferror(fp)) goto end_loop;
hdr = fgetc(fp);
+ if(hdr == EOF) goto end_loop;
switch(hdr) {
case HDR_PROCESS:
/* Call read_process_state_raw */
- read_process_state_raw(self, fp);
+ read_process_state_raw(self, fp, quarktable);
break;
case HDR_TRACEFILE:
case HDR_TRACESET:
case HDR_USERTRACE:
case HDR_PROCESS_STATE:
case HDR_CPU:
- g_error("Error while parsing saved state file :"
- " unexpected data header %d",
- hdr);
+ ungetc(hdr, fp);
+ goto end_loop;
break;
default:
g_error("Error while parsing saved state file : unknown data header %d",
// fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
// tfcs->parent.timestamp.tv_sec,
// tfcs->parent.timestamp.tv_nsec);
+ g_tree_remove(pqueue, &tfcs->parent);
hdr = fgetc(fp);
g_assert(hdr == HDR_TRACEFILE);
fread(&tfcs->parent.timestamp, sizeof(tfcs->parent.timestamp), 1, fp);
/* Note : if timestamp if LTT_TIME_INFINITE, there will be no
* position following : end of trace */
- if(ltt_time_compare(tfcs->parent.timestamp, LTT_TIME_INFINITE) != 0) {
+ if(ltt_time_compare(tfcs->parent.timestamp, ltt_time_infinite) != 0) {
fread(&nb_block, sizeof(nb_block), 1, fp);
fread(&offset, sizeof(offset), 1, fp);
fread(&tsc, sizeof(tsc), 1, fp);
- ltt_event_position_set(ep, tf, nb_block, offset, tsc);
- g_assert(ltt_tracefile_seek_position(tfc->tf, ep) == 0);
+ ltt_event_position_set(ep, tfcs->parent.tf, nb_block, offset, tsc);
+ gint ret = ltt_tracefile_seek_position(tfcs->parent.tf, ep);
+ g_assert(ret == 0);
+ g_tree_insert(pqueue, &tfcs->parent, &tfcs->parent);
}
}
g_free(ep);
- saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
+ saved_states_tree = lttv_attribute_find_subdir(self->parent.t_a,
LTTV_STATE_SAVED_STATES);
saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
value = lttv_attribute_add(saved_states_tree,
*(value.v_gobject) = (GObject *)saved_state_tree;
value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
*(value.v_time) = t;
- lttv_state_save(tcs, saved_state_tree);
+ lttv_state_save(self, saved_state_tree);
g_debug("Saving state at time %lu.%lu", t.tv_sec,
- self->parent.timestamp.tv_nsec);
+ t.tv_nsec);
*(self->max_time_state_recomputed_in_seek) = t;
+
}
/* Called when a HDR_TRACE is found */
-void lttv_trace_states_read_raw(LttvTraceState *tcs, FILE *fp)
+void lttv_trace_states_read_raw(LttvTraceState *tcs, FILE *fp,
+ GPtrArray *quarktable)
{
int hdr;
do {
if(feof(fp) || ferror(fp)) goto end_loop;
hdr = fgetc(fp);
+ if(hdr == EOF) goto end_loop;
switch(hdr) {
case HDR_PROCESS_STATE:
/* Call read_process_state_raw */
- lttv_state_read_raw(tcs, fp);
+ lttv_state_read_raw(tcs, fp, quarktable);
break;
case HDR_TRACEFILE:
case HDR_TRACESET:
};
} while(1);
end_loop:
-
*(tcs->max_time_state_recomputed_in_seek) = tcs->parent.time_span.end_time;
+ restore_init_state(tcs);
+ lttv_process_trace_seek_time(tcs, ltt_time_zero);
+ return;
}
g_quark_to_string(process->name),
g_quark_to_string(process->brand),
g_quark_to_string(process->state->s));
+ g_printf("MATD1 Different execution mode type (%lu.%09lu): ignore it\n",
+ tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
+ g_printf("MATD1 process state has %s when pop_int is %s\n",
+ g_quark_to_string(process->state->t),
+ g_quark_to_string(t));
+ g_printf("MATD1 { %u, %u, %s, %s, %s }\n",
+ process->pid,
+ process->ppid,
+ g_quark_to_string(process->name),
+ g_quark_to_string(process->brand),
+ g_quark_to_string(process->state->s));
+
return;
}
if(depth == 1){
g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
+ g_printf("MATD1 Trying to pop last state on stack (%lu.%09lu): ignore it\n",
+ tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
return;
}
LttvProcessState *
lttv_state_find_process_or_create(LttvTraceState *ts, guint cpu, guint pid,
- LttTime *timestamp)
+ const LttTime *timestamp)
{
LttvProcessState *process = lttv_state_find_process(ts, cpu, pid);
LttvExecutionState *es;
static gboolean syscall_entry(void *hook_data, void *call_data)
{
LttvTracefileState *s = (LttvTracefileState *)call_data;
+ guint cpu = s->cpu;
+ LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
+ LttvProcessState *process = ts->running_process[cpu];
LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
LttField *f = thf->f1;
submode = g_quark_from_string(string->str);
g_string_free(string, TRUE);
}
- push_state(s, LTTV_STATE_SYSCALL, submode);
+ /* There can be no system call from PID 0 : unknown state */
+ if(process->pid != 0)
+ push_state(s, LTTV_STATE_SYSCALL, submode);
return FALSE;
}
static gboolean syscall_exit(void *hook_data, void *call_data)
{
LttvTracefileState *s = (LttvTracefileState *)call_data;
+ guint cpu = s->cpu;
+ LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
+ LttvProcessState *process = ts->running_process[cpu];
- pop_state(s, LTTV_STATE_SYSCALL);
+ /* There can be no system call from PID 0 : unknown state */
+ if(process->pid != 0)
+ pop_state(s, LTTV_STATE_SYSCALL);
return FALSE;
}
//if(unlikely(process->pid != pid_out)) {
// g_assert(process->pid == 0);
//}
-
+ if(process->pid == 0 && process->state->t == LTTV_STATE_MODE_UNKNOWN) {
+ /* Scheduling out of pid 0 at beginning of the trace :
+ * we know for sure it is in syscall mode at this point. */
+ g_assert(process->execution_stack->len == 1);
+ process->state->t = LTTV_STATE_SYSCALL;
+ }
if(unlikely(process->state->s == LTTV_STATE_EXIT)) {
process->state->s = LTTV_STATE_ZOMBIE;
process->state->change = s->parent.timestamp;
/* Keep the stack bottom : a running user mode */
/* Disabled because of inconsistencies in the current statedump states. */
if(type == LTTV_STATE_KERNEL_THREAD) {
- /* Only keep the bottom */
+ /* Only keep the bottom
+ * FIXME Kernel thread : can be in syscall or interrupt or trap. */
+ /* Will cause expected trap when in fact being syscall (even after end of
+ * statedump event)
+ * Will cause expected interrupt when being syscall. (only before end of
+ * statedump event) */
+ // This will cause a "popping last state on stack, ignoring it."
process->execution_stack = g_array_set_size(process->execution_stack, 1);
es = process->state = &g_array_index(process->execution_stack,
LttvExecutionState, 0);
es->s = status;
es->n = submode;
} else {
- /* On top of it : */
+ /* User space process :
+ * bottom : user mode
+ * either currently running or scheduled out.
+ * can be scheduled out because interrupted in (user mode or in syscall)
+ * or because of an explicit call to the scheduler in syscall. Note that
+ * the scheduler call comes after the irq_exit, so never in interrupt
+ * context. */
+ // temp workaround : set size to 1 : only have user mode bottom of stack.
+ // will cause g_info message of expected syscall mode when in fact being
+ // in user mode. Can also cause expected trap when in fact being user
+ // mode in the event of a page fault reenabling interrupts in the handler.
+ // Expected syscall and trap can also happen after the end of statedump
+ // This will cause a "popping last state on stack, ignoring it."
+ process->execution_stack = g_array_set_size(process->execution_stack, 1);
+#if 0
es = process->state = &g_array_index(process->execution_stack,
LttvExecutionState, 1);
es->t = LTTV_STATE_USER_MODE;
es->s = status;
es->n = submode;
+#endif //0
}
#if 0
/* UNKNOWN STATE */
nb_trace = lttv_traceset_number(traceset);
for(i = 0 ; i < nb_trace ; i++) {
ts = LTTV_TRACE_STATE(self->parent.traces[i]);
+
lttv_attribute_find(ts->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
hooks = *(val.v_pointer);
ts = (LttvTraceState *)self->parent.traces[i];
nb_tracefile = ts->parent.tracefiles->len;
+ if(ts->has_precomputed_states) continue;
+
guint *event_count = g_new(guint, 1);
*event_count = 0;
ts = (LttvTraceState *)self->parent.traces[i];
nb_tracefile = ts->parent.tracefiles->len;
+ if(ts->has_precomputed_states) continue;
+
guint *event_count = NULL;
for(j = 0 ; j < nb_tracefile ; j++) {