From b445142a71748192520cfd645b4963e23070a486 Mon Sep 17 00:00:00 2001 From: dagenais Date: Fri, 3 Oct 2003 02:00:03 +0000 Subject: [PATCH] Add a module to compute various statistics git-svn-id: http://ltt.polymtl.ca/svn@290 04897980-b3bd-0310-b5e0-8ef037075253 --- ltt/branches/poly/configure.in | 2 +- ltt/branches/poly/include/lttv/attribute.h | 11 +- ltt/branches/poly/include/lttv/hook.h | 2 +- ltt/branches/poly/include/lttv/iattribute.h | 4 +- ltt/branches/poly/include/lttv/lttv.h | 3 + ltt/branches/poly/include/lttv/processTrace.h | 19 + ltt/branches/poly/include/lttv/state.h | 80 +- ltt/branches/poly/include/lttv/stats.h | 239 ++++- ltt/branches/poly/ltt/tracefile.c | 2 +- ltt/branches/poly/lttv/Makefile.am | 2 +- ltt/branches/poly/lttv/attribute.c | 89 +- ltt/branches/poly/lttv/batchAnalysis.c | 50 +- ltt/branches/poly/lttv/countEvents.c | 261 ------ ltt/branches/poly/lttv/hook.c | 7 +- ltt/branches/poly/lttv/iattribute.c | 6 +- ltt/branches/poly/lttv/main.c | 41 + ltt/branches/poly/lttv/module.c | 40 +- ltt/branches/poly/lttv/option.c | 22 +- ltt/branches/poly/lttv/processTrace.c | 67 +- ltt/branches/poly/lttv/state.c | 448 +++++----- ltt/branches/poly/lttv/stats.c | 824 ++++++++++++++++++ ltt/branches/poly/lttv/textDump.c | 149 +++- 22 files changed, 1772 insertions(+), 596 deletions(-) delete mode 100644 ltt/branches/poly/lttv/countEvents.c create mode 100644 ltt/branches/poly/lttv/stats.c diff --git a/ltt/branches/poly/configure.in b/ltt/branches/poly/configure.in index b4013234..5d4ce8e9 100644 --- a/ltt/branches/poly/configure.in +++ b/ltt/branches/poly/configure.in @@ -5,7 +5,7 @@ AC_PREREQ(2.57) AC_INIT(FULL-PACKAGE-NAME, VERSION, BUG-REPORT-ADDRESS) #AC_WITH_LTDL # not needed ? AM_INIT_AUTOMAKE(LinuxTraceToolkit,0.9.7-30092003) -AM_CONFIG_HEADER([config.h]) +AM_CONFIG_HEADER(config.h) AM_PROG_LIBTOOL AM_PATH_GLIB_2_0(2.0.0, ,AC_MSG_ERROR([glib is required in order to compile LinuxTraceToolkit - download it from ftp://ftp.gtk.org/pub/gtk]) , gmodule) diff --git a/ltt/branches/poly/include/lttv/attribute.h b/ltt/branches/poly/include/lttv/attribute.h index e8cbcb6b..93acb13f 100644 --- a/ltt/branches/poly/include/lttv/attribute.h +++ b/ltt/branches/poly/include/lttv/attribute.h @@ -78,11 +78,20 @@ void lttv_attribute_remove_by_name(LttvAttribute *self, attribute of that name already exists but is not a GObject supporting the iattribute interface, return NULL. */ -LttvIAttribute* lttv_attribute_create_subdir(LttvAttribute *self, +LttvAttribute* lttv_attribute_find_subdir(LttvAttribute *self, LttvAttributeName name); gboolean lttv_attribute_find(LttvAttribute *self, LttvAttributeName name, LttvAttributeType t, LttvAttributeValue *v); +/* Free recursively a tree of attributes. All contained gobject of type + LttvAttribute are freed (unreferenced) recursively. */ + +void lttv_attribute_recursive_free(LttvAttribute *self); + +/* Add items from a tree of attributes to another tree. */ + +void lttv_attribute_recursive_add(LttvAttribute *dest, LttvAttribute *src); + #endif // ATTRIBUTE_H diff --git a/ltt/branches/poly/include/lttv/hook.h b/ltt/branches/poly/include/lttv/hook.h index 22624238..b1da6ea1 100644 --- a/ltt/branches/poly/include/lttv/hook.h +++ b/ltt/branches/poly/include/lttv/hook.h @@ -63,7 +63,7 @@ void lttv_hooks_remove_by_position(LttvHooks *h, unsigned i); /* Call all the hooks in the list, each with its hook data, - with the specified call data. Return TRUE is one hook returned TRUE. */ + with the specified call data. Return TRUE if one hook returned TRUE. */ gboolean lttv_hooks_call(LttvHooks *h, void *call_data); diff --git a/ltt/branches/poly/include/lttv/iattribute.h b/ltt/branches/poly/include/lttv/iattribute.h index 944092a2..1613a451 100644 --- a/ltt/branches/poly/include/lttv/iattribute.h +++ b/ltt/branches/poly/include/lttv/iattribute.h @@ -68,7 +68,7 @@ struct _LttvIAttributeClass { void (*remove_by_name) (LttvIAttribute *self, LttvAttributeName name); - LttvIAttribute* (*create_subdir) (LttvIAttribute *self, + LttvIAttribute* (*find_subdir) (LttvIAttribute *self, LttvAttributeName name); }; @@ -121,7 +121,7 @@ void lttv_iattribute_remove_by_name(LttvIAttribute *self, attribute of that name already exists but is not a GObject supporting the iattribute interface, return NULL. */ -LttvIAttribute* lttv_iattribute_create_subdir(LttvIAttribute *self, +LttvIAttribute* lttv_iattribute_find_subdir(LttvIAttribute *self, LttvAttributeName name); diff --git a/ltt/branches/poly/include/lttv/lttv.h b/ltt/branches/poly/include/lttv/lttv.h index 77dac57e..5017718e 100644 --- a/ltt/branches/poly/include/lttv/lttv.h +++ b/ltt/branches/poly/include/lttv/lttv.h @@ -31,4 +31,7 @@ LttvAttribute *lttv_global_attributes(); */ +#define g_info(format...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, format) +#define g_debug(format...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, format) + #endif // LTTV_H diff --git a/ltt/branches/poly/include/lttv/processTrace.h b/ltt/branches/poly/include/lttv/processTrace.h index f59f95e9..08b28e35 100644 --- a/ltt/branches/poly/include/lttv/processTrace.h +++ b/ltt/branches/poly/include/lttv/processTrace.h @@ -188,4 +188,23 @@ void lttv_traceset_context_remove_hooks(LttvTracesetContext *self, LttvHooks *before_event, LttvHooks *after_event); +typedef struct _LttvTraceHook { + LttvHook h; + guint id; + LttField *f1; + LttField *f2; + LttField *f3; +} LttvTraceHook; + + +/* Search in the trace for the id of the named event type within the named + facility. Then, find the three (if non null) named fields. All that + information is then used to fill the LttvTraceHook structure. This + is useful to find the specific id for an event within a trace, for + registering a hook using this structure as event data; + it already contains the (up to three) needed fields handles. */ + +void lttv_trace_find_hook(LttTrace *t, char *facility, char *event_type, + char *field1, char *field2, char *field3, LttvHook h, LttvTraceHook *th); + #endif // PROCESSTRACE_H diff --git a/ltt/branches/poly/include/lttv/state.h b/ltt/branches/poly/include/lttv/state.h index bf9fa1ae..f85847b4 100644 --- a/ltt/branches/poly/include/lttv/state.h +++ b/ltt/branches/poly/include/lttv/state.h @@ -14,22 +14,6 @@ (one per cpu) per trace and multiple traces per trace set. The state objects defined here simply add fields to the relevant context objects. */ - -/* The LttvProcessState structure defines the current state for each process. - A process can make system calls (in some rare cases nested) and receive - interrupts/faults. For instance, a process may issue a system call, - generate a page fault while reading an argument from user space, and - get caught by an interrupt. To represent these nested states, an - interrupt stack is maintained. The stack bottom is normal user mode and - the top of stack is the current interrupt state. - - The interrupt state tells about the process status, interrupt type and - interrupt number. All these could be defined as enumerations but may - need extensions (e.g. new process state). GQuark are thus used being - as easy to manipulate as integers but having a string associated, just - like enumerations. */ - - typedef struct _LttvTracesetState LttvTracesetState; typedef struct _LttvTracesetStateClass LttvTracesetStateClass; @@ -43,27 +27,44 @@ gboolean lttv_state_add_event_hooks(LttvTracesetState *self); gboolean lttv_state_remove_event_hooks(LttvTracesetState *self); +/* The LttvProcessState structure defines the current state for each process. + A process can make system calls (in some rare cases nested) and receive + interrupts/faults. For instance, a process may issue a system call, + generate a page fault while reading an argument from user space, and + get caught by an interrupt. To represent these nested states, an + execution mode stack is maintained. The stack bottom is normal user mode + and the top of stack is the current execution mode. + + The execution mode stack tells about the process status, execution mode and + submode (interrupt, system call or IRQ number). All these could be + defined as enumerations but may need extensions (e.g. new process state). + GQuark are thus used. They are as easy to manipulate as integers but have + a string associated, just like enumerations. -/* The interrupt type is one of "user mode", "kernel thread", "system call", + The execution mode is one of "user mode", "kernel thread", "system call", "interrupt request", "fault". */ -typedef GQuark LttvInterruptType; +typedef GQuark LttvExecutionMode; -extern LttvInterruptType +extern LttvExecutionMode LTTV_STATE_USER_MODE, LTTV_STATE_SYSCALL, LTTV_STATE_TRAP, - LTTV_STATE_IRQ; + LTTV_STATE_IRQ, + LTTV_STATE_MODE_UNKNOWN; -/* The interrupt number depends on the interrupt type. For user mode or kernel - thread, which are the normal mode (interrupt stack bottom), it is set to - "none". For interrupt requests, faults and system calls, it is set - respectively to the interrupt name (e.g. "timer"), fault name +/* The submode number depends on the execution mode. For user mode or kernel + thread, which are the normal mode (execution mode stack bottom), + it is set to "none". For interrupt requests, faults and system calls, + it is set respectively to the interrupt name (e.g. "timer"), fault name (e.g. "page fault"), and system call name (e.g. "select"). */ -typedef GQuark LttvInterruptNumber; +typedef GQuark LttvExecutionSubmode; +extern LttvExecutionSubmode + LTTV_STATE_SUBMODE_NONE, + LTTV_STATE_SUBMODE_UNKNOWN; /* The process status is one of "running", "wait-cpu" (runnable), or "wait-*" where "*" describes the resource waited for (e.g. timer, process, @@ -80,26 +81,30 @@ extern LttvProcessStatus LTTV_STATE_RUN; -typedef struct _LttvInterruptState { - LttvInterruptType t; - LttvInterruptNumber n; +typedef struct _LttvExecutionState { + LttvExecutionMode t; + LttvExecutionSubmode n; LttTime entry; - LttTime last_change; + LttTime change; LttvProcessStatus s; -} LttvInterruptState; +} LttvExecutionState; typedef struct _LttvProcessState { guint pid; guint ppid; - LttTime birth; + LttTime creation_time; GQuark name; - GArray *interrupt_stack; /* Array of LttvInterruptState */ - LttvInterruptState *state; /* Top of interrupt stack */ - /* opened file descriptors, address map... */ + GQuark pid_time; + GArray *execution_stack; /* Array of LttvExecutionState */ + LttvExecutionState *state; /* Top of interrupt stack */ + /* opened file descriptors, address map?... */ } LttvProcessState; +LttvProcessState *lttv_state_find_process(LttvTracefileState *tfs, guint pid); + + /* The LttvTracesetState, LttvTraceState and LttvTracefileState types inherit from the corresponding Context objects defined in processTrace. */ @@ -133,6 +138,10 @@ struct _LttvTraceState { GHashTable *processes; /* LttvProcessState objects indexed by pid */ /* Block/char devices, locks, memory pages... */ + GQuark *eventtype_names; + GQuark *syscall_names; + GQuark *trap_names; + GQuark *irq_names; }; struct _LttvTraceStateClass { @@ -153,6 +162,7 @@ struct _LttvTracefileState { LttvTracefileContext parent; LttvProcessState *process; + GQuark cpu_name; }; struct _LttvTracefileStateClass { @@ -162,4 +172,4 @@ struct _LttvTracefileStateClass { GType lttv_tracefile_state_get_type (void); -#endif // PROCESSTRACE_H +#endif // STATE_H diff --git a/ltt/branches/poly/include/lttv/stats.h b/ltt/branches/poly/include/lttv/stats.h index a98f9640..87130b0f 100644 --- a/ltt/branches/poly/include/lttv/stats.h +++ b/ltt/branches/poly/include/lttv/stats.h @@ -1,52 +1,201 @@ +#ifndef STATS_H +#define STATS_H + +#include +#include /* The statistics are for a complete time interval. These structures differ from the system state since they relate to static components of the system (all processes which existed instead of just the currently existing processes). - At each level are kept statistics as well as pointers to subcomponents. - During the trace processing, the statistics are accumulated at the - lowest level component level. Then, in the "after" hooks of the processing, - these statistics are summed to get the values at higher levels (process, - CPU, trace, traceSet). */ - -typedef struct _lttv_trace_set_stats { - lttv_attributes *stats; - lttv_attributes *traces; -} lttv_trace_set_stats; - -typedef struct _lttv_trace_stats { - lttv_attributes *stats; - lttv_attributes *CPUs; - lttv_attributes *processes; - lttv_attributes *int_calls; - lttv_attributes *block_devices; -} lttv_trace_stats; - -typedef struct _lttv_cpu_stats { - lttv_attributes *processes; - lttv_attributes *int_calls; - lttv_attributes *block_devices; -} lttv_cpu_stats; - -typedef struct _lttv_process_identity { - char *names; - lttv_time entry, exit; -} lttv_process_identity; - -typedef struct _lttv_process_stats { - lttv_attributes *stats; - lttv_process_identify *p; - lttv_attributes *int_calls; - lttv_attributes *block_devices; -} lttv_process_stats; - -typedef lttv_int_stats { - lttv_attributes *stats; - lttv_int_type type; -} lttv_int_stats; - -typedef lttv_block_device_stats { - lttv_attributes *stats; -} lttv_block_device_stats; + The basic attributes tree to gather for several different execution modes + (e.g., user mode, syscall, irq), thereafter called the "events tree", + contains the following attributes: the number of events of each type, + the total number of events, the number of bytes written, the time spent + executing, waiting for a resource, waiting for a cpu, and possibly many + others. The name "facility-event_type" below is to be replaced + by specific event types (e.g., core-schedchange, code-syscall_entry...). + + event_types/ + "facility-event_type" + events_count + cpu_time + elapsed_time + wait_time + bytes_written + packets_sent + ... + + The events for several different execution modes are joined together to + form the "execution modes tree". The name "execution mode" is to be replaced + by "system call", "trap", "irq", "user mode" or "kernel thread". + The name "submode" is to be replaced by the specific system call, trap or + irq name. The "submode" is an empty string if none is applicable, which is + the case for "user mode" and "kernel thread". + + An "events tree" for each "execution mode" contains the sum for all its + different submodes. An "events tree" in the "execution modes tree" contains + the sum for all its different execution modes. + + mode_types/ + "execution mode"/ + submodes/ + "submode"/ + Events Tree + events/ + Event Tree + events/ + Events Tree + + Each trace set contains an "execution modes tree". While the traces + come from possibly different systems, which may differ in their system + calls..., most of the system calls will have the same name, even if their + actual internal numeric id differs. Categories such as cpu id and process + id are not kept since these are specific to each system. When several + traces are taken from the same system, these categories may make sense and + could eventually be considered. + + Each trace contains a global "execution modes tree", one for each + cpu and process, and one for each process/cpu combination. The name + "cpu number" stands for the cpu identifier, and "process_id-start_time" + is a unique process identifier composed of the process id + (unique at any given time but which may be reused over time) concatenated + with the process start time. + + modes/ + Execution Modes Tree + cpu/ + "cpu number"/ + Execution Modes Tree + processes/ + "process_id-start_time"/ + exec_file_name + parent + start_time + end_time + modes/ + Execution Modes Tree + cpu/ + "cpu number"/ + Execution Modes Tree + + All the events and derived values (cpu, elapsed and wait time) are + added during the trace analysis in the relevant + trace / processes / * / cpu / * / mode_types / * /submodes / * + "events tree". To achieve this efficiently, each tracefile context + contains a pointer to the current relevant "events tree" and "event_types" + tree within it. + + Once all the events are processed, the total number of events is computed + within each trace / processes / * / cpu / * / mode_types / * / submodes / *. + Then, the "events tree" are summed for all submodes within each mode type + and for all mode types within a processes / * / cpu / * + "execution modes tree". + + Finally, the "execution modes trees" for all cpu within a process, + for all processes, and for all traces are computed. Separately, + the "execution modes tree" for each cpu but for all processes within a + trace are summed in the trace / cpu / * subtrees. + + */ + + +/* The various statistics branch names are GQuarks. They are pre-computed for + easy and efficient access */ + +extern GQuark + LTTV_STATS_PROCESS_UNKNOWN, + LTTV_STATS_PROCESSES, + LTTV_STATS_CPU, + LTTV_STATS_MODE_TYPES, + LTTV_STATS_SUBMODES, + LTTV_STATS_EVENT_TYPES, + LTTV_STATS_CPU_TIME, + LTTV_STATS_ELAPSED_TIME, + LTTV_STATS_EVENTS, + LTTV_STATS_EVENTS_COUNT, + LTTV_STATS_BEFORE_HOOKS, + LTTV_STATS_AFTER_HOOKS; + + +typedef struct _LttvTracesetStats LttvTracesetStats; +typedef struct _LttvTracesetStatsClass LttvTracesetStatsClass; + +typedef struct _LttvTraceStats LttvTraceStats; +typedef struct _LttvTraceStatsClass LttvTraceStatsClass; + +typedef struct _LttvTracefileStats LttvTracefileStats; +typedef struct _LttvTracefileStatsClass LttvTracefileStatsClass; + +gboolean lttv_stats_add_event_hooks(LttvTracesetStats *self); + +gboolean lttv_stats_remove_event_hooks(LttvTracesetStats *self); + + +/* The LttvTracesetStats, LttvTraceStats and LttvTracefileStats types + inherit from the corresponding State objects defined in state.h.. */ + +#define LTTV_TRACESET_STATS_TYPE (lttv_traceset_stats_get_type ()) +#define LTTV_TRACESET_STATS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), LTTV_TRACESET_STATS_TYPE, LttvTracesetStats)) +#define LTTV_TRACESET_STATS_CLASS(vtable) (G_TYPE_CHECK_CLASS_CAST ((vtable), LTTV_TRACESET_STATS_TYPE, LttvTracesetStatsClass)) +#define LTTV_IS_TRACESET_STATS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), LTTV_TRACESET_STATS_TYPE)) +#define LTTV_IS_TRACESET_STATS_CLASS(vtable) (G_TYPE_CHECK_CLASS_TYPE ((vtable), LTTV_TRACESET_STATS_TYPE)) +#define LTTV_TRACESET_STATS_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), LTTV_TRACESET_STATS_TYPE, LttvTracesetStatsClass)) + +struct _LttvTracesetStats { + LttvTracesetState parent; + + LttvAttribute *stats; +}; + +struct _LttvTracesetStatsClass { + LttvTracesetStateClass parent; +}; + +GType lttv_traceset_stats_get_type (void); + + +#define LTTV_TRACE_STATS_TYPE (lttv_trace_stats_get_type ()) +#define LTTV_TRACE_STATS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), LTTV_TRACE_STATS_TYPE, LttvTraceStats)) +#define LTTV_TRACE_STATS_CLASS(vtable) (G_TYPE_CHECK_CLASS_CAST ((vtable), LTTV_TRACE_STATS_TYPE, LttvTraceStatsClass)) +#define LTTV_IS_TRACE_STATS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), LTTV_TRACE_STATS_TYPE)) +#define LTTV_IS_TRACE_STATS_CLASS(vtable) (G_TYPE_CHECK_CLASS_TYPE ((vtable), LTTV_TRACE_STATS_TYPE)) +#define LTTV_TRACE_STATS_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), LTTV_TRACE_STATS_TYPE, LttvTraceStatsClass)) + +struct _LttvTraceStats { + LttvTraceState parent; + + LttvAttribute *stats; +}; + +struct _LttvTraceStatsClass { + LttvTraceStateClass parent; +}; + +GType lttv_trace_stats_get_type (void); + + +#define LTTV_TRACEFILE_STATS_TYPE (lttv_tracefile_stats_get_type ()) +#define LTTV_TRACEFILE_STATS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), LTTV_TRACEFILE_STATS_TYPE, LttvTracefileStats)) +#define LTTV_TRACEFILE_STATS_CLASS(vtable) (G_TYPE_CHECK_CLASS_CAST ((vtable), LTTV_TRACEFILE_STATS_TYPE, LttvTracefileStatsClass)) +#define LTTV_IS_TRACEFILE_STATS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), LTTV_TRACEFILE_STATS_TYPE)) +#define LTTV_IS_TRACEFILE_STATS_CLASS(vtable) (G_TYPE_CHECK_CLASS_TYPE ((vtable), LTTV_TRACEFILE_STATS_TYPE)) +#define LTTV_TRACEFILE_STATS_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), LTTV_TRACEFILE_STATS_TYPE, LttvTracefileStatsClass)) + +struct _LttvTracefileStats { + LttvTracefileState parent; + + LttvAttribute *stats; + LttvAttribute *current_events_tree; + LttvAttribute *current_event_types_tree; +}; + +struct _LttvTracefileStatsClass { + LttvTracefileStateClass parent; +}; + +GType lttv_tracefile_stats_get_type (void); + +#endif // STATS_H diff --git a/ltt/branches/poly/ltt/tracefile.c b/ltt/branches/poly/ltt/tracefile.c index 1bcc111a..e3829fbf 100644 --- a/ltt/branches/poly/ltt/tracefile.c +++ b/ltt/branches/poly/ltt/tracefile.c @@ -571,7 +571,7 @@ unsigned ltt_trace_eventtype_number(LttTrace *t) int i; unsigned count = 0; LttFacility * f; - for(i=0;i=t->facility_number;i++){ + for(i=0;ifacility_number;i++){ f = (LttFacility*)g_ptr_array_index(t->facilities, i); count += f->event_number; } diff --git a/ltt/branches/poly/lttv/Makefile.am b/ltt/branches/poly/lttv/Makefile.am index cdaeeaeb..c91d0138 100644 --- a/ltt/branches/poly/lttv/Makefile.am +++ b/ltt/branches/poly/lttv/Makefile.am @@ -9,7 +9,7 @@ bin_PROGRAMS = lttv #INCLUDES=$(top_srcdir)/include lttv_SOURCES = main.c module.c option.c hook.c attribute.c \ - iattribute.c processTrace.c state.c traceset.c + iattribute.c processTrace.c state.c stats.c traceset.c libdir = ${lttvplugindir} diff --git a/ltt/branches/poly/lttv/attribute.c b/ltt/branches/poly/lttv/attribute.c index 176772de..648beee4 100644 --- a/ltt/branches/poly/lttv/attribute.c +++ b/ltt/branches/poly/lttv/attribute.c @@ -1,5 +1,6 @@ #include +#include typedef union _AttributeValue { int dv_int; @@ -173,8 +174,8 @@ lttv_attribute_remove_by_name(LttvAttribute *self, LttvAttributeName name) attribute of that name already exists but is not a GObject supporting the iattribute interface, return NULL. */ -LttvIAttribute* -lttv_attribute_create_subdir(LttvAttribute *self, LttvAttributeName name) +/*CHECK*/LttvAttribute* +lttv_attribute_find_subdir(LttvAttribute *self, LttvAttributeName name) { unsigned i; @@ -186,13 +187,13 @@ lttv_attribute_create_subdir(LttvAttribute *self, LttvAttributeName name) if(i != 0) { a = g_array_index(self->attributes, Attribute, i - 1); if(a.type == LTTV_GOBJECT && LTTV_IS_IATTRIBUTE(a.value.dv_gobject)) { - return LTTV_IATTRIBUTE(a.value.dv_gobject); + return LTTV_ATTRIBUTE(a.value.dv_gobject); } else return NULL; } new = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL); *(lttv_attribute_add(self, name, LTTV_GOBJECT).v_gobject) = G_OBJECT(new); - return (LttvIAttribute *)new; + return (LttvAttribute *)new; } gboolean @@ -216,6 +217,79 @@ lttv_attribute_find(LttvAttribute *self, LttvAttributeName name, } +void lttv_attribute_recursive_free(LttvAttribute *self) +{ + int i, nb; + + Attribute *a; + + nb = self->attributes->len; + + for(i = 0 ; i < nb ; i++) { + a = &g_array_index(self->attributes, Attribute, i); + if(a->type == LTTV_GOBJECT && LTTV_IS_ATTRIBUTE(a->value.dv_gobject)) { + lttv_attribute_recursive_free((LttvAttribute *)(a->value.dv_gobject)); + } + } + g_object_unref(self); +} + + +void lttv_attribute_recursive_add(LttvAttribute *dest, LttvAttribute *src) +{ + int i, nb; + + Attribute *a; + + LttvAttributeValue value; + + nb = src->attributes->len; + + for(i = 0 ; i < nb ; i++) { + a = &g_array_index(src->attributes, Attribute, i); + if(a->type == LTTV_GOBJECT && LTTV_IS_ATTRIBUTE(a->value.dv_gobject)) { + lttv_attribute_recursive_add( + /*CHECK*/(LttvAttribute *)lttv_attribute_find_subdir(dest, a->name), + (LttvAttribute *)(a->value.dv_gobject)); + } + else { + g_assert(lttv_attribute_find(dest, a->name, a->type, &value)); + switch(a->type) { + case LTTV_INT: + *value.v_int += a->value.dv_int; + break; + case LTTV_UINT: + *value.v_uint += a->value.dv_uint; + break; + case LTTV_LONG: + *value.v_long += a->value.dv_long; + break; + case LTTV_ULONG: + *value.v_ulong += a->value.dv_ulong; + break; + case LTTV_FLOAT: + *value.v_float += a->value.dv_float; + break; + case LTTV_DOUBLE: + *value.v_double += a->value.dv_double; + break; + case LTTV_TIME: + TimeAdd(*value.v_time, *value.v_time, a->value.dv_time); + break; + case LTTV_POINTER: + break; + case LTTV_STRING: + break; + case LTTV_GOBJECT: + break; + case LTTV_NONE: + break; + } + } + } +} + + static void attribute_interface_init (gpointer g_iface, gpointer iface_data) { @@ -243,8 +317,8 @@ attribute_interface_init (gpointer g_iface, gpointer iface_data) klass->remove_by_name = (void (*) (LttvIAttribute *self, LttvAttributeName name)) lttv_attribute_remove_by_name; - klass->create_subdir = (LttvIAttribute* (*) (LttvIAttribute *self, - LttvAttributeName name)) lttv_attribute_create_subdir; + klass->find_subdir = (LttvIAttribute* (*) (LttvIAttribute *self, + LttvAttributeName name)) lttv_attribute_find_subdir; } @@ -262,7 +336,8 @@ attribute_finalize (LttvAttribute *self) { g_hash_table_destroy(self->names); g_array_free(self->attributes, TRUE); - G_OBJECT_CLASS(g_type_class_peek_parent(LTTV_ATTRIBUTE_GET_CLASS(self)))->finalize(G_OBJECT(self)); + G_OBJECT_CLASS(g_type_class_peek_parent( + g_type_class_peek(LTTV_ATTRIBUTE_TYPE)))->finalize(G_OBJECT(self)); } diff --git a/ltt/branches/poly/lttv/batchAnalysis.c b/ltt/branches/poly/lttv/batchAnalysis.c index a8d1c824..2db57830 100644 --- a/ltt/branches/poly/lttv/batchAnalysis.c +++ b/ltt/branches/poly/lttv/batchAnalysis.c @@ -9,6 +9,7 @@ #include #include #include +#include static LttvTraceset *traceset; @@ -25,6 +26,7 @@ static LttvHooks static char *a_trace; +static gboolean a_stats; void lttv_trace_option(void *hook_data) { @@ -38,31 +40,47 @@ void lttv_trace_option(void *hook_data) static gboolean process_traceset(void *hook_data, void *call_data) { - LttvTracesetState *tc; + LttvTracesetStats *tscs; + + LttvTracesetContext *tc; LttTime start, end; - tc = g_object_new(LTTV_TRACESET_STATE_TYPE, NULL); - lttv_context_init(LTTV_TRACESET_CONTEXT(tc), traceset); + g_info("BatchAnalysis begin process traceset"); + + tscs = g_object_new(LTTV_TRACESET_STATS_TYPE, NULL); + tc = &tscs->parent.parent; + + g_info("BatchAnalysis initialize context"); - lttv_traceset_context_add_hooks(LTTV_TRACESET_CONTEXT(tc), + lttv_context_init(tc, traceset); + lttv_state_add_event_hooks(&tscs->parent); + if(a_stats) lttv_stats_add_event_hooks(tscs); + + lttv_traceset_context_add_hooks(tc, before_traceset, after_traceset, NULL, before_trace, after_trace, NULL, before_tracefile, after_tracefile, NULL, before_event, after_event); - lttv_state_add_event_hooks(tc); start.tv_sec = 0; start.tv_nsec = 0; end.tv_sec = G_MAXULONG; end.tv_nsec = G_MAXULONG; - lttv_process_trace(start, end, traceset, LTTV_TRACESET_CONTEXT(tc),G_MAXULONG); - lttv_traceset_context_remove_hooks(LTTV_TRACESET_CONTEXT(tc), + g_info("BatchAnalysis process traceset"); + + lttv_process_trace(start, end, traceset, tc, G_MAXULONG); + + g_info("BatchAnalysis destroy context"); + + lttv_traceset_context_remove_hooks(tc, before_traceset, after_traceset, NULL, before_trace, after_trace, NULL, before_tracefile, after_tracefile, NULL, before_event, after_event); + lttv_state_remove_event_hooks(&tscs->parent); + if(a_stats) lttv_stats_remove_event_hooks(tscs); + lttv_context_fini(tc); + g_object_unref(tscs); - lttv_state_remove_event_hooks(tc); - lttv_context_fini(LTTV_TRACESET_CONTEXT(tc)); - g_object_unref(tc); + g_info("BatchAnalysis end process traceset"); } @@ -72,11 +90,20 @@ G_MODULE_EXPORT void init(LttvModule *self, int argc, char **argv) LttvIAttribute *attributes = LTTV_IATTRIBUTE(lttv_global_attributes()); + g_info("Init batchAnalysis.c"); + lttv_option_add("trace", 't', "add a trace to the trace set to analyse", "pathname of the directory containing the trace", LTTV_OPT_STRING, &a_trace, lttv_trace_option, NULL); + a_stats = FALSE; + lttv_option_add("stats", 's', + "write the traceset and trace statistics", + "", + LTTV_OPT_NONE, &a_stats, NULL, NULL); + + traceset = lttv_traceset_new(); before_traceset = lttv_hooks_new(); @@ -124,7 +151,10 @@ G_MODULE_EXPORT void destroy() { guint i, nb; + g_info("Destroy batchAnalysis.c"); + lttv_option_remove("trace"); + lttv_option_remove("stats"); lttv_hooks_destroy(before_traceset); lttv_hooks_destroy(after_traceset); diff --git a/ltt/branches/poly/lttv/countEvents.c b/ltt/branches/poly/lttv/countEvents.c deleted file mode 100644 index 0d15defb..00000000 --- a/ltt/branches/poly/lttv/countEvents.c +++ /dev/null @@ -1,261 +0,0 @@ -/* The countEvents module accumulates data for various basic reports - - Not only does it count the events for each event type, it also tracks - the current state (current process and user/system mode) in order to - categorize accordingly the event counts. */ - -void init(int argc, char **argv) -{ - lttv_attributes *a; - lttv_hooks *before, *after; - - a = lttv_global_attributes(); - before = (lttv_hooks *)lttv_attributes_get_pointer_pathname(a, - "hooks/trace_set/before"); - after = (lttv_hooks *)lttv_attributes_get_pointer_pathname(a, - "hooks/trace_set/after"); - lttv_hooks_add(before, countEvents_trace_set_before, NULL); - lttv_hooks_add(after, countEvents_trace_set_after, NULL); -} - - -void destroy() -{ - lttv_attributes *a; - lttv_hooks *before, *after; - - a = lttv_global_attributes(); - before = (lttv_hooks *)lttv_attributes_get_pointer_pathname(a, - "hooks/trace_set/before"); - after = (lttv_hooks *)lttv_attributes_get_pointer_pathname(a, - "hooks/trace_set/after"); - lttv_hooks_remove(before, countEvents_trace_set_before, NULL); - lttv_hooks_remove(after, countEvents_trace_set_after, NULL); -} - - -/* Insert the hooks before and after each trace and tracefile */ - -typedef struct _trace_context { - unsigned nb_cpu; - struct cpu_context *cpus; - lttv_attributes *processes; - lttv_key *key; - lttv_attributes *event_counts; - lttv_attributes *trace_attributes; -} trace_context; - -static bool countEvents_trace_set_before(void *hook_data, void *call_data) -{ - int i, j, nb, nbtf; - lttv_trace_set *s; - lttv_attributes *a; - trace_context *c; - - s = (lttv_trace_set *)call_data; - - /* For each trace prepare the contexts and insert the hooks */ - - nb = lttv_trace_set_number(s); - for(i = 0 ; i < nb ; i++) { - c = g_new(trace_context); - a = lttv_trace_set_trace_attributes(s, i); - - if(lttv_attributes_get_pointer_pathname(a, "countEvents/context") != NULL){ - g_error("Recursive call to TextDump"); - } - - lttv_attributes_set_pointer_pathname(a, "countEvents/context", c); - - h = lttv_attributes_get_hooks(a, "hooks/before"); - lttv_hooks_add(h, countEvents_trace_before, c); - h = lttv_attributes_get_hooks(a, "hooks/after"); - lttv_hooks_add(h, countEvents_trace_after, c); - h = lttv_attributes_get_hooks(a, "hooks/tacefile/before"); - lttv_hooks_add(h, countEvents_tracefile_before, c); - h = lttv_attributes_get_hooks(a, "hooks/tracefile/after"); - lttv_hooks_add(h, countEvents_tracefile_after, c); - h = lttv_attributes_get_hooks(a, "hooks/event/selected"); - lttv_hooks_add(h, couneEvents_event, c); - } - - return TRUE; -} - - -/* Remove the hooks before and after each trace and tracefile, and for each - event. Print trace set level statistics. */ - -static bool countEvents_trace_set_after(void *hook_data, void *call_data) -{ - int i, j, nb, nbtf; - lttv_trace_set *s; - lttv_attributes *a; - trace_context *c; - - s = (lttv_trace_set *)call_data; - - /* Get the file pointer */ - - fp = (FILE *)lttv_attributes_get_pointer_pathname(ga, "textDump/file"); - - /* For each trace remove the hooks */ - - nb = lttv_trace_set_number(s); - for(i = 0 ; i < nb ; i++) { - a = lttv_trace_set_trace_attributes(s, i); - c = (trace_context *)lttv_attributes_get_pointer_pathname(a, - "textDump/context"); - lttv_attributes_set_pointer_pathname(a, "textDump/context", NULL); - - h = lttv_attributes_get_hooks(a, "hooks/before"); - lttv_hooks_remove(h, countEvents_trace_before, c); - h = lttv_attributes_get_hooks(a, "hooks/after"); - lttv_hooks_remove(h, countEvents_trace_after, c); - h = lttv_attributes_get_hooks(a, "hooks/tacefile/before"); - lttv_hooks_remove(h, countEvents_tracefile_before, c); - h = lttv_attributes_get_hooks(a, "hooks/tracefile/after"); - lttv_hooks_remove(h, countEvents_tracefile_after, c); - h = lttv_attributes_get_hooks(a, "hooks/event/selected"); - lttv_hooks_remove(h, countEvents_event, c); - g_free(c); - } - - /* Compute statistics for the complete trace set */ - - return TRUE; -} - - -static bool countEvents_trace_before(void *hook_data, void *call_data) -{ - ltt_trace *t; - trace_context *c; - - c = (trace_context *)hook_data; - t = (ltt_trace *)call_data; - - /* Initialize the context */ - - return TRUE; -} - - -/* Print trace level statistics */ - -static bool countEvents_trace_after(void *hook_data, void *call_data) -{ - ltt_trace *t; - trace_context *c; - - c = (trace_context *)hook_data; - t = (ltt_trace *)call_data; - - /* Sum events in different ways for the whole trace */ - - return TRUE; -} - - -static bool countEvents_tracefile_before(void *hook_data, void *call_data) -{ - ltt_tracefile *tf; - trace_context *c; - - c = (trace_context *)hook_data; - tf = (ltt_tracefile *)call_data; - - /* Nothing special to do for now */ - - return TRUE; -} - - -static bool countEvents_tracefile_after(void *hook_data, void *call_data) -{ - ltt_tracefile *tf; - trace_context *c; - - c = (trace_context *)hook_data; - tf = (ltt_tracefile *)call_data; - - /* Nothing special to do for now */ - - return TRUE; -} - - -static bool countEvents_event(void *hook_data, void *call_data) -{ - ltt_event *e; - trace_context *c; - unsigned cpu; - unsigned eventtype; - ltt_time t; - - e = (ltt_event *)call_data; - c = (event_context *)hook_data; - - eventtype = ltt_event_eventtype_id(e); - cpu = ltt_event_cpu_id(e); - time = ltt_event_time(e); - - /* Accumulate the CPU time spent in that state */ - - key = c->cpu[cpu].key; - last_time = c->cpu[cpu].last_time; - c->cpu[cpu].last_time; = time; - lttv_key_index(key,LTTV_KEY_TYPE) = KEY_CPU; - total_time = lttv_attributes_time_get(c->main_attributes, key); - - lttv_sub_time_value(delta_time, last_time, time); - lttv_add_time_valie(*total_time, *total_time, delta_time); - - /* Some events indicate a state change to remember (syscall goes from user to - system mode, open assigns a new file to a file descriptor, exec changes - the memory map for the text section...) or have additional statistics - gathered. */ - - switch(c->eventtype_class[eventtype]) { - - case LTTV_EVENT_SYSCALL_ENTRY: - n = ltt_event_get_unsigned(e,c->syscall_field) - push_state(c, cpu, KEY_SYSCALL, n, time); - /* For page faults it may be interesting to note waiting on which file */ - break; - - case LTTV_EVENT_SYSCALL_EXIT: - pop_state(c->cpu, cpu, KEY_SYSCALL, time); - break; - - case LTTV_EVENT_TRAP_ENTRY: - n = ltt_event_get_unsigned(e,c->trap_field) - push_state(c, cpu, KEY_TRAP, n, time); - break; - - case LTTV_EVENT_TRAP_EXIT: - pop_state(c->cpu, cpu, KEY_TRAP, time); - break; - - case LTTV_EVENT_IRQ_ENTRY: - n = ltt_event_get_unsigned(e,c->irq_field) - push_state(c, cpu, KEY_IRQ, n, time); - break; - - case LTTV_EVENT_IRQ_EXIT: - pop_state(c->cpu, cpu, KEY_IRQ, time); - break; - - - default: - } - - /* The key already specifies the host, cpu, process and state, add the - event type and simply count one for the current event. */ - - lttv_key_index(key,LTTV_KEY_TYPE) = c->eventtype_key[eventtype]; - count = lttv_attributes_get_integer(c->main_attributes, key); - (*count)++; - - return TRUE; -} diff --git a/ltt/branches/poly/lttv/hook.c b/ltt/branches/poly/lttv/hook.c index 5edc6230..dc9b3ac8 100644 --- a/ltt/branches/poly/lttv/hook.c +++ b/ltt/branches/poly/lttv/hook.c @@ -132,7 +132,7 @@ void lttv_hooks_remove_by_position(LttvHooks *h, unsigned i) gboolean lttv_hooks_call(LttvHooks *h, void *call_data) { - gboolean ret = FALSE; + gboolean ret, sum_ret = FALSE; LttvHookClosure *c; @@ -141,10 +141,11 @@ gboolean lttv_hooks_call(LttvHooks *h, void *call_data) if(h != NULL) { for(i = 0 ; i < h->len ; i++) { c = &g_array_index(h, LttvHookClosure, i); - ret = ret || c->hook(c->hook_data,call_data); + ret = c->hook(c->hook_data,call_data); + sum_ret = sum_ret || ret; } } - return ret; + return sum_ret; } diff --git a/ltt/branches/poly/lttv/iattribute.c b/ltt/branches/poly/lttv/iattribute.c index d9934f06..e39d7e08 100644 --- a/ltt/branches/poly/lttv/iattribute.c +++ b/ltt/branches/poly/lttv/iattribute.c @@ -80,10 +80,10 @@ void lttv_iattribute_remove_by_name(LttvIAttribute *self, return LTTV_IATTRIBUTE_GET_CLASS (self)->remove_by_name (self, name); } -LttvIAttribute* lttv_iattribute_create_subdir(LttvIAttribute *self, +LttvIAttribute* lttv_iattribute_find_subdir(LttvIAttribute *self, LttvAttributeName name) { - return LTTV_IATTRIBUTE_GET_CLASS (self)->create_subdir (self, name); + return LTTV_IATTRIBUTE_GET_CLASS (self)->find_subdir (self, name); } @@ -142,7 +142,7 @@ gboolean lttv_iattribute_find_by_path(LttvIAttribute *self, char *path, else { found_type = lttv_iattribute_get_by_name(node, name, v); if(found_type == LTTV_NONE) { - node = lttv_iattribute_create_subdir(node, name); + node = lttv_iattribute_find_subdir(node, name); } else if(found_type == LTTV_GOBJECT && LTTV_IS_IATTRIBUTE(*(v->v_gobject))) { diff --git a/ltt/branches/poly/lttv/main.c b/ltt/branches/poly/lttv/main.c index 7da2a99d..de3c7709 100644 --- a/ltt/branches/poly/lttv/main.c +++ b/ltt/branches/poly/lttv/main.c @@ -19,6 +19,9 @@ void lttv_module_destroy(); void lttv_state_init(int argc, char **argv); void lttv_state_destroy(); +void lttv_stats_init(int argc, char **argv); +void lttv_stats_destroy(); + /* The main program maintains a few central data structures and relies on modules for the rest. These data structures may be accessed by modules through an exported API */ @@ -35,6 +38,10 @@ static char *a_module, *a_module_path; +static gboolean + a_verbose, + a_debug; + static int a_argc; static char **a_argv; @@ -43,6 +50,10 @@ static void lttv_module_option(void *hook_data); static void lttv_module_path_option(void *hook_data); +static void lttv_verbose(void *hook_data); + +static void lttv_debug(void *hook_data); + static void lttv_help(void); /* Since everything is done in modules, the main program only takes care @@ -84,9 +95,12 @@ int main(int argc, char **argv) { /* Initialize the command line options processing */ + a_argc = argc; + a_argv = argv; lttv_option_init(argc,argv); lttv_module_init(argc,argv); lttv_state_init(argc,argv); + lttv_stats_init(argc,argv); /* Initialize the module loading */ @@ -104,6 +118,14 @@ int main(int argc, char **argv) { lttv_option_add("help",'h', "basic help", "none", LTTV_OPT_NONE, NULL, lttv_help, NULL); + + a_verbose = FALSE; + lttv_option_add("verbose",'v', "print information messages", "none", + LTTV_OPT_NONE, NULL, lttv_verbose, NULL); + + a_debug = FALSE; + lttv_option_add("debug",'d', "print debugging messages", "none", + LTTV_OPT_NONE, NULL, lttv_debug, NULL); lttv_hooks_call(before_options, NULL); @@ -113,6 +135,7 @@ int main(int argc, char **argv) { lttv_hooks_call(before_main, NULL); lttv_hooks_call(after_main, NULL); + lttv_stats_destroy(); lttv_state_destroy(); lttv_module_destroy(); lttv_option_destroy(); @@ -147,6 +170,18 @@ void lttv_module_path_option(void *hook_data) lttv_module_path_add(a_module_path); } +void lttv_verbose(void *hook_data) +{ + g_log_set_handler(NULL, G_LOG_LEVEL_INFO, g_log_default_handler, NULL); + g_info("Logging set to include INFO level messages"); +} + +void lttv_debug(void *hook_data) +{ + g_log_set_handler(NULL, G_LOG_LEVEL_DEBUG, g_log_default_handler, NULL); + g_info("Logging set to include DEBUG level messages"); +} + void lttv_help() { printf("Linux Trace Toolkit Visualizer\n"); @@ -154,3 +189,9 @@ void lttv_help() lttv_option_show_help(); printf("\n"); } + +/* remove countEvents.c, add alias to init to allow static/dynamic loading + MODULE_INFO(name, init, destroy, { require} ). This info could be used + by module_load and as a constructor function when not a module + -> check constructor functions versus dynamic loading and init section + -> have a list of available modules builtin as default or mandatory */ diff --git a/ltt/branches/poly/lttv/module.c b/ltt/branches/poly/lttv/module.c index a77aa736..f73e6e93 100644 --- a/ltt/branches/poly/lttv/module.c +++ b/ltt/branches/poly/lttv/module.c @@ -5,6 +5,8 @@ #include +#define g_info(format...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, format) +#define g_debug(format...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, format) struct _LttvModule { @@ -26,6 +28,7 @@ static void lttv_module_unload_all(); void lttv_module_init(int argc, char **argv) { + g_info("Init module.c"); modules = g_hash_table_new(g_str_hash, g_str_equal); modulesPaths = g_ptr_array_new(); } @@ -35,6 +38,8 @@ void lttv_module_destroy() { int i; + g_info("Destroy module.c"); + /* Unload all modules */ lttv_module_unload_all(); @@ -55,6 +60,7 @@ void lttv_module_destroy() void lttv_module_path_add(const char *name) { + g_info("Add module path %s", name); g_ptr_array_add(modulesPaths,(char*)g_strdup(name)); } @@ -74,29 +80,35 @@ module_load(const char *name, int argc, char **argv) LttvModuleInit init_function; + g_info("Load module %s", name); + /* Try to find the module along all the user specified paths */ for(i = 0 ; i < modulesPaths->len ; i++) { pathname = g_module_build_path(modulesPaths->pdata[i],name); - gm = g_module_open(pathname,G_MODULE_BIND_LAZY); - g_critical("loading module : %s", pathname); - g_critical("module error : %s", g_module_error()); + g_info("Try path %s", pathname); + gm = g_module_open(pathname,0); g_free(pathname); if(gm != NULL) break; + g_info("Trial failed, %s", g_module_error()); } /* Try the default system path */ if(gm == NULL) { pathname = g_module_build_path(NULL,name); - gm = g_module_open(pathname,G_MODULE_BIND_LAZY); - g_critical("loading module : %s", pathname); + g_info("Try default path"); + gm = g_module_open(pathname,0); g_free(pathname); } /* Module cannot be found */ - if(gm == NULL) return NULL; + if(gm == NULL) { + g_info("Trial failed, %s", g_module_error()); + g_info("Failed to load %s", name); + return NULL; + } /* Check if the module was already opened using the hopefully canonical name returned by g_module_name. */ @@ -106,6 +118,7 @@ module_load(const char *name, int argc, char **argv) m = g_hash_table_lookup(modules, module_name); if(m == NULL) { + g_info("Module %s (%s) loaded, call its init function", name, module_name); /* Module loaded for the first time. Insert it in the table and call the init function if any. */ @@ -127,6 +140,8 @@ module_load(const char *name, int argc, char **argv) /* Module was already opened, check that it really is the same and undo the extra g_module_open */ + g_info("Module %s (%s) was already loaded, no need to call init function", + name, module_name); if(m->module != gm) g_error("Two gmodules with the same pathname"); g_module_close(gm); } @@ -139,6 +154,7 @@ module_load(const char *name, int argc, char **argv) LttvModule * lttv_module_load(const char *name, int argc, char **argv) { + g_info("Load module %s explicitly", name); LttvModule *m = module_load(name, argc, argv); if(m != NULL) m->load_count++; return m; @@ -150,6 +166,8 @@ lttv_module_require(LttvModule *m, const char *name, int argc, char **argv) { LttvModule *module; + g_info("Load module %s, as %s is a dependent requiring it", name, + g_module_name(m->module)); module = module_load(name, argc, argv); if(module != NULL) g_ptr_array_add(m->dependents, module); return module; @@ -166,12 +184,16 @@ static void module_unload(LttvModule *m) /* Decrement the reference count */ + g_info("Unload module %s", g_module_name(m->module)); m->ref_count--; - if(m->ref_count > 0) return; - + if(m->ref_count > 0) { + g_info("Module usage count decremented to %d", m->ref_count); + return; + } /* We really have to unload the module, first unload its dependents */ len = m->dependents->len; + g_info("Unload dependent modules"); for(i = 0 ; i < len ; i++) { module_unload(m->dependents->pdata[i]); @@ -181,6 +203,7 @@ static void module_unload(LttvModule *m) /* Unload the module itself */ + g_info("Call the destroy function and unload the module"); if(!g_module_symbol(m->module, "destroy", (gpointer)&destroy_function)) { g_warning("module (%s) has no destroy function", pathname); } @@ -195,6 +218,7 @@ static void module_unload(LttvModule *m) void lttv_module_unload(LttvModule *m) { + g_info("Explicitly unload module %s", g_module_name(m->module)); if(m->load_count <= 0) { g_error("more unload than load (%s)", g_module_name(m->module)); return; diff --git a/ltt/branches/poly/lttv/option.c b/ltt/branches/poly/lttv/option.c index 01237acb..590f9def 100644 --- a/ltt/branches/poly/lttv/option.c +++ b/ltt/branches/poly/lttv/option.c @@ -3,6 +3,9 @@ #include #include +#define g_info(format...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, format) +#define g_debug(format...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, format) + typedef struct _LttvOption { char *long_name; char char_name; @@ -36,6 +39,7 @@ free_option(LttvOption *option) void lttv_option_init(int argc, char **argv) { + g_info("Init option.c"); options = g_hash_table_new(g_str_hash, g_str_equal); } @@ -48,6 +52,7 @@ void lttv_option_destroy() int i; + g_info("Destroy option.c"); g_hash_table_foreach(options, list_options, list); g_hash_table_destroy(options); @@ -65,6 +70,7 @@ void lttv_option_add(const char *long_name, const char char_name, { LttvOption *option; + g_info("Add option %s", long_name); if(g_hash_table_lookup(options, long_name) != NULL) { g_warning("duplicate option"); return; @@ -88,6 +94,7 @@ lttv_option_remove(const char *long_name) { LttvOption *option = g_hash_table_lookup(options, long_name); + g_info("Remove option %s", long_name); if(option == NULL) { g_warning("trying to remove unknown option %s", long_name); return; @@ -184,11 +191,17 @@ void lttv_option_parse(int argc, char **argv) if(rc > 0) { option = (LttvOption *)(list->pdata[rc - 1]); - if(option->hook != NULL) option->hook(option->hook_data); + g_info("Option %s encountered", option->long_name); + if(option->hook != NULL) { + g_info("Option %s hook called", option->long_name); + option->hook(option->hook_data); + } i++; } else if(rc == POPT_ERROR_BADOPT && i != first_arg) { + g_info("Option %s not recognized, rescan options with new additions", + poptBadOption(c,0)); /* Perhaps this option is newly added, restart parsing */ @@ -198,7 +211,11 @@ void lttv_option_parse(int argc, char **argv) /* Get back to the same argument */ first_arg = i; - for(i = 0; i < first_arg; i++) poptGetNextOpt(c); + for(i = 0; i < first_arg; i++) { + rc = poptGetNextOpt(c); + option = (LttvOption *)(list->pdata[rc - 1]); + g_info("Option %s rescanned, skipped", option->long_name); + } } else { @@ -244,3 +261,4 @@ void lttv_option_show_help(void) } + diff --git a/ltt/branches/poly/lttv/processTrace.c b/ltt/branches/poly/lttv/processTrace.c index 122ce510..c4f650c4 100644 --- a/ltt/branches/poly/lttv/processTrace.c +++ b/ltt/branches/poly/lttv/processTrace.c @@ -1,6 +1,7 @@ #include #include +#include void lttv_context_init(LttvTracesetContext *self, LttvTraceset *ts) { @@ -288,7 +289,8 @@ traceset_context_instance_init (GTypeInstance *instance, gpointer g_class) static void traceset_context_finalize (LttvTracesetContext *self) { - G_OBJECT_CLASS(g_type_class_peek_parent(LTTV_TRACESET_CONTEXT_GET_CLASS(self)))->finalize(G_OBJECT(self)); + G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACESET_CONTEXT_TYPE))) + ->finalize(G_OBJECT(self)); } @@ -340,7 +342,8 @@ trace_context_instance_init (GTypeInstance *instance, gpointer g_class) static void trace_context_finalize (LttvTraceContext *self) { - G_OBJECT_CLASS(g_type_class_peek_parent(LTTV_TRACE_CONTEXT_GET_CLASS(self)))->finalize(G_OBJECT(self)); + G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACE_CONTEXT_TYPE)))-> + finalize(G_OBJECT(self)); } @@ -387,7 +390,8 @@ tracefile_context_instance_init (GTypeInstance *instance, gpointer g_class) static void tracefile_context_finalize (LttvTracefileContext *self) { - G_OBJECT_CLASS(g_type_class_peek_parent(LTTV_TRACEFILE_CONTEXT_GET_CLASS(self)))->finalize(G_OBJECT(self)); + G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACEFILE_CONTEXT_TYPE))) + ->finalize(G_OBJECT(self)); } @@ -543,11 +547,11 @@ void lttv_process_trace(LttTime start, LttTime end, LttvTraceset *traceset, tfc = g_tree_lookup(pqueue, &(tfc->timestamp)); g_tree_remove(pqueue, &(tfc->timestamp)); - if(!lttv_hooks_call(tfc->check_event, context)) { + if(!lttv_hooks_call(tfc->check_event, tfc)) { id = ltt_event_eventtype_id(tfc->e); lttv_hooks_call(tfc->before_event, tfc); lttv_hooks_call(lttv_hooks_by_id_get(tfc->before_event_by_id, id), tfc); - lttv_hooks_call(tfc->after_event, context); + lttv_hooks_call(tfc->after_event, tfc); lttv_hooks_call(lttv_hooks_by_id_get(tfc->after_event_by_id, id), tfc); } @@ -586,3 +590,56 @@ void lttv_process_trace(LttTime start, LttTime end, LttvTraceset *traceset, g_ptr_array_free(traces, TRUE); g_tree_destroy(pqueue); } + +static LttField * +find_field(LttEventType *et, const char *field) +{ + LttType *t; + + LttField *f; + + guint i, nb; + + char *name; + + if(field == NULL) return NULL; + + f = ltt_eventtype_field(et); + t = ltt_eventtype_type(et); + g_assert(ltt_type_class(t) == LTT_STRUCT); + nb = ltt_type_member_number(t); + for(i = 0 ; i < nb ; i++) { + ltt_type_member_type(t, i, &name); + if(strcmp(name, field) == 0) break; + } + g_assert(i < nb); + return ltt_field_member(f, i); +} + + +void +lttv_trace_find_hook(LttTrace *t, char *facility, char *event_type, + char *field1, char *field2, char *field3, LttvHook h, LttvTraceHook *th) +{ + LttFacility *f; + + LttEventType *et; + + guint nb, pos, i; + + char *name; + + nb = ltt_trace_facility_find(t, facility, &pos); + if(nb < 1) g_error("No %s facility", facility); + f = ltt_trace_facility_get(t, pos); + et = ltt_facility_eventtype_get_by_name(f, event_type); + if(et == NULL) g_error("Event %s does not exist", event_type); + + th->h = h; + th->id = ltt_eventtype_id(et); + th->f1 = find_field(et, field1); + th->f2 = find_field(et, field2); + th->f3 = find_field(et, field3); +} + + diff --git a/ltt/branches/poly/lttv/state.c b/ltt/branches/poly/lttv/state.c index 340f639c..d53aef72 100644 --- a/ltt/branches/poly/lttv/state.c +++ b/ltt/branches/poly/lttv/state.c @@ -3,12 +3,16 @@ #include #include -LttvInterruptType +LttvExecutionMode + LTTV_STATE_MODE_UNKNOWN, LTTV_STATE_USER_MODE, LTTV_STATE_SYSCALL, LTTV_STATE_TRAP, LTTV_STATE_IRQ; +LttvExecutionSubmode + LTTV_STATE_SUBMODE_UNKNOWN, + LTTV_STATE_SUBMODE_NONE; LttvProcessStatus LTTV_STATE_UNNAMED, @@ -21,7 +25,12 @@ LttvProcessStatus static GQuark LTTV_STATE_HOOKS; -void remove_all_processes(GHashTable *processes); + +static void fill_name_tables(LttvTraceState *tcs); + +static void free_name_tables(LttvTraceState *tcs); + +static void remove_all_processes(GHashTable *processes); LttvProcessState *create_process(LttvTracefileState *tfs, LttvProcessState *parent, guint pid); @@ -29,37 +38,40 @@ LttvProcessState *create_process(LttvTracefileState *tfs, static void init(LttvTracesetState *self, LttvTraceset *ts) { - guint i, j, nb_trace, nb_tracefile; + guint i, j, nb_trace, nb_control, nb_per_cpu, nb_tracefile; LttvTraceContext *tc; LttvTraceState *tcs; - LttvTracefileContext *tfc; - LttvTracefileState *tfcs; LttTime timestamp = {0,0}; - LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek_parent(LTTV_TRACESET_STATE_GET_CLASS(self)))->init((LttvTracesetContext *)self, ts); + LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))-> + init((LttvTracesetContext *)self, ts); nb_trace = lttv_traceset_number(ts); for(i = 0 ; i < nb_trace ; i++) { - tcs = (LttvTraceState *)tc = (LTTV_TRACESET_CONTEXT(self)->traces[i]); + tc = self->parent.traces[i]; + tcs = (LttvTraceState *)tc; tcs->processes = g_hash_table_new(g_direct_hash, g_direct_equal); + fill_name_tables(tcs); - nb_tracefile = ltt_trace_control_tracefile_number(tc->t); + nb_control = ltt_trace_control_tracefile_number(tc->t); + nb_per_cpu = ltt_trace_per_cpu_tracefile_number(tc->t); + nb_tracefile = nb_control + nb_per_cpu; for(j = 0 ; j < nb_tracefile ; j++) { - tfcs = (LttvTracefileState *)tfc = tc->control_tracefiles[j]; - tfc->timestamp = timestamp; - tfcs->process = create_process(tfcs, NULL,0); - } + if(j < nb_control) { + tfcs = LTTV_TRACEFILE_STATE(tc->control_tracefiles[j]); + } + else { + tfcs = LTTV_TRACEFILE_STATE(tc->per_cpu_tracefiles[j - nb_control]); + } - nb_tracefile = ltt_trace_per_cpu_tracefile_number(tc->t); - for(j = 0 ; j < nb_tracefile ; j++) { - tfcs = (LttvTracefileState *)tfc = tc->per_cpu_tracefiles[j]; - tfc->timestamp = timestamp; + tfcs->parent.timestamp = timestamp; tfcs->process = create_process(tfcs, NULL,0); + tfcs->cpu_name= g_quark_from_string(ltt_tracefile_name(tfcs->parent.tf)); } } } @@ -79,8 +91,10 @@ fini(LttvTracesetState *self) tcs = (LttvTraceState *)(LTTV_TRACESET_CONTEXT(self)->traces[i]); remove_all_processes(tcs->processes); g_hash_table_destroy(tcs->processes); + free_name_tables(tcs); } - LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek_parent(LTTV_TRACESET_STATE_GET_CLASS(self)))->fini((LttvTracesetContext *)self); + LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))-> + fini((LttvTracesetContext *)self); } @@ -114,7 +128,8 @@ traceset_state_instance_init (GTypeInstance *instance, gpointer g_class) static void traceset_state_finalize (LttvTracesetState *self) { - G_OBJECT_CLASS(g_type_class_peek_parent(g_type_class_peek_parent(LTTV_TRACESET_STATE_GET_CLASS(self))))->finalize(G_OBJECT(self)); + G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))-> + finalize(G_OBJECT(self)); } @@ -165,7 +180,8 @@ trace_state_instance_init (GTypeInstance *instance, gpointer g_class) static void trace_state_finalize (LttvTraceState *self) { - G_OBJECT_CLASS(g_type_class_peek_parent(g_type_class_peek_parent(LTTV_TRACE_STATE_GET_CLASS(self))))->finalize(G_OBJECT(self)); + G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE))-> + finalize(G_OBJECT(self)); } @@ -211,7 +227,8 @@ tracefile_state_instance_init (GTypeInstance *instance, gpointer g_class) static void tracefile_state_finalize (LttvTracefileState *self) { - G_OBJECT_CLASS(g_type_class_peek_parent(g_type_class_peek_parent(LTTV_TRACEFILE_STATE_GET_CLASS(self))))->finalize(G_OBJECT(self)); + G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE))-> + finalize(G_OBJECT(self)); } @@ -248,49 +265,128 @@ lttv_tracefile_state_get_type(void) } -struct HookData { - LttField *f1; - LttField *f2; - LttField *f3; -}; +static void +fill_name_tables(LttvTraceState *tcs) +{ + int i, nb; + char *f_name, *e_name; -struct HookId { - LttvHook h; - guint id; - void *hook_data; - gboolean free_hook_data; -}; + LttvTraceHook h; + + LttEventType *et; + + LttType *t; + + GString *fe_name = g_string_new(""); + + nb = ltt_trace_eventtype_number(tcs->parent.t); + tcs->eventtype_names = g_new(GQuark, nb); + for(i = 0 ; i < nb ; i++) { + et = ltt_trace_eventtype_get(tcs->parent.t, i); + e_name = ltt_eventtype_name(et); + f_name = ltt_facility_name(ltt_eventtype_facility(et)); + g_string_printf(fe_name, "%s.%s", f_name, e_name); + tcs->eventtype_names[i] = g_quark_from_string(fe_name->str); + } + lttv_trace_find_hook(tcs->parent.t, "core", "syscall_entry", + "syscall_id", NULL, NULL, NULL, &h); + t = ltt_field_type(h.f1); + nb = ltt_type_element_number(t); + + /* CHECK syscalls should be an emun but currently are not! + tcs->syscall_names = g_new(GQuark, nb); + + for(i = 0 ; i < nb ; i++) { + tcs->syscall_names[i] = g_quark_from_string(ltt_enum_string_get(t, i)); + } + */ + + tcs->syscall_names = g_new(GQuark, 256); + for(i = 0 ; i < 256 ; i++) { + g_string_printf(fe_name, "syscall %d", i); + tcs->syscall_names[i] = g_quark_from_string(fe_name->str); + } + + lttv_trace_find_hook(tcs->parent.t, "core", "trap_entry", + "trap_id", NULL, NULL, NULL, &h); + t = ltt_field_type(h.f1); + nb = ltt_type_element_number(t); + + /* + tcs->trap_names = g_new(GQuark, nb); + for(i = 0 ; i < nb ; i++) { + tcs->trap_names[i] = g_quark_from_string(ltt_enum_string_get(t, i)); + } + */ + + tcs->trap_names = g_new(GQuark, 256); + for(i = 0 ; i < 256 ; i++) { + g_string_printf(fe_name, "trap %d", i); + tcs->trap_names[i] = g_quark_from_string(fe_name->str); + } + + lttv_trace_find_hook(tcs->parent.t, "core", "irq_entry", + "irq_id", NULL, NULL, NULL, &h); + t = ltt_field_type(h.f1); + nb = ltt_type_element_number(t); + + /* + tcs->irq_names = g_new(GQuark, nb); + for(i = 0 ; i < nb ; i++) { + tcs->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i)); + } + */ + + tcs->irq_names = g_new(GQuark, 256); + for(i = 0 ; i < 256 ; i++) { + g_string_printf(fe_name, "irq %d", i); + tcs->irq_names[i] = g_quark_from_string(fe_name->str); + } + + g_string_free(fe_name, TRUE); +} + + +static void +free_name_tables(LttvTraceState *tcs) +{ + g_free(tcs->eventtype_names); + g_free(tcs->syscall_names); + g_free(tcs->trap_names); + g_free(tcs->irq_names); +} -static void push_state(LttvTracefileState *tfs, LttvInterruptType t, + +static void push_state(LttvTracefileState *tfs, LttvExecutionMode t, guint state_id) { - LttvInterruptState *intr; + LttvExecutionState *es; LttvProcessState *process = tfs->process; - guint depth = process->interrupt_stack->len; + guint depth = process->execution_stack->len; - g_array_set_size(process->interrupt_stack, depth + 1); - intr = &g_array_index(process->interrupt_stack, LttvInterruptState, depth); - intr->t = t; - intr->n = state_id; - intr->entry = intr->last_change = LTTV_TRACEFILE_CONTEXT(tfs)->timestamp; - intr->s = process->state->s; - process->state = intr; + g_array_set_size(process->execution_stack, depth + 1); + es = &g_array_index(process->execution_stack, LttvExecutionState, depth); + es->t = t; + es->n = state_id; + es->entry = es->change = tfs->parent.timestamp; + es->s = process->state->s; + process->state = es; } -static void pop_state(LttvTracefileState *tfs, LttvInterruptType t) +static void pop_state(LttvTracefileState *tfs, LttvExecutionMode t) { LttvProcessState *process = tfs->process; - guint depth = process->interrupt_stack->len - 1; + guint depth = process->execution_stack->len - 1; - // g_assert(process->state->t == t); if(process->state->t != t){ - g_warning("Different interrupt type: ignore it\n"); + g_warning("Different execution mode type (%d.%09d): ignore it\n", + tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec); g_warning("process state has %s when pop_int is %s\n", g_quark_to_string(process->state->t), g_quark_to_string(t)); @@ -301,10 +397,18 @@ static void pop_state(LttvTracefileState *tfs, LttvInterruptType t) g_quark_to_string(process->state->s)); return; } - g_array_remove_index(process->interrupt_stack, depth); + + if(depth == 0){ + g_warning("Trying to pop last state on stack (%d.%09d): ignore it\n", + tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec); + return; + } + + g_array_remove_index(process->execution_stack, depth); depth--; - process->state = &g_array_index(process->interrupt_stack, LttvInterruptState, + process->state = &g_array_index(process->execution_stack, LttvExecutionState, depth); + process->state->change = tfs->parent.timestamp; } @@ -313,38 +417,48 @@ LttvProcessState *create_process(LttvTracefileState *tfs, { LttvProcessState *process = g_new(LttvProcessState, 1); - LttvInterruptState *intr; + LttvExecutionState *es; LttvTraceContext *tc; LttvTraceState *tcs; - LttvTracefileContext *tfc = LTTV_TRACEFILE_CONTEXT(tfs); + char buffer[128]; - tcs = (LttvTraceState *)tc = tfc->t_context; + tcs = (LttvTraceState *)tc = tfs->parent.t_context; g_hash_table_insert(tcs->processes, GUINT_TO_POINTER(pid), process); process->pid = pid; - if(parent) process->ppid = parent->pid; - else process->ppid = 0; - process->birth = tfc->timestamp; - process->name = LTTV_STATE_UNNAMED; - process->interrupt_stack = g_array_new(FALSE, FALSE, - sizeof(LttvInterruptState)); - g_array_set_size(process->interrupt_stack, 1); - intr = process->state = &g_array_index(process->interrupt_stack, - LttvInterruptState, 0); - intr->t = LTTV_STATE_USER_MODE; - intr->n = 0; - intr->entry = tfc->timestamp; - intr->last_change = tfc->timestamp; - intr->s = LTTV_STATE_WAIT_FORK; + + if(parent) { + process->ppid = parent->pid; + process->name = parent->name; + } + else { + process->ppid = 0; + process->name = LTTV_STATE_UNNAMED; + } + + process->creation_time = tfs->parent.timestamp; + sprintf(buffer,"%d-%lu.%lu",pid, process->creation_time.tv_sec, + process->creation_time.tv_nsec); + process->pid_time = g_quark_from_string(buffer); + process->execution_stack = g_array_new(FALSE, FALSE, + sizeof(LttvExecutionState)); + g_array_set_size(process->execution_stack, 1); + es = process->state = &g_array_index(process->execution_stack, + LttvExecutionState, 0); + es->t = LTTV_STATE_USER_MODE; + es->n = LTTV_STATE_SUBMODE_NONE; + es->entry = tfs->parent.timestamp; + es->change = tfs->parent.timestamp; + es->s = LTTV_STATE_WAIT_FORK; return process; } -LttvProcessState *find_process(LttvTracefileState *tfs, guint pid) +LttvProcessState *lttv_state_find_process(LttvTracefileState *tfs, guint pid) { LttvTraceState *ts =(LttvTraceState *)LTTV_TRACEFILE_CONTEXT(tfs)->t_context; LttvProcessState *process = g_hash_table_lookup(ts->processes, @@ -354,42 +468,45 @@ LttvProcessState *find_process(LttvTracefileState *tfs, guint pid) } -void exit_process(LttvTracefileState *tfs, LttvProcessState *process) +static void exit_process(LttvTracefileState *tfs, LttvProcessState *process) { LttvTraceState *ts = LTTV_TRACE_STATE(tfs->parent.t_context); g_hash_table_remove(ts->processes, GUINT_TO_POINTER(process->pid)); - g_array_free(process->interrupt_stack, TRUE); + g_array_free(process->execution_stack, TRUE); g_free(process); } -void free_process_state(gpointer key, gpointer value, gpointer user_data) +static void free_process_state(gpointer key, gpointer value,gpointer user_data) { - g_array_free(((LttvProcessState *)value)->interrupt_stack, TRUE); + g_array_free(((LttvProcessState *)value)->execution_stack, TRUE); g_free(value); } -void remove_all_processes(GHashTable *processes) +static void remove_all_processes(GHashTable *processes) { g_hash_table_foreach(processes, free_process_state, NULL); } -gboolean syscall_entry(void *hook_data, void *call_data) +static gboolean syscall_entry(void *hook_data, void *call_data) { - LttField *f = (LttField *)hook_data; + LttField *f = ((LttvTraceHook *)hook_data)->f1; LttvTracefileState *s = (LttvTracefileState *)call_data; - push_state(s, LTTV_STATE_SYSCALL, ltt_event_get_unsigned( - LTTV_TRACEFILE_CONTEXT(s)->e, f)); + LttvExecutionSubmode submode; + + submode = ((LttvTraceState *)(s->parent.t_context))->syscall_names[ + ltt_event_get_unsigned(s->parent.e, f)]; + push_state(s, LTTV_STATE_SYSCALL, submode); return FALSE; } -gboolean syscall_exit(void *hook_data, void *call_data) +static gboolean syscall_exit(void *hook_data, void *call_data) { LttvTracefileState *s = (LttvTracefileState *)call_data; @@ -398,18 +515,22 @@ gboolean syscall_exit(void *hook_data, void *call_data) } -gboolean trap_entry(void *hook_data, void *call_data) +static gboolean trap_entry(void *hook_data, void *call_data) { - LttField *f = (LttField *)hook_data; + LttField *f = ((LttvTraceHook *)hook_data)->f1; LttvTracefileState *s = (LttvTracefileState *)call_data; - push_state(s, LTTV_STATE_TRAP, ltt_event_get_unsigned(s->parent.e, f)); + LttvExecutionSubmode submode; + + submode = ((LttvTraceState *)(s->parent.t_context))->trap_names[ + ltt_event_get_unsigned(s->parent.e, f)]; + push_state(s, LTTV_STATE_TRAP, submode); return FALSE; } -gboolean trap_exit(void *hook_data, void *call_data) +static gboolean trap_exit(void *hook_data, void *call_data) { LttvTracefileState *s = (LttvTracefileState *)call_data; @@ -418,19 +539,24 @@ gboolean trap_exit(void *hook_data, void *call_data) } -gboolean irq_entry(void *hook_data, void *call_data) +static gboolean irq_entry(void *hook_data, void *call_data) { - LttField *f = (LttField *)hook_data; + LttField *f = ((LttvTraceHook *)hook_data)->f1; LttvTracefileState *s = (LttvTracefileState *)call_data; + LttvExecutionSubmode submode; + + submode = ((LttvTraceState *)(s->parent.t_context))->irq_names[ + ltt_event_get_unsigned(s->parent.e, f)]; + /* Do something with the info about being in user or system mode when int? */ - push_state(s, LTTV_STATE_IRQ, ltt_event_get_unsigned(s->parent.e, f)); + push_state(s, LTTV_STATE_IRQ, submode); return FALSE; } -gboolean irq_exit(void *hook_data, void *call_data) +static gboolean irq_exit(void *hook_data, void *call_data) { LttvTracefileState *s = (LttvTracefileState *)call_data; @@ -439,9 +565,9 @@ gboolean irq_exit(void *hook_data, void *call_data) } -gboolean schedchange(void *hook_data, void *call_data) +static gboolean schedchange(void *hook_data, void *call_data) { - struct HookData *h = (struct HookData *)hook_data; + LttvTraceHook *h = (LttvTraceHook *)hook_data; LttvTracefileState *s = (LttvTracefileState *)call_data; @@ -450,7 +576,9 @@ gboolean schedchange(void *hook_data, void *call_data) pid_in = ltt_event_get_unsigned(s->parent.e, h->f1); 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(state_out == 0) s->process->state->s = LTTV_STATE_WAIT_CPU; else if(s->process->state->s == LTTV_STATE_EXIT) exit_process(s, s->process); @@ -458,16 +586,19 @@ gboolean schedchange(void *hook_data, void *call_data) if(s->process->pid == 0) s->process->pid == pid_out; + + s->process->state->change = s->parent.timestamp; } - s->process = find_process(s, pid_in); + s->process = lttv_state_find_process(s, pid_in); s->process->state->s = LTTV_STATE_RUN; + s->process->state->change = s->parent.timestamp; return FALSE; } -gboolean process_fork(void *hook_data, void *call_data) +static gboolean process_fork(void *hook_data, void *call_data) { - LttField *f = (LttField *)hook_data; + LttField *f = ((LttvTraceHook *)hook_data)->f1; LttvTracefileState *s = (LttvTracefileState *)call_data; @@ -479,7 +610,7 @@ gboolean process_fork(void *hook_data, void *call_data) } -gboolean process_exit(void *hook_data, void *call_data) +static gboolean process_exit(void *hook_data, void *call_data) { LttvTracefileState *s = (LttvTracefileState *)call_data; @@ -490,72 +621,6 @@ gboolean process_exit(void *hook_data, void *call_data) } -static LttField * -find_field(LttEventType *et, const char *field) -{ - LttType *t; - - LttField *f; - - guint i, nb; - - char *name; - - if(field == NULL) return NULL; - - f = ltt_eventtype_field(et); - t = ltt_eventtype_type(et); - g_assert(ltt_type_class(t) == LTT_STRUCT); - nb = ltt_type_member_number(t); - for(i = 0 ; i < nb ; i++) { - ltt_type_member_type(t, i, &name); - if(strcmp(name, field) == 0) break; - } - g_assert(i < nb); - return ltt_field_member(f, i); -} - - -static struct HookId -find_hook(LttTrace *t, char *facility, char *event, - char *field1, char *field2, char *field3, LttvHook h) -{ - LttFacility *f; - - LttEventType *et; - - guint nb, pos, i; - - struct HookId hook_id; - - struct HookData hook_data, *phook_data; - - char *name; - - nb = ltt_trace_facility_find(t, facility, &pos); - if(nb < 1) g_error("No %s facility", facility); - f = ltt_trace_facility_get(t, pos); - et = ltt_facility_eventtype_get_by_name(f, event); - if(et == NULL) g_error("Event %s does not exist", event); - - hook_id.id = ltt_eventtype_id(et); - hook_id.h = h; - hook_id.free_hook_data = FALSE; - hook_data.f1 = find_field(et, field1); - hook_data.f2 = find_field(et, field2); - hook_data.f3 = find_field(et, field3); - if(hook_data.f1 == NULL) hook_id.hook_data = NULL; - else if(hook_data.f2 == NULL) hook_id.hook_data = hook_data.f1; - else { - phook_data = g_new(struct HookData, 1); - *phook_data = hook_data; - hook_id.hook_data = phook_data; - hook_id.free_hook_data = TRUE; - } - return hook_id; -} - - lttv_state_add_event_hooks(LttvTracesetState *self) { LttvTraceset *traceset = self->parent.ts; @@ -574,7 +639,7 @@ lttv_state_add_event_hooks(LttvTracesetState *self) GArray *hooks; - struct HookId hook_id; + LttvTraceHook hook; LttvAttributeValue val; @@ -585,42 +650,35 @@ lttv_state_add_event_hooks(LttvTracesetState *self) /* Find the eventtype id for the following events and register the associated by id hooks. */ - hooks = g_array_new(FALSE, FALSE, sizeof(struct HookId)); - hook_id = find_hook(ts->parent.t, "core","syscall_entry","syscall_id", - NULL, NULL, syscall_entry); - g_array_append_val(hooks, hook_id); + hooks = g_array_new(FALSE, FALSE, sizeof(LttvTraceHook)); + g_array_set_size(hooks, 9); + + lttv_trace_find_hook(ts->parent.t, "core","syscall_entry","syscall_id", + NULL, NULL, syscall_entry, &g_array_index(hooks, LttvTraceHook, 0)); - hook_id = find_hook(ts->parent.t, "core", "syscall_exit", - NULL, NULL, NULL, syscall_exit); - g_array_append_val(hooks, hook_id); + lttv_trace_find_hook(ts->parent.t, "core", "syscall_exit", NULL, NULL, + NULL, syscall_exit, &g_array_index(hooks, LttvTraceHook, 1)); - hook_id = find_hook(ts->parent.t, "core", "trap_entry", "trap_id", - NULL, NULL, trap_entry); - g_array_append_val(hooks, hook_id); + lttv_trace_find_hook(ts->parent.t, "core", "trap_entry", "trap_id", + NULL, NULL, trap_entry, &g_array_index(hooks, LttvTraceHook, 2)); - hook_id = find_hook(ts->parent.t, "core", "trap_exit", NULL, NULL, - NULL, trap_exit); - g_array_append_val(hooks, hook_id); + lttv_trace_find_hook(ts->parent.t, "core", "trap_exit", NULL, NULL, NULL, + trap_exit, &g_array_index(hooks, LttvTraceHook, 3)); - hook_id = find_hook(ts->parent.t, "core", "irq_entry", "irq_id", - NULL, NULL, irq_entry); - g_array_append_val(hooks, hook_id); + lttv_trace_find_hook(ts->parent.t, "core", "irq_entry", "irq_id", NULL, + NULL, irq_entry, &g_array_index(hooks, LttvTraceHook, 4)); - hook_id = find_hook(ts->parent.t, "core", "irq_exit", NULL, NULL, - NULL, irq_exit); - g_array_append_val(hooks, hook_id); + lttv_trace_find_hook(ts->parent.t, "core", "irq_exit", NULL, NULL, NULL, + irq_exit, &g_array_index(hooks, LttvTraceHook, 5)); - hook_id = find_hook(ts->parent.t, "core", "schedchange", - "in", "out", "out_state", schedchange); - g_array_append_val(hooks, hook_id); + lttv_trace_find_hook(ts->parent.t, "core", "schedchange", "in", "out", + "out_state", schedchange, &g_array_index(hooks, LttvTraceHook, 6)); - hook_id = find_hook(ts->parent.t, "core", "process_fork", - "child_pid", NULL, NULL, process_fork); - g_array_append_val(hooks, hook_id); + lttv_trace_find_hook(ts->parent.t, "core", "process_fork", "child_pid", + NULL, NULL, process_fork, &g_array_index(hooks, LttvTraceHook, 7)); - hook_id = find_hook(ts->parent.t, "core", "process_exit", - NULL, NULL, NULL, process_exit); - g_array_append_val(hooks, hook_id); + lttv_trace_find_hook(ts->parent.t, "core", "process_exit", NULL, NULL, + NULL, process_exit, &g_array_index(hooks, LttvTraceHook, 8)); /* Add these hooks to each before_event_by_id hooks list */ @@ -636,9 +694,9 @@ lttv_state_add_event_hooks(LttvTracesetState *self) } for(k = 0 ; k < hooks->len ; k++) { - hook_id = g_array_index(hooks, struct HookId, k); - lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.before_event_by_id, - hook_id.id), hook_id.h, hook_id.hook_data); + hook = g_array_index(hooks, LttvTraceHook, k); + lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.after_event_by_id, + hook.id), hook.h, &g_array_index(hooks, LttvTraceHook, k)); } } lttv_attribute_find(self->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val); @@ -661,7 +719,7 @@ lttv_state_remove_event_hooks(LttvTracesetState *self) GArray *hooks; - struct HookId hook_id; + LttvTraceHook hook; LttvAttributeValue val; @@ -685,16 +743,11 @@ lttv_state_remove_event_hooks(LttvTracesetState *self) } for(k = 0 ; k < hooks->len ; k++) { - hook_id = g_array_index(hooks, struct HookId, k); + hook = g_array_index(hooks, LttvTraceHook, k); lttv_hooks_remove_data( - lttv_hooks_by_id_find(tfs->parent.before_event_by_id, - hook_id.id), hook_id.h, hook_id.hook_data); - if(hook_id.free_hook_data) g_free(hook_id.hook_data); + lttv_hooks_by_id_find(tfs->parent.after_event_by_id, + hook.id), hook.h, &g_array_index(hooks, LttvTraceHook, k)); } - // for(k = 0 ; k < hooks->len ; k++) { - // hook_id = g_array_index(hooks, struct HookId, k); - // if(hook_id.free_hook_data) g_free(hook_id.hook_data); - // } } g_array_free(hooks, TRUE); } @@ -704,11 +757,14 @@ lttv_state_remove_event_hooks(LttvTracesetState *self) void lttv_state_init(int argc, char **argv) { 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_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_WAIT = g_quark_from_string("wait for I/O"); diff --git a/ltt/branches/poly/lttv/stats.c b/ltt/branches/poly/lttv/stats.c new file mode 100644 index 00000000..d0bb4cdf --- /dev/null +++ b/ltt/branches/poly/lttv/stats.c @@ -0,0 +1,824 @@ + +#include +#include +#include +#include + +GQuark + LTTV_STATS_PROCESS_UNKNOWN, + LTTV_STATS_PROCESSES, + LTTV_STATS_CPU, + LTTV_STATS_MODE_TYPES, + LTTV_STATS_MODES, + LTTV_STATS_SUBMODES, + LTTV_STATS_EVENT_TYPES, + LTTV_STATS_CPU_TIME, + LTTV_STATS_ELAPSED_TIME, + LTTV_STATS_EVENTS, + LTTV_STATS_EVENTS_COUNT; + +static GQuark + LTTV_STATS_BEFORE_HOOKS, + LTTV_STATS_AFTER_HOOKS; + +static void remove_all_processes(GHashTable *processes); + +static void +find_event_tree(LttvTracefileStats *tfcs, GQuark process, GQuark cpu, + GQuark mode, GQuark sub_mode, LttvAttribute **events_tree, + LttvAttribute **event_types_tree); + +static void +init(LttvTracesetStats *self, LttvTraceset *ts) +{ + guint i, j, nb_trace, nb_control, nb_per_cpu, nb_tracefile; + + LttvTraceContext *tc; + + LttvTraceStats *tcs; + + LttvTracefileContext *tfc; + + LttvTracefileStats *tfcs; + + LttTime timestamp = {0,0}; + + LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_STATE_TYPE))-> + init((LttvTracesetContext *)self, ts); + + self->stats = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL); + nb_trace = lttv_traceset_number(ts); + + for(i = 0 ; i < nb_trace ; i++) { + tcs = (LttvTraceStats *)tc = (LTTV_TRACESET_CONTEXT(self)->traces[i]); + tcs->stats = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL); + + nb_control = ltt_trace_control_tracefile_number(tc->t); + nb_per_cpu = ltt_trace_per_cpu_tracefile_number(tc->t); + nb_tracefile = nb_control + nb_per_cpu; + for(j = 0 ; j < nb_tracefile ; j++) { + if(j < nb_control) { + tfcs = LTTV_TRACEFILE_STATS(tc->control_tracefiles[j]); + } + else { + tfcs = LTTV_TRACEFILE_STATS(tc->per_cpu_tracefiles[j - nb_control]); + } + + tfcs->stats = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL); + find_event_tree(tfcs, LTTV_STATS_PROCESS_UNKNOWN, + tfcs->parent.cpu_name, LTTV_STATE_MODE_UNKNOWN, + LTTV_STATE_SUBMODE_UNKNOWN, &tfcs->current_events_tree, + &tfcs->current_event_types_tree); + } + } +} + + +static void +fini(LttvTracesetStats *self) +{ + guint i, j, nb_trace, nb_tracefile; + + LttvTraceset *ts; + + LttvTraceContext *tc; + + LttvTraceStats *tcs; + + LttvTracefileContext *tfc; + + LttvTracefileStats *tfcs; + + LttTime timestamp = {0,0}; + + lttv_attribute_recursive_free(self->stats); + ts = self->parent.parent.ts; + nb_trace = lttv_traceset_number(ts); + + for(i = 0 ; i < nb_trace ; i++) { + tcs = (LttvTraceStats *)tc = (LTTV_TRACESET_CONTEXT(self)->traces[i]); + lttv_attribute_recursive_free(tcs->stats); + + nb_tracefile = ltt_trace_control_tracefile_number(tc->t); + for(j = 0 ; j < nb_tracefile ; j++) { + tfcs = (LttvTracefileStats *)tfc = tc->control_tracefiles[j]; + lttv_attribute_recursive_free(tfcs->stats); + tfcs->current_events_tree = NULL; + tfcs->current_event_types_tree = NULL; + } + + nb_tracefile = ltt_trace_per_cpu_tracefile_number(tc->t); + for(j = 0 ; j < nb_tracefile ; j++) { + tfcs = (LttvTracefileStats *)tfc = tc->per_cpu_tracefiles[j]; + lttv_attribute_recursive_free(tfcs->stats); + tfcs->current_events_tree = NULL; + tfcs->current_event_types_tree = NULL; + } + } + LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_STATE_TYPE))-> + fini((LttvTracesetContext *)self); +} + + +static LttvTracesetContext * +new_traceset_context(LttvTracesetContext *self) +{ + return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATS_TYPE, NULL)); +} + + +static LttvTraceContext * +new_trace_context(LttvTracesetContext *self) +{ + return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATS_TYPE, NULL)); +} + + +static LttvTracefileContext * +new_tracefile_context(LttvTracesetContext *self) +{ + return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATS_TYPE, NULL)); +} + + +static void +traceset_stats_instance_init (GTypeInstance *instance, gpointer g_class) +{ +} + + +static void +traceset_stats_finalize (LttvTracesetStats *self) +{ + G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_STATE_TYPE))-> + finalize(G_OBJECT(self)); +} + + +static void +traceset_stats_class_init (LttvTracesetContextClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS(klass); + + gobject_class->finalize = (void (*)(GObject *self)) traceset_stats_finalize; + klass->init = (void (*)(LttvTracesetContext *self, LttvTraceset *ts))init; + klass->fini = (void (*)(LttvTracesetContext *self))fini; + klass->new_traceset_context = new_traceset_context; + klass->new_trace_context = new_trace_context; + klass->new_tracefile_context = new_tracefile_context; +} + + +GType +lttv_traceset_stats_get_type(void) +{ + static GType type = 0; + if (type == 0) { + static const GTypeInfo info = { + sizeof (LttvTracesetStatsClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) traceset_stats_class_init, /* class_init */ + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (LttvTracesetContext), + 0, /* n_preallocs */ + (GInstanceInitFunc) traceset_stats_instance_init /* instance_init */ + }; + + type = g_type_register_static (LTTV_TRACESET_STATE_TYPE, "LttvTracesetStatsType", + &info, 0); + } + return type; +} + + +static void +trace_stats_instance_init (GTypeInstance *instance, gpointer g_class) +{ +} + + +static void +trace_stats_finalize (LttvTraceStats *self) +{ + G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_STATE_TYPE))-> + finalize(G_OBJECT(self)); +} + + +static void +trace_stats_class_init (LttvTraceContextClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS(klass); + + gobject_class->finalize = (void (*)(GObject *self)) trace_stats_finalize; +} + + +GType +lttv_trace_stats_get_type(void) +{ + static GType type = 0; + if (type == 0) { + static const GTypeInfo info = { + sizeof (LttvTraceStatsClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) trace_stats_class_init, /* class_init */ + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (LttvTraceStats), + 0, /* n_preallocs */ + (GInstanceInitFunc) trace_stats_instance_init /* instance_init */ + }; + + type = g_type_register_static (LTTV_TRACE_STATE_TYPE, + "LttvTraceStatsType", &info, 0); + } + return type; +} + + +static void +tracefile_stats_instance_init (GTypeInstance *instance, gpointer g_class) +{ +} + + +static void +tracefile_stats_finalize (LttvTracefileStats *self) +{ + G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_STATE_TYPE))-> + finalize(G_OBJECT(self)); +} + + +static void +tracefile_stats_class_init (LttvTracefileStatsClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS(klass); + + gobject_class->finalize = (void (*)(GObject *self)) tracefile_stats_finalize; +} + + +GType +lttv_tracefile_stats_get_type(void) +{ + static GType type = 0; + if (type == 0) { + static const GTypeInfo info = { + sizeof (LttvTracefileStatsClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) tracefile_stats_class_init, /* class_init */ + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (LttvTracefileStats), + 0, /* n_preallocs */ + (GInstanceInitFunc) tracefile_stats_instance_init /* instance_init */ + }; + + type = g_type_register_static (LTTV_TRACEFILE_STATE_TYPE, + "LttvTracefileStatsType", &info, 0); + } + return type; +} + + +static void +find_event_tree(LttvTracefileStats *tfcs, GQuark process, GQuark cpu, + GQuark mode, GQuark sub_mode, LttvAttribute **events_tree, + LttvAttribute **event_types_tree) +{ + LttvAttribute *a; + + LttvTraceStats *tcs = LTTV_TRACE_STATS(tfcs->parent.parent.t_context); + a = lttv_attribute_find_subdir(tcs->stats, LTTV_STATS_PROCESSES); + a = lttv_attribute_find_subdir(a, tfcs->parent.process->pid_time); + a = lttv_attribute_find_subdir(a, LTTV_STATS_CPU); + a = lttv_attribute_find_subdir(a, tfcs->parent.cpu_name); + a = lttv_attribute_find_subdir(a, LTTV_STATS_MODE_TYPES); + a = lttv_attribute_find_subdir(a, tfcs->parent.process->state->t); + a = lttv_attribute_find_subdir(a, LTTV_STATS_SUBMODES); + a = lttv_attribute_find_subdir(a, tfcs->parent.process->state->n); + *events_tree = a; + a = lttv_attribute_find_subdir(a, LTTV_STATS_EVENT_TYPES); + *event_types_tree = a; +} + + +static void update_event_tree(LttvTracefileStats *tfcs) +{ + LttvExecutionState *es = tfcs->parent.process->state; + + find_event_tree(tfcs, tfcs->parent.process->pid_time, tfcs->parent.cpu_name, + es->t, es->n, &(tfcs->current_events_tree), + &(tfcs->current_event_types_tree)); +} + + +static void mode_change(LttvTracefileStats *tfcs) +{ + LttvAttributeValue cpu_time; + + LttTime delta; + + lttv_attribute_find(tfcs->current_events_tree, LTTV_STATS_CPU_TIME, + LTTV_TIME, &cpu_time); + TimeSub(delta, tfcs->parent.parent.timestamp, + tfcs->parent.process->state->change); + TimeAdd(*(cpu_time.v_time), *(cpu_time.v_time), delta); +} + + +static void mode_end(LttvTracefileStats *tfcs) +{ + LttvAttributeValue elapsed_time, cpu_time; + + LttTime delta; + + lttv_attribute_find(tfcs->current_events_tree, LTTV_STATS_ELAPSED_TIME, + LTTV_TIME, &elapsed_time); + TimeSub(delta, tfcs->parent.parent.timestamp, + tfcs->parent.process->state->entry); + TimeAdd(*(elapsed_time.v_time), *(elapsed_time.v_time), delta); + + lttv_attribute_find(tfcs->current_events_tree, LTTV_STATS_CPU_TIME, + LTTV_TIME, &cpu_time); + TimeSub(delta, tfcs->parent.parent.timestamp, + tfcs->parent.process->state->change); + TimeAdd(*(cpu_time.v_time), *(cpu_time.v_time), delta); +} + + +static gboolean before_syscall_entry(void *hook_data, void *call_data) +{ + mode_change((LttvTracefileStats *)call_data); + return FALSE; +} + + +static gboolean after_syscall_entry(void *hook_data, void *call_data) +{ + update_event_tree((LttvTracefileStats *)call_data); + return FALSE; +} + + +gboolean before_syscall_exit(void *hook_data, void *call_data) +{ + mode_end((LttvTracefileStats *)call_data); + return FALSE; +} + + +static gboolean after_syscall_exit(void *hook_data, void *call_data) +{ + update_event_tree((LttvTracefileStats *)call_data); + return FALSE; +} + + +gboolean before_trap_entry(void *hook_data, void *call_data) +{ + mode_change((LttvTracefileStats *)call_data); + return FALSE; +} + + +static gboolean after_trap_entry(void *hook_data, void *call_data) +{ + update_event_tree((LttvTracefileStats *)call_data); + return FALSE; +} + + +gboolean before_trap_exit(void *hook_data, void *call_data) +{ + mode_end((LttvTracefileStats *)call_data); + return FALSE; +} + + +gboolean after_trap_exit(void *hook_data, void *call_data) +{ + update_event_tree((LttvTracefileStats *)call_data); + return FALSE; +} + + +gboolean before_irq_entry(void *hook_data, void *call_data) +{ + mode_change((LttvTracefileStats *)call_data); + return FALSE; +} + + +gboolean after_irq_entry(void *hook_data, void *call_data) +{ + update_event_tree((LttvTracefileStats *)call_data); + return FALSE; +} + + +gboolean before_irq_exit(void *hook_data, void *call_data) +{ + mode_end((LttvTracefileStats *)call_data); + return FALSE; +} + + +gboolean after_irq_exit(void *hook_data, void *call_data) +{ + update_event_tree((LttvTracefileStats *)call_data); + return FALSE; +} + + +gboolean before_schedchange(void *hook_data, void *call_data) +{ + LttvTraceHook *h = (LttvTraceHook *)hook_data; + + LttvTracefileStats *tfcs = (LttvTracefileStats *)call_data; + + guint pid_in, pid_out, state_out; + + LttvProcessState *process; + + pid_in = ltt_event_get_unsigned(tfcs->parent.parent.e, h->f1); + pid_out = ltt_event_get_unsigned(tfcs->parent.parent.e, h->f2); + state_out = ltt_event_get_unsigned(tfcs->parent.parent.e, h->f3); + + /* compute the time for the process to schedule out */ + + mode_change(tfcs); + + /* get the information for the process scheduled in */ + + process = lttv_state_find_process(&(tfcs->parent), pid_in); + + find_event_tree(tfcs, process->pid_time, tfcs->parent.cpu_name, + process->state->t, process->state->n, &(tfcs->current_events_tree), + &(tfcs->current_event_types_tree)); + + /* compute the time waiting for the process to schedule in */ + + mode_change(tfcs); + return FALSE; +} + + +gboolean process_fork(void *hook_data, void *call_data) +{ + /* nothing to do for now */ + return FALSE; +} + + +gboolean process_exit(void *hook_data, void *call_data) +{ + /* We should probably exit all modes here or we could do that at + schedule out. */ + return FALSE; +} + + +gboolean every_event(void *hook_data, void *call_data) +{ + LttvTracefileStats *tfcs = (LttvTracefileStats *)call_data; + + LttvAttributeValue v; + + /* The current branch corresponds to the tracefile/process/interrupt state. + Statistics are added within it, to count the number of events of this + type occuring in this context. A quark has been pre-allocated for each + event type and is used as name. */ + + lttv_attribute_find(tfcs->current_event_types_tree, + ((LttvTraceState *)(tfcs->parent.parent.t_context))-> + eventtype_names[ltt_event_eventtype_id(tfcs->parent.parent.e)], + LTTV_UINT, &v); + (*(v.v_uint))++; + return FALSE; +} + + +static gboolean +sum_stats(void *hook_data, void *call_data) +{ + LttvTracesetStats *tscs = (LttvTracesetStats *)call_data; + + LttvTraceStats *tcs; + + LttvTraceset *traceset = tscs->parent.parent.ts; + + LttvAttributeType type; + + LttvAttributeValue value; + + LttvAttributeName name; + + unsigned sum; + + int i, j, k, l, m, n, nb_trace, nb_process, nb_cpu, nb_mode_type, nb_submode, + nb_event_type; + + LttvAttribute *main_tree, *processes_tree, *process_tree, *cpus_tree, + *cpu_tree, *mode_tree, *mode_types_tree, *submodes_tree, + *submode_tree, *event_types_tree, *mode_events_tree, + *cpu_events_tree, *process_modes_tree, *trace_cpu_tree, + *trace_modes_tree, *traceset_modes_tree; + + traceset_modes_tree = lttv_attribute_find_subdir(tscs->stats, + LTTV_STATS_MODES); + nb_trace = lttv_traceset_number(traceset); + + for(i = 0 ; i < nb_trace ; i++) { + tcs = (LttvTraceStats *)(tscs->parent.parent.traces[i]); + main_tree = tcs->stats; + processes_tree = lttv_attribute_find_subdir(main_tree, + LTTV_STATS_PROCESSES); + trace_modes_tree = lttv_attribute_find_subdir(main_tree, LTTV_STATS_MODES); + nb_process = lttv_attribute_get_number(processes_tree); + + for(j = 0 ; j < nb_process ; j++) { + type = lttv_attribute_get(processes_tree, j, &name, &value); + process_tree = LTTV_ATTRIBUTE(*(value.v_gobject)); + + cpus_tree = lttv_attribute_find_subdir(process_tree, LTTV_STATS_CPU); + process_modes_tree = lttv_attribute_find_subdir(process_tree, + LTTV_STATS_MODES); + nb_cpu = lttv_attribute_get_number(cpus_tree); + + for(k = 0 ; k < nb_cpu ; k++) { + type = lttv_attribute_get(cpus_tree, k, &name, &value); + cpu_tree = LTTV_ATTRIBUTE(*(value.v_gobject)); + + mode_types_tree = lttv_attribute_find_subdir(cpu_tree, + LTTV_STATS_MODE_TYPES); + cpu_events_tree = lttv_attribute_find_subdir(cpu_tree, + LTTV_STATS_EVENTS); + trace_cpu_tree = lttv_attribute_find_subdir(main_tree, LTTV_STATS_CPU); + trace_cpu_tree = lttv_attribute_find_subdir(trace_cpu_tree, name); + nb_mode_type = lttv_attribute_get_number(mode_types_tree); + + for(l = 0 ; l < nb_mode_type ; l++) { + type = lttv_attribute_get(mode_types_tree, l, &name, &value); + mode_tree = LTTV_ATTRIBUTE(*(value.v_gobject)); + + submodes_tree = lttv_attribute_find_subdir(mode_tree, + LTTV_STATS_SUBMODES); + mode_events_tree = lttv_attribute_find_subdir(mode_tree, + LTTV_STATS_EVENTS); + nb_submode = lttv_attribute_get_number(submodes_tree); + + for(m = 0 ; m < nb_submode ; m++) { + type = lttv_attribute_get(submodes_tree, m, &name, &value); + submode_tree = LTTV_ATTRIBUTE(*(value.v_gobject)); + + event_types_tree = lttv_attribute_find_subdir(submode_tree, + LTTV_STATS_EVENT_TYPES); + nb_event_type = lttv_attribute_get_number(event_types_tree); + + sum = 0; + for(n = 0 ; n < nb_event_type ; n++) { + type = lttv_attribute_get(event_types_tree, n, &name, &value); + sum += *(value.v_uint); + } + lttv_attribute_find(submode_tree, LTTV_STATS_EVENTS_COUNT, + LTTV_UINT, &value); + *(value.v_uint) = sum; + lttv_attribute_recursive_add(mode_events_tree, submode_tree); + } + lttv_attribute_recursive_add(cpu_events_tree, mode_events_tree); + } + lttv_attribute_recursive_add(process_modes_tree, cpu_tree); + lttv_attribute_recursive_add(trace_cpu_tree, cpu_tree); + } + lttv_attribute_recursive_add(trace_modes_tree, process_modes_tree); + } + lttv_attribute_recursive_add(traceset_modes_tree, trace_modes_tree); + } + return FALSE; +} + + +lttv_stats_add_event_hooks(LttvTracesetStats *self) +{ + LttvTraceset *traceset = self->parent.parent.ts; + + guint i, j, k, nb_trace, nb_control, nb_per_cpu, nb_tracefile; + + LttFacility *f; + + LttEventType *et; + + LttvTraceStats *ts; + + LttvTracefileStats *tfs; + + void *hook_data; + + GArray *hooks, *before_hooks, *after_hooks; + + LttvTraceHook hook; + + LttvAttributeValue val; + + nb_trace = lttv_traceset_number(traceset); + for(i = 0 ; i < nb_trace ; i++) { + ts = (LttvTraceStats *)self->parent.parent.traces[i]; + + /* Find the eventtype id for the following events and register the + associated by id hooks. */ + + hooks = g_array_new(FALSE, FALSE, sizeof(LttvTraceHook)); + g_array_set_size(hooks, 7); + + lttv_trace_find_hook(ts->parent.parent.t, "core","syscall_entry", + "syscall_id", NULL, NULL, before_syscall_entry, + &g_array_index(hooks, LttvTraceHook, 0)); + + lttv_trace_find_hook(ts->parent.parent.t, "core", "syscall_exit", NULL, + NULL, NULL, before_syscall_exit, + &g_array_index(hooks, LttvTraceHook, 1)); + + lttv_trace_find_hook(ts->parent.parent.t, "core", "trap_entry", "trap_id", + NULL, NULL, before_trap_entry, + &g_array_index(hooks, LttvTraceHook, 2)); + + lttv_trace_find_hook(ts->parent.parent.t, "core", "trap_exit", NULL, NULL, + NULL, before_trap_exit, &g_array_index(hooks, LttvTraceHook, 3)); + + lttv_trace_find_hook(ts->parent.parent.t, "core", "irq_entry", "irq_id", + NULL, NULL, before_irq_entry, &g_array_index(hooks, LttvTraceHook, 4)); + + lttv_trace_find_hook(ts->parent.parent.t, "core", "irq_exit", NULL, NULL, + NULL, before_irq_exit, &g_array_index(hooks, LttvTraceHook, 5)); + + lttv_trace_find_hook(ts->parent.parent.t, "core", "schedchange", "in", + "out", "out_state", before_schedchange, + &g_array_index(hooks, LttvTraceHook, 6)); + + before_hooks = hooks; + + hooks = g_array_new(FALSE, FALSE, sizeof(LttvTraceHook)); + g_array_set_size(hooks, 8); + + lttv_trace_find_hook(ts->parent.parent.t, "core","syscall_entry", + "syscall_id", NULL, NULL, after_syscall_entry, + &g_array_index(hooks, LttvTraceHook, 0)); + + lttv_trace_find_hook(ts->parent.parent.t, "core", "syscall_exit", NULL, + NULL, NULL, after_syscall_exit, + &g_array_index(hooks, LttvTraceHook, 1)); + + lttv_trace_find_hook(ts->parent.parent.t, "core", "trap_entry", "trap_id", + NULL, NULL, after_trap_entry, &g_array_index(hooks, LttvTraceHook, 2)); + + lttv_trace_find_hook(ts->parent.parent.t, "core", "trap_exit", NULL, NULL, + NULL, after_trap_exit, &g_array_index(hooks, LttvTraceHook, 3)); + + lttv_trace_find_hook(ts->parent.parent.t, "core", "irq_entry", "irq_id", + NULL, NULL, after_irq_entry, &g_array_index(hooks, LttvTraceHook, 4)); + + lttv_trace_find_hook(ts->parent.parent.t, "core", "irq_exit", NULL, NULL, + NULL, after_irq_exit, &g_array_index(hooks, LttvTraceHook, 5)); + + lttv_trace_find_hook(ts->parent.parent.t, "core", "process_fork", + "child_pid", NULL, NULL, process_fork, + &g_array_index(hooks, LttvTraceHook, 6)); + + lttv_trace_find_hook(ts->parent.parent.t, "core", "process_exit", NULL, + NULL, NULL, process_exit, &g_array_index(hooks, LttvTraceHook, 7)); + + after_hooks = hooks; + + /* Add these hooks to each before_event_by_id hooks list */ + + nb_control = ltt_trace_control_tracefile_number(ts->parent.parent.t); + nb_per_cpu = ltt_trace_per_cpu_tracefile_number(ts->parent.parent.t); + nb_tracefile = nb_control + nb_per_cpu; + for(j = 0 ; j < nb_tracefile ; j++) { + if(j < nb_control) { + tfs = LTTV_TRACEFILE_STATS(ts->parent.parent.control_tracefiles[j]); + } + else { + tfs = LTTV_TRACEFILE_STATS(ts->parent.parent.per_cpu_tracefiles[ + j-nb_control]); + } + + lttv_hooks_add(tfs->parent.parent.after_event, every_event, NULL); + + for(k = 0 ; k < before_hooks->len ; k++) { + hook = g_array_index(before_hooks, LttvTraceHook, k); + lttv_hooks_add(lttv_hooks_by_id_find( + tfs->parent.parent.before_event_by_id, + hook.id), hook.h, &g_array_index(before_hooks, LttvTraceHook, k)); + } + for(k = 0 ; k < after_hooks->len ; k++) { + hook = g_array_index(after_hooks, LttvTraceHook, k); + lttv_hooks_add(lttv_hooks_by_id_find( + tfs->parent.parent.after_event_by_id, + hook.id), hook.h, &g_array_index(after_hooks, LttvTraceHook, k)); + } + } + lttv_attribute_find(self->parent.parent.a, LTTV_STATS_BEFORE_HOOKS, + LTTV_POINTER, &val); + *(val.v_pointer) = before_hooks; + lttv_attribute_find(self->parent.parent.a, LTTV_STATS_AFTER_HOOKS, + LTTV_POINTER, &val); + *(val.v_pointer) = after_hooks; + } + lttv_hooks_add(self->parent.parent.after, sum_stats, NULL); +} + + +lttv_stats_remove_event_hooks(LttvTracesetStats *self) +{ + LttvTraceset *traceset = self->parent.parent.ts; + + guint i, j, k, nb_trace, nb_control, nb_per_cpu, nb_tracefile; + + LttvTraceStats *ts; + + LttvTracefileStats *tfs; + + void *hook_data; + + GArray *before_hooks, *after_hooks; + + LttvTraceHook hook; + + LttvAttributeValue val; + + nb_trace = lttv_traceset_number(traceset); + for(i = 0 ; i < nb_trace ; i++) { + ts = LTTV_TRACE_STATS(self->parent.parent.traces[i]); + lttv_attribute_find(self->parent.parent.a, LTTV_STATS_BEFORE_HOOKS, + LTTV_POINTER, &val); + before_hooks = *(val.v_pointer); + lttv_attribute_find(self->parent.parent.a, LTTV_STATS_AFTER_HOOKS, + LTTV_POINTER, &val); + after_hooks = *(val.v_pointer); + + /* Add these hooks to each before_event_by_id hooks list */ + + nb_control = ltt_trace_control_tracefile_number(ts->parent.parent.t); + nb_per_cpu = ltt_trace_per_cpu_tracefile_number(ts->parent.parent.t); + nb_tracefile = nb_control + nb_per_cpu; + for(j = 0 ; j < nb_tracefile ; j++) { + if(j < nb_control) { + tfs = LTTV_TRACEFILE_STATS(ts->parent.parent.control_tracefiles[j]); + } + else { + tfs =LTTV_TRACEFILE_STATS(ts->parent.parent.per_cpu_tracefiles[ + j-nb_control]); + } + + lttv_hooks_remove_data(tfs->parent.parent.after_event, every_event, + NULL); + + for(k = 0 ; k < before_hooks->len ; k++) { + hook = g_array_index(before_hooks, LttvTraceHook, k); + lttv_hooks_remove_data( + lttv_hooks_by_id_find(tfs->parent.parent.before_event_by_id, + hook.id), hook.h, &g_array_index(before_hooks, LttvTraceHook, k)); + } + for(k = 0 ; k < after_hooks->len ; k++) { + hook = g_array_index(after_hooks, LttvTraceHook, k); + lttv_hooks_remove_data( + lttv_hooks_by_id_find(tfs->parent.parent.after_event_by_id, + hook.id), hook.h, &g_array_index(after_hooks, LttvTraceHook, k)); + } + } + g_array_free(before_hooks, TRUE); + g_array_free(after_hooks, TRUE); + } + lttv_hooks_remove_data(self->parent.parent.after, sum_stats, NULL); +} + + +void lttv_stats_init(int argc, char **argv) +{ + LTTV_STATS_PROCESS_UNKNOWN = g_quark_from_string("unknown process"); + LTTV_STATS_PROCESSES = g_quark_from_string("processes"); + LTTV_STATS_CPU = g_quark_from_string("cpu"); + LTTV_STATS_MODE_TYPES = g_quark_from_string("mode_types"); + LTTV_STATS_MODES = g_quark_from_string("modes"); + LTTV_STATS_SUBMODES = g_quark_from_string("submodes"); + LTTV_STATS_EVENT_TYPES = g_quark_from_string("event_types"); + LTTV_STATS_CPU_TIME = g_quark_from_string("cpu time"); + LTTV_STATS_ELAPSED_TIME = g_quark_from_string("elapsed time"); + LTTV_STATS_EVENTS = g_quark_from_string("events"); + LTTV_STATS_EVENTS_COUNT = g_quark_from_string("events count"); + LTTV_STATS_BEFORE_HOOKS = g_quark_from_string("saved stats before hooks"); + LTTV_STATS_AFTER_HOOKS = g_quark_from_string("saved stats after hooks"); +} + +void lttv_stats_destroy() +{ +} + diff --git a/ltt/branches/poly/lttv/textDump.c b/ltt/branches/poly/lttv/textDump.c index 04bc344d..73cd5b90 100644 --- a/ltt/branches/poly/lttv/textDump.c +++ b/ltt/branches/poly/lttv/textDump.c @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include #include #include @@ -17,10 +17,12 @@ static gboolean a_field_names, - a_state; + a_state, + a_cpu_stats, + a_process_stats; static char - *a_file_name; + *a_file_name = NULL; static LttvHooks *before_traceset, @@ -112,9 +114,10 @@ void lttv_event_to_string(LttEvent *e, LttTracefile *tf, GString *s, if(mandatory_fields) { time = ltt_event_time(e); - g_string_append_printf(s,"%s.%s: %ld.%ld (%s)",ltt_facility_name(facility), + g_string_append_printf(s,"%s.%s: %ld.%09ld (%s)", + ltt_facility_name(facility), ltt_eventtype_name(event_type), (long)time.tv_sec, time.tv_nsec, - ltt_tracefile_name(tf)); + g_quark_to_string(tfs->cpu_name)); /* Print the process id and the state/interrupt type of the process */ g_string_append_printf(s,", %u, %u, %s", tfs->process->pid, tfs->process->ppid, @@ -126,6 +129,106 @@ void lttv_event_to_string(LttEvent *e, LttTracefile *tf, GString *s, } +static void +print_tree(FILE *fp, GString *indent, LttvAttribute *tree) +{ + int i, nb, saved_length; + + LttvAttribute *subtree; + + LttvAttributeName name; + + LttvAttributeValue value; + + LttvAttributeType type; + + nb = lttv_attribute_get_number(tree); + for(i = 0 ; i < nb ; i++) { + type = lttv_attribute_get(tree, i, &name, &value); + fprintf(fp, "%s%s: ", indent->str, g_quark_to_string(name)); + + switch(type) { + case LTTV_INT: + fprintf(fp, "%d\n", *value.v_int); + break; + case LTTV_UINT: + fprintf(fp, "%u\n", *value.v_uint); + break; + case LTTV_LONG: + fprintf(fp, "%ld\n", *value.v_long); + break; + case LTTV_ULONG: + fprintf(fp, "%lu\n", *value.v_ulong); + break; + case LTTV_FLOAT: + fprintf(fp, "%f\n", (double)*value.v_float); + break; + case LTTV_DOUBLE: + fprintf(fp, "%f\n", *value.v_double); + break; + case LTTV_TIME: + fprintf(fp, "%10u.%09u\n", value.v_time->tv_sec, + value.v_time->tv_nsec); + break; + case LTTV_POINTER: + fprintf(fp, "POINTER\n"); + break; + case LTTV_STRING: + fprintf(fp, "%s\n", *value.v_string); + break; + case LTTV_GOBJECT: + if(LTTV_IS_ATTRIBUTE(*(value.v_gobject))) { + fprintf(fp, "\n"); + subtree = (LttvAttribute *)*(value.v_gobject); + saved_length = indent->len; + g_string_append(indent, " "); + print_tree(fp, indent, subtree); + g_string_truncate(indent, saved_length); + } + else fprintf(fp, "GOBJECT\n"); + break; + case LTTV_NONE: + break; + } + } +} + + +static void +print_stats(FILE *fp, LttvTracesetStats *tscs) +{ + int i, nb, saved_length; + + LttvTraceset *ts; + + LttvTraceStats *tcs; + + GString *indent; + + LttSystemDescription *desc; + + if(tscs->stats == NULL) return; + indent = g_string_new(""); + fprintf(fp, "Traceset statistics:\n\n"); + print_tree(fp, indent, tscs->stats); + + ts = tscs->parent.parent.ts; + nb = lttv_traceset_number(ts); + + for(i = 0 ; i < nb ; i++) { + tcs = (LttvTraceStats *)(LTTV_TRACESET_CONTEXT(tscs)->traces[i]); + desc = ltt_trace_system_description(tcs->parent.parent.t); + fprintf(fp, "Trace on system %s at time %d secs:\n", desc->node_name, + desc->trace_start.tv_sec); + saved_length = indent->len; + g_string_append(indent, " "); + print_tree(fp, indent, tcs->stats); + g_string_truncate(indent, saved_length); + } + g_string_free(indent, TRUE); +} + + /* Insert the hooks before and after each trace and tracefile, and for each event. Print a global header. */ @@ -137,6 +240,8 @@ static gboolean write_traceset_header(void *hook_data, void *call_data) { LttvTracesetContext *tc = (LttvTracesetContext *)call_data; + g_info("TextDump traceset header"); + if(a_file_name == NULL) a_file = stdout; else a_file = fopen(a_file_name, "w"); @@ -154,8 +259,14 @@ static gboolean write_traceset_footer(void *hook_data, void *call_data) { LttvTracesetContext *tc = (LttvTracesetContext *)call_data; + g_info("TextDump traceset footer"); + fprintf(a_file,"End trace set\n\n"); + if(LTTV_IS_TRACESET_STATS(tc)) { + print_stats(a_file, (LttvTracesetStats *)tc); + } + if(a_file_name != NULL) fclose(a_file); return FALSE; @@ -203,16 +314,8 @@ G_MODULE_EXPORT void init(LttvModule *self, int argc, char **argv) LttvIAttribute *attributes = LTTV_IATTRIBUTE(lttv_global_attributes()); - LttvModule *batchAnalysis = - lttv_module_require(self, "batchAnalysis", argc, argv); + g_info("Init textDump.c"); - if(batchAnalysis == NULL) - { - g_error("Can't load required module batchAnalysis"); - return; - } - - a_string = g_string_new(""); a_file_name = NULL; @@ -233,6 +336,18 @@ G_MODULE_EXPORT void init(LttvModule *self, int argc, char **argv) "", LTTV_OPT_NONE, &a_state, NULL, NULL); + a_cpu_stats = FALSE; + lttv_option_add("cpu_stats", 's', + "write the per cpu statistics", + "", + LTTV_OPT_NONE, &a_cpu_stats, NULL, NULL); + + a_process_stats = FALSE; + lttv_option_add("process_stats", 's', + "write the per process statistics", + "", + LTTV_OPT_NONE, &a_process_stats, NULL, NULL); + g_assert(lttv_iattribute_find_by_path(attributes, "hooks/event/before", LTTV_POINTER, &value)); g_assert((before_event = *(value.v_pointer)) != NULL); @@ -257,12 +372,18 @@ G_MODULE_EXPORT void init(LttvModule *self, int argc, char **argv) G_MODULE_EXPORT void destroy() { + g_info("Destroy textDump"); + lttv_option_remove("output"); lttv_option_remove("field_names"); lttv_option_remove("process_state"); + lttv_option_remove("cpu_stats"); + + lttv_option_remove("process_stats"); + g_string_free(a_string, TRUE); lttv_hooks_remove_data(before_event, write_event_content, NULL); -- 2.34.1