From dc87756342c051418eccb2b7d932ffa5453c6788 Mon Sep 17 00:00:00 2001 From: dagenais Date: Mon, 4 Aug 2003 21:36:23 +0000 Subject: [PATCH] Refine the interactions between the hooks provided by the different modules. This is a partial redesign for the first cut at having a functional minimal batch analysis system. git-svn-id: http://ltt.polymtl.ca/svn@163 04897980-b3bd-0310-b5e0-8ef037075253 --- ltt/branches/poly/include/lttv/attribute.h | 233 ++----- .../poly/include/lttv/batchAnalysis.h | 44 ++ ltt/branches/poly/include/lttv/hook.h | 100 ++- ltt/branches/poly/include/lttv/iattribute.h | 157 +++++ ltt/branches/poly/include/lttv/lttv.h | 55 +- ltt/branches/poly/include/lttv/module.h | 76 +-- ltt/branches/poly/include/lttv/option.h | 32 +- ltt/branches/poly/include/lttv/processTrace.h | 183 +++++ ltt/branches/poly/include/lttv/state.h | 149 +++++ ltt/branches/poly/include/lttv/stats.h | 52 ++ ltt/branches/poly/include/lttv/textDump.h | 0 ltt/branches/poly/include/lttv/traceSet.h | 48 -- ltt/branches/poly/include/lttv/traceset.h | 37 ++ ltt/branches/poly/lttv/attribute.c | 527 ++++++--------- ltt/branches/poly/lttv/batchAnalysis.c | 187 +++--- ltt/branches/poly/lttv/hook.c | 193 +++++- ltt/branches/poly/lttv/iattribute.c | 260 ++++++++ ltt/branches/poly/lttv/main.c | 126 ++-- ltt/branches/poly/lttv/module.c | 380 +++++------ ltt/branches/poly/lttv/option.c | 288 ++++---- ltt/branches/poly/lttv/processTrace.c | 559 ++++++++++++++++ ltt/branches/poly/lttv/state.c | 624 ++++++++++++++++++ ltt/branches/poly/lttv/textDump.c | 363 ++++------ ltt/branches/poly/lttv/traceSet.c | 178 ----- ltt/branches/poly/lttv/traceset.c | 83 +++ 25 files changed, 3306 insertions(+), 1628 deletions(-) create mode 100644 ltt/branches/poly/include/lttv/batchAnalysis.h create mode 100644 ltt/branches/poly/include/lttv/iattribute.h create mode 100644 ltt/branches/poly/include/lttv/processTrace.h create mode 100644 ltt/branches/poly/include/lttv/state.h create mode 100644 ltt/branches/poly/include/lttv/stats.h create mode 100644 ltt/branches/poly/include/lttv/textDump.h delete mode 100644 ltt/branches/poly/include/lttv/traceSet.h create mode 100644 ltt/branches/poly/include/lttv/traceset.h create mode 100644 ltt/branches/poly/lttv/iattribute.c create mode 100644 ltt/branches/poly/lttv/processTrace.c create mode 100644 ltt/branches/poly/lttv/state.c delete mode 100644 ltt/branches/poly/lttv/traceSet.c create mode 100644 ltt/branches/poly/lttv/traceset.c diff --git a/ltt/branches/poly/include/lttv/attribute.h b/ltt/branches/poly/include/lttv/attribute.h index be79a330..e8cbcb6b 100644 --- a/ltt/branches/poly/include/lttv/attribute.h +++ b/ltt/branches/poly/include/lttv/attribute.h @@ -1,219 +1,88 @@ #ifndef ATTRIBUTE_H #define ATTRIBUTE_H +#include +#include -#include -#include +#define LTTV_ATTRIBUTE_TYPE (lttv_attribute_get_type ()) +#define LTTV_ATTRIBUTE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), LTTV_ATTRIBUTE_TYPE, LttvAttribute)) +#define LTTV_ATTRIBUTE_CLASS(vtable) (G_TYPE_CHECK_CLASS_CAST ((vtable), LTTV_ATTRIBUTE_TYPE, LttvAttributeClass)) +#define LTTV_IS_ATTRIBUTE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), LTTV_ATTRIBUTE_TYPE)) +#define LTTV_IS_ATTRIBUTE_CLASS(vtable) (G_TYPE_CHECK_CLASS_TYPE ((vtable), LTTV_ATTRIBUTE_TYPE)) +#define LTTV_ATTRIBUTE_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), LTTV_ATTRIBUTE_TYPE, LttvAttributeClass)) -/* Attributes are used to store any value identified by a key. They are - typically used to store state information or accumulated statistics for - some object. Each value is accessed through a multi-component key, which - resembles hierarchical pathnames in filesystems. - The attributes may store integers, doubles or time values, in which case - the values are created upon first access of a key and with a default - value of 0. Pointer values are also available with a default value of NULL - and must thus be set explicitely to user managed (statically or dynamically - allocated) memory. */ +typedef struct _LttvAttribute LttvAttribute; +typedef struct _LttvAttributeClass LttvAttributeClass; +struct _LttvAttribute { + GObject parent; -typedef guint32 lttv_string_id; + /* private members */ + GHashTable *names; + GArray *attributes; +}; -typedef GArray _lttv_key; +struct _LttvAttributeClass { + GObjectClass parent; +}; -typedef _lttv_key lttv_key; +GType lttv_attribute_get_type (void); -typedef struct timespec lttv_time; +/* The functions exported in the IAttribute interface are also available + directly. */ -typedef struct _lttv_attributes { - GHashTable *ints; - GHashTable *times; - GHashTable *doubles; - GHashTable *pointers; -} lttv_attributes; +/* Total number of attributes */ -/* A unique integer identifier represents each different string - used as a key component. A single copy of each different string is - stored but its usage count is incremented each time the corresponding id - is returned by lttv_string_id_from_string. The usage count is decremented - each time an id is released. */ +unsigned int lttv_attribute_get_number(LttvAttribute *self); -lttv_string_id lttv_string_id_from_string(const char *s); -void lttv_string_id_release(lttv_string_id i); +/* Container type. Named (fields in struct or elements in a hash table) + or unnamed (elements in an array) attributes, homogeneous type or not. */ -const char *lttv_string_id_to_string(lttv_string_id i); +gboolean lttv_attribute_named(LttvAttribute *self, gboolean *homogeneous); -/* Keys are created and subsequently filled with key components */ +/* Get the i th attribute along with its type and a pointer to its value. */ -lttv_key *lttv_key_new(); - -void lttv_key_destroy(lttv_key *k); - -/* macro to access/replace a the i th component of key k */ - -#define lttv_key_index(k,i) _lttv_key_index(k,i) - - -/* Append a new component */ - -void lttv_key_append(lttv_key *k, lttv_string_id i); - - -/* Number of components in a key */ - -unsigned int lttv_key_number(lttv_key *k); - - -/* It is also possible to create a key directly from a pathname, - key components separated by /, (e.g., "/hooks/options/before"). */ - -lttv_key *lttv_key_new_pathname(const char *pathname); - - -/* Create a new set of attributes */ - -lttv_attributes *lttv_attributes_new(); - - -/* Destroy the set of attributes including all the memory allocated - internally for it (copies of keys, and integer, double and time - values...). */ - -void lttv_attributes_destroy(lttv_attributes *a); - - -/* Total number of attributes in a lttv_attributes. */ - -unsigned int lttv_attributes_number(lttv_attributes *a); - - -/* Obtain a pointer to the value of the corresponding type associated with - the specified key. New values are created on demand with 0 as initial - value. These values are freed when the attributes set is destroyed. */ - -int *lttv_attributes_get_integer(lttv_attributes *a, lttv_key *k); - -lttv_time *lttv_attributes_get_time(lttv_attributes *a, lttv_key *k); - -double *lttv_attributes_get_double(lttv_attributes *a, lttv_key *k); - - -/* Set or get the pointer value associated with the specified key. - NULL is returned if no pointer was set for the key. */ - -void *lttv_attributes_get_pointer(lttv_attributes *a, lttv_key *k); - -void lttv_attributes_set_pointer(lttv_attributes *a, lttv_key *k, void *p); - -void *lttv_attributes_get_pointer_pathname(lttv_attributes *a, char *pn); - -void lttv_attributes_set_pointer_pathname(lttv_attributes *a,char *pn,void *p); - - -/* It is often useful to copy over some elements from the source attributes - table to the destination table. While doing so, constraints on each key - component may be used to select the elements of interest. Finally, some - numerical elements may need to be summed, for example summing the number - of page faults over all processes. A flexible function to copy attributes - may be used for all these operations. - - If the key of the element copied already exists in the destination - attributes, numerical values (integer, double or time) are summed and - pointers are replaced. - - The lttv_key_select_data structure specifies for each key component the - test applied to decide to copy or not the corresponding element. - It contains the relation to apply to each key component, the rel vector, - and the comparison key, both of size length. To decide if an element - should be copied, each component of its key is compared with the - comparison key, and the relation specified for each component must - be verified. The relation ANY is always verified and the comparison key - component is not used. The relation NONE is only verified if the key - examined contains fewer components than the position examined. The EQ, NE, - LT, LE, GT, GE relations are verified if the key is long enough and the - component satisfies the relation with respect to the comparison key. - Finally, the CUT relation is satisfied if the key is long enough, but the - element is copied with that component removed from its key. All the keys - which only differ by that component become identical after being shortened - and their numerical values are thus summed when copied. */ - -typedef enum _lttv_key_select_relation -{ LTTV_KEY_ANY, /* Any value is good */ - LTTV_KEY_NONE, /* No value is good, i.e. the key must be shorter */ - LTTV_KEY_EQ, /* key[n] is equal to match[n] */ - LTTV_KEY_NE, /* key[n] is not equal to match[n] */ - LTTV_KEY_LT, /* key[n] is lower than match[n] */ - LTTV_KEY_LE, /* key[n] is lower or equal than match[n] */ - LTTV_KEY_GT, /* key[n] is greater than match[n] */ - LTTV_KEY_GE, /* key[n] is greater or equal than match[n] */ - LTTV_KEY_CUT /* cut key[n], shortening the key for the copy */ -} lttv_key_select_relation; - -typedef struct _lttv_key_select_data -{ - unsigned length; - lttv_key_select_relation *rel; - lttv_key *comparison; -} lttv_key_select_data; - -void lttv_attributes_copy(lttv_attributes *src, lttv_attributes *dest, - lttv_key_select_data d); +LttvAttributeType lttv_attribute_get(LttvAttribute *self, unsigned i, + LttvAttributeName *name, LttvAttributeValue *v); + +/* Get the named attribute in the table along with its type and a pointer to + its value. If the named attribute does not exist, the type is LTTV_NONE. */ -/* Sometimes the attributes must be accessed in bulk, sorted in different - ways. For this purpose they may be converted to arrays and sorted - multiple times. The keys used in the array belong to the lttv_attributes - object from which the array was obtained and are freed when it is - destroyed. Each element in the array is an lttv_attribute, a structure - containing the key, the value type, and a union containing a value of - that type. Multiple attributes with equal keys may be possible in some - implementations if their type differs. */ +LttvAttributeType lttv_attribute_get_by_name(LttvAttribute *self, + LttvAttributeName name, LttvAttributeValue *v); -typedef enum _lttv_attribute_type -{ LTTV_INTEGER, LTTV_TIME, LTTV_DOUBLE, LTTV_POINTER } -lttv_attribute_type; +/* Add an attribute, which must not exist. The name is an empty string for + containers with unnamed attributes. */ -typedef union _lttv_value_any -{ int i; - lttv_time t; - double d; - void *p; -} lttv_value_any; +LttvAttributeValue lttv_attribute_add(LttvAttribute *self, + LttvAttributeName name, LttvAttributeType t); -typedef struct _lttv_attribute { - lttv_key *key; - lttv_attribute_type t; - lttv_value_any v; -} lttv_attribute; +/* Remove an attribute */ -/* Obtain all the attributes in an array */ +void lttv_attribute_remove(LttvAttribute *self, unsigned i); -lttv_attribute *lttv_attributes_array_get(lttv_attributes *a); +void lttv_attribute_remove_by_name(LttvAttribute *self, + LttvAttributeName name); -lttv_attribute *lttv_attribute_array_destroy(lttv_attribute *a); +/* Create an empty iattribute object and add it as an attribute under the + specified name, or return an existing iattribute attribute. If an + attribute of that name already exists but is not a GObject supporting the + iattribute interface, return NULL. */ -/* The sorting order is determined by the supplied comparison function. - The comparison function must return a negative value if a < b, - 0 if a = b, and a positive if a > b. */ +LttvIAttribute* lttv_attribute_create_subdir(LttvAttribute *self, + LttvAttributeName name); -typedef int (*lttv_key_compare)(lttv_key *a, lttv_key *b, void *user_data); +gboolean lttv_attribute_find(LttvAttribute *self, LttvAttributeName name, + LttvAttributeType t, LttvAttributeValue *v); -void lttv_attribute_array_sort(lttv_attribute *a, unsigned size, - lttv_key_compare f, void *user_data); - - -/* Sort in lexicographic order using the specified key components as primary, - secondary... keys. A vector containing the key components positions is - specified. */ - -int lttv_attribute_array_sort_lexicographic(lttv_attribute *a, unsigned size, - unsigned *positions, unsigned nb_positions); #endif // ATTRIBUTE_H diff --git a/ltt/branches/poly/include/lttv/batchAnalysis.h b/ltt/branches/poly/include/lttv/batchAnalysis.h new file mode 100644 index 00000000..f166178c --- /dev/null +++ b/ltt/branches/poly/include/lttv/batchAnalysis.h @@ -0,0 +1,44 @@ +#ifndef BATCH_ANALYSIS_H +#define BATCH_ANALYSIS_H + +/* The batch analysis module defines a main traceset and command line options + to specify the traces in the main traceset. It then processes that + traceset calling hooks lists at various stages of the analysis. + + The hooks lists are defined in the global attributes for these various + stages of the analysis. Loaded modules may add hooks to these lists. + Thus, by requesting that a certain module be loaded, the analysis may + produce additional information as the module adds hooks and these hooks + are called during the analysis. + + The hooks lists defined are as follows. These may be split in more + specific lists eventually to select the hooks applicable to state update, + incremental or batch processing... + + /hooks/traceset/before + Before analyzing a traceset. + + /hooks/traceset/after + After analyzing a traceset. + + /hooks/trace/before + Before each trace. + + /hooks/trace/after + After each trace. + + /hooks/tracefile/before + Before each tracefile. + + /hooks/tracefile/after + After each tracefile. + + /hooks/event/before + Before each event. + + /hooks/event/after + After each event. + +*/ + +#endif // BATCH_ANALYSIS_H diff --git a/ltt/branches/poly/include/lttv/hook.h b/ltt/branches/poly/include/lttv/hook.h index e3417d01..2fd17e1a 100644 --- a/ltt/branches/poly/include/lttv/hook.h +++ b/ltt/branches/poly/include/lttv/hook.h @@ -6,48 +6,104 @@ /* A hook is a function to call with the supplied hook data, and with call site specific data (e.g., hooks for events are called with a pointer to the current event). */ -// MD compile fix: int instead of bool as return value -typedef int (*lttv_hook)(void *hook_data, void *call_data); + +typedef gboolean (*LttvHook)(void *hook_data, void *call_data); /* A list of hooks allows registering hooks to be called later. */ -typedef GArray _lttv_hooks; -typedef _lttv_hooks lttv_hooks; +typedef struct _LttvHooks LttvHooks; + + +/* Create and destroy a list of hooks */ + +LttvHooks *lttv_hooks_new(); + +void lttv_hooks_destroy(LttvHooks *h); + + +/* Add a hook and its hook data to the list */ + +void lttv_hooks_add(LttvHooks *h, LttvHook f, void *hook_data); + + +/* Add a list of hooks to the list h */ + +void lttv_hooks_add(LttvHooks *h, LttvHooks *list); + + +/* Remove a hook from the list. Return the hook data. */ + +void *lttv_hooks_remove(LttvHooks *h, LttvHook f); + + +/* Remove a hook from the list checking that the hook data match. */ + +void lttv_hooks_remove_data(LttvHooks *h, LttvHook f, void *hook_data); + + +/* Remove a list of hooks from the hooks list in h. */ -lttv_hooks *lttv_hooks_new(); +void lttv_hooks_remove_data(LttvHooks *h, LttvHook *list); -void lttv_hooks_destroy(lttv_hooks *h); -void lttv_hooks_add(lttv_hooks *h, lttv_hook f, void *hook_data); +/* Return the number of hooks in the list */ -void lttv_hooks_remove(lttv_hooks *h, lttv_hook f, void *hook_data); +unsigned lttv_hooks_number(LttvHooks *h); -unsigned lttv_hooks_number(lttv_hooks *h); -void lttv_hooks_get(lttv_hooks *h, unsigned i, lttv_hook *f, void **hook_data); +/* Return the hook at the specified position in the list */ -void lttv_hooks_remove_by_position(lttv_hooks *h, unsigned i); +void lttv_hooks_get(LttvHooks *h, unsigned i, LttvHook *f, void **hook_data); -int lttv_hooks_call(lttv_hooks *h, void *call_data); -int lttv_hooks_call_check(lttv_hooks *h, void *call_data); +/* Remove the specified hook. The position of the following hooks may change */ + +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. */ + +gboolean lttv_hooks_call(LttvHooks *h, void *call_data); + + +/* Call the hooks in the list until one returns true, in which case TRUE is + returned. */ + +gboolean lttv_hooks_call_check(LttvHooks *h, void *call_data); /* Sometimes different hooks need to be called based on the case. The - case is represented by an unsigned integer id and may represent different - event types, for instance. */ + case is represented by an unsigned integer id */ + +typedef struct _LttvHooksById LttvHooksById; + + +/* Create and destroy a hooks by id list */ + +LttvHooksById *lttv_hooks_by_id_new(); + +void lttv_hooks_by_id_destroy(LttvHooksById *h); + + +/* Obtain the hooks for a given id, creating a list if needed */ + +LttvHooks *lttv_hooks_by_id_find(LttvHooksById *h, unsigned id); + + +/* Return an id larger than any for which a list exists. */ + +unsigned lttv_hooks_by_id_max_id(LttvHooksById *h); + -typedef GPtrArray _lttv_hooks_by_id; -typedef _lttv_hooks_by_id lttv_hooks_by_id; +/* Get the list of hooks for an id, NULL if none exists */ -lttv_hooks_by_id *lttv_hooks_by_id_new(); +LttvHooks *lttv_hooks_by_id_get(LttvHooksById *h, unsigned id); -void lttv_hooks_by_id_destroy(lttv_hooks_by_id *h); -void lttv_hooks_by_id_add(lttv_hooks_by_id *h, lttv_hook f, void *hook_data, - unsigned int id); +/* Remove the list of hooks associated with an id */ -void lttv_hooks_by_id_call(lttv_hooks_by_id *h, void *call_data, unsigned int id); +void lttv_hooks_by_id_remove(LttvHooksById *h, unsigned id); #endif // HOOK_H diff --git a/ltt/branches/poly/include/lttv/iattribute.h b/ltt/branches/poly/include/lttv/iattribute.h new file mode 100644 index 00000000..e9f853cf --- /dev/null +++ b/ltt/branches/poly/include/lttv/iattribute.h @@ -0,0 +1,157 @@ +#ifndef IATTRIBUTE_H +#define IATTRIBUTE_H + + +#include +#include + +/* The content of a data structure may be seen as an array of pairs of + attribute name and value. This simple model allows generic navigation + and access functions over a wide range of structures. The names are + represented by unique integer identifiers, GQuarks. */ + +typedef GQuark LttvAttributeName; + +typedef struct timespec LttvTime; + +typedef enum _LttvAttributeType { + LTTV_INT, LTTV_UINT, LTTV_LONG, LTTV_ULONG, LTTV_FLOAT, LTTV_DOUBLE, + LTTV_TIME, LTTV_POINTER, LTTV_STRING, LTTV_GOBJECT, LTTV_NONE +} LttvAttributeType; + +typedef union LttvAttributeValue { + int *v_int; + unsigned *v_uint; + long *v_long; + unsigned long *v_ulong; + float *v_float; + double *v_double; + timespec *v_timespec; + gpointer *v_pointer; + char **v_string; + gobject **v_gobject; +} LttvAttributeValue; + + +/* GObject interface type macros */ + +#define LTTV_IATTRIBUTE_TYPE (lttv_iattribute_get_type ()) +#define LTTV_IATTRIBUTE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), LTTV_IATTRIBUTE_TYPE, LttvIAttribute)) +#define LTTV_IATTRIBUTE_CLASS(vtable) (G_TYPE_CHECK_CLASS_CAST ((vtable), LTTV_IATTRIBUTE_TYPE, LttvIAttributeClass)) +#define LTTV_IS_IATTRIBUTE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), LTTV_IATTRIBUTE_TYPE)) +#define LTTV_IS_IATTRIBUTE_CLASS(vtable) (G_TYPE_CHECK_CLASS_TYPE ((vtable), LTTV_IATTRIBUTE_TYPE)) +#define LTTV_IATTRIBUTE_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), LTTV_IATTRIBUTE_TYPE, LttvIAttributeClass)) + + +typedef struct _LttvIattribute LttvIAttribute; /* dummy object */ +typedef struct _LttvIAttributeClass LttvIAttributeClass; + + +struct _LttvIAttributeClass { + GTypeInterface parent; + + unsigned int (*get_number) (LttvIAttribute *self); + + gboolean (*named) (LttvIAttribute *self, gboolean *homogeneous); + + LttvAttributeType (*get) (LttvIAttribute *self, unsigned i, + LttvAttributeName *name, LttvAttributeValue *v); + + LttvAttributeType (*get_by_name) (LttvIAttribute *self, + LttvAttributeName name, LttvAttributeValue *v); + + LttvAttributeValue (*add) (LttvIAttribute *self, LttvAttributeName name, + LttvAttributeType t); + + void (*remove) (LttvIAttribute *self, unsigned i); + + void (*remove_by_name) (LttvIAttribute *self, + LttvAttributeName name); + + LttvIAttribute* (*create_subdir) (LttvIAttribute *self, + LttvAttributeName name); +}; + + +GType lttv_iattribute_get_type(void); + + +/* Total number of attributes */ + +unsigned int lttv_iattribute_get_number(LttvIAttribute *self); + + +/* Container type. Named (fields in struct or elements in a hash table) + or unnamed (elements in an array) attributes, homogeneous type or not. */ + +gboolean lttv_iattribute_named(LttvIAttribute *self, gboolean *homogeneous); + + +/* Get the i th attribute along with its type and a pointer to its value. */ + +LttvAttributeType lttv_iattribute_get(LttvIAttribute *self, unsigned i, + LttvAttributeName *name, LttvAttributeValue *v); + + +/* Get the named attribute in the table along with its type and a pointer to + its value. If the named attribute does not exist, the type is LTTV_NONE. */ + +LttvAttributeType lttv_iattribute_get_by_name(LttvIAttribute *self, + LttvAttributeName name, LttvAttributeValue *v); + + +/* Add an attribute, which must not exist. The name is an empty string for + containers with unnamed attributes. Its value is initialized to 0 or NULL + and its pointer returned. */ + +LttvAttributeValue lttv_iattribute_add(LttvIAttribute *self, + LttvAttributeName name, LttvAttributeType t); + + +/* Remove an attribute */ + +void lttv_iattribute_remove(LttvIAttribute *self, unsigned i); + +void lttv_iattribute_remove_by_name(LttvIAttribute *self, + LttvAttributeName name); + + +/* Create an empty iattribute object and add it as an attribute under the + specified name, or return an existing iattribute attribute. If an + attribute of that name already exists but is not a GObject supporting the + iattribute interface, return NULL. */ + +LttvIAttribute* lttv_iattribute_create_subdir(LttvIAttribute *self, + LttvAttributeName name); + + +/* The remaining utility functions are not part of the LttvIAttribute + interface but operate on objects implementing it. */ + +/* Find the named attribute in the table, which must be of the specified type. + If it does not exist, it is created with a default value of 0 (NULL for + pointer types). Since the address of the value is obtained, it may be + changed easily afterwards. The function returns false when the attribute + exists but is of incorrect type. */ + +gboolean lttv_iattribute_find(LttvIAttribute *self, LttvAttributeName name, + LttvAttributeType t, LttvAttributeValue *v); + + +/* Trees of attribute tables may be accessed using a hierarchical path with + components separated by /, like in filesystems */ + +gboolean lttv_iattribute_find_by_path(LttvIAttribute *self, char *path, + LttvAttributeType t, LttvAttributeValue *v); + + +/* Shallow and deep copies */ + +void lttv_iattribute_copy_value(LttvAttributeType t, LttvAttributeValue dest, + LttvAttributeValue src); + +LttvIAttribute *lttv_iattribute_shallow_copy(LttvIAttribute *self); + +LttvIAttribute *lttv_iattribute_deep_copy(LttvIAttribute *self); + +#endif // IATTRIBUTE_H diff --git a/ltt/branches/poly/include/lttv/lttv.h b/ltt/branches/poly/include/lttv/lttv.h index ad9f3044..4f1fda61 100644 --- a/ltt/branches/poly/include/lttv/lttv.h +++ b/ltt/branches/poly/include/lttv/lttv.h @@ -3,36 +3,10 @@ #include "attribute.h" -/* Initial draft by Michel Dagenais May 2003 - * Reworked by Mathieu Desnoyers, May 2003 - */ - - /* The modules in the visualizer communicate with the main module and - with each other through attributes. There is a global set of attributes as - well as attributes attached to each trace set, trace and tracefile. */ - -lttv_attributes *lttv_global_attributes(); - - - -/* Modules are allowed to define new command line options. - - Each option has a long name (--long_name), a short one character - name (-c), a descriptive text, the argument type, and a - pointer to where the argument value will be stored. For an option of - type LTTV_OPT_NONE, the argument is a boolean value set to true when the - option is present. */ - -/* Those are already in option.h, cause conflict */ -//typedef enum _lttv_option_type -//{LTTV_OPT_NONE, LTTV_OPT_STRING, LTTV_OPT_INT, LTTV_OPT_LONG } -//lttv_option_type; - - -//void lttv_option_add(char *long_name, char char_name, char *description, -// lttv_option_type t, void *p); + with each other through attributes. There is a global set of attributes */ +LttvAttributes *lttv_global_attributes(); /* A number of global attributes are initialized before modules are @@ -51,30 +25,9 @@ lttv_attributes *lttv_global_attributes(); /hooks/options/after Read the values set by the command line options. - /hooks/trace_set/before - Before any analysis. - - /hooks/trace_set/after - After all traces were analyzed. - - /hooks/trace/before - Before each trace. - - /hooks/trace/after - After each trace. - - /hooks/tracefile/before - Before each tracefile. - - /hooks/tracefile/after - After each tracefile. - - /hooks/event - Called for each event + /hooks/main/before - /hooks/event_id - This attribute contains an lttv_hooks_by_id, where the hooks for each - id are to be called when an event of the associated type are found. + /hooks/main/after */ diff --git a/ltt/branches/poly/include/lttv/module.h b/ltt/branches/poly/include/lttv/module.h index 5d1c3bae..6a0a45fb 100644 --- a/ltt/branches/poly/include/lttv/module.h +++ b/ltt/branches/poly/include/lttv/module.h @@ -6,78 +6,64 @@ /* lttv modules are shared object files, to be loaded dynamically, which interact with the main module to provide additional capabilities. They typically register hooks to be called at various places, read and add - global or trace attributes, and add menu items and tabbed windows to the - graphical user interface. Both the hooks lists and the menus and windows - are accessed as global attributes. */ + attributes... + Each lttv module must define a function named "init" with + the following signature. The init function may itself require other + modules using lttv_module_require. -/* Each lttv module must define a function named "init" with - the following signature. The init function may itself load pre-requisite - modules using lttv_module_load. - - It should also define a function named "destroy", which free the + It should also define a function named "destroy" to free the resources reserved during execution. Most modules will not use the command line arguments passed as init arguments. It is easier to simply register command line options to be parsed by the main module. However, some modules - may require an "early access" to these arguments, for example a embedded + may require an "early access" to these arguments, for example an embedded python interpreter module which needs to know the modules written in python to load. */ -/* Initial draft by Michel Dagenais May 2003 - * Reworked by Mathieu Desnoyers, May 2003 - */ +typedef struct _LttvModule LttvModule; -/* index_standalone is the index of the module in the modulesStanalone array. - * If the module is only loaded "DEPENDANT", index is -1. - */ +typedef void (*LttvModuleInit)(int argc, char **argv); -typedef struct lttv_module_info_ { - GModule *module; - char *name; - char *directory; - char *pathname; - guint ref_count; - gint index_standalone; -} lttv_module_info; +typedef void (*LttvModuleDestroy)(); -/* Loading type of modules : - * STANDALONE : the program takes care of unloading the moduels - * DEPENDANT : The module that load this module is required to unload - * it in it's destroy function. - */ -typedef enum _loadtype -{ STANDALONE, DEPENDANT -} loadtype; +/* Additional module search paths may be defined. */ -typedef void (*lttv_module_load_init)(int argc, char **argv) ; +void lttv_module_path_add(const char *name); -/* Load (if not already loaded) the named module. The init function of the - module is executed upon loading. */ +/* Load (or increment its reference count if already loaded) the named module. + The init function of the module is executed upon loading. */ -lttv_module_info *lttv_module_load(const char *name, int argc, char **argv,loadtype); +LttvModule *lttv_module_load(const char *name, int argc, char **argv); +/* Module m depends on the named module. The named module will be loaded, + remembered by m as a dependent, and unloaded when m is unloaded. */ -/* Unload (if already loaded) the named module. The destroy function of the - module is executed before unloading. */ +LttvModule *lttv_module_require(LttvModule *m, const char *name, int argc, + char **argv); -typedef void (*lttv_module_unload_destroy)() ; -int lttv_module_unload_pathname(const char *pathname,loadtype) ; +/* Decrement the reference count of the specified module and unload it if 0. + The destroy function of the module is executed before unloading. + Dependent modules are unloaded. */ -int lttv_module_unload_name(const char *name,loadtype) ; +void lttv_module_unload(LttvModule *m) ; -int lttv_module_unload(lttv_module_info *moduleInfo,loadtype); -/* Unload all the modules */ -void lttv_module_unload_all(); +/* List the loaded modules. The returned array contains nb elements and + must be freed with g_free. */ -/* Additional module search paths may be defined. */ +LttvModule **lttv_module_list(guint *nb); -void lttv_module_path_add(const char *name); + +/* Obtain information about a module. The list of dependent module is + returned and must be freed with g_free. */ + +LttvModule **lttv_module_info(LttvModule *m, const char **name, + guint *ref_count, guint *load_count, guint *nb_dependents); #endif // MODULES_H diff --git a/ltt/branches/poly/include/lttv/option.h b/ltt/branches/poly/include/lttv/option.h index 09fd803b..4447f9f6 100644 --- a/ltt/branches/poly/include/lttv/option.h +++ b/ltt/branches/poly/include/lttv/option.h @@ -1,29 +1,33 @@ #ifndef OPTION_H #define OPTION_H -/* Options parsing mechanism */ - -/* Define a new command line option with a long name (--long_name), a short +/* Define a new option with a long name (--long_name), a short one character name (-c), a descriptive text, the argument type, and a pointer to where the argument value will be stored. For an option of type LTTV_OPT_NONE, the argument is a boolean value set to true when the - option is present. */ - -/* Initial draft by Michel Dagenais May 2003 - * Reworked by Mathieu Desnoyers, May 2003 - */ + option is present. The option hook is called if non NULL. */ -typedef enum _lttv_option_type +typedef enum _LttvOptionType {LTTV_OPT_NONE, LTTV_OPT_STRING, LTTV_OPT_INT, LTTV_OPT_LONG } -lttv_option_type; +LttvOptionType; -typedef void (*lttv_option_hook)(void *hook_data); +typedef void (*LttvOptionHook)(void *hook_data); void lttv_option_add(const char *long_name, const char char_name, - const char *description, const char *argDescription, - const lttv_option_type t, void *p, - const lttv_option_hook h, void *hook_data); + const char *description, const char *arg_description, + const LttvOptionType t, void *p, + const LttvOptionHook h, void *hook_data); + + +/* Remove an option */ + +void lttv_option_remove(const char *long_name); + +/* Parse command line options. It is possible to add options (through the + hooks being called) while the parsing is done. The new options will be + used for subsequent command line arguments. */ +void lttv_option_parse(int argc, char **argv); #endif // OPTION_H diff --git a/ltt/branches/poly/include/lttv/processTrace.h b/ltt/branches/poly/include/lttv/processTrace.h new file mode 100644 index 00000000..60dfd7ba --- /dev/null +++ b/ltt/branches/poly/include/lttv/processTrace.h @@ -0,0 +1,183 @@ +#ifndef PROCESSTRACE_H +#define PROCESSTRACE_H + +#include +#include +#include + +/* This is the generic part of trace processing. All events within a + certain time interval are accessed and processing hooks are called for + each. The events are examined in monotonically increasing time to more + closely follow the traced system behavior. + + Hooks are called at several different places during the processing: + before traceset, after traceset, check trace, before trace, after trace, + check tracefile, before tracefile, after tracefile, + check_event, before_event, before_event_by_id, + after_event, after_event_by_id. + + In each case the "check" hooks are called first to determine if further + processing of the trace, tracefile or event is wanted. Then, the before + hooks and the after hooks are called. The before hooks for a traceset + are called before those for the contained traces, which are called before + those for the contained tracefiles. The after hooks are called in reverse + order. The event hooks are called after all the before_tracefile hooks + and before all the after_tracefile hooks. + + The hooks receive two arguments, the hook_data and call_data. The hook_data + is specified when the hook is registered and typically links to the + object registering the hook (e.g. a graphical events viewer). The call_data + must contain all the context related to the call. The traceset hooks receive + the LttvTracesetContext provided by the caller. The trace hooks receive + the LttvTraceContext from the traces array in the LttvTracesetContext. + The tracefile and event hooks receive the LttvTracefileContext from + the tracefiles array in the LttvTraceContext. The LttEvent and LttTime + fields in the tracefile context are set to the current event and current + event time before calling the event hooks. No other context field is + modified. + + The contexts in the traces and tracefiles arrays must be allocated by + the caller, either before the call or during the before hooks of the + enclosing traceset or trace. The order in the traces array must + correspond to the lttv_traceset_get function. The order in the tracefiles + arrays must correspond to the ltt_trace_control_tracefile_get and + ltt_trace_per_cpu_tracefile_get functions. The traceset, trace and + tracefile contexts may be subtyped as needed. Indeed, both the contexts + and the hooks are defined by the caller. */ + +#define LTTV_TRACESET_CONTEXT_TYPE (lttv_traceset_context_get_type ()) +#define LTTV_TRACESET_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), LTTV_TRACESET_CONTEXT_TYPE, LttvTracesetContext)) +#define LTTV_TRACESET_CONTEXT_CLASS(vtable) (G_TYPE_CHECK_CLASS_CAST ((vtable), LTTV_TRACESET_CONTEXT_TYPE, LttvTracesetContextClass)) +#define LTTV_IS_TRACESET_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), LTTV_TRACESET_CONTEXT_TYPE)) +#define LTTV_IS_TRACESET_CONTEXT_CLASS(vtable) (G_TYPE_CHECK_CLASS_TYPE ((vtable), LTTV_TRACESET_CONTEXT_TYPE)) +#define LTTV_TRACESET_CONTEXT_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), LTTV_TRACESET_CONTEXT_TYPE, LttvTracesetContextClass)) + +typedef struct _LttvTracesetContext LttvTracesetContext; +typedef struct _LttvTracesetContextClass LttvTracesetContextClass; + +struct _LttvTracesetContext { + GObject parent; + + LttvTraceset *ts; + LttvHooks *before; + LttvHooks *after; + LttvTraceContext **traces; + LttvAttribute *a; +}; + +struct _LttvTracesetContextClass { + GObjectClass parent; + + void (*init) (LttvTracesetContext *self, LttvTraceset *ts); + void (*fini) (LttvTracesetContext *self); + LttvTracesetContext* (*new_traceset_context) (LttvTracesetContext *self); + LttvTraceContext* (*new_trace_context) (LttvTracesetContext *self); + LttvTracefileContext* (*new_tracefile_context) (LttvTracesetContext *self); +}; + +GType lttv_traceset_context_get_type (void); + +void lttv_context_init(LttvTracesetContext *self, LttvTraceset *ts); + +void lttv_context_fini(LttvTracesetContext *self); + +LttvTracesetContext * +lttv_context_new_traceset_context(LttvTracesetContext *self); + +LttvTraceContext * +lttv_context_new_trace_context(LttvTracesetContext *self); + +LttvTracefileContext * +lttv_context_new_tracefile_context(LttvTracesetContext *self); + + +#define LTTV_TRACE_CONTEXT_TYPE (lttv_trace_context_get_type ()) +#define LTTV_TRACE_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), LTTV_TRACE_CONTEXT_TYPE, LttvTraceContext)) +#define LTTV_TRACE_CONTEXT_CLASS(vtable) (G_TYPE_CHECK_CLASS_CAST ((vtable), LTTV_TRACE_CONTEXT_TYPE, LttvTraceContextClass)) +#define LTTV_IS_TRACE_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), LTTV_TRACE_CONTEXT_TYPE)) +#define LTTV_IS_TRACE_CONTEXT_CLASS(vtable) (G_TYPE_CHECK_CLASS_TYPE ((vtable), LTTV_TRACE_CONTEXT_TYPE)) +#define LTTV_TRACE_CONTEXT_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), LTTV_TRACE_CONTEXT_TYPE, LttvTraceContextClass)) + +typedef struct _LttvTraceContext LttvTraceContext; +typedef struct _LttvTraceContextClass LttvTraceContextClass; + +struct _LttvTraceContext { + GObject parent; + + LttvTracesetContext *ts_context; + guint index; /* in ts_context->traces */ + LttvTrace *t; + LttvHooks *check; + LttvHooks *before; + LttvHooks *after; + LttvTracefileContext **control_tracefiles; + LttvTracefileContext **per_cpu_tracefiles; + LttvAttribute *a; +}; + +struct _LttvTraceContextClass { + GObjectClass parent; +}; + +GType lttv_trace_context_get_type (void); + +#define LTTV_TRACEFILE_CONTEXT_TYPE (lttv_tracefile_context_get_type ()) +#define LTTV_TRACEFILE_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), LTTV_TRACEFILE_CONTEXT_TYPE, LttvTracefileContext)) +#define LTTV_TRACEFILE_CONTEXT_CLASS(vtable) (G_TYPE_CHECK_CLASS_CAST ((vtable), LTTV_TRACEFILE_CONTEXT_TYPE, LttvTracefileContextClass)) +#define LTTV_IS_TRACEFILE_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), LTTV_TRACEFILE_CONTEXT_TYPE)) +#define LTTV_IS_TRACEFILE_CONTEXT_CLASS(vtable) (G_TYPE_CHECK_CLASS_TYPE ((vtable), LTTV_TRACEFILE_CONTEXT_TYPE)) +#define LTTV_TRACEFILE_CONTEXT_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), LTTV_TRACEFILE_CONTEXT_TYPE, LttvTracefileContextClass)) + +typedef struct _LttvTracefileContext LttvTracefileContext; +typedef struct _LttvTracefileContextClass LttvTracefileContextClass; + +struct _LttvTracefileContext { + GObject parent; + + LttvTraceContext *t_context; + gboolean control; + guint index; /* in ts_context->control/per_cpu_tracefiles */ + LttvTracefile *tf; + LttvHooks *check; + LttvHooks *before; + LttvHooks *after; + LttvEvent *e; + LttvHooks *check_event; + LttvHooks *before_event; + LttvHooksById *before_event_by_id; + LttvHooks *after_event; + LttvHooksById *after_event_by_id; + LttTime *time; + LttvAttribute *a; +}; + +struct _LttvTracefileContextClass { + GObjectClass parent; +}; + +GType lttv_tracefile_context_get_type (void); + +void lttv_process_trace(LttvTime start, LttvTime end, LttvTraceset *traceset, + LttvTracesetContext *context); + +void lttv_traceset_context_add_hooks(LttvTracesetContext *self, + LttvHooks *before_traceset, + LttvHooks *after_traceset, + LttvHooks *check_trace, + LttvHooks *before_trace, + LttvHooks *after_trace, + LttvHooks *check_event, + LttvHooks *before_event, + LttvHooks *after_event) + +void lttv_traceset_context_remove_hooks(LttvTracesetContext *self, + LttvHooks *before_traceset, + LttvHooks *after_traceset, + LttvHooks *check_trace, + LttvHooks *before_trace, + LttvHooks *after_trace, + LttvHooks *check_event, + LttvHooks *before_event, + LttvHooks *after_event) + +#endif // PROCESSTRACE_H diff --git a/ltt/branches/poly/include/lttv/state.h b/ltt/branches/poly/include/lttv/state.h new file mode 100644 index 00000000..4a4664d4 --- /dev/null +++ b/ltt/branches/poly/include/lttv/state.h @@ -0,0 +1,149 @@ +#ifndef STATE_H +#define STATE_H + +#include + +/* The operating system state kept during the trace analysis + contains a subset of the real operating system state, + sufficient for the analysis, and possibly organized quite differently. + + The state information is added to LttvTraceSetContext, LttvTraceContext + and LttvTracefileContext objects, used by processTrace, through + subtyping. The context objects already reflect the multiple tracefiles + (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. */ + + +gboolean lttv_state_add_event_hooks(void *hook_data, void *call_data); + +gboolean lttv_state_remove_event_hooks(void *hook_data, void *call_data); + + +/* The interrupt type is one of "user mode", "kernel thread", "system call", + "interrupt request", "fault". */ + +typedef GQuark LttvInterruptType; + + +/* 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 + (e.g. "page fault"), and system call name (e.g. "select"). + +typedef GQuark LttvInterruptNumber; + + +/* The process status is one of "running", "wait-cpu" (runnable), or "wait-*" + where "*" describes the resource waited for (e.g. timer, process, + disk...). */ + +typedef GQuark LttvProcessStatus; + + +typedef _LttvInterruptState { + LttvInterruptType t; + LttvInterruptNumber n; + LttvTime entry; + LttvTime last_change; + LttvProcessStatus s; +} LttvInterruptState; + + +typedef struct _LttvProcessState { + guint pid; + LttvTime birth; + GQuark name; + GArray *interrupt_stack; /* Array of LttvInterruptState */ + LttvInterruptState *state; /* Top of interrupt stack */ + /* opened file descriptors, address map... */ +} LttvProcessState; + + +/* The LttvTraceSetState, LttvTraceState and LttvTracefileState types + inherit from the corresponding Context objects defined in processTrace. */ + +#define LTTV_TRACESET_STATE_TYPE (lttv_traceset_state_get_type ()) +#define LTTV_TRACESET_STATE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), LTTV_TRACESET_STATE_TYPE, LttvTraceSetState)) +#define LTTV_TRACESET_STATE_CLASS(vtable) (G_TYPE_CHECK_CLASS_CAST ((vtable), LTTV_TRACESET_STATE_TYPE, LttvTraceSetStateClass)) +#define LTTV_IS_TRACESET_STATE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), LTTV_TRACESET_STATE_TYPE)) +#define LTTV_IS_TRACESET_STATE_CLASS(vtable) (G_TYPE_CHECK_CLASS_TYPE ((vtable), LTTV_TRACESET_STATE_TYPE)) +#define LTTV_TRACESET_STATE_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), LTTV_TRACESET_STATE_TYPE, LttvTraceSetStateClass)) + +typedef struct _LttvTraceSetState LttvTraceSetState; +typedef struct _LttvTraceSetStateClass LttvTraceSetStateClass; + +struct _LttvTraceSetState { + LttvTraceSetContext parent; +}; + +struct _LttvTracesetStateClass { + LttvTraceSetClass parent; +}; + +GType lttv_traceset_state_get_type (void); + + +#define LTTV_TRACE_STATE_TYPE (lttv_trace_state_get_type ()) +#define LTTV_TRACE_STATE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), LTTV_TRACE_STATE_TYPE, LttvTraceState)) +#define LTTV_TRACE_STATE_CLASS(vtable) (G_TYPE_CHECK_CLASS_CAST ((vtable), LTTV_TRACE_STATE_TYPE, LttvTraceStateClass)) +#define LTTV_IS_TRACE_STATE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), LTTV_TRACE_STATE_TYPE)) +#define LTTV_IS_TRACE_STATE_CLASS(vtable) (G_TYPE_CHECK_CLASS_TYPE ((vtable), LTTV_TRACE_STATE_TYPE)) +#define LTTV_TRACE_STATE_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), LTTV_TRACE_STATE_TYPE, LttvTraceStateClass)) + +typedef struct _LttvTraceState LttvTraceState; +typedef struct _LttvTraceStateClass LttvTraceStateClass; + +struct _LttvTraceState { + LttvTraceContext parent; + + GHashTable *processes; /* LttvProcessState objects indexed by pid */ + /* Block/char devices, locks, memory pages... */ +}; + +struct _LttvTraceStateClass { + LttvTraceContextClass parent; +}; + +GType lttv_trace_state_get_type (void); + + +#define LTTV_TRACEFILE_STATE_TYPE (lttv_tracefile_state_get_type ()) +#define LTTV_TRACEFILE_STATE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), LTTV_TRACEFILE_STATE_TYPE, LttvTracefileState)) +#define LTTV_TRACEFILE_STATE_CLASS(vtable) (G_TYPE_CHECK_CLASS_CAST ((vtable), LTTV_TRACEFILE_STATE_TYPE, LttvTracefileStateClass)) +#define LTTV_IS_TRACEFILE_STATE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), LTTV_TRACEFILE_STATE_TYPE)) +#define LTTV_IS_TRACEFILE_STATE_CLASS(vtable) (G_TYPE_CHECK_CLASS_TYPE ((vtable), LTTV_TRACEFILE_STATE_TYPE)) +#define LTTV_TRACEFILE_STATE_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), LTTV_TRACEFILE_STATE_TYPE, LttvTracefileStateClass)) + +typedef struct _LttvTracefileState LttvTracefileState; +typedef struct _LttvTracefileStateClass LttvTracefileStateClass; + +struct _LttvTracefileState { + LttvTracefileContext parent; + + LttvProcessState *process; +}; + +struct _LttvTracefileStateClass { + LttvTracefileContextClass parent; +}; + +GType lttv_tracefile_state_get_type (void); + + +#endif // PROCESSTRACE_H diff --git a/ltt/branches/poly/include/lttv/stats.h b/ltt/branches/poly/include/lttv/stats.h new file mode 100644 index 00000000..a98f9640 --- /dev/null +++ b/ltt/branches/poly/include/lttv/stats.h @@ -0,0 +1,52 @@ + +/* 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; + diff --git a/ltt/branches/poly/include/lttv/textDump.h b/ltt/branches/poly/include/lttv/textDump.h new file mode 100644 index 00000000..e69de29b diff --git a/ltt/branches/poly/include/lttv/traceSet.h b/ltt/branches/poly/include/lttv/traceSet.h deleted file mode 100644 index 292b6e83..00000000 --- a/ltt/branches/poly/include/lttv/traceSet.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef TRACESET_H -#define TRACESET_H - -#include -#include -#include - -/* A traceSet is a set of traces to be analyzed together. */ - -typedef struct _lttv_trace_set lttv_trace_set; - - -/* Trace sets may be added to, removed from and their content listed. */ - -lttv_trace_set *lttv_trace_set_new(); - -lttv_trace_set *lttv_trace_set_destroy(lttv_trace_set *s); - -void lttv_trace_set_add(lttv_trace_set *s, ltt_trace *t); - -unsigned lttv_trace_set_number(lttv_trace_set *s); - -ltt_trace *lttv_trace_set_get(lttv_trace_set *s, unsigned i); - -ltt_trace *lttv_trace_set_remove(lttv_trace_set *s, unsigned i); - - -/* An attributes table is attached to the set and to each trace in the set. */ - -lttv_attributes *lttv_trace_set_attributes(lttv_trace_set *s); - -lttv_attributes *lttv_trace_set_trace_attributes(lttv_trace_set *s, - unsigned i); - - -/* Process the events in a trace set. Lists of hooks are provided to be - called before and after the trace set and each trace and tracefile. - For each event, a trace set filter function is called to verify if the - event is of interest (if it returns TRUE). If this is the case, hooks - are called for the event, as well as type specific hooks if applicable. - Any of the hooks lists and the filter may be null if not to be used. */ - -lttv_trace_set_process(lttv_trace_set *s, - lttv_hooks *before_trace_set, lttv_hooks *after_trace_set, - char *filter, ltt_time start, ltt_time end); - -#endif // TRACESET_H - diff --git a/ltt/branches/poly/include/lttv/traceset.h b/ltt/branches/poly/include/lttv/traceset.h new file mode 100644 index 00000000..6bf940d1 --- /dev/null +++ b/ltt/branches/poly/include/lttv/traceset.h @@ -0,0 +1,37 @@ +#ifndef TRACESET_H +#define TRACESET_H + +#include +#include +#include + +/* A traceset is a set of traces to be analyzed together. */ + +typedef struct LttvTraceset LttvTraceset; + + +/* Tracesets may be added to, removed from and their content listed. */ + +LttvTraceset *lttv_traceset_new(); + +void lttv_traceset_destroy(LttvTraceset *s); + +void lttv_traceset_add(LttvTraceset *s, LttTrace *t); + +unsigned lttv_traceset_number(LttvTraceset *s); + +LttTrace *lttv_traceset_get(LttvTraceset *s, unsigned i); + +void lttv_traceset_remove(LttvTraceset *s, unsigned i); + + +/* An attributes table is attached to the set and to each trace in the set. */ + +LttvAttribute *lttv_traceset_attribute(LttvTraceset *s); + +LttvAttribute *lttv_traceset_trace_attribute(LttvTraceset *s, + unsigned i); + + +#endif // TRACESET_H + diff --git a/ltt/branches/poly/lttv/attribute.c b/ltt/branches/poly/lttv/attribute.c index b08c24da..6fab25dc 100644 --- a/ltt/branches/poly/lttv/attribute.c +++ b/ltt/branches/poly/lttv/attribute.c @@ -1,424 +1,275 @@ + #include -inline lttv_string_id lttv_string_id_from_string(const char *s) { - return g_quark_from_string(s); +typedef union _AttributeValue { + int dv_int; + unsigned dv_uint; + long dv_long; + unsigned long dv_ulong; + float dv_float; + double dv_double; + timespec dv_timespec; + gpointer dv_pointer; + char *dv_string; + gobject *dv_gobject; +} AttributeValue; + + +typedef struct _Attribute { + LttvAttributeName name; + LttvAttributeType type; + AttributeValue value; +} Attribute; + + +GType +lttv_attribute_get_type (void) +{ + static GType type = 0; + if (type == 0) { + static const GTypeInfo info = { + sizeof (LttvAttributeClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + attribute_class_init, /* class_init */ + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (LttvAttribute), + 0, /* n_preallocs */ + attribute_instance_init /* instance_init */ + }; + + static const GInterfaceInfo iattribute_info = { + (GInterfaceInitFunc) attribute_interface_init, /* interface_init */ + NULL, /* interface_finalize */ + NULL /* interface_data */ + }; + + type = g_type_register_static (G_TYPE_OBJECT, "LttvAttributeType", &info, + 0); + g_type_add_interface_static (type, LTTV_IATTRIBUTE_TYPE, &iattribute_info); + } + return type; } -inline void lttv_string_id_release(lttv_string_id i) {} - - -inline const char *lttv_string_id_to_string(lttv_string_id i) { - return g_quark_to_string(i); +unsigned int +lttv_attribute_get_number(LttvAttribute *self) +{ + return self->attributes->len; } -inline lttv_key *lttv_key_new() { - return g_array_new(FALSE, FALSE, sizeof(lttv_string_id)); -} - -/* Changed this function to destroy the element also, caused memory leak? */ -/* Mathieu Desnoyers */ -inline void lttv_key_destroy(lttv_key *k) { - g_array_free(k, TRUE); +gboolean +lttv_attribute_named(LttvAttribute *self, gboolean *homogeneous) +{ + *homogeneous = FALSE; + return TRUE; } -#define _lttv_key_index(k,i) g_array_index(k, lttv_string_id, i) - +LttvAttributeType +lttv_attribute_get(LttvAttribute *self, unsigned i, LttvAttributeName *name, + LttvAttributeValue *v) +{ + Attribute *a; -inline void lttv_key_append(lttv_key *k, lttv_string_id i) { - g_array_append_val(k,i); + a = &g_array_index(self->attributes, Attribute, i); + *name = a->name; + *v = address_of_value(a->type, a->value); + return a->type; } -inline unsigned int lttv_key_component_number(lttv_key *k) { - return k->len; -} +LttvAttributeType +lttv_attribute_get_by_name(LttvAttribute *self, LttvAttributeName name, + LttvAttributeValue *v) +{ + Attribute *a; + unsigned i; -lttv_key *lttv_key_copy(lttv_key *k) { - lttv_key *nk; - int i; + i = (unsigned)g_hash_table_lookup(self->names, (gconstpointer)name); + if(i == 0) return LTTV_NONE; - nk = lttv_key_new(); - for(i = 0 ; i < k->len ; i++) lttv_key_append(nk,lttv_key_index(k,i)); - return nk; + i--; + a = &g_array_index(self->attributes, Attribute, i); + *v = address_of_value(a->type, a->value); + return a->type; } -/* It is also possible to create a key directly from a pathname, - key components separated by /, (e.g., "/hooks/options/before"). */ -lttv_key *lttv_key_new_pathname(const char *p) { - char **v, **cursor; - lttv_key *k; - - v = cursor = g_strsplit(p, "/", -1); - k = lttv_key_new(); - - while(*cursor != NULL) { - lttv_key_append(k, lttv_string_id_from_string(*cursor)); - cursor++; - } - g_strfreev(v); - return k; -} +LttvAttributeValue +lttv_attribute_add(LttvAttribute *self, LttvAttributeName name, + LttvAttributeType t) +{ + unsigned i; -static guint lttv_key_hash(gconstpointer key) { - lttv_key * k = (lttv_key *)key; - guint h = 0; - int i; - for(i = 0 ; i < k->len ; i++) h = h ^ lttv_key_index(k,i); - return h; -} + Attribute a, *pa; -static gboolean lttv_key_equal(gconstpointer key1,gconstpointer key2) { - lttv_key * k1 = (lttv_key *)key1; - lttv_key * k2 = (lttv_key *)key2; - int i; + i = (unsigned)g_hash_table_lookup(self->names, (gconstpointer)name); + if(i != 0) g_error("duplicate entry in attribute table"); - if(k1->len != k2->len) return FALSE; - for(i = 0 ; i < k1->len ; i++) - if(lttv_key_index(k1,i) != lttv_key_index(k2,i)) return FALSE; - return TRUE; + a->name = name; + a->type = t; + a->value = init_value(t); + g_array_append_val(self->attributes, a); + i = self->attributes->len - 1; + pa = &g_array_index(self->attributes, Attribute, i) + g_hash_table_insert(self->names, (gconstpointer)name, (gconstpointer)i + 1); + return address_of_value(pa->value, t); } -static void lttv_key_free(gpointer data) -{ - lttv_key_destroy((lttv_key *)data); -} - +/* Remove an attribute */ -static void lttv_attribute_value_free(gpointer data) +void +lttv_attribute_remove(LttvAttribute *self, unsigned i) { - g_free(data); -} - - -lttv_attributes *lttv_attributes_new() { - lttv_attributes *a; + Attribute *a; - a = g_new(lttv_attributes, 1); - a->ints = g_hash_table_new_full(lttv_key_hash, lttv_key_equal, - lttv_key_free, lttv_attribute_value_free); - a->times = g_hash_table_new_full(lttv_key_hash, lttv_key_equal, - lttv_key_free, lttv_attribute_value_free); - a->doubles = g_hash_table_new_full(lttv_key_hash, lttv_key_equal, - lttv_key_free, lttv_attribute_value_free); - a->pointers = g_hash_table_new(lttv_key_hash, lttv_key_equal); + a = &g_array_index(self->attributes, Attribute, i); - return a; -} + /* Remove the array element and its entry in the name index */ + g_hash_table_remove(self->names, (gconspointer)a->name); + g_array_remove_index_fast(self->attributes, i); -/* Free the hash table containing the stats and all the contained keys/vals */ + /* The element used to replace the removed element has its index entry + all wrong now. Reinsert it with its new position. */ -static void lttv_attribute_key_free(gpointer k, gpointer v, gpointer data) { - lttv_key_free(k); + g_hash_table_remove(self->names, (gconstpointer)a->name); + g_hash_table_insert(self->names, (gconstpointer)a->name, i + 1); } +void +lttv_attribute_remove_by_name(LttvAttribute *self, LttvAttributeName name) +{ + unsigned i; -void lttv_attributes_destroy(lttv_attributes *a) { - g_hash_table_destroy(a->ints); - g_hash_table_destroy(a->times); - g_hash_table_destroy(a->doubles); - - g_hash_table_foreach(a->pointers, lttv_attribute_key_free, NULL); - g_hash_table_destroy(a->pointers); - g_free(a); -} + i = (unsigned)g_hash_table_lookup(self->names, (gconstpointer)name); + if(i == 0) g_error("remove by name non existent attribute"); -unsigned int lttv_attributes_number(lttv_attributes *a) { - return g_hash_table_size(a->ints) + g_hash_table_size(a->times) + - g_hash_table_size(a->doubles) + g_hash_table_size(a->pointers); + lttv_attribute_remove(self, i - 1); } +/* Create an empty iattribute object and add it as an attribute under the + specified name, or return an existing iattribute attribute. If an + attribute of that name already exists but is not a GObject supporting the + iattribute interface, return NULL. */ -/* If it is a new entry, insert it in the hash table, and set it to 0 */ - -int *lttv_attributes_get_integer(lttv_attributes *a, lttv_key *k) +LttvIAttribute* +lttv_attribute_create_subdir(LttvAttribute *self, LttvAttributeName name) { - gpointer found; + unsigned i; - found = g_hash_table_lookup(a->ints, k); - if(found == NULL) { - found = g_new(gint, 1); - *(gint *)found = 0; - g_hash_table_insert(a->ints, lttv_key_copy(k), found); - } - return found; -} + Attribute a; + LttvAttribute *new; -lttv_time *lttv_attributes_get_time(lttv_attributes *a, lttv_key *k) -{ - gpointer found; - - found = g_hash_table_lookup(a->times, k); - if(found == NULL) { - found = g_new0(lttv_time, 1); - /* *(lttv_time *)found = ZeroTime; */ - g_hash_table_insert(a->times, lttv_key_copy(k), found); + i = (unsigned)g_hash_table_lookup(self->names, (gconstpointer)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); + } + else return NULL; } - return found; + new = g_object_new(LTTV_ATTRIBUTE_TYPE); + *(lttv_attribute_add(self, name, LTTV_GOBJECT)->v_gobject) = new; + return new; } -double *lttv_attributes_get_double(lttv_attributes *a, lttv_key *k) +gboolean +lttv_attribute_find(LttvAttribute *self, LttvAttributeName name, + LttvAttributeType t, LttvAttributeValue *v) { - gpointer found; - - found = g_hash_table_lookup(a->doubles,k); - if(found == NULL) { - found = g_new(double,1); - *(double *)found = 0; - g_hash_table_insert(a->doubles, lttv_key_copy(k),found); - } - return found; -} + unsigned i; -void *lttv_attributes_get_pointer_pathname(lttv_attributes *a, char *pn) -{ - lttv_key *key; - void *p; + Attribute *a; - key = lttv_key_new_pathname(pn); - p = lttv_attributes_get_pointer(a, key); - lttv_key_destroy(key); + i = (unsigned)g_hash_table_lookup(self->names, (gconstpointer)name); + if(i != 0) { + a = &g_array_index(self->attributes, Attribute, i - 1); + if(a->type != t) return FALSE; + *v = address_of_value(a->value, t); + return TRUE; + } - return p; + *v = lttv_attribute_add(self, name, t); + return TRUE; } -void *lttv_attributes_get_pointer(lttv_attributes *a, lttv_key *k) -{ - return g_hash_table_lookup(a->pointers,k); -} -void lttv_attributes_set_pointer_pathname(lttv_attributes *a,char *pn,void *p) +static void +attribute_interface_init (gpointer g_iface, gpointer iface_data) { - lttv_key *key = lttv_key_new_pathname(pn); - - lttv_attributes_set_pointer(a, key, p); - lttv_key_destroy(key); -} + LttvIAttributeClass *klass = (LttvIAttributeClass *)g_iface; -void lttv_attributes_set_pointer(lttv_attributes *a, lttv_key *k, void *p) { - lttv_key * oldk; - void *oldv; + klass->get_number = (unsigned int (*) (LttvIAttribute *self)) + lttv_attribute_get_number; - if(g_hash_table_lookup_extended(a->pointers, k, (gpointer)oldk, &oldv)) { - if(p == NULL) { - g_hash_table_remove(a->pointers,k); - } - else { - g_hash_table_insert(a->pointers,oldk,p); - } - } - else { - if(p == NULL) return; - g_hash_table_insert(a->pointers,lttv_key_copy(k),p); - } -} + klass->named = (gboolean (*) (LttvIAttribute *self, gboolean *homogeneous)) + lttv_attribute_named; + klass->get = (LttvAttributeType (*) (LttvIAttribute *self, unsigned i, + LttvAttributeName *name, LttvAttributeValue *v)) lttv_attribute_get; -#ifdef EXT_ATTRIBS -/* Sometimes the attributes must be accessed in bulk, sorted in different - ways. For this purpose they may be converted to arrays and sorted - multiple times. The keys used in the array belong to the lttv_attributes - object from which the array was obtained and are freed when it is - destroyed. Each element in the array is an lttv_attribute, a structure - containing the key, the value type, and a union containing a value of - that type. Multiple attributes with equal keys may be possible in some - implementations if their type differs. */ + klass->get_by_name = (LttvAttributeType (*) (LttvIAttribute *self, + LttvAttributeName name, LttvAttributeValue *v)) + lttv_attribute_get_by_name; + klass->add = (LttvAttributeValue (*) (LttvIAttribute *self, + LttvAttributeName name, LttvAttributeType t)) lttv_attribute_add; -typedef struct _lttv_attribute_fill_position { - unsigned i; - lttv_attribute_type t; - lttv_attribute *a; -} lttv_attribute_fill_position; - - -static void lttv_attribute_fill(void *key, void *value, void *user_data) { - lttv_attribute_fill_position * p = (lttv_attribute_fill_position *)user_data; - lttv_attribute *a = p->a + p->i; - - a->key = (lttv_key *)key; - a->t = p->t; - switch(p->t) { - case LTTV_INTEGER: - a->v.i = *((int *)value); - case LTTV_TIME: - a->v.t = *((lttv_time *)value); - case LTTV_DOUBLE: - a->v.d = *((double *)value); - case LTTV_POINTER: - a->v.p = value; - } - p->i++; -} + klass->remove = (void (*) (LttvIAttribute *self, unsigned i)) + lttv_attribute_remove; + klass->remove_by_name = (void (*) (LttvIAttribute *self, + LttvAttributeName name)) lttv_attribute_remove_by_name; -lttv_attribute *lttv_attributes_array_get(lttv_attributes *a) { - unsigned size; - lttv_attribute *v; - lttv_attribute_fill_position p; - - size = lttv_attributes_number(a); - v = g_new(lttv_attribute,size); - - p.a = v; - p.i = 0; - p.t = LTTV_INTEGER; - g_hash_table_foreach(a->ints, lttv_attribute_fill, &p); - p.t = LTTV_TIME; - g_hash_table_foreach(a->times, lttv_attribute_fill, &p); - p.t = LTTV_DOUBLE; - g_hash_table_foreach(a->doubles, lttv_attribute_fill, &p); - p.t = LTTV_POINTER; - g_hash_table_foreach(a->pointers, lttv_attribute_fill, &p); - return v; + klass->create_subdir = (LttvIAttribute* (*) (LttvIAttribute *self, + LttvAttributeName name)) lttv_attribute_create_subdir; } -lttv_attribute *lttv_attribute_array_destroy(lttv_attribute *a) { - g_free(a); -} - - -void lttv_attribute_array_sort(lttv_attribute *a, - unsigned size, lttv_key_compare f, - void *compare_data) +static guint +quark_hash(gconstpointer key) { - - g_qsort_with_data(a, size, sizeof(lttv_attribute), f, - compare_data); + return (guint)key; } -int lttv_key_compare_priority(lttv_key *a, lttv_key *b, void *compare_data) +static gboolean +quark_equal(gconstpointer a, gconstpointer b) { - int i, res; - int *priority = (int *)compare_data; - - g_assert(a->len == b->len); - - for(i = 0 ; i < a->len ; i++) - { - res = strcmp(lttv_string_id_to_string(lttv_key_index(a,priority[i])), - lttv_string_id_to_string(lttv_key_index(a,priority[i]))); - if(res != 0) return res; - } - return 0; + return (a == b) } -typedef struct _select_data { - lttv_attributes *a; - lttv_key *k; - void *user_data; - lttv_key_select select; -} select_data; - -static void select_integer(void *key, void *value, void *user_data); -static void select_double(void *key, void *value, void *user_data); -static void select_time(void *key, void *value, void *user_data); -static void select_pointer(void *key, void *value, void *user_data); - -lttv_attributes *lttv_attributes_select(lttv_attributes *a, lttv_key_select f, - void *user_data) +static void +attribute_instance_init (GTypeInstance *instance, gpointer g_class) { - select_data *d; - - d = g_new(select_data, 1); - d->a = lttv_attributes_new(); - d->k = lttv_key_new(); - d->user_data = user_data; - d->select = f; - - g_hash_table_foreach(a->ints,select_integer, d); - g_hash_table_foreach(a->doubles,select_double, d); - g_hash_table_foreach(a->times,select_time, d); - g_hash_table_foreach(a->pointers,select_pointer, d); + LttvAttribute *self = (LttvAttribute *)instance; + self->names = g_hash_table_new(quark_hash, quark_equal); + self->attributes = g_array_new(FALSE, FALSE, + sizeof(Attribute)); } -int lttv_key_select_spec(lttv_key *in, lttv_key *out, void *user_data) -{ - lttv_key_select_spec_data *d = (lttv_key_select_spec_data *)user_data; - int i; - - /* not defined yet */ - /* lttv_key_set_size(out, 0); */ - - for(i = 0 ; i < d->length ; i++) { - switch(d->spec[i]) { - case LTTV_KEEP: - break; - - case LTTV_KEEP_EQUAL: - break; - - case LTTV_KEEP_SMALLER: - break; - case LTTV_KEEP_GREATER: - break; - - case LTTV_IGNORE: - break; - - } - } - - return 1; -} - -static void select_integer(void *key, void *value, void *user_data) -{ - lttv_key *k = (lttv_key *)key; - int *pi = (int *)value; - select_data *d = (select_data *)user_data; - - if(d->select(k,d->k,d->user_data)) { - *(lttv_attributes_get_integer(d->a,d->k)) += *pi; - } -} - -static void select_double(void *key, void *value, void *user_data) +static void +attribute_finalize (LttvAttribute *self) { - lttv_key *k = (lttv_key *)key; - double *pf = (double *)value; - select_data *d = (select_data *)user_data; - - if(d->select(k,d->k,d->user_data)) { - *(lttv_attributes_get_double(d->a,d->k)) += *pf; - } + g_hash_table_free(self->names); + g_array_free(self->attributes, TRUE); + G_OBJECT_CLASS(g_type_class_peek_parent(LTTV_ATTRIBUTE_TYPE))->finalize(self); } -static void select_time(void *key, void *value, void *user_data) -{ - lttv_key *k = (lttv_key *)key; - lttv_time *ptSum, *pt = (lttv_time *)value; - select_data *d = (select_data *)user_data; - - if(d->select(k,d->k,d->user_data)) { - ptSum = lttv_attributes_get_time(d->a,d->k); - ptSum->tv_sec += pt->tv_sec; - ptSum->tv_nsec += pt->tv_nsec; - } -} -static void select_pointer(void *key, void *value, void *user_data) +static void +attribute_class_init (LttvAttributeClass *klass) { - lttv_key *k = (lttv_key *)key; - select_data *d = (select_data *)user_data; + GObjectClass *gobject_class = G_OBJECT_CLASS(klass); - if(d->select(k,d->k,d->user_data)) { - lttv_attributes_set_pointer(d->a,d->k,value); - } + gobject_class->finalize = attribute_finalize; } - - - - -#endif // EXT_ATTRIBS diff --git a/ltt/branches/poly/lttv/batchAnalysis.c b/ltt/branches/poly/lttv/batchAnalysis.c index 30bb1bb8..02b3dea4 100644 --- a/ltt/branches/poly/lttv/batchAnalysis.c +++ b/ltt/branches/poly/lttv/batchAnalysis.c @@ -5,100 +5,139 @@ #include #include #include +#include +#include -static void process_trace_set(void *hook_data, void *call_data) +static LttvTraceset *traceset; + +static LttvHooks + *before_traceset, + *after_traceset, + *before_trace, + *after_trace, + *before_tracefile, + *after_tracefile, + *before_event, + *after_event, + *main_hooks; + +static char *a_trace; + + +void lttv_trace_option(void *hook_data) +{ + LttTrace *trace; + + trace = ltt_trace_open(a_trace); + if(trace == NULL) g_critical("cannot open trace %s", a_trace); + lttv_traceset_add(traceset, trace); +} + + +static void process_traceset(void *hook_data, void *call_data) { - int i, nb; - lttv_attributes *a, *sa; - lttv_trace_set *s; - lttv_hooks *global_before, *before, *global_after, *after; - ltt_time start, end; - lttv_key *key; - lttv_hook f; - void *hook_data; - - a = lttv_global_attributes(); - global_before = (lttv_hooks *)lttv_attributes_get_pointer_pathname(a, - "hooks/trace_set/before"); - global_after = (lttv_hooks *)lttv_attributes_get_pointer_pathname(a, - "hooks/trace_set/after"); - s = (lttv_trace_set *)lttv_attributes_get_pointer_pathname(a, - "traceSet/main"); - - key = lttv_key_new_pathname("time/start"); - start = lttv_attributes_get_time(a,key); - lttv_key_destroy(key); - - key = lttv_key_new_pathname("time/end"); - end = lttv_attributes_get_time(a,key); - lttv_key_destroy(key); - - sa = lttv_trace_set_attributes(s); - - before = (lttv_hooks *)lttv_attributes_get_pointer_pathname(sa, - "hooks/before"); - if(before == NULL) { - before = lttv_hooks_new(); - lttv_attributes_set_pointer_pathname(sa, "hooks/before", before); - } + LttvTracesetState *tc; - after = (lttv_hooks *)lttv_attributes_get_pointer_pathname(sa, - "hooks/after"); - if(after == NULL) { - after = lttv_hooks_new(); - lttv_attributes_set_pointer_pathname(sa, "hooks/after", after); - } + LttTime start, end; - nb = lttv_hooks_number(global_before); - for(i = 0 ; i < nb ; i++) { - lttv_hooks_get(global_before, i, &f, &hook_data); - lttv_hooks_add(before, f, hook_data); - } + tc = g_object_new(LTTV_TRACESET_STATE); + lttv_context_init(LTTV_TRACESET_CONTEXT(tc), traceset); - nb = lttv_hooks_number(global_after); - for(i = 0 ; i < nb ; i++) { - lttv_hooks_get(global_after, i, &f, &hook_data); - lttv_hooks_add(after, f, hook_data); - } + lttv_traceset_context_add_hooks(LTTV_TRACESET_CONTEXT(tc), + before_traceset, after_traceset, before_trace, after_trace, + before_tracefile, after_tracefile, before_event, after_event); + lttv_state_add_event_hooks(tc); - lttv_trace_set_process(s, before_trace_set, after_trace_set, filter, start, - end); + start.tv_sec = 0; + start.tv_nsec = 0; + end.tv_sec = G_MAXULONG; + end.tv_nsec = G_MAXULONG; - nb = lttv_hooks_number(global_before); - for(i = 0 ; i < nb ; i++) { - lttv_hooks_get(global_before, i, &f, &hook_data); - lttv_hooks_remove(before, f, hook_data); - } + lttv_process_trace(start, end, traceset, tc); + lttv_traceset_context_remove_hooks(LTTV_TRACESET_CONTEXT(tc), + before_traceset, after_traceset, before_trace, after_trace, + before_tracefile, after_tracefile, before_event, after_event); - nb = lttv_hooks_number(global_after); - for(i = 0 ; i < nb ; i++) { - lttv_hooks_get(global_after, i, &f, &hook_data); - lttv_hooks_remove(after, f, hook_data); - } + lttv_state_remove_event_hooks(tc); + lttv_context_fini(LTTV_TRACESET_CONTEXT(tc)); + g_object_unref(tc); } void init(int argc, char **argv) { - lttv_attributes *a; - lttv_hooks *h; - - a = lttv_global_attributes(); - h = (lttv_hooks *)lttv_attributes_get_pointer_pathname(a,"hooks/main"); - lttv_hooks_add(h, process_trace_set, NULL); + LttvAttribute_value *value; + + LttvIAttributes *attributes = LTTV_IATTRIBUTES(lttv_global_attributes()); + + lttv_option_add("trace", 't', + "add a trace to the trace set to analyse", + "pathname of the directory containing the trace", + LTTV_OPT_STRING, &aTrace, lttv_trace_option, NULL); + + traceset = lttv_traceset_new(); + + before_traceset = lttv_hooks_new(); + after_traceset = lttv_hooks_new(); + before_trace = lttv_hooks_new(); + after_trace = lttv_hooks_new(); + before_tracefile = lttv_hooks_new(); + after_tracefile = lttv_hooks_new(); + before_event = lttv_hooks_new(); + after_event = lttv_hooks_new(); + + g_assert(lttv_iattribute_find_by_path(attributes, "hooks/traceset/before", + LTTV_POINTER, &value)); + *(value->v_pointer) = before_traceset; + g_assert(lttv_iattribute_find_by_path(attributes, "hooks/traceset/after", + LTTV_POINTER, &value)); + *(value->v_pointer) = after_traceset; + g_assert(lttv_iattribute_find_by_path(attributes, "hooks/trace/before", + LTTV_POINTER, &value)); + *(value->v_pointer) = before_trace; + g_assert(lttv_iattribute_find_by_path(attributes, "hooks/trace/after", + LTTV_POINTER, &value)); + *(value->v_pointer) = after_trace; + g_assert(lttv_iattribute_find_by_path(attributes, "hooks/tracefile/before", + LTTV_POINTER, &value)); + *(value->v_pointer) = before_tracefile; + g_assert(lttv_iattribute_find_by_path(attributes, "hooks/tracefile/after", + LTTV_POINTER, &value)); + *(value->v_pointer) = after_tracefile; + g_assert(lttv_iattribute_find_by_path(attributes, "hooks/event/before", + LTTV_POINTER, &value)); + *(value->v_pointer) = before_event; + g_assert(lttv_iattribute_find_by_path(attributes, "hooks/event/after", + LTTV_POINTER, &value)); + *(value->v_pointer) = after_event; + + g_assert(lttv_iattribute_find_by_path(attributes, "hooks/main/before", + LTTV_POINTER, &value)); + g_assert((main_hooks = *(value->v_pointer)) != NULL); + lttv_hooks_add(main_hooks, process_traceset, NULL); } void destroy() { - lttv_attributes *a; - lttv_hooks *h; + guint i, nb; - a = lttv_global_attributes(); - h = (lttv_hooks *)lttv_attributes_get_pointer_pathname(a,"hooks/main"); - lttv_hooks_remove(h, process_trace_set, NULL); -} + lttv_hooks_remove(main_hooks, process_traceset, NULL); + lttv_option_remove("trace"); + lttv_hooks_destroy(before_traceset); + lttv_hooks_destroy(after_traceset); + lttv_hooks_destroy(before_trace); + lttv_hooks_destroy(after_trace); + lttv_hooks_destroy(before_tracefile); + lttv_hooks_destroy(after_tracefile); + lttv_hooks_destroy(before_event); + lttv_hooks_destroy(after_event); + nb = lttv_traceset_number(traceset); + for(i = 0 ; i < nb, i++) { + ltt_trace_close(lttv_traceset_get(traceset); + } +} diff --git a/ltt/branches/poly/lttv/hook.c b/ltt/branches/poly/lttv/hook.c index eb7c5d9f..12f12198 100644 --- a/ltt/branches/poly/lttv/hook.c +++ b/ltt/branches/poly/lttv/hook.c @@ -1,28 +1,29 @@ #include -typedef struct _lttv_hook_closure { +typedef struct _LttvHookClosure { lttv_hook hook; void *hook_data; -} lttv_hook_closure; +} LttvHookClosure; -inline lttv_hooks *lttv_hooks_new() { - return g_array_new(FALSE, FALSE, sizeof(lttv_hook_closure)); +LttvHooks *lttv_hooks_new() +{ + return g_array_new(FALSE, FALSE, sizeof(LttvHookClosure)); } -/* MD: delete elements of the array also, but don't free pointed addresses - * (functions). - */ -inline void lttv_hooks_destroy(lttv_hooks *h) { + +void lttv_hooks_destroy(LttvHooks *h) +{ g_array_free(h, TRUE); } -inline void lttv_hooks_add(lttv_hooks *h, lttv_hook f, void *hook_data) { - lttv_hook_closure c; - /* if h is null, do nothing, or popup a warning message */ - if(h == NULL)return; +void lttv_hooks_add(LttvHooks *h, LttvHook f, void *hook_data) +{ + LttvHookClosure c; + + if(h == NULL)g_error("Null hook added"); c.hook = f; c.hook_data = hook_data; @@ -30,47 +31,173 @@ inline void lttv_hooks_add(lttv_hooks *h, lttv_hook f, void *hook_data) { } -int lttv_hooks_call(lttv_hooks *h, void *call_data) +void lttv_hooks_add_list(LttvHooks *h, LttvHooks *list) +{ + guint i; + + for(i = 0 ; i < list->len; i++) { + g_array_append_val(h,g_array_index(list, LttvHookClosure, i)); + } +} + + +void *lttv_hooks_remove(LttvHooks *h, LttvHook f) +{ + unsigned i; + + void *hook_data; + + LttvHookClosure *c; + + for(i = 0 ; i < h->len ; i++) { + c = &g_array_index(h, LttvHookClosure, i); + if(c->hook == f) { + hook_data = c->hook_data; + lttv_hooks_remove_by_position(h, i); + return hook_data; + } + } + return NULL; +} + + +void lttv_hooks_remove_data(LttvHooks *h, LttvHook f, void *hook_data) { - int i; - lttv_hook_closure * c; + unsigned i; + + LttvHookClosure *c; for(i = 0 ; i < h->len ; i++) { - c = ((lttv_hook_closure *)h->data) + i; - if(c != NULL) - c->hook(c->hook_data,call_data); - else - g_critical("NULL hook called\n"); + c = &g_array_index(h, LttvHookClosure, i); + if(c->hook == f && c->hook_data == hook_data) { + lttv_hooks_remove_by_position(h, i); + return; + } + } +} + + +void lttv_hooks_remove_list(LttvHooks *h, LttvHooks *list) +{ + guint i, j; + + LttvHookClosure *c, *c_list; + + for(i = 0, j = 0 ; i < h->len && j < list->len ;) { + c = &g_array_index(h, LttvHookClosure, i); + c_list = &g_array_index(list, LttvHookClosure, j); + if(c->hook == c_list->hook && c->hook_data == c_list->hook_data) { + lttv_hooks_remove_by_position(h, i); + j++; + } + else i++; + } + + /* Normally the hooks in h are ordered as in list. If this is not the case, + try harder here. */ + + if(j < list->len) { + for(; j < list->len ; j++) { + c_list = &g_array_index(list, LttvHookClosure, j); + lttv_hooks_remove_data(h, c_list->hook, c_list->hook_data); + } } } -/* Sometimes different hooks need to be called based on the case. The - case is represented by an unsigned integer id and may represent different - event types, for instance. */ +unsigned lttv_hooks_number(LttvHooks *h) +{ + return h->len; +} -inline lttv_hooks_by_id *lttv_hooks_by_id_new() { + +void lttv_hooks_get(LttvHooks *h, unsigned i, LttvHook *f, void **hook_data) +{ + LttvHookClosure *c; + + c = &g_array_index(h, LttvHookClosure, i); + *f = c->hook; + *hook_data = c->hook_data; +} + + +void lttv_hooks_remove_by_position(LttvHooks *h, unsigned i); +{ + g_array_remove_index(h, i) +} + + +gboolean lttv_hooks_call(LttvHooks *h, void *call_data) +{ + gboolean ret = FALSE; + + LttvHookClosure *c; + + 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); + } + } + return ret; +} + + +gboolean lttv_hooks_call_check(LttvHooks *h, void *call_data) +{ + LttvHookClosure *c; + + for(i = 0 ; i < h->len ; i++) { + c = &g_array_index(h, LttvHookClosure, i); + if(c->hook(c->hook_data,call_data)) return TRUE; + } + return FALSE; +} + + +LttvHooksById *lttv_hooks_by_id_new() +{ return g_ptr_array_new(); } -inline void lttv_hooks_by_id_destroy(lttv_hooks_by_id *h) { - /* MD: delete elements of the array also */ +void lttv_hooks_by_id_destroy(LttvHooksById *h) +{ + guint i; + + for(i = 0 ; i < h->len ; i++) { + if(h->pdata[i] != NULL) lttv_hooks_destroy((LttvHooks *)(h->pdata[i])); + } g_ptr_array_free(h, TRUE); } -void lttv_hooks_by_id_add(lttv_hooks_by_id *h, lttv_hook f, void *hook_data, - unsigned int id) +LttvHooks *lttv_hooks_by_id_find(LttvHooksById *h, unsigned id); { - if(h->len < id) g_ptr_array_set_size(h, id); + if(h->len <= id) g_ptr_array_set_size(h, id + 1); if(h->pdata[id] == NULL) h->pdata[id] = lttv_hooks_new(); - lttv_hooks_add(h->pdata[id], f, hook_data); + return h->pdata[id]; } -void lttv_hooks_by_id_call(lttv_hooks_by_id *h, void *call_data, unsigned int id) + +unsigned lttv_hooks_by_id_max_id(LttvHooksById *h) { - if(h->len <= id || h->pdata[id] == NULL) return; - lttv_hooks_call(h->pdata[id],call_data); + return h->len; +} + + +LttvHooks *lttv_hooks_by_id_get(LttvHooksById *h, unsigned id) +{ + if(id < h->len) return h->pdata[id]; + return NULL; +} + + +void lttv_hooks_by_id_remove(LttvHooksById *h, unsigned id) +{ + if(id < h->len && h->pdata[id] != NULL) { + lttv_hooks_destroy((LttvHooks *)h->pdata[id]); + h->pdata[id] = NULL; + } } diff --git a/ltt/branches/poly/lttv/iattribute.c b/ltt/branches/poly/lttv/iattribute.c new file mode 100644 index 00000000..5cf9dbe4 --- /dev/null +++ b/ltt/branches/poly/lttv/iattribute.c @@ -0,0 +1,260 @@ + +static void +lttv_iattribute_base_init (gpointer g_class) +{ + static gboolean initialized = FALSE; + + if (!initialized) { + initialized = TRUE; + } +} + + +GType +lttv_iattribute_get_type (void) +{ + static GType type = 0; + if (type == 0) { + static const GTypeInfo info = { + sizeof (LttvIAttributeClass), + lttv_iattribute_base_init, /* base_init */ + NULL, /* base_finalize */ + NULL, /* class_init */ + NULL, /* class_finalize */ + NULL, /* class_data */ + 0, + 0, /* n_preallocs */ + NULL /* instance_init */ + }; + type = g_type_register_static (G_TYPE_INTERFACE, "LttvIAttribute", + &info, 0); + } + return type; +} + + +unsigned int lttv_iattribute_get_number(LttvIAttribute *self) +{ + return LTTV_IATTRIBUTE_GET_CLASS (self)->get_number (self); +} + + +gboolean lttv_iattribute_named(LttvIAttribute *self, gboolean *homogeneous) +{ + return LTTV_IATTRIBUTE_GET_CLASS (self)->named (self, homogeneous); +} + + +LttvAttributeType lttv_iattribute_get(LttvIAttribute *self, unsigned i, + LttvAttributeName *name, LttvAttributeValue *v) +{ + return LTTV_IATTRIBUTE_GET_CLASS (self)->get (self, i, name, v); +} + + +LttvAttributeType lttv_iattribute_get_by_name(LttvIAttribute *self, + LttvAttributeName name, LttvAttributeValue *v) +{ + return LTTV_IATTRIBUTE_GET_CLASS (self)->get_by_name (self, name, v); +} + + +void lttv_iattribute_add(LttvIAttribute *self, LttvAttributeName name, + LttvAttributeType t, LttvAttributeValue *v) +{ + return LTTV_IATTRIBUTE_GET_CLASS (self)->add (self, name, t, v); +} + + +void lttv_iattribute_remove(LttvIAttribute *self, unsigned i) +{ + return LTTV_IATTRIBUTE_GET_CLASS (self)->remove (self, i); +} + + +void lttv_iattribute_remove_by_name(LttvIAttribute *self, + LttvAttributeName name) +{ + return LTTV_IATTRIBUTE_GET_CLASS (self)->remove_by_name (self, name); +} + +LttvIAttribute* lttv_iattribute_create_subdir(LttvIAttribute *self, + LttvAttributeName name) +{ + return LTTV_IATTRIBUTE_GET_CLASS (self)->get_number (self, name); +} + + +/* Find the named attribute in the table, which must be of the specified type. + If it does not exist, it is created with a default value of 0 (NULL for + pointer types). Since the address of the value is obtained, it may be + changed easily afterwards. The function returns false when the attribute + exists but is of incorrect type. */ + +gboolean lttv_iattribute_find(LttvIAttribute *self, LttvAttributeName name, + LttvAttributeType t, LttvAttributeValue *v) +{ + LttvAttributeType found_type; + + found_type = lttv_iattribute_get_by_name(self, name, v); + if(found_type == t) return TRUE; + + if(found_type == LTTV_NONE) { + v = lttv_iattribute_add(self, name, t); + return TRUE; + } + + return FALSE; +} + + +/* Trees of attribute tables may be accessed using a hierarchical path with + components separated by /, like in filesystems */ + +gboolean lttv_iattribute_find_by_path(LttvIAttribute *self, char *path, + LttvAttributeType t, LttvAttributeValue *v) +{ + char *cursor; + + LttvIAttribute *node = self; + + LttvAttributeType found_type; + + LttvAttributeName name; + + gchar **components, **cursor; + + components = g_strsplit(path, "\"", G_MAXINT); + + if(components == NULL || *components == NULL) { + g_strfreev(components); + return FALSE; + } + + while(cursor = components;;) { + name = g_quark_from_string(*cursor); + cursor++; + + if(*cursor == NULL) { + g_strfreev(components); + return lttv_iattribute_find(node, name, t, v); + } + else { + found_type = lttv_iattribute_get_by_name(node, name, v); + if(found_type == LTTV_NONE) { + node = lttv_iattribute_create_subdir(node, name); + } + else if(found_type == LTTV_GOBJECT && + LTTV_IS_IATTRIBUTE(*(v->v_gobject))) { + node = LTTV_IATTRIBUTE(*(v->v_gobject)); + } + else { + g_strfreev(components); + return FALSE; + } + } + } +} + +/* Shallow and deep copies */ + +LttvIAttribute *lttv_iattribute_shallow_copy(LttvIAttribute *self) +{ + LttvIAttribute copy; + + LttvAttributeType t; + + LttvAttributeValue v, v_copy; + + LttvAttributeName name; + + int i; + + int nb_attributes = lttv_iattribute_get_number(self); + + copy = LTTV_IATTRIBUTE(g_object_new(G_OBJECT_TYPE(self))); + + for(i = 0 ; i < nb_attributes ; i++) { + t = lttv_iattribute_get(self, i, &name, &v); + v_copy = lttv_iattribute_add(copy, name, t); + lttv_iattribute_copy_value(v_copy, v); + } +} + +LttvIAttribute *lttv_iattribute_deep_copy(LttvIAttribute *self) +{ + LttvIAttribute copy, child; + + LttvAttributeType t; + + LttvAttributeValue v, v_copy; + + LttvAttributeName name; + + int i; + + int nb_attributes = lttv_iattribute_get_number(self); + + copy = LTTV_IATTRIBUTE(g_object_new(G_OBJECT_TYPE(self))); + + for(i = 0 ; i < nb_attributes ; i++) { + t = lttv_iattribute_get(self, i, &name, &v); + v_copy = lttv_iattribute_add(copy, name, t); + if(t == LTTV_GOBJECT && LTTV_IS_IATTRIBUTE(*(v->v_gobject))) { + child = LTTV_IATTRIBUTE(*(v->v_gobject)); + *(v_copy->v_gobject) = lttv_iattribute_deep_copy(child); + } + else lttv_iattribute_copy_value(t, v_copy, v); + } +} + +void lttv_iattribute_copy_value(LttvAttributeType t, LttvAttributeValue dest, + LttvAttributeValue src) +{ + switch(t) { + case LTTV_INT: + *(dest->v_int) = *(src->v_int); + break; + + case LTTV_UINT: + *(dest->v_uint) = *(src->v_uint); + break; + + case LTTV_LONG: + *(dest->v_long) = *(src->v_long); + break; + + case LTTV_ULONG: + *(dest->v_ulong) = *(src->v_ulong); + break; + + case LTTV_FLOAT: + *(dest->v_float) = *(src->v_float); + break; + + case LTTV_DOUBLE: + *(dest->v_double) = *(src->v_double); + break; + + case LTTV_TIME: + *(dest->v_time) = *(src->v_time); + break; + + case LTTV_POINTER: + *(dest->v_pointer) = *(src->v_pointer); + break; + + case LTTV_STRING: + *(dest->v_string) = *(src->v_string); + break; + + case LTTV_GOBJECT: + *(dest->v_gobject) = *(src->v_gobject); + break; + + case LTTV_NONE: + break; + } +} + + diff --git a/ltt/branches/poly/lttv/main.c b/ltt/branches/poly/lttv/main.c index d44d8f51..b588e429 100644 --- a/ltt/branches/poly/lttv/main.c +++ b/ltt/branches/poly/lttv/main.c @@ -1,56 +1,53 @@ #include #include - #include #include #include +#include +#include -#include +void lttv_option_init(int argc, char **argv); +void lttv_option_destroy(); + +void lttv_module_init(int argc, char **argv); +void lttv_module_destroy(); -#include /* 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 */ -/* Extensible array of popt command line options. Modules add options as - they are loaded and initialized. */ - - -static lttv_attributes *attributes_global; +static LttvIAttributes *attributes; -static lttv_hooks - *hooks_init_after, - *hooks_program_before, - *hooks_program_main, - *hooks_program_after; +static LttvHooks + *before_options, + *after_options, + *before_main, + *after_main; -// trace sets has to be put one in each new window_traceset -static lttv_trace_set *traces; +static char + *a_module, + *a_module_path; -static char *aModule, *aPath, *aTrace; +static int a_argc; -static int aArgc; - -static char **aArgv; +static char **a_argv; static void lttv_module_option(void *hook_data); static void lttv_module_path_option(void *hook_data); -static void lttv_trace_option(void *hook_data); - #ifdef MEMDEBUG extern struct GMemVTable *glib_mem_profiler_table; #endif + /* Since everything is done in modules, the main program only takes care of the infrastructure. */ int main(int argc, char **argv) { - aArgc = argc; - aArgv = argv; + LttvAttributeValue *value; #ifdef MEMDEBUG g_mem_set_vtable(glib_mem_profiler_table); @@ -58,35 +55,31 @@ int main(int argc, char **argv) { g_mem_profile(); #endif - attributes_global = lttv_attributes_new(); - -// traces = lttv_trace_set_new(); -// lttv_attributes_set_pointer_pathname(attributes_global, "trace_set/default", traces); - - /* Initialize the hooks */ - - hooks_init_after = lttv_hooks_new(); - lttv_attributes_set_pointer_pathname(attributes_global, "hooks/init/after", - hooks_init_after); + attributes = LTTV_IATTRIBUTES(g_object_new(LTTV_ATTRIBUTES_TYPE)); + before_options = lttv_hooks_new(); + after_options = lttv_hooks_new(); + before_main = lttv_hooks_new(); + after_main = lttv_hooks_new(); - hooks_program_before = lttv_hooks_new(); - lttv_attributes_set_pointer_pathname(attributes_global, "hooks/program/before", - hooks_program_before); + g_assert(lttv_iattribute_find_by_path(attributes, "hooks/options/before", + LTTV_POINTER, &value)); + *(value->v_pointer) = before_options; + g_assert(lttv_iattribute_find_by_path(attributes, "hooks/options/after", + LTTV_POINTER, &value)); + *(value->v_pointer) = after_options; + g_assert(lttv_iattribute_find_by_path(attributes, "hooks/main/before", + LTTV_POINTER, &value)); + *(value->v_pointer) = before_main; + g_assert(lttv_iattribute_find_by_path(attributes, "hooks/main/after", + LTTV_POINTER, &value)); + *(value->v_pointer) = after_main; - hooks_program_main = lttv_hooks_new(); - lttv_attributes_set_pointer_pathname(attributes_global, "hooks/program/main", - hooks_program_main); - - hooks_program_after = lttv_hooks_new(); - lttv_attributes_set_pointer_pathname(attributes_global, "hooks/program/after", - hooks_program_after); /* Initialize the command line options processing */ lttv_option_init(argc,argv); lttv_module_init(argc,argv); - // FIXME lttv_analyse_init(argc,argv); /* Initialize the module loading */ @@ -99,58 +92,43 @@ int main(int argc, char **argv) { lttv_option_add("modules-path", 'L', "add a directory to the module search path", - "directory to add to the path", LTTV_OPT_STRING, &aPath, + "directory to add to the path", LTTV_OPT_STRING, &aModulePath, lttv_module_path_option, NULL); - lttv_option_add("trace", 't', - "add a trace to the trace set to analyse", - "pathname of the directory containing the trace", - LTTV_OPT_STRING, &aTrace, lttv_trace_option, NULL); - - lttv_hooks_call(hooks_init_after, NULL); - - lttv_hooks_call(hooks_program_before, NULL); - lttv_hooks_call(hooks_program_main, NULL); - lttv_hooks_call(hooks_program_after, NULL); + lttv_hooks_call(before_options, NULL); + lttv_hooks_call(after_options, NULL); + lttv_hooks_call(before_main, NULL); + lttv_hooks_call(after_main, NULL); - /* Finalize the command line options processing */ lttv_module_destroy(); lttv_option_destroy(); - // FIXME lttv_analyse_destroy(); - lttv_attributes_destroy(attributes_global); + + lttv_hooks_destroy(before_options); + lttv_hooks_destroy(after_options); + lttv_hooks_destroy(before_main); + lttv_hooks_destroy(after_main); + g_object_unref(attributes); #ifdef MEMDEBUG g_message("Memory summary after main"); g_mem_profile(); #endif - - } + lttv_attributes *lttv_global_attributes() { - return attributes_global; + return attributes; } void lttv_module_option(void *hook_data) { - lttv_module_load(aModule,aArgc,aArgv,STANDALONE); + lttv_module_load(a_module,a_argc,a_argv); } void lttv_module_path_option(void *hook_data) { - lttv_module_path_add(aPath); + lttv_module_path_add(a_path); } - - -void lttv_trace_option(void *hook_data) -{ -// lttv_trace *trace; - -// trace = lttv_trace_open(aTrace); -// if(trace == NULL) g_critical("cannot open trace %s", aTrace); -// lttv_trace_set_add(traces, trace); -} - diff --git a/ltt/branches/poly/lttv/module.c b/ltt/branches/poly/lttv/module.c index 384ad343..ccb2bdde 100644 --- a/ltt/branches/poly/lttv/module.c +++ b/ltt/branches/poly/lttv/module.c @@ -3,288 +3,268 @@ * */ -/* Initial draft by Michel Dagenais May 2003 - * Reworked by Mathieu Desnoyers, May 2003 - */ - -#include #include -#include + + +struct _LttvModule +{ + GModule *module; + guint ref_count; + guint load_count; + GPtrArray *dependents; +}; + /* Table of loaded modules and paths where to search for modules */ static GHashTable *modules = NULL; -static GPtrArray *modulesStandalone = NULL; - static GPtrArray *modulesPaths = NULL; -void lttv_module_init(int argc, char **argv) { +static void lttv_module_unload_all(); + + +void lttv_module_init(int argc, char **argv) +{ modules = g_hash_table_new(g_str_hash, g_str_equal); - modulesStandalone = g_ptr_array_new(); modulesPaths = g_ptr_array_new(); } -void lttv_module_destroy() { - + +void lttv_module_destroy() +{ int i; /* Unload all modules */ lttv_module_unload_all(); /* Free the modules paths pointer array as well as the elements */ - for(i = 0; i< modulesPaths->len; i++) { + for(i = 0; i < modulesPaths->len ; i++) { g_free(modulesPaths->pdata[i]); } g_ptr_array_free(modulesPaths,TRUE) ; - g_ptr_array_free(modulesStandalone,TRUE) ; modulesPaths = NULL; - modulesStandalone = NULL; /* destroy the hash table */ g_hash_table_destroy(modules) ; modules = NULL; } + /* Add a new pathname to the modules loading search path */ -void lttv_module_path_add(const char *name) { +void lttv_module_path_add(const char *name) +{ g_ptr_array_add(modulesPaths,(char*)g_strdup(name)); } -/* Load (if not already loaded) the named module. Its init function is - called. We pass the options of the command line to it in case it has - preliminary things to get from it. Note that the normal way to add a - command line option for a module is through the options parsing mecanism. - */ - -lttv_module_info *lttv_module_load(const char *name, int argc, char **argv, loadtype load) { +static LttvModuleInfo * +module_load(const char *name, int argc, char **argv) +{ + GModule *gm; - GModule *gmodule; - - lttv_module_info *moduleInfo; + LttvModule *m; int i; char *pathname; - lttv_module_load_init init_Function; - - /* Find and load the module, It will increase the usage counter - * If the module is already loaded, only the reference counter will - * be incremented. It's part of the gmodule architecture. Very useful - * for modules dependencies. - */ + LttvModuleInit init_function; - g_assert(name != NULL); + /* 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); - gmodule = g_module_open(pathname,0) ; + gm = g_module_open(pathname,0); + g_free(pathname); - - if(gmodule != NULL) { - g_message("Loading module %s ... found!",pathname); - - /* Was the module already opened? */ - moduleInfo = g_hash_table_lookup(modules,g_module_name(gmodule)); - - /* First time the module is opened */ - - if(moduleInfo == NULL ) { - moduleInfo = g_new(lttv_module_info, 1); - moduleInfo->module = gmodule; - moduleInfo->pathname = g_module_name(gmodule); - moduleInfo->directory = modulesPaths->pdata[i]; - moduleInfo->name = (char *)g_strdup(name); - moduleInfo->ref_count = 0; - moduleInfo->index_standalone = -1; - g_hash_table_insert(modules, moduleInfo->pathname, moduleInfo); - if(!g_module_symbol(gmodule, "init", (gpointer) &init_Function)) { - g_critical("module %s (%s) does not have init function", - moduleInfo->pathname,moduleInfo->name); - } - else { - init_Function(argc,argv); - } - } - - /* Add the module in the standalone array if the module is - * standalone and not in the array. Otherwise, set index to - * -1 (dependant only). - */ - if(load == STANDALONE) { - - if(moduleInfo->index_standalone == -1) { - - g_ptr_array_add(modulesStandalone, moduleInfo); - moduleInfo->index_standalone = modulesStandalone->len - 1; - - moduleInfo->ref_count++ ; - } - else { - g_warning("Module %s is already loaded standalone.",pathname); - /* Decrease the gmodule use_count. Has previously been increased in the g_module_open. */ - g_module_close(moduleInfo->module) ; - } - } - else { /* DEPENDANT */ - moduleInfo->ref_count++ ; - } - - return moduleInfo; - } - g_message("Loading module %s ... missing.",pathname); + if(gm != NULL) break; + } + + /* Try the default system path */ + + if(gm == NULL) { + pathname = g_module_build_path(NULL,name); + gm = g_module_open(pathname,0); g_free(pathname); } - g_critical("module %s not found",name); - return NULL; -} -/* Unload the named module. */ + /* Module cannot be found */ + + if(gm == NULL) return NULL; + + /* Check if the module was already opened using the hopefully canonical name + returned by g_module_name. */ + + pathname = g_module_name(gm); -int lttv_module_unload_pathname(const char *pathname, loadtype load) { + m = g_hash_table_lookup(modules, pathname); - lttv_module_info *moduleInfo; + if(m == NULL) { - moduleInfo = g_hash_table_lookup(modules, pathname); + /* Module loaded for the first time. Insert it in the table and call the + init function if any. */ - /* If no module of that name is loaded, nothing to unload. */ - if(moduleInfo != NULL) { - g_message("Unloading module %s : is loaded.\n", pathname) ; - lttv_module_unload(moduleInfo, load) ; - return 1; + m = g_new(LttvModule); + m->module = gm; + m->ref_count = 0; + m->load_count = 0; + m->dependents = g_ptr_array_new(); + g_hash_table_insert(modules, pathname, m); + + if(!g_module_symbol(gm, "init", (gpointer)&init_function)) { + g_warning("module %s (%s) has no init function", name, pathname); + } + else init_Function(argc,argv); } else { - g_message("Unloading module %s : is not loaded.\n", pathname) ; - return 0; + + /* Module was already opened, check that it really is the same and + undo the extra g_module_open */ + + if(m->module != gm) g_error("Two gmodules with the same pathname"); + g_module_close(gm); } + m->ref_count++; + return m; } -int lttv_module_unload_name(const char *name, loadtype load) { - int i; +LttvModuleInfo * +lttv_module_load(const char *name, int argc, char **argv) +{ + LttvModule *m = module_load(name, argc, argv); - char *pathname; - - /* Find and load the module, It will increase the usage counter - * If the module is already loaded, only the reference counter will - * be incremented. It's part of the gmodule architecture. Very useful - * for modules dependencies. - */ + if(m != NULL) m->load_count++; + return m; +} - g_assert(name != NULL); - for(i = 0 ; i < modulesPaths->len ; i++) { +LttvModule * +lttv_module_require(LttvModule *m, const char *name, int argc, char **argv) +{ + LttvModule *module; - pathname = g_module_build_path(modulesPaths->pdata[i],name); - - if(lttv_module_unload_pathname(pathname, load) == TRUE) - return TRUE ; - } - g_critical("module %s not found",name); - return FALSE; + module = module_load(name, argc, argv); + if(module != NULL) g_ptr_array_add(m->dependents, module); + return module; } +static void module_unload(LttvModule *m) +{ + LttvModuleDestroy destroy_function; -/* Unload the module. We use a call_gclose boolean to keep the g_module_close call - * after the call to the module's destroy function. */ - -int lttv_module_unload(lttv_module_info *moduleInfo, loadtype load) { + char *pathname; - lttv_module_unload_destroy destroy_Function; + guint len; - char *moduleName ; + /* Decrement the reference count */ - gboolean call_gclose = FALSE; + m->ref_count--; + if(m->ref_count > 0) return; - if(moduleInfo == NULL) return FALSE; + /* We really have to unload the module, first unload its dependents */ - /* Closing the module decrements the usage counter if previously higher than - * 1. If 1, it unloads the module. - */ + len = m->dependents->len; - /* Add the module in the standalone array if the module is - * standalone and not in the array. Otherwise, set index to - * -1 (dependant only). - */ - if(load == STANDALONE) { - - if(moduleInfo->index_standalone == -1) { - - g_warning("Module %s is not loaded standalone.",moduleInfo->pathname); - } - else { - /* We do not remove the element of the array, it would change - * the index orders. We will have to check if index is -1 in - * unload all modules. - */ - moduleInfo->index_standalone = -1; - g_message("Unloading module %s, reference count passes from %u to %u", - moduleInfo->pathname,moduleInfo->ref_count, - moduleInfo->ref_count-1); - - moduleInfo->ref_count-- ; - call_gclose = TRUE ; - } + for(i = 0 ; i < len ; i++) { + module_unload(m->dependents->pdata[i]); } - else { /* DEPENDANT */ - g_message("Unloading module %s, reference count passes from %u to %u", - moduleInfo->pathname, - moduleInfo->ref_count,moduleInfo->ref_count-1); - moduleInfo->ref_count-- ; - call_gclose = TRUE ; + if(len != m->dependents->len) g_error("dependents list modified"); + + /* Unload the module itself */ + + if(!g_module_symbol(m->module, "destroy", (gpointer)&destroy_function)) { + g_warning("module (%s) has no destroy function", pathname); } + else destroy_function(); - /* The module is really closing if ref_count is 0 */ - if(!moduleInfo->ref_count) { - g_message("Unloading module %s : closing module.",moduleInfo->pathname); + g_hash_table_remove(modules, g_module_name(m->module)); + g_ptr_array_free(m->dependents, TRUE); + g_module_close(m->module); + g_free(m); +} - /* Call the destroy function of the module */ - if(!g_module_symbol(moduleInfo->module, "destroy", (gpointer) &destroy_Function)) { - g_critical("module %s (%s) does not have destroy function", - moduleInfo->pathname,moduleInfo->name); - } - else { - destroy_Function(); - } - - /* If the module will effectively be closed, remove the moduleInfo from - * the hash table and free the module name. - */ - g_free(moduleInfo->name) ; - g_hash_table_remove(modules, moduleInfo->pathname); +void lttv_module_unload(LttvModule *m) +{ + if(m->load_count <= 0) { + g_error("more unload than load (%s)", g_module_name(m->module)); + return; } - - if(call_gclose) g_module_close(moduleInfo->module) ; + m->load_count--; + module_unload(m); +} + - return TRUE ; +static void +list_modules(gpointer key, gpointer value, gpointer user_data) +{ + g_ptr_array_add((GPtrArray *)user_data, value); } -#define MODULE_I ((lttv_module_info *)modulesStandalone->pdata[i]) -//FIXME use g_ptr_array_index instead -/* unload all the modules in the hash table, calling module_destroy for - * each of them. - * - * We first take all the moduleInfo in the hash table, put it in an - * array. We use qsort on the array to have the use count of 1 first. - */ -void lttv_module_unload_all() { - - int i = 0; - - /* call the unload for each module. - */ - for(i = 0; i < modulesStandalone->len; i++) { - - if(MODULE_I->index_standalone != -1) { - lttv_module_unload(MODULE_I,STANDALONE) ; - } + +LttvModule ** +lttv_module_list(guint *nb) +{ + GPtrArray *list = g_ptr_array_new(); + + LttvModule **array; + + g_hash_table_foreach(modules, list_modules, list); + *nb = list->len; + array = (LttvModule **)list->pdata; + g_ptr_array_free(list, FALSE); + return array; +} + + +LttvModule ** +lttv_module_info(LttvModule *m, const char **name, + guint *ref_count, guint *load_count, guint *nb_dependents) +{ + guint i, len = m->dependents->len; + + LttvModule **array = g_new(LttvModule *, len); + + *name = g_module_name(m->module); + *ref_count = m->ref_count; + *load_count = m->load_count; + *nb_dependents = len; + for(i = 0 ; i < len ; i++) array[i] = m->dependents->pdata[i]; + return array; +} + + +static void +list_independent(gpointer key, gpointer value, gpointer user_data) +{ + LttvModule *m = (LttvModule *)value; + + if(m->load_count > 0) g_ptr_array_add((GPtrArray *)user_data, m); +} + + +void +lttv_module_unload_all() +{ + guint i; + + LttvModule *m; + + GPtrArray *independent_modules = g_ptr_array_new(); + + g_hash_table_foreach(modules, list_independent, independent_modules); + + for(i = 0 ; i < independent_modules->len ; i++) { + m = (LttvModule)independent_modules->pdata[i]; + while(m->load_count > 0) lttv_module_unload(m); } - + + g_ptr_array_free(independent_modules, TRUE); + if(g_hash_table_size(modules) != 0) g_warning("cannot unload all modules"); } diff --git a/ltt/branches/poly/lttv/option.c b/ltt/branches/poly/lttv/option.c index b7e4270a..3a95a4af 100644 --- a/ltt/branches/poly/lttv/option.c +++ b/ltt/branches/poly/lttv/option.c @@ -1,192 +1,216 @@ #include -#include -#include #include -/* Extensible array of popt command line options. Modules add options as - they are loaded and initialized. */ +typedef struct _LttvOption { + const char *long_name; + char char_name; + const char *description; + const char *arg_description; + LttvOptionType t; + gpointer p; + LttvOptionHook h; + gpointer hook_data; +} LttvOption; -typedef struct _lttv_option { - lttv_option_hook hook; - void *hook_data; -} lttv_option; +GHashTable *options; -static GArray *lttv_options_command; -static GArray *lttv_options_command_popt; - -// unneeded static lttv_key *key ; +static void +list_options(gpointer key, gpointer value, gpointer user_data) +{ + g_ptr_array_add((GPtrArray *)user_data, value); +} -static int command_argc; -static char **command_argv; +static void +free_option(LttvOption *option) +{ + g_free(option->long_name); + g_free(option->description); + g_free(option->arg_description); + g_free(option); +} -/* Lists of hooks to be called at different places */ -static lttv_hooks - *hooks_options_before, - *hooks_options_after; +void lttv_option_init(int argc, char **argv) +{ + options = g_hash_table_new(g_str_hash, g_str_equal); +} -static gboolean init_done = FALSE; -void lttv_options_command_parse(void *hook_data, void *call_data); +void lttv_option_destroy() +{ + LttvOption option; + GPtrArray list = g_ptr_array_new(); -void lttv_option_init(int argc, char **argv) { + int i; - lttv_hooks *hooks_init_after; + g_hash_table_foreach(options, list_options, list); + g_hash_table_destroy(options); - if(init_done) return; - else init_done = TRUE; + for(i = 0 ; i < list->len ; i++) { + free_option((LttvOption *)list->pdata[i]); + } + g_ptr_array_free(list, TRUE); +} - command_argc = argc; - command_argv = argv; - hooks_options_before = lttv_hooks_new(); - hooks_options_after = lttv_hooks_new(); +void lttv_option_add(const char *long_name, const char char_name, + const char *description, const char *arg_description, + const LttvOptionType t, void *p, + const LttvOptionHook h, void *hook_data) +{ + LttvOption *option; - lttv_attributes_set_pointer_pathname(lttv_global_attributes(), - "hooks/options/before", hooks_options_before); + if(g_hash_table_lookup(options, long_name) != NULL) { + g_warning("duplicate option"); + return; + } - lttv_attributes_set_pointer_pathname(lttv_global_attributes(), - "hooks/options/after", hooks_options_after); + option = g_new(LttvOption, 1); + option->long_name = g_strdup(long_name); + option->char_name = char_name; + option->description = g_strdup(description); + option->arg_description = g_strdup(arg_description); + option->t = t; + option->p = p; + option->h = h; + option->hook_data = hook_data; + g_hash_table_insert(options, option->long_name, option); +} - lttv_options_command_popt = g_array_new(0,0,sizeof(struct poptOption)); - lttv_options_command = g_array_new(0,0,sizeof(lttv_option)); - hooks_init_after = lttv_attributes_get_pointer_pathname(lttv_global_attributes(), - "hooks/init/after"); - lttv_hooks_add(hooks_init_after, lttv_options_command_parse, NULL); +void +lttv_option_remove(const char *long_name) +{ + LttvOption *option = g_hash_table_lookup(options, long_name); + if(option == NULL) { + g_warning("trying to remove unknown option %s", long_name); + return; + } + g_hash_table_remove(options, long_name); + free_option(option); } -void lttv_option_destroy() { - struct poptOption *poption; +static int poptToLTT[] = { + POPT_ARG_NONE, POPT_ARG_STRING, POPT_ARG_INT, POPT_ARG_LONG +}; - int i; - - for(i=0; i < lttv_options_command_popt->len ; i++) { - poption = &g_array_index (lttv_options_command_popt, struct poptOption, i); +static struct poptOption endOption = { NULL, '\0', 0, NULL, 0}; - g_free((gpointer)poption->longName); - g_free((gpointer)poption->descrip); - g_free((gpointer)poption->argDescrip); - } - g_array_free(lttv_options_command_popt,TRUE) ; - g_array_free(lttv_options_command,TRUE) ; - lttv_attributes_set_pointer_pathname(lttv_global_attributes(), - "hooks/options/before", NULL); +static void +build_popts(GPtrArray **plist, struct poptOption **ppopts, poptContext *pc, + int argv, char **argv) +{ + LttvOption *option; - lttv_attributes_set_pointer_pathname(lttv_global_attributes(), - "hooks/options/after", NULL); + GPtrArray *list; - lttv_hooks_destroy(hooks_options_before); - lttv_hooks_destroy(hooks_options_after); + struct poptOption *popts; -} + poptContext c; + guint i; -static int poptToLTT[] = { - POPT_ARG_NONE, POPT_ARG_STRING, POPT_ARG_INT, POPT_ARG_LONG -}; + list = g_ptr_array_new(); + g_hash_table_foreach(options, list_options, list); -void lttv_option_add(const char *long_name, const char char_name, - const char *description, const char *argDescription, - const lttv_option_type t, void *p, - const lttv_option_hook h, void *hook_data) -{ - struct poptOption poption; + /* Build a popt options array from our list */ - lttv_option option; + popts = g_new(struct poptOption, list->len + 1); - poption.longName = (char *)g_strdup(long_name); - poption.shortName = char_name; - poption.descrip = (char *)g_strdup(description); - poption.argDescrip = (char *)g_strdup(argDescription); - poption.argInfo = poptToLTT[t]; - poption.arg = p; - poption.val = lttv_options_command->len + 1; + for(i = 0 ; i < list->len ; i++) { + option = (LttvOption *)list->pdata[i]; + popts[i].longName = option->long_name; + popts[i].shortName = option->char_name; + popts[i].descrip = option->description; + popts[i].argDescrip = option->arg_description; + popts[i].argInfo = poptToLTT[option->t]; + popts[i].arg = option->p; + popts[i].val = i + 1; + } + + /* Terminate the array for popt and create the context */ - option.hook = h; - option.hook_data = hook_data; + popts[list->len] = endOption; + c = poptGetContext(argv[0], argc, (const char**)argv, popts, 0); - g_array_append_val(lttv_options_command_popt,poption); - g_array_append_val(lttv_options_command,option); + *plist = list; + *ppopts = popts; + *pc = c; } -static struct poptOption endOption = { NULL, '\0', 0, NULL, 0}; +static void +destroy_popts(GPtrArray **plist, struct poptOption **ppopts, poptContext *pc) +{ + g_ptr_array_free(*plist, TRUE); *plist = NULL; + g_free(*ppopts); *ppopts = NULL; + poptFreeContext(*c); +} -/* As we may load modules in the hooks called for argument processing, - * we have to recreate the argument context each time the - * lttv_options_command_popt is modified. This way we will be able to - * parse arguments defined by the modules - */ -void lttv_options_command_parse(void *hook_data, void *call_data) +void lttv_option_parse(int argc, char **argv) { - int rc; - int lastrc; + GPtrArray *list; + + LttvOption *option; + + int i, rc, first_arg; + + struct poptOption *popts; + poptContext c; - lttv_option *option; - lttv_hooks_call(hooks_options_before,NULL); - /* Always add then remove the null option around the get context */ - g_array_append_val(lttv_options_command_popt, endOption); - /* Compiler warning caused by const char ** for command_argv in header */ - /* Nothing we can do about it. Header should not put it const. */ - c = poptGetContext("lttv", command_argc, (const char**)command_argv, - (struct poptOption *)(lttv_options_command_popt->data),0); + i = 0; - /* We remove the null option here to be able to add options correctly */ - g_array_remove_index(lttv_options_command_popt, - lttv_options_command_popt->len - 1); + first_arg = 0; - /* There is no last good offset */ - lastrc = -1; + build_popts(&list, &popts, &c, argc, argv); /* Parse options while not end of options event */ + while((rc = poptGetNextOpt(c)) != -1) { - - if(rc == POPT_ERROR_BADOPT) { - /* We need to redo the context with information added by modules */ - g_array_append_val(lttv_options_command_popt, endOption); - poptFreeContext(c); - c = poptGetContext("lttv", command_argc, (const char**)command_argv, - (struct poptOption *)lttv_options_command_popt->data,0); - g_array_remove_index(lttv_options_command_popt, - lttv_options_command_popt->len -1); - - /* Cut out the already parsed elements */ - if(lastrc != -1) - while(poptGetNextOpt(c) != lastrc) { } ; - - /* Get the same option once again */ - g_assert(rc = poptGetNextOpt(c) != -1) ; - if(rc == POPT_ERROR_BADOPT) { - /* If here again we have a parsing error with all context info ok, - * then there is a problem in the arguments themself, give up */ - g_critical("option %s: %s", poptBadOption(c,0), poptStrerror(rc)); - break ; - } + + /* The option was recognized and the rc value returned is the argument + position in the array. Call the associated hook if present. */ + + if(rc > 0) { + option = (LttvOption *)(list->pdata[rc - 1]); + if(option->hook != NULL) option->hook(option->hook_data); + i++; + } + + else if(rc == POPT_ERROR_BADOPT && i != first_arg) { + + /* Perhaps this option is newly added, restart parsing */ + + destroy_popts(&list, &popts, &c); + build_popts(&list, &popts, &c, argc, argv); + + /* Get back to the same argument */ + + first_arg = i; + for(i = 0; i < first_arg; i++) poptGetNextOpt(c); } - - /* Remember this offset as the last good option value */ - lastrc = rc; - /* Execute the hook registered with this option */ - option = ((lttv_option *)lttv_options_command->data) + rc - 1; - if(option->hook != NULL) option->hook(option->hook_data); - - } + else { - poptFreeContext(c); + /* The option has some error and it is not because this is a newly + added option not recognized. */ - lttv_hooks_call(hooks_options_after,NULL); - + g_error("option %s: %s", poptBadOption(c,0), poptStrerror(rc)); + break; + } + + } + + destroy_popts(&list, &popts, &c); } diff --git a/ltt/branches/poly/lttv/processTrace.c b/ltt/branches/poly/lttv/processTrace.c new file mode 100644 index 00000000..66ba155d --- /dev/null +++ b/ltt/branches/poly/lttv/processTrace.c @@ -0,0 +1,559 @@ + +#include + +void lttv_context_init(LttvTracesetContext *self) +{ + LTTV_TRACESET_CONTEXT_GET_CLASS(self)->init(self); +} + + +void lttv_context_fini(LttvTracesetContext *self) +{ + LTTV_TRACESET_CONTEXT_GET_CLASS(self)->fini(self); +} + + +LttvTracesetContext * +lttv_context_new_traceset_context(LttvTracesetContext *self) +{ + return LTTV_TRACESET_CONTEXT_GET_CLASS(self)->new_traceset_context(self); +} + + + + +LttvTraceContext * +lttv_context_new_trace_context(LttvTracesetContext *self) +{ + return LTTV_TRACESET_CONTEXT_GET_CLASS(self)->new_trace_context(self); +} + + +LttvTracefileContext * +lttv_context_new_tracefile_context(LttvTracesetContext *self) +{ + LTTV_TRACESET_CONTEXT_GET_CLASS(self)->new_tracefile_context(self); +} + + +static void +init(LttvTracesetContext *self, LttvTraceset *ts) +{ + guint i, j, nb_trace, nb_control, nb_per_cpu, nb_tracefile; + + LttvTraceContext *tc; + + LttvTracefileContext *tfc; + + nb_trace = lttv_traceset_number(ts); + self->ts = ts; + self->traces = g_new((LttvTraceContext *), nb_trace); + self->before = lttv_hooks_new(); + self->after = lttv_hooks_new(); + self->attributes = g_object_new(LTTV_ATTRIBUTE_TYPE); + for(i = 0 ; i < nb_trace ; i++) { + tc = self->new_trace_context(); + self->traces[i] = tc; + + tc->ts_context = self; + tc->index = i; + tc->t = lttv_traceset_get(ts, i); + tc->check = lttv_hooks_new(); + tc->before = lttv_hooks_new(); + tc->after = lttv_hooks_new(); + tc->attributes = g_object_new(LTTV_ATTRIBUTE_TYPE); + 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; + tc->control_tracefiles = g_new((LttvTracefileContext *), nb_control); + tc->per_cpu_tracefiles = g_new((LttvTracefileContext *), nb_per_cpu); + + for(j = 0 ; j < nb_tracefile ; j++) { + tfc = self->new_tracefile_context(); + if(j < nb_control) { + tc->control_tracefiles[j] = tfc; + tfc->control = TRUE; + tfc->index = j; + tfc->tf = ltt_trace_control_tracefile_get(j); + } + else { + tc->per_cpu_tracefiles[j - nb_control] = tfc; + tfc->control = FALSE; + tfc->index = j - nb_control; + tfc->tf = ltt_trace_per_cpu_tracefile_get(j - nb_control); + } + tfc->t_context = tc; + tfc->check = lttv_hooks_new(); + tfc->before = lttv_hooks_new(); + tfc->after = lttv_hooks_new(); + tfc->check_event = lttv_hooks_new(); + tfc->before_event = lttv_hooks_new(); + tfc->before_event_by_id = lttv_hooks_by_id_new(); + tfc->after_event = lttv_hooks_new(); + tfc->after_event_by_id = lttv_hooks_by_id_new(); + tfc->attributes = g_object_new(LTTV_ATTRIBUTE_TYPE); + } + } +} + + +void fini(LttvTracesetContext *self) +{ + guint i, j, nb_trace, nb_control, nb_per_cpu, nb_tracefile; + + LttvTraceContext *tc; + + LttvTracefileContext *tfc; + + LttvTraceset *ts = tc->ts; + + lttv_hooks_destroy(self->before); + lttv_hooks_destroy(self->after); + g_object_unref(self->attributes); + + nb_trace = lttv_traceset_number(ts); + + for(i = 0 ; i < nb_trace ; i++) { + tc = self->traces[i]; + + lttv_hooks_destroy(tc->check); + lttv_hooks_destroy(tc->before); + lttv_hooks_destroy(tc->after); + g_object_unref(tc->attributes); + + 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) tfc = tc->control_tracefiles[j]; + else tfc = tc->per_cpu_tracefiles[j - nb_control]; + + lttv_hooks_destroy(tfc->check); + lttv_hooks_destroy(tfc->before); + lttv_hooks_destroy(tfc->after); + lttv_hooks_destroy(tfc->check_event); + lttv_hooks_destroy(tfc->before_event); + lttv_hooks_by_id_destroy(tfc->before_event_by_id); + lttv_hooks_destroy(tfc->after_event); + lttv_hooks_by_id_destroy(tfc->after_event_by_id); + g_object_unref(tfc->attributes); + g_object_unref(tfc); + } + g_free(tc->control_tracefiles); + g_free(tc->per_cpu_tracefiles); + g_object_unref(tc); + } + g_free(self->traces); +} + + +void lttv_traceset_context_add_hooks(LttvTracesetContext *self, + LttvHooks *before_traceset, + LttvHooks *after_traceset, + LttvHooks *check_trace, + LttvHooks *before_trace, + LttvHooks *after_trace, + LttvHooks *check_event, + LttvHooks *before_event, + LttvHooks *after_event) +{ + LttvTraceset *ts = self->ts; + + guint i, j, nb_trace, nb_control, nb_per_cpu, nb_tracefile; + + LttvTraceContext *tc; + + LttvTracefileContext *tfc; + + void *hook_data; + + lttv_hooks_add_list(self->before, before_traceset); + lttv_hooks_add_list(self->after, after_traceset); + nb_trace = lttv_traceset_number(ts); + + for(i = 0 ; i < nb_trace ; i++) { + tc = self->traces[i]; + lttv_hooks_add_list(tc->check, check_trace); + lttv_hooks_add_list(tc->before, before_trace); + lttv_hooks_add_list(tc->after, after_trace); + nb_control = ltt_trace_control_tracefile_number(tc->t); + nb_per_cpu = ltt_trace_control_tracefile_number(tc->t); + nb_tracefile = nb_control + nb_per_cpu; + + for(j = 0 ; j < nb_tracefile ; j++) { + if(j < nb_control) { + tfc = tc->control_tracefiles[j]; + } + else { + tfc = tc->per_cpu_tracefiles[j]; + } + lttv_hooks_add_list(tfc->check, check_tracefile); + lttv_hooks_add_list(tfc->before, before_tracefile); + lttv_hooks_add_list(tfc->after, after_tracefile); + lttv_hooks_add_list(tfc->check_event, check_event); + lttv_hooks_add_list(tfc->before_event, before_event); + lttv_hooks_add_list(tfc->after_event, after_event); + } + } +} + + +void lttv_traceset_context_remove_hooks(LttvTracesetContext *self, + LttvHooks *before_traceset, + LttvHooks *after_traceset, + LttvHooks *check_trace, + LttvHooks *before_trace, + LttvHooks *after_trace, + LttvHooks *check_event, + LttvHooks *before_event, + LttvHooks *after_event) +{ + LttvTraceset *ts = self->ts; + + guint i, j, nb_trace, nb_control, nb_per_cpu, nb_tracefile; + + LttvTraceContext *tc; + + LttvTracefileContext *tfc; + + void *hook_data; + + lttv_hooks_remove_list(self->before, before_traceset); + lttv_hooks_remove_list(self->after, after_traceset); + nb_trace = lttv_traceset_number(ts); + + for(i = 0 ; i < nb_trace ; i++) { + tc = self->traces[i]; + lttv_hooks_remove_list(tc->check, check_trace); + lttv_hooks_remove_list(tc->before, before_trace); + lttv_hooks_remove_list(tc->after, after_trace); + nb_control = ltt_trace_control_tracefile_number(tc->t); + nb_per_cpu = ltt_trace_control_tracefile_number(tc->t); + nb_tracefile = nb_control + nb_per_cpu; + + for(j = 0 ; j < nb_tracefile ; j++) { + if(j < nb_control) { + tfc = tc->control_tracefiles[j]; + } + else { + tfc = tc->per_cpu_tracefiles[j]; + } + lttv_hooks_remove_list(tfc->check, check_tracefile); + lttv_hooks_remove_list(tfc->before, before_tracefile); + lttv_hooks_remove_list(tfc->after, after_tracefile); + lttv_hooks_remove_list(tfc->check_event, check_event); + lttv_hooks_remove_list(tfc->before_event, before_event); + lttv_hooks_remove_list(tfc->after_event, after_event); + } + } +} + + +LttvTracesetContext * +new_traceset_context(LttvTracesetContext *self) +{ + return g_object_new(LTTV_TRACESET_CONTEXT_TYPE); +} + + +LttvTraceContext * +new_trace_context(LttvTracesetContext *self) +{ + return g_object_new(LTTV_TRACE_CONTEXT_TYPE); +} + + +LttvTracefileContext * +new_tracefile_context(LttvTracesetContext *self) +{ + return g_object_new(LTTV_TRACEFILE_CONTEXT_TYPE); +} + + +GType +lttv_traceset_context_get_type(void) +{ + static GType type = 0; + if (type == 0) { + static const GTypeInfo info = { + sizeof (LttvTracesetContextClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + traceset_context_class_init, /* class_init */ + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (LttvTracesetContext), + 0, /* n_preallocs */ + traceset_context_instance_init /* instance_init */ + }; + + type = g_type_register_static (G_TYPE_OBJECT, "LttvTracesetContextType", + &info, 0); + } + return type; +} + + +static void +traceset_context_instance_init (GTypeInstance *instance, gpointer g_class) +{ + /* Be careful of anything which would not work well with shallow copies */ +} + + +static void +traceset_context_finalize (LttvTracesetContext *self) +{ + G_OBJECT_CLASS(g_type_class_peek_parent(LTTV_TRACESET_CONTEXT_TYPE))->finalize(self); +} + + +static void +traceset_context_class_init (LttvTracesetContextClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS(klass); + + gobject_class->finalize = traceset_context_finalize; + klass->init = init; + klass->fini = fini; + klass->new_traceset_context = new_traceset_context; + klass->new_trace_context = new_trace_context; + klass->new_tracefile_context = new_tracefile_context; +} + + +GType +lttv_trace_context_get_type(void) +{ + static GType type = 0; + if (type == 0) { + static const GTypeInfo info = { + sizeof (LttvTraceContextClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + trace_context_class_init, /* class_init */ + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (LttvTraceSetContext), + 0, /* n_preallocs */ + trace_context_instance_init /* instance_init */ + }; + + type = g_type_register_static (G_TYPE_OBJECT, "LttvTraceContextType", + &info, 0); + } + return type; +} + + +static void +trace_context_instance_init (GTypeInstance *instance, gpointer g_class) +{ + /* Be careful of anything which would not work well with shallow copies */ +} + + +static void +trace_context_finalize (LttvTraceContext *self) +{ + G_OBJECT_CLASS(g_type_class_peek_parent(LTTV_TRACE_CONTEXT_TYPE))->finalize(self); +} + + +static void +trace_context_class_init (LttvTraceContextClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS(klass); + + gobject_class->finalize = trace_context_finalize; +} + + +GType +lttv_tracefile_context_get_type(void) +{ + static GType type = 0; + if (type == 0) { + static const GTypeInfo info = { + sizeof (LttvTracefileContextClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + tracefile_context_class_init, /* class_init */ + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (LttvTracefileContext), + 0, /* n_preallocs */ + tracefile_context_instance_init /* instance_init */ + }; + + type = g_type_register_static (G_TYPE_OBJECT, "LttvTracefileContextType", + &info, 0); + } + return type; +} + + +static void +tracefile_context_instance_init (GTypeInstance *instance, gpointer g_class) +{ + /* Be careful of anything which would not work well with shallow copies */ +} + + +static void +tracefile_context_finalize (LttvTracefileContext *self) +{ + G_OBJECT_CLASS(g_type_class_peek_parent(LTTV_TRACEFILE_CONTEXT_TYPE))->finalize(self); +} + + +static void +tracefile_context_class_init (LttvTracefileContextClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS(klass); + + gobject_class->finalize = tracefile_context_finalize; +} + + +guint compare_tracefile(gconstpointer a, gconstpointer b) +{ + if((LttvTime *)a->tv_sec > (LttvTime *)b->tv_sec) return 1; + if((LttvTime *)a->tv_sec < (LttvTime *)b->tv_sec) return -1; + if((LttvTime *)a->tv_nsec > (LttvTime *)b->tv_nsec) return 1; + if((LttvTime *)a->tv_nsec < (LttvTime *)b->tv_nsec) return -1; + return 0; +} + + +gboolean get_first(gpointer key, gpointer value, gpointer user_data) { + *((LttvTracefileContext **)user_data) = (LttvTracefileContext *)value; + return TRUE; +} + + +void lttv_process_trace(LttvTime start, LttvTime end, LttvTraceset *traceset, + LttvTracesetContext *context) +{ + GPtrArray *traces = g_ptr_array_new(); + + GPtrArray *tracefiles = g_ptr_array_new(); + + GTree *pqueue = g_tree_new(compare_tracefile); + + guint i, j, nbi, nbj, id; + + LttTrace *trace; + + LttvTraceContext *tc; + + LttTracefile *tracefile; + + LttvTracefileContext *tfc; + + LttEvent *event; + + /* Call all before_traceset, before_trace, and before_tracefile hooks. + For all qualifying tracefiles, seek to the start time, create a context, + read one event and insert in the pqueue based on the event time. */ + + lttv_hooks_call(context->before, context); + nbi = ltt_trace_set_number(traceset); + + for(i = 0 ; i < nbi ; i++) { + tc = context->traces[i]; + trace = tc->t; + + if(!lttv_hooks_call_check(tc->check, tc)) { + g_ptr_array_add(traces, tc); + lttv_hooks_call(tc->before, tc); + nb_control = ltt_trace_control_tracefile_number(trace); + nb_cpu = ltt_trace_per_cpu_tracefile_number(trace); + nbj = nb_control + nb_cpu; + + for(j = 0 ; j < nbj ; j++) { + if(j < nb_control) { + tfc = tc->control_tracefiles[j]; + } + else { + tfc = tc->per_cpu_tracefiles[j - nb_control]; + } + + tracefile = tfc->tf; + + if(!lttv_hooks_call_check(tfc->check, tfc)) { + g_ptr_array_add(tracefiles, tfc); + lttv_hooks_call(tfc->before, tfc); + + ltt_tracefile_seek_time(tracefile, start); + event = ltt_tracefile_read(tracefile); + tfc->e = event; + + if(event != NULL) { + tfc->time = ltt_event_time(event); + g_tree_insert(pqueue, &(tfc->time), tfc); + } + } + } + } + } + + /* Get the next event from the pqueue, call its hooks, + reinsert in the pqueue the following event from the same tracefile + unless the tracefile is finished or the event is later than the + start time. */ + + while() { + tfc = NULL; + g_tree_foreach(pqueue, get_first, &tfc); + if(tfc == NULL) break; + + /* Get the tracefile with an event for the smallest time found. If two + or more tracefiles have events for the same time, hope that lookup + and remove are consistent. */ + + tfc = g_tree_lookup(pqueue, &(tfc->time)); + g_tree_remove(pqueue, &(tfc->time)); + + if(!lttv_hooks_call(tfc->check_event, context)) { + id = lttv_event_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(lttv_hooks_by_id_get(tfc->after_event_by_id, id), tfc); + } + + event = ltt_tracefile_read(tfc->tf); + if(event != NULL) { + tfc->e = event; + tfc->time = ltt_event_time(event); + g_tree_insert(pqueue, &(tfc->time), tfc); + } + } + + /* Call all the after_tracefile, after_trace and after_traceset hooks. */ + + for(i = 0, j = 0 ; i < traces->len ; i++) { + tc = traces->pdata[i]; + while(j < tracefiles->len) { + tfc = tracefiles->pdata[j]; + + if(tfc->t_context == tc) { + lttv_hooks_call(tfc->after, tfc); + j++; + } + else break; + } + lttv_hooks_call(tc->after, tc); + } + + g_assert(j == tracefiles->len); + lttv_hooks_call(after_traceset, context); + + /* Free the traces, tracefiles and pqueue */ + + g_ptr_array_free(tracefiles, TRUE); + g_ptr_array_free(traces, TRUE); + g_tree_destroy(pqueue, TRUE); +} diff --git a/ltt/branches/poly/lttv/state.c b/ltt/branches/poly/lttv/state.c new file mode 100644 index 00000000..808bced7 --- /dev/null +++ b/ltt/branches/poly/lttv/state.c @@ -0,0 +1,624 @@ + +#include + + +static void +init(LttvTracesetState *self, LttvTraceset *ts) +{ + guint i, j, nb_trace, nb_tracefile; + + LttvTraceState *tc; + + LttvTracefileState *tfc; + + LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek_parent(LTTV_TRACESET_STATE_TYPE))->init(self, ts); + + nb_trace = lttv_traceset_number(ts); + for(i = 0 ; i < nb_trace ; i++) { + tc = (LttvTraceState *)self->traces[i]; + tc->processes = g_hash_table_new(g_direct_hash, g_direct_equal); + + nb_tracefile = ltt_trace_control_tracefile_number(tc->t); + for(j = 0 ; j < nb_tracefile ; j++) { + tfc = tc->control_tracefiles[j]; + tfc->process = NULL; + } + + nb_tracefile = ltt_trace_per_cpu_tracefile_number(tc->t); + for(j = 0 ; j < nb_tracefile ; j++) { + tfc = tc->per_cpu_tracefiles[j]; + tfc->process = NULL; + } + } +} + + +static void +fini(LttvTracesetState *self) +{ + guint i, j, nb_trace, nb_tracefile; + + LttvTraceState *tc; + + LttvTracefileState *tfc; + + nb_trace = lttv_traceset_number(ts); + for(i = 0 ; i < nb_trace ; i++) { + tc = (LttvTraceState *)self->traces[i]; + remove_all_processes(tc->processes); + g_hash_table_destroy(tc->processes); + } + LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek_parent(LTTV_TRACESET_STATE_TYPE))->fini(self); +} + + +LttvTracesetContext * +new_traceset_context(LttvTracesetContext *self) +{ + return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE)); +} + + +LttvTraceContext * +new_trace_context(LttvTracesetContext *self) +{ + return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE)); +} + + +LttvTracefileContext * +new_tracefile_context(LttvTracesetContext *self) +{ + return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE)); +} + + +GType +lttv_traceset_state_get_type(void) +{ + static GType type = 0; + if (type == 0) { + static const GTypeInfo info = { + sizeof (LttvTracesetStateClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + traceset_state_class_init, /* class_init */ + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (LttvTracesetContext), + 0, /* n_preallocs */ + traceset_state_instance_init /* instance_init */ + }; + + type = g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE, "LttvTracesetStateType", + &info, 0); + } + return type; +} + + +static void +traceset_state_instance_init (GTypeInstance *instance, gpointer g_class) +{ +} + + +static void +traceset_context_finalize (LttvTracesetContext *self) +{ + G_OBJECT_CLASS(g_type_class_peek_parent(LTTV_TRACESET_STATE_TYPE))->finalize(self); +} + + +static void +traceset_state_class_init (LttvTracesetContextClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS(klass); + + gobject_class->finalize = traceset_state_finalize; + klass->init = init; + klass->fini = fini; + klass->new_traceset_context = new_traceset_context; + klass->new_trace_context = new_trace_context; + klass->new_tracefile_context = new_tracefile_context; +} + + +GType +lttv_trace_state_get_type(void) +{ + static GType type = 0; + if (type == 0) { + static const GTypeInfo info = { + sizeof (LttvTraceStateClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + trace_state_class_init, /* class_init */ + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (LttvTracesetState), + 0, /* n_preallocs */ + trace_state_instance_init /* instance_init */ + }; + + type = g_type_register_static (LTTV_TRACE_CONTEXT_TYPE, + "LttvTraceStateType", &info, 0); + } + return type; +} + + +static void +trace_state_instance_init (GTypeInstance *instance, gpointer g_class) +{ +} + + +static void +trace_state_finalize (LttvTraceContext *self) +{ + G_OBJECT_CLASS(g_type_class_peek_parent(LTTV_TRACE_STATE_TYPE))->finalize(self); +} + + +static void +trace_state_class_init (LttvTraceContextClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS(klass); + + gobject_class->finalize = trace_state_finalize; +} + + +GType +lttv_tracefile_state_get_type(void) +{ + static GType type = 0; + if (type == 0) { + static const GTypeInfo info = { + sizeof (LttvTracefileStateClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + tracefile_state_class_init, /* class_init */ + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (LttvTracefileState), + 0, /* n_preallocs */ + tracefile_state_instance_init /* instance_init */ + }; + + type = g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE, + "LttvTracefileStateType", &info, 0); + } + return type; +} + + +static void +tracefile_state_instance_init (GTypeInstance *instance, gpointer g_class) +{ +} + + +static void +tracefile_state_finalize (LttvTracefileState *self) +{ + G_OBJECT_CLASS(g_type_class_peek_parent(LTTV_TRACEFILE_STATE_TYPE))->finalize(self); +} + + +static void +tracefile_state_class_init (LttvTracefileStateClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS(klass); + + gobject_class->finalize = tracefile_state_finalize; +} + + +struct HookData { + LttField *f1; + LttField *f2; + LttField *f3; +} + + +struct HookId { + LttvHook h; + guint id; + void *hook_data; + gboolean free_hook_data; +} + + +void push_state(LttvTracefileState *tfs, LttvInterruptType t, guint state_id) +{ + LttvInterruptState intr; + + LttvProcessState *process = tfs->process; + + guint depth = process->interrupt_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 = tfs->time; + intr->last_change = tfs->time; + intr->s = process->state->s; +} + + +void pop_state(LttvTracefileState *tfs, LttvInterruptType t) +{ + LttvProcessState *process = tfs->process; + + guint depth = process->interrupt_stack->len - 1; + + g_assert(process->state->t == t); + g_array_remove_index(process->interrupt_stack, depth); + depth--; + process->state = &g_array_index(process->interrupt_stack, LttvInterruptState, + depth); +} + + +LttvProcessState *create_process(LttvTraceState *tfs, LttvProcessState *parent, + guint pid) +{ + LttvProcessState *process = g_new(LttvProcessState, 1); + + LttvInterruptState *intr; + + g_hash_table_insert(tfs->ts->processes, pid, process); + process->pid = pid; + process->birth = tfs->time; + 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 = process->interrupt_stack->data; + intr->t = LTTV_STATE_USER_MODE + intr->n = 0; + intr->entry = tfs->time; + intr->last_change = tfs->time; + intr->s = LTTV_STATE_WAIT_FORK; +} + + +LttvProcessState *find_process(LttvTraceState *tfs, guint pid) +{ + LttvProcessState *process = g_hash_table_lookup(tfs->processes, pid); + if(process == NULL) process = create_process(tfs, NULL, pid); + return process; +} + + +void exit_process(LttvTraceState *ts, LttvProcessState *process) +{ + g_hash_table_remove(tfs-ts->processes, process->pid); + g_array_free(process->interrupt_stack, TRUE); + g_free(process); +} + + +void free_process_state(gpointer key, gpointer value, gpointer user_data) +{ + g_array_free(((LttvProcessState *)value)->interrupt_stack, TRUE); + g_free(value); +} + + +void remove_all_processes(GHashTable *processes) +{ + g_hash_table_foreach(processes, free_process_state, NULL); +} + + +gboolean syscall_entry(void *hook_data, void *call_data) +{ + LttField *f = (LttField *)hook_data; + + struct LttvTracefileState *s = (LttvTraceFileState *)call_data; + + push_state(s, STATE_SYSCALL, ltt_event_get_unsigned(s->e, f)); + return FALSE; +} + + +gboolean syscall_exit(void *hook_data, void *call_data) +{ + struct LttvTracefileState *s = (LttvTraceFileState *)call_data; + + pop_state(s, STATE_SYSCALL); + return FALSE; +} + + +gboolean trap_entry(void *hook_data, void *call_data) +{ + LttField *f = (LttField *)hook_data; + + struct LttvTracefileState *s = (LttvTraceFileState *)call_data; + + push_state(s, STATE_TRAP, ltt_event_get_unsigned(s->e, f)); + return FALSE; +} + + +gboolean trap_exit(void *hook_data, void *call_data) +{ + struct LttvTracefileState *s = (LttvTraceFileState *)call_data; + + pop_state(s, STATE_TRAP); + return FALSE; +} + + +gboolean irq_entry(void *hook_data, void *call_data) +{ + LttField *f = (LttField *)hook_data; + + struct LttvTracefileState *s = (LttvTraceFileState *)call_data; + + /* Do something with the info about being in user or system mode when int? */ + push_state(s, STATE_IRQ, ltt_event_get_unsigned(s->e, f)); + return FALSE; +} + + +gboolean irq_exit(void *hook_data, void *call_data) +{ + struct LttvTracefileState *s = (LttvTraceFileState *)call_data; + + pop_state(s, STATE_IRQ); + return FALSE; +} + + +gboolean schedchange(void *hook_data, void *call_data) +{ + struct HookData *h = (struct HookData *)hook_data; + + struct LttvTracefileState *s = (LttvTraceFileState *)call_data; + + guint pid_in, pid_out, state_out; + + pid_in = ltt_event_get_int(s->e, h->f1); + pid_out = ltt_event_get_int(s->e, h->f2); + state_out = ltt_event_get_int(s->e, h->f3); + if(s->process != NULL) { + if(state_out == 0) s->process->state->s = STATE_WAIT_CPU; + else if(s->process->state->s == STATE_EXIT) + exit_process(s->tc, s->process); + else s->process->state->s = STATE_WAIT; + } + s->process = find_process(s->tc, pid_in); + s->process->state->s = STATE_RUN; + return FALSE; +} + + +gboolean process_fork(void *hook_data, void *call_data) +{ + LttField *f = (LttField *)hook_data; + + struct LttvTracefileState *s = (LttvTraceFileState *)call_data; + + guint child_pid; + + child_pid = ltt_event_get_int(s->e, f); + create_process(s->tc, s->process, child_pid); + return FALSE; +} + + +gboolean process_exit(void *hook_data, void *call_data) +{ + struct LttvTracefileState *s = (LttvTraceFileState *)call_data; + + if(s->process != NULL) { + s->process->state->s = STATE_EXIT; + } + return FALSE; +} + + +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 HookId +find_hook(LttTrace *t, const char *facility, const char *event, + const char *field1, *field2, *field3, LttHook 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_facility_get(t, pos); + et = ltt_facility_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 *ts = self->ts; + + guint i, j, nb_trace, nb_control, nb_per_cpu, nb_tracefile; + + LttFacility *f; + + LttEventType *et; + + LttvTraceState *tc; + + LttvTracefileState *tfc; + + void *hook_data; + + GArray *hooks; + + struct HookId hook_id; + + LttvAttributeValue val; + + nb_trace = lttv_traceset_number(ts); + for(i = 0 ; i < nb_trace ; i++) { + tc = (LttvTraceState *)self->traces[i]; + + /* Find the eventtype id for the following events and register the + associated by id hooks. */ + + hooks = g_array_new(FALSE, FALSE, struct HookId); + g_array_add(hooks, find_hook(tc->t, "core","syscall_entry", "syscall_id", + NULL, NULL, syscall_entry)); + g_array_add(hooks, find_hook(tc->t, "core", "syscall_exit", NULL, NULL, + NULL, syscall_exit)); + g_array_add(hooks, find_hook(tc->t, "core", "trap_entry", "trap_id", + NULL, trap_entry)); + g_array_add(hooks, find_hook(tc->t, "core", "trap_exit", NULL, NULL, + NULL, trap_exit)); + g_array_add(hooks, find_hook(tc->t, "core", "irq_entry", "irq_id", + NULL, irq_entry)); + g_array_add(hooks, find_hook(tc->t, "core", "irq_exit", NULL, NULL, + NULL, irq_exit)); + g_array_add(hooks, find_hook(tc->t, "core", "schedchange", "in", "out", + "out_state", schedchange)); + g_array_add(hooks, find_hook(tc->t, "core", "process_fork", "child_pid", + NULL, NULL, process_fork)); + g_array_add(hooks, find_hook(tc->t, "core", "process_exit", NULL, NULL, + NULL, process_exit)); + + /* Add these hooks to each before_event_by_id hooks list */ + + nb_control = ltt_trace_control_tracefile_number(tc->t); + nb_per_cpu = ltt_trace_control_tracefile_number(tc->t); + nb_tracefile = nb_control + nb_per_cpu; + for(j = 0 ; j < nb_tracefile ; j++) { + if(j < nb_control) { + tfc = tc->control_tracefiles[j]; + } + else { + tfc = tc->per_cpu_tracefiles[j]; + } + + for(k = 0 ; k < hooks->len ; k++) { + hook_id = g_array_index(hooks, struct HookId, k); + lttv_hooks_add(lttv_hooks_by_id_find(tfc->before_event_by_id, + hook_id->id), hook_id->h, hook_id->hook_data); + } + lttv_attribute_find(self->a, STATE_HOOKS, LTTV_POINTER, val); + val->v_pointer = hooks; + } +} + + +lttv_state_remove_event_hooks(LttvTracesetState *self) +{ + LttvTraceset *ts = self->ts; + + guint i, j, nb_trace, nb_control, nb_per_cpu, nb_tracefile; + + LttvTraceState *tc; + + LttvTracefileState *tfc; + + void *hook_data; + + GArray *hooks; + + struct HookId hook_id; + + LttvAttributeValue val; + + nb_trace = lttv_traceset_number(ts); + for(i = 0 ; i < nb_trace ; i++) { + tc = (LttvTraceState *)self->traces[i]; + lttv_attribute_find(self->a, STATE_HOOKS, LTTV_POINTER, val); + hooks = val->v_pointer; + + /* Add these hooks to each before_event_by_id hooks list */ + + nb_control = ltt_trace_control_tracefile_number(tc->t); + nb_per_cpu = ltt_trace_control_tracefile_number(tc->t); + nb_tracefile = nb_control + nb_per_cpu; + for(j = 0 ; j < nb_tracefile ; j++) { + if(j < nb_control) { + tfc = tc->control_tracefiles[j]; + } + else { + tfc = tc->per_cpu_tracefiles[j]; + } + + for(k = 0 ; k < hooks->len ; k++) { + hook_id = g_array_index(hooks, struct HookId, k); + lttv_hooks_remove_data(lttv_hooks_by_id_find(tfc->before_event_by_id, + hook_id->id), hook_id->h, hook_id->hook_data); + } + 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); + } +} + + + + + + + + + + diff --git a/ltt/branches/poly/lttv/textDump.c b/ltt/branches/poly/lttv/textDump.c index 3a72927c..189f9202 100644 --- a/ltt/branches/poly/lttv/textDump.c +++ b/ltt/branches/poly/lttv/textDump.c @@ -2,287 +2,166 @@ before each trace, to print each event, and to print statistics after each trace. */ -#include -#include -#include +static gboolean + a_field_names, + a_state; + +static char + *a_file_name; + +static LttvHooks + *before_traceset, + *after_traceset, + *before_trace, + *before_event; + 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, textDump_trace_set_before, NULL); - lttv_hooks_add(after, textDump_trace_set_after, NULL); + LttvAttribute_value *value; + + LttvIAttributes *attributes = LTTV_IATTRIBUTES(lttv_global_attributes()); + + a_file_name = NULL; + lttv_option_add("output", 'o', + "output file where the text is written", + "file name", + LTTV_OPT_STRING, &a_file_name, NULL, NULL); + + a_field_names = FALSE; + lttv_option_add("field_names", 'l', + "write the field names for each event", + "", + LTTV_OPT_NONE, &a_field_names, NULL, NULL); + + a_state = FALSE; + lttv_option_add("process_state", 's', + "write the pid and state for each event", + "", + LTTV_OPT_NONE, &a_state, NULL, NULL); + + g_assert(lttv_iattribute_find_by_path(attributes, "hooks/event/before", + LTTV_POINTER, &value)); + g_assert((before_event = *(value->v_pointer)) != NULL); + lttv_hooks_add(before_event, write_event_content, NULL); + + g_assert(lttv_iattribute_find_by_path(attributes, "hooks/trace/before", + LTTV_POINTER, &value)); + g_assert((before_trace = *(value->v_pointer)) != NULL); + lttv_hooks_add(before_trace, write_trace_header, NULL); + + g_assert(lttv_iattribute_find_by_path(attributes, "hooks/traceset/before", + LTTV_POINTER, &value)); + g_assert((before_traceset = *(value->v_pointer)) != NULL); + lttv_hooks_add(before_traceset, write_traceset_header, NULL); + + g_assert(lttv_iattribute_find_by_path(attributes, "hooks/traceset/after", + LTTV_POINTER, &value)); + g_assert((after_traceset = *(value->v_pointer)) != NULL); + lttv_hooks_add(after_traceset, write_traceset_footer, 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, textDump_trace_set_before, NULL); - lttv_hooks_remove(after, textDump_trace_set_after, NULL); -} + lttv_option_remove("output"); -/* Insert the hooks before and after each trace and tracefile, and for each - event. Print a global header. */ + lttv_option_remove("field_names"); -typedef struct _trace_context { - g_string s; - FILE *fp; - bool mandatory_fields; - lttv_attributes *a; -} trace_context; + lttv_option_remove("process_state"); -static bool textDump_trace_set_before(void *hook_data, void *call_data) -{ - FILE *fp; - int i, j, nb, nbtf; - lttv_trace_set *s; - lttv_attributes *a; - trace_context *c; - - a = lttv_global_attributes(); - s = (lttv_trace_set *)call_data - - /* Get the file pointer */ - - fp = (FILE *)lttv_attributes_get_pointer_pathname(a, "textDump/file"); - - /* 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, "textDump/context") != NULL) { - g_error("Recursive call to TextDump"); - } - - c->fp = fp; - c->mandatory_fields = TRUE; - c->s = g_string_new(); - c->a = a; - - lttv_attributes_set_pointer_pathname(a, "textDump/context", c); - - h = lttv_attributes_get_hooks(a, "hooks/before"); - lttv_hooks_add(h, textDump_trace_before, c); - h = lttv_attributes_get_hooks(a, "hooks/after"); - lttv_hooks_add(h, textDump_trace_after, c); - h = lttv_attributes_get_hooks(a, "hooks/tacefile/before"); - lttv_hooks_add(h, textDump_tracefile_before, c); - h = lttv_attributes_get_hooks(a, "hooks/tracefile/after"); - lttv_hooks_add(h, textDump_tracefile_after, c); - h = lttv_attributes_get_hooks(a, "hooks/event/selected"); - lttv_hooks_add(h, textDump_event, c); - } + lttv_hooks_remove(before_event, write_event, NULL); - /* Print the trace set header */ - fprintf(fp,"Trace set contains %d traces\n\n", nb); + lttv_hooks_remove(before_trace, write_trace_header, NULL); + + lttv_hooks_remove(before_trace, write_traceset_header, NULL); - return TRUE; + lttv_hooks_remove(before_trace, write_traceset_footer, NULL); } -/* Remove the hooks before and after each trace and tracefile, and for each - event. Print trace set level statistics. */ +/* Insert the hooks before and after each trace and tracefile, and for each + event. Print a global header. */ + +static FILE *a_file; -static bool textDump_trace_set_after(void *hook_data, void *call_data) +static GString *a_string; + +static static gboolean write_traceset_header(void *hook_data, void *call_data) { - FILE *fp; - int i, j, nb, nbtf; - lttv_trace_set *s; - lttv_attributes *ga, *a; - trace_context *c; - - ga = lttv_global_attributes(); - s = (lttv_trace_set *)lttv_attributes_get_pointer_pathname(ga, - "trace_set/main"); - - /* 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); - g_string_free(c->s); - - h = lttv_attributes_get_hooks(a, "hooks/before"); - lttv_hooks_remove(h, textDump_trace_before, c); - h = lttv_attributes_get_hooks(a, "hooks/after"); - lttv_hooks_remove(h, textDump_trace_after, c); - h = lttv_attributes_get_hooks(a, "hooks/tacefile/before"); - lttv_hooks_remove(h, textDump_tracefile_before, c); - h = lttv_attributes_get_hooks(a, "hooks/tracefile/after"); - lttv_hooks_remove(h, textDump_tracefile_after, c); - h = lttv_attributes_get_hooks(a, "hooks/event/selected"); - lttv_hooks_remove(h, textDump_event, c); - g_free(c); - } + LttvTracesetContext *tc = (LttvTracesetContext *)call_data; - /* Print the trace set statistics */ + if(a_file_name == NULL) a_file = stdout; + else a_file = fopen(a_file_name, "w"); - fprintf(fp,"Trace set contains %d traces\n\n", nb); + if(a_file == NULL) g_error("cannot open file %s", a_file_name); - print_stats(fp, ga); + /* Print the trace set header */ + fprintf(a_file,"Trace set contains %d traces\n\n", + lttv_traceset_number(tc->ta); - return TRUE; + return FALSE; } -/* Print a trace level header */ - -static bool textDump_trace_before(void *hook_data, void *call_data) +static static gboolean write_traceset_footer(void *hook_data, void *call_data) { - ltt_trace *t; - trace_context *c; - - c = (trace_context *)hook_data; - t = (ltt_trace *)call_data; - fprintf(c->fp,"Start trace\n"); - return TRUE; -} + LttvTracesetContext *tc = (LttvTracesetContext *)call_data; + if(a_file_name != NULL) a_file = fclose(a_file); -/* Print trace level statistics */ + fprintf(a_file,"End trace set\n\n"); -static bool textDump_trace_after(void *hook_data, void *call_data) -{ - ltt_trace *t; - trace_context *c; - - c = (trace_context *)hook_data; - t = (ltt_trace *)call_data; - fprintf(c->fp,"End trace\n"); - print_stats(c->fp,c->a); - return TRUE; + return FALSE; } -static bool textDump_tracefile_before(void *hook_data, void *call_data) +static gboolean write_trace_header(void *hook_data, void *call_data) { - ltt_tracefile *tf; - trace_context *c; + LttvTraceContext *tc = (LttvTraceContext *)call_data; + + LttSystemDescription *system = ltt_trace_system_description(tc->t); - c = (trace_context *)hook_data; - tf = (ltt_tracefile *)call_data; - fprintf(c->fp,"Start tracefile\n"); - return TRUE; + fprintf(a_file," Trace from %s in %s\n%s\n\n", system->node_name, + system->domain_name, system->description); + return FALSE; } -static bool textDump_tracefile_after(void *hook_data, void *call_data) +static int write_event_content(void *hook_data, void *call_data) { - ltt_tracefile *tf; - trace_context *c; + LttvTracefileContext *tfc = (LttvTracefileContext *)call_data; - c = (trace_context *)hook_data; - tf = (ltt_tracefile *)call_data; - fprintf(c->fp,"End tracefile\n"); - return TRUE; -} + LttvTracefileState *tfs = (LttvTracefileState *)call_data; + LttEvent *e; -/* Print the event content */ + e = tfc->e; -static bool textDump_event(void *hook_data, void *call_data) -{ - ltt_event *e; - trace_context *c; + lttv_event_to_string(e, tfc->tf, a_string, TRUE, a_field_names); + + if(a_state) { + g_string_append_printf(a_string, " %s", + g_quark_to_string(tfs->process->state->s); + } - e = (ltt_event *)call_data; - c = (event_context *)hook_data; - lttv_event_to_string(e,c->s,c->mandatory_fields); fputs(s, c->fd); - return TRUE; + return FALSE; } -static void print_stats(FILE *fp, lttv_attributes *a) +void lttv_event_to_string(LttEvent *e, LttTracefile *tf, g_string *s, + gboolean mandatory_fields, gboolean field_names) { - int i, j, k, nb, nbc; - - lttv_attributes *sa, *ra; - lttv_attribute *reports, *content; - lttv_key *key, *previous_key, null_key; - - null_key = lttv_key_new_pathname(""); - sa = (lttv_attributes *)lttv_attributes_get_pointer_pathname(a,"stats"); - reports = lttv_attributes_array_get(sa); - nb= lttv_attributes_number(sa); - - for(i = 0 ; i < nb ; i++) { - ra = (lttv_attributes *)reports[i].v.p; - key = reports[i].key; - g_assert(reports[i].t == LTTV_POINTER); - - /* CHECK maybe have custom handlers registered for some specific reports */ - - print_key(fp,key); - - content = lttv_attributes_array_get(ra); - nbc = lttv_attributes_number(ra); - lttv_attribute_array_sort_lexicographic(content, nbc, NULL, 0); - previous_key = nullKey; - for(j = 0 ; j < nbc ; j++) { - key = content[j].key; - for(k = 0 ; lttv_key_index(previous_key,k) == lttv_index(key,k) ; k++) - for(; k < lttv_key_number(key) ; k++) { - for(l = 0 ; l < k ; l++) fprintf(fp," "); - fprintf(fp, "%s", lttv_string_id_to_string(lttv_index(key,k))); - if(k == lttv_key_number(key)) { - switch(content[j].t) { - case LTTV_INTEGER: - fprintf(fp," %d\n", content[j].v.i); - break; - case LTTV_TIME: - fprintf(fp," %d.%09d\n", content[j].v.t.tv_sec, - content[j].v.t.tv_nsec); - break; - case LTTV_DOUBLE: - fprintf(fp," %g\n", content[j].v.d); - break; - case LTTV_POINTER: - fprintf(fp," pointer\n"); - break; - } - } - else fprintf(fp,"\n"); - } - } - lttv_attribute_array_destroy(content); - } - lttv_attribute_array_destroy(reports); - lttv_key_destroy(null_key); -} + LttFacility *facility; + LttEventType *event_type; -void lttv_event_to_string(ltt_event *e, lttv_string *s, bool mandatory_fields) -{ - ltt_facility *facility; - ltt_eventtype *eventtype; - ltt_type *type; - ltt_field *field; - ltt_time time; + LttType *type; + + LttField *field; + + LttTime time; g_string_set_size(s,0); @@ -292,16 +171,22 @@ void lttv_event_to_string(ltt_event *e, lttv_string *s, bool mandatory_fields) if(mandatory_fields) { time = ltt_event_time(e); - g_string_append_printf(s,"%s.%s: %ld.%ld",ltt_facility_name(facility), - ltt_eventtype_name(eventtype), (long)time.tv_sec, time.tv_nsec); + g_string_append_printf(s,"%s.%s: %ld.%ld (%s)",ltt_facility_name(facility), + ltt_eventtype_name(eventtype), (long)time.tv_sec, time.tv_nsec, + ltt_tracefile_name(tf)); } - print_field(e,f,s); + print_field(e,f,s, field_names); } -void print_field(ltt_event *e, ltt_field *f, lttv_string *s) { - ltt_type *type; - ltt_field *element; + +void print_field(LttEvent *e, LttField *f, g_string *s, gboolean field_names) { + + LttType *type; + + LttField *element; + + char *name; int nb, i; @@ -345,6 +230,10 @@ void print_field(ltt_event *e, ltt_field *f, lttv_string *s) { nb = ltt_type_member_number(type); for(i = 0 ; i < nb ; i++) { element = ltt_field_member(f,i); + if(name) { + ltt_type_member_type(type, &name); + g_string_append_printf(s, " %s = ", field_names); + } print_field(e,element,s); } g_string_append_printf(s, " }"); diff --git a/ltt/branches/poly/lttv/traceSet.c b/ltt/branches/poly/lttv/traceSet.c deleted file mode 100644 index b889a893..00000000 --- a/ltt/branches/poly/lttv/traceSet.c +++ /dev/null @@ -1,178 +0,0 @@ -/* A trace is a sequence of events gathered in the same tracing session. The - events may be stored in several tracefiles in the same directory. - A trace set is defined when several traces are to be analyzed together, - possibly to study the interactions between events in the different traces. -*/ - -struct _lttv_trace_set { - GPtrArray *traces; - GPtrArray *attributes; - lttv_attributes *a; -}; - - -lttv_trace_set *lttv_trace_set_new() -{ - lttv_trace_set s; - - s = g_new(lttv_trace_set, 1); - s->traces = g_ptr_array_new(); - s->attributes = g_ptr_array_new(); - s->a = lttv_attributes_new(); -} - -lttv_trace_set *lttv_trace_set_destroy(lttv_trace_set *s) -{ - int i, nb; - - for(i = 0 ; i < s->attributes->len ; i++) { - lttv_attributes_destroy((lttv_attributes *)s->attributes->pdata[i]); - } - g_ptr_array_free(s->attributes); - g_ptr_array_free(s->traces); - lttv_attributes_destroy(s->a); - return g_free(s); -} - -void lttv_trace_set_add(lttv_trace_set *s, lttv_trace *t) -{ - g_ptr_array_add(s,t); - g_ptr_array_add(s,lttv_attributes_new()); -} - -unsigned lttv_trace_set_number(lttv_trace_set *s) -{ - return s->traces.len; -} - - -lttv_trace *lttv_trace_set_get(lttv_trace_set *s, unsigned i) -{ - g_assert(s->traces->len <= i); - return s->traces.pdata[i]; -} - - -lttv_trace *lttv_trace_set_remove(lttv_trace_set *s, unsigned i) -{ - return g_ptr_array_remove_index(s->traces,i); - lttv_attributes_destroy(g_ptr_array_remove_index(s->attributes,i)); -} - - -/* A set of attributes is attached to each trace set, trace and tracefile - to store user defined data as needed. */ - -lttv_attributes *lttv_trace_set_attributes(lttv_trace_set *s) -{ - return s->a; -} - -lttv_attributes *lttv_trace_set_trace_attributes(lttv_trace_set *s, unsigned i) -{ - return t->a; -} - -lttv_attributes *lttv_tracefile_attributes(lttv_tracefile *tf) { - return (lttv_attributes *)s->attributes->pdata[i]; -} - - -static void lttv_analyse_trace(lttv_trace *t); - -static void lttv_analyse_tracefile(lttv_tracefile *t); - -lttv_trace_set_process(lttv_trace_set *s, ltt_time start, ltt_time end) -{ - int i, nb; - lttv_hooks *before, *after; - lttv_attributes *a; - ltt_trace *t; - lttv_filter *filter_data; - - a = lttv_trace_set_attributes(s); - before = (lttv_hooks*)lttv_attributes_get_pointer_pathname(a,"hooks/before"); - after = (lttv_hooks*)lttv_attributes_get_pointer_pathname(a,"hooks/after"); - nb = lttv_trace_set_number(s); - - lttv_hooks_call(before, s); - - for(i = 0; i < nb; i++) { - t = lttv_trace_set_get(s,i); - a = lttv_trace_set_trace_attributes(s,i); - lttv_analyse_trace(t, a, start, end); - } - - lttv_hooks_call(after, s); -} - - -static void lttv_analyse_trace(ltt_trace *t, lttv_attributes *a, - ltt_time start, ltt_time end) -{ - int i, nb_all_cpu, nb_per_cpu; - lttv_hooks *before, *after; - - before = (lttv_hooks*)lttv_attributes_get_pointer_pathname(a,"hooks/before"); - after = (lttv_hooks*)lttv_attributes_get_pointer_pathname(a,"hooks/after"); - - nb_all_cpu = ltt_trace_tracefile_number_all_cpu(t); - nb_per_cpu = ltt_trace_tracefile_number_per_cpu(t); - - lttv_hooks_call(before, t); - - for(i = 0; i < nb_all_cpu; i++) { - lttv_analyse_tracefile(ltt_trace_get_all_cpu(t,i), a, start, end); - } - - for(i = 0; i < nb_per_cpu; i++) { - lttv_analyse_tracefile(ltt_trace_get_per_cpu(t,i), a, start, end); - } - - lttv_hooks_call(after, t); -} - - -static void lttv_analyse_tracefile(ltt_tracefile *t, lttv_attributes *a, - ltt_time start, ltt_time end) -{ - ltt_event *event; - unsigned id; - lttv_hooks *before, *after, *event_hooks, *tracefile_check, *event_check; - lttv_hooks_by_id *event_hooks_by_id; - lttv_attributes *a; - - before = (lttv_hooks *)lttv_attributes_get_pointer_pathname(a, - "hooks/tracefile/before"); - after = (lttv_hooks *)lttv_attributes_get_pointer_pathname(a, - "hooks/tracefile/after"); - event_hooks = (lttv_hooks*)lttv_attributes_get_pointer_pathname(a, - "hooks/event/selected"); - event_hooks_by_id = (lttv_hooks_by_id*) - lttv_attributes_get_pointer_pathname(a, "hooks/event/byid"); - tracefile_check = (lttv_hooks *)lttv_attributes_get_pointer_pathname(a, - "hooks/tracefile/check"); - event_check = (lttv_hooks *)lttv_attributes_get_pointer_pathname(a, - "hooks/event/check"); - - lttv_hooks_call(before, t); - - if(lttv_hooks_call_check(tracefile_check,t) && - ( lttv_hooks_number(event_hooks) != 0 || - lttv_hooks_by_id_number(event_hooks_by_id) != 0) { - - ltt_tracefile_seek_time(t, start); - while((event = ltt_tracefile_read(t)) != NULL && - ltt_event_time(event) < end) { - if(lttv_hooks_call_check(event_check)) { - lttv_hooks_call(event_hooks,event); - lttv_hooks_by_id_call(event_hooks_by_id,event, - ltt_event_type_id(event)); - } - } - } - lttv_hooks_call(after, t); -} - - - diff --git a/ltt/branches/poly/lttv/traceset.c b/ltt/branches/poly/lttv/traceset.c new file mode 100644 index 00000000..ab04a4ee --- /dev/null +++ b/ltt/branches/poly/lttv/traceset.c @@ -0,0 +1,83 @@ + +#include + +/* A trace is a sequence of events gathered in the same tracing session. The + events may be stored in several tracefiles in the same directory. + A trace set is defined when several traces are to be analyzed together, + possibly to study the interactions between events in the different traces. +*/ + +struct _LttvTraceset { + GPtrArray *traces; + GPtrArray *attributes; + LttvAttribute *a; +}; + + +LttvTraceset *lttv_trace_set_new() +{ + LttvTraceset s; + + s = g_new(LttvTraceset, 1); + s->traces = g_ptr_array_new(); + s->attributes = g_ptr_array_new(); + s->a = g_object_new(LTTV_ATTRIBUTE_TYPE); +} + + +LttvTraceset *lttv_traceset_destroy(LttvTraceset *s) +{ + int i, nb; + + for(i = 0 ; i < s->attributes->len ; i++) { + lttv_attribute_free((lttv_attributes *)s->attributes->pdata[i]); + } + g_ptr_array_free(s->attributes); + g_ptr_array_free(s->traces); + lttv_attribute_free(s->a); + return g_free(s); +} + + +void lttv_traceset_add(LttvTraceset *s, LttTrace *t) +{ + g_ptr_array_add(s->traces, t); + g_ptr_array_add(s->attributes, g_object_new(LTTV_ATTRIBUTE_TYPE)); +} + + +unsigned lttv_traceset_number(LttvTraceset *s) +{ + return s->traces.len; +} + + +LttTrace *lttv_traceset_get(LttvTraceset *s, unsigned i) +{ + g_assert(s->traces->len > i); + return ((LttTrace *)s->traces.pdata[i]); +} + + +LttTrace *lttv_traceset_remove(LttvTraceset *s, unsigned i) +{ + return g_ptr_array_remove_index(s->traces, i); + lttv_attribute_free(g_ptr_array_remove_index(s->attributes,i)); +} + + +/* A set of attributes is attached to each trace set, trace and tracefile + to store user defined data as needed. */ + +LttvAttribute *lttv_traceset_attribute(LttvTraceset *s) +{ + return s->a; +} + + +LttvAttribute *lttv_traceset_trace_attribute(LttvTraceset *s, unsigned i) +{ + return (LttAttribute *)s->attributes->pdata[i]; +} + + -- 2.34.1