From 08b1c66e3a5ad9588d08f9477af98c0cda4f070c Mon Sep 17 00:00:00 2001 From: dagenais Date: Tue, 9 Mar 2004 22:04:49 +0000 Subject: [PATCH] Make modules more flexible (builtin or loaded are identical). Add a test module to verify the state updating/saving functionality and performance. git-svn-id: http://ltt.polymtl.ca/svn@493 04897980-b3bd-0310-b5e0-8ef037075253 --- ltt/branches/poly/include/lttv/lttv.h | 7 +- ltt/branches/poly/include/lttv/mainwindow.h | 8 - ltt/branches/poly/include/lttv/module.h | 197 ++++-- ltt/branches/poly/lttv/main/main.c | 54 +- ltt/branches/poly/lttv/main/module.c | 626 ++++++++++++------ ltt/branches/poly/lttv/main/option.c | 56 +- ltt/branches/poly/lttv/main/state.c | 80 ++- ltt/branches/poly/lttv/main/stats.c | 51 +- .../poly/lttv/modules/examples/sampledep.c | 13 +- .../poly/lttv/modules/examples/samplemodule.c | 11 +- .../lttv/modules/examples/samplemodule2.c | 11 +- .../lttv/modules/gui/controlflow/module.c | 18 +- .../lttv/modules/gui/detailedevents/events.c | 100 ++- .../lttv/modules/gui/main/src/callbacks.c | 45 +- .../lttv/modules/gui/main/src/callbacks.h | 2 +- .../lttv/modules/gui/main/src/init_module.c | 25 +- .../lttv/modules/gui/statistics/statistics.c | 104 ++- .../poly/lttv/modules/text/batchAnalysis.c | 8 +- .../poly/lttv/modules/text/batchtest.c | 569 ++++++++++++++++ .../poly/lttv/modules/text/textDump.c | 11 +- 20 files changed, 1485 insertions(+), 511 deletions(-) create mode 100644 ltt/branches/poly/lttv/modules/text/batchtest.c diff --git a/ltt/branches/poly/include/lttv/lttv.h b/ltt/branches/poly/include/lttv/lttv.h index 4c9477ad..27c610a2 100644 --- a/ltt/branches/poly/include/lttv/lttv.h +++ b/ltt/branches/poly/include/lttv/lttv.h @@ -26,6 +26,11 @@ LttvAttribute *lttv_global_attributes(); +extern gboolean lttv_profile_memory; + +extern int lttv_argc; + +extern char **lttv_argv; /* A number of global attributes are initialized before modules are loaded, for example hooks lists. More global attributes are defined @@ -52,6 +57,4 @@ LttvAttribute *lttv_global_attributes(); #define g_info(format...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, format) #define g_debug(format...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, format) -extern gboolean lttv_profile_memory; - #endif // LTTV_H diff --git a/ltt/branches/poly/include/lttv/mainwindow.h b/ltt/branches/poly/include/lttv/mainwindow.h index db39fd6e..ffdeefe5 100644 --- a/ltt/branches/poly/include/lttv/mainwindow.h +++ b/ltt/branches/poly/include/lttv/mainwindow.h @@ -31,12 +31,6 @@ #include #include -typedef struct _WindowCreationData { - int argc; - char ** argv; -} WindowCreationData; - - typedef struct _TracesetInfo { //FIXME? TracesetContext and stats in same or different variable ? LttvTracesetStats * traceset_context; @@ -69,8 +63,6 @@ struct _MainWindow{ Tab * tab; Tab * current_tab; - WindowCreationData * win_creation_data; - GHashTable * hash_menu_item; GHashTable * hash_toolbar_item; }; diff --git a/ltt/branches/poly/include/lttv/module.h b/ltt/branches/poly/include/lttv/module.h index 39319151..e88b7b92 100644 --- a/ltt/branches/poly/include/lttv/module.h +++ b/ltt/branches/poly/include/lttv/module.h @@ -19,70 +19,189 @@ #ifndef MODULES_H #define MODULES_H -#include +#include -/* 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 - attributes... +/* A module contains some functionality which becomes available atfer it is + initialized and before it is destroyed. A module is characterized by a name, + a description (short and long), a list of names of other modules on which + it depends, and an initialization and a destruction function. - 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. + A library contains one or more modules and may be loaded dynamically. + The modules contained in a library are automatically registered through + constructors which are called when the library is loaded. For modules + directly linked with the main program (builtin), the constructors are + called before the main program starts. (However, neither malloc nor glib + functions are used during the registration process). - 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 an embedded - python interpreter module which needs to know the modules written in - python to load. */ + The library loading path is a set of directories, where requested + libraries and modules are searched for. +*/ typedef struct _LttvModule LttvModule; -typedef void (*LttvModuleInit)(LttvModule *self, int argc, char **argv); +typedef struct _LttvLibrary LttvLibrary; + +typedef void (*LttvModuleInit)(); typedef void (*LttvModuleDestroy)(); +typedef struct _LttvModuleInfo +{ + char *name; + char *short_description; + char *description; + LttvModuleInit init; + LttvModuleDestroy destroy; + LttvLibrary *library; + unsigned require_count; + unsigned use_count; + unsigned prerequisites_number; +} LttvModuleInfo; + + +typedef struct _LttvLibraryInfo +{ + char *name; + char *path; + unsigned load_count; +} LttvLibraryInfo; + + +typedef enum _LttvModuleError +{ + LTTV_MODULE_NOT_FOUND, + LTTV_MODULE_NO_INIT +} LttvModuleError; + + +/* Insure that a module is loaded and initialized. Require count + (number of times the module was required) and use count + (number of times required or used as prerequisite) serve to + insure that a module is destroyed only after it has been released + as many times as it was required (and prerequired). + + The module is searched among the modules currently loaded, then as a + similarly named library to load which should contain the named module. + If the module cannot be found or loaded, NULL is returned and an + explanation is provided in error. */ + +LttvModule *lttv_module_require(char *name, GError **error); + +void lttv_module_release(LttvModule *m); + + +/* Obtain information about the module, including the containing library */ + +void lttv_module_info(LttvModule *m, LttvModuleInfo *info); + + +/* List the modules on which this module depends */ + +unsigned lttv_module_prerequisite_number(LttvModule *m); + +LttvModule *lttv_module_prerequisite_get(LttvModule *m, unsigned i); + + +/* Insure that a library is loaded. A load count insures that a library + is unloaded only after it has been asked to unload as + many times as it was loaded, and its modules are not in use. The library + is searched along the library path if name is a relative pathname. + If the library cannot be found or loaded, NULL is returned and an + explanation is provided in error. */ + +LttvLibrary *lttv_library_load(char *name, GError **error); -/* Additional module search paths may be defined. */ +void lttv_library_unload(LttvLibrary *l); -void lttv_module_path_add(const char *name); +/* Obtain information about the library */ -/* Load (or increment its reference count if already loaded) the named module. - The init function of the module is executed upon loading. */ +void lttv_library_info(LttvLibrary *l, LttvLibraryInfo *info); -LttvModule *lttv_module_load(const char *name, int argc, char **argv); +/* List the modules contained in a library */ -/* 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. */ +unsigned lttv_library_module_number(LttvLibrary *l); -LttvModule *lttv_module_require(LttvModule *m, const char *name, int argc, - char **argv); +LttvModule *lttv_library_module_get(LttvLibrary *l, unsigned i); -/* 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. */ +/* List the currently loaded libraries */ -void lttv_module_unload(LttvModule *m) ; +unsigned lttv_library_number(); +LttvLibrary *lttv_library_get(unsigned i); -/* List the loaded modules. The returned array contains nb elements and - must be freed with g_free. */ -LttvModule **lttv_module_list(guint *nb); +/* Add or remove directory names to the library search path */ -/* Obtain information about a module. The list of dependent module is - returned and must be freed with g_free. */ +void lttv_library_path_add(char *name); -LttvModule **lttv_module_info(LttvModule *m, const char **name, - guint *ref_count, guint *load_count, guint *nb_dependents); +void lttv_library_path_remove(char *name); + + +/* List the directory names in the library search path */ + +unsigned lttv_library_path_number(); + +char *lttv_library_path_get(unsigned i); + + +/* To define a module, simply call the LTTV_MODULE macro with the needed + arguments: single word name, one line short description, larger + description, initialization function, destruction function, and + list of names for required modules (e.g., "moduleA", "moduleB"). + This will insure that the module is registered at library load time. + + Example: + + LTTV_MODULE("option", "Command line options processing", "...", \ + init, destroy, "moduleA", "moduleB") +*/ + +#define LTTV_MODULE(name, short_desc, desc, init, destroy, ...) \ + \ + static void _LTTV_MODULE_REGISTER(__LINE__)() \ + __attribute__((constructor)); \ + \ + static void _LTTV_MODULE_REGISTER(__LINE__)() \ + { \ + static char *module_prerequisites[] = { __VA_ARGS__ }; \ + \ + static struct _LttvModuleDescription module = { \ + name, short_desc, desc, init, destroy, \ + sizeof(module_prerequisites) / sizeof(char *), \ + module_prerequisites, NULL}; \ + \ + lttv_module_register(&module); \ + } + + +/* Internal structure and function used to register modules, called by + LTTV_MODULE */ + +#define __LTTV_MODULE_REGISTER(line) _lttv_module_register_ ## line +#define _LTTV_MODULE_REGISTER(line) __LTTV_MODULE_REGISTER(line) + +struct _LttvModuleDescription +{ + char *name; + char *short_description; + char *description; + LttvModuleInit init; + LttvModuleDestroy destroy; + unsigned prerequisites_number; + char **prerequisites; + struct _LttvModuleDescription *next; +}; + +void lttv_module_register(struct _LttvModuleDescription *d); -char * lttv_module_name(LttvModule *m); #endif // MODULES_H + + + + + + diff --git a/ltt/branches/poly/lttv/main/main.c b/ltt/branches/poly/lttv/main/main.c index fb9c7164..a27519e8 100644 --- a/ltt/branches/poly/lttv/main/main.c +++ b/ltt/branches/poly/lttv/main/main.c @@ -26,21 +26,8 @@ #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(); - -void lttv_state_init(int argc, char **argv); -void lttv_state_destroy(); - -void lttv_stats_init(int argc, char **argv); -void lttv_stats_destroy(); - /* The main program maintains a few central data structures and relies on modules for the rest. These data structures may be accessed by modules through an exported API */ @@ -63,9 +50,9 @@ static gboolean gboolean lttv_profile_memory; -static int a_argc; +int lttv_argc; -static char **a_argv; +char **lttv_argv; static void lttv_module_option(void *hook_data); @@ -100,6 +87,8 @@ int main(int argc, char **argv) { LttvAttributeValue value; + lttv_argc = argc; + lttv_argv = argv; /* Before anything else, check if memory profiling is requested */ @@ -107,7 +96,6 @@ int main(int argc, char **argv) { if(*(argv[i]) != '-') break; if(strcmp(argv[i], profile_memory_short_option) == 0 || strcmp(argv[i], profile_memory_long_option) == 0) { - mcheck(0); g_mem_set_vtable(glib_mem_profiler_table); g_message("Memory summary before main"); g_mem_profile(); @@ -153,17 +141,16 @@ int main(int argc, char **argv) { /* Initialize the command line options processing */ - a_argc = argc; - a_argv = argv; - lttv_option_init(argc,argv); - lttv_module_init(argc,argv); - lttv_state_init(argc,argv); - lttv_stats_init(argc,argv); + GError *error = NULL; + LttvModule *module_module = lttv_module_require("module", &error); + if(error != NULL) g_error(error->message); + LttvModule *module_option = lttv_module_require("option", &error); + if(error != NULL) g_error(error->message); /* Initialize the module loading */ - lttv_module_path_add(PACKAGE_PLUGIN_DIR); + lttv_library_path_add(PACKAGE_PLUGIN_DIR); /* Add some built-in options */ @@ -214,10 +201,8 @@ int main(int argc, char **argv) { /* Clean up everything */ - lttv_stats_destroy(); - lttv_state_destroy(); - lttv_module_destroy(); - lttv_option_destroy(); + lttv_module_release(module_option); + lttv_module_release(module_module); lttv_hooks_destroy(before_options); lttv_hooks_destroy(after_options); @@ -229,6 +214,7 @@ int main(int argc, char **argv) { g_message("Memory summary after main"); g_mem_profile(); } + return 0; } @@ -240,13 +226,16 @@ LttvAttribute *lttv_global_attributes() void lttv_module_option(void *hook_data) { - lttv_module_load(a_module,a_argc,a_argv); + GError *error = NULL; + + lttv_module_require(a_module, &error); + if(error != NULL) g_error(error->message); } void lttv_module_path_option(void *hook_data) { - lttv_module_path_add(a_module_path); + lttv_library_path_add(a_module_path); } @@ -272,13 +261,6 @@ void lttv_help(void *hook_data) /* -- Make it easier to change modules from builtin to externally loaded. - - have: MODULE_INFO(name, init, destroy, { require} ) in each module. - Maintain the list of builtin modules and search these first (or - optionally last). Add the lib prefix if needed to avoid having to - specify libbatchAnalysis instead of batchAnalysis. - - Define formally traceset/trace in the GUI for the user and decide how trace/traceset sharing goes in the application. diff --git a/ltt/branches/poly/lttv/main/module.c b/ltt/branches/poly/lttv/main/module.c index df98aacf..c4d3d6b0 100644 --- a/ltt/branches/poly/lttv/main/module.c +++ b/ltt/branches/poly/lttv/main/module.c @@ -1,3 +1,4 @@ + /* This file is part of the Linux Trace Toolkit viewer * Copyright (C) 2003-2004 Michel Dagenais * @@ -17,312 +18,567 @@ */ -/* module.c : Implementation of the module loading/unloading mechanism. - * - */ +/* module.c : Implementation of the module loading/unloading mechanism. */ #include +#include + + +struct _LttvLibrary +{ + LttvLibraryInfo info; + GPtrArray *modules; + GModule *gm; + guint locked_loaded; +}; + struct _LttvModule { - GModule *module; - guint ref_count; - guint load_count; - GPtrArray *dependents; + LttvModuleInfo info; + char **prerequisites_names; + GPtrArray *prerequisites; }; -/* Table of loaded modules and paths where to search for modules */ +/* Modules are searched by name. However, a library may be loaded which + provides a module with the same name as an existing one. A stack of + modules is thus maintained for each name. + + Libraries correspond to glib modules. The g_module function is + responsible for loading each library only once. */ + +static GHashTable *modules_by_name = NULL; -static GHashTable *modules = NULL; +static GPtrArray *libraries = NULL; -static GPtrArray *modulesPaths = NULL; +static GHashTable *libraries_by_g_module = NULL; -static void lttv_module_unload_all(); +static GPtrArray *library_paths = NULL; +static gboolean initialized = FALSE; -void lttv_module_init(int argc, char **argv) +static gboolean destroyed = TRUE; + +static struct _LttvModuleDescription *builtin_chain = NULL; + +static struct _LttvModuleDescription *module_chain = NULL; + +static struct _LttvModuleDescription **module_next = &module_chain; + +static GQuark lttv_module_error; + +static void init(); + +static finish_destroy(); + +static void module_release(LttvModule *m); + + +static LttvLibrary *library_add(char *name, char *path, GModule *gm) { - g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "Init module.c"); - modules = g_hash_table_new(g_str_hash, g_str_equal); - modulesPaths = g_ptr_array_new(); -} + LttvLibrary *l; + LttvModule *m; -void lttv_module_destroy() -{ - int i; + struct _LttvModuleDescription *link; - g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "Destroy module.c"); + GPtrArray *modules; + + l = g_new(LttvLibrary, 1); + l->modules = g_ptr_array_new(); + l->gm = gm; + l->locked_loaded = 0; + l->info.name = g_strdup(name); + l->info.path = g_strdup(path); + l->info.load_count = 0; - /* Unload all modules */ - lttv_module_unload_all(); + g_ptr_array_add(libraries, l); + g_hash_table_insert(libraries_by_g_module, gm, l); - /* Free the modules paths pointer array as well as the elements */ - for(i = 0; i < modulesPaths->len ; i++) { - g_free(modulesPaths->pdata[i]); + *module_next = NULL; + for(link = module_chain; link != NULL; link = link->next) { + m = g_new(LttvModule, 1); + g_ptr_array_add(l->modules, m); + + modules = g_hash_table_lookup(modules_by_name, link->name); + if(modules == NULL) { + modules = g_ptr_array_new(); + g_hash_table_insert(modules_by_name, g_strdup(link->name), modules); + } + g_ptr_array_add(modules, m); + + m->prerequisites_names = link->prerequisites; + m->prerequisites = g_ptr_array_new(); + m->info.name = link->name; + m->info.short_description = link->short_description; + m->info.description = link->description; + m->info.init = link->init; + m->info.destroy = link->destroy; + m->info.library = l; + m->info.require_count = 0; + m->info.use_count = 0; + m->info.prerequisites_number = link->prerequisites_number; } - g_ptr_array_free(modulesPaths,TRUE) ; - modulesPaths = NULL; - - /* destroy the hash table */ - g_hash_table_destroy(modules) ; - modules = NULL; + return l; } -/* Add a new pathname to the modules loading search path */ - -void lttv_module_path_add(const char *name) +static void library_remove(LttvLibrary *l) { - g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "Add module path %s", name); - g_ptr_array_add(modulesPaths,(char*)g_strdup(name)); + LttvModule *m; + + GPtrArray *modules; + + guint i; + + char *key; + + for(i = 0 ; i < l->modules->len ; i++) { + m = (LttvModule *)(l->modules->pdata[i]); + + g_hash_table_lookup_extended(modules_by_name, m->info.name, + (gpointer *)&key, (gpointer *)&modules); + g_assert(modules != NULL); + g_ptr_array_remove(modules, m); + if(modules->len == 0) { + g_hash_table_remove(modules_by_name, m->info.name); + g_ptr_array_free(modules, TRUE); + g_free(key); + } + + g_ptr_array_free(m->prerequisites, TRUE); + g_free(m); + } + + g_ptr_array_remove(libraries, l); + g_hash_table_remove(libraries_by_g_module, l->gm); + g_ptr_array_free(l->modules, TRUE); + g_free(l->info.name); + g_free(l->info.path); + g_free(l); } -static LttvModule * -module_load(const char *name, int argc, char **argv) +static LttvLibrary *library_load(char *name, GError **error) { GModule *gm; - LttvModule *m; + int i, nb; + + char *path, *pathname; + + LttvLibrary *l; - int i; + GString *messages = g_string_new(""); - char *pathname; + /* insure that module.c is initialized */ - const char *module_name; - - LttvModuleInit init_function; + init(); - g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "Load module %s", name); + /* Try to find the library along all the user specified paths */ - /* Try to find the module along all the user specified paths */ + g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "Load library %s", name); + nb = lttv_library_path_number(); + for(i = 0 ; i <= nb ; i++) { + if(i < nb) path = lttv_library_path_get(i); + else path = NULL; - for(i = 0 ; i < modulesPaths->len ; i++) { - pathname = g_module_build_path(modulesPaths->pdata[i],name); - g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Try path %s", pathname); + pathname = g_module_build_path(path ,name); + g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "Try path %s", pathname); + module_chain = NULL; + module_next = &module_chain; gm = g_module_open(pathname,0); g_free(pathname); if(gm != NULL) break; - g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG,"Trial failed, %s",g_module_error()); - } - - /* Try the default system path */ - if(gm == NULL) { - pathname = g_module_build_path(NULL,name); - g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Try default path"); - gm = g_module_open(pathname,0); - g_free(pathname); + g_string_append(messages, g_module_error()); + g_string_append(messages, "\n"); + g_log(G_LOG_DOMAIN,G_LOG_LEVEL_INFO,"Trial failed, %s", g_module_error()); } /* Module cannot be found */ + if(gm == NULL) { - g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG,"Trial failed, %s",g_module_error()); - g_warning("Failed to load module %s", name); + g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "Failed to load %s", name); + g_set_error(error, lttv_module_error, LTTV_MODULE_NOT_FOUND, + "Cannot load library %s: %s", name, messages->str); + g_string_free(messages, TRUE); return NULL; } + g_string_free(messages, TRUE); + + /* Check if the library was already loaded */ + + l = g_hash_table_lookup(libraries_by_g_module, gm); - /* Check if the module was already opened using the hopefully canonical name - returned by g_module_name. */ + /* This library was not already loaded */ - module_name = g_module_name(gm); + if(l == NULL) { + g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "Library %s (%s) loaded", name, + g_module_name(gm)); + l = library_add(name, path, gm); + } + return l; +} - m = g_hash_table_lookup(modules, module_name); - if(m == NULL) { - g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, - "Module %s (%s) loaded, call its init function", name, module_name); +LttvLibrary *lttv_library_load(char *name, GError **error) +{ + LttvLibrary *l = library_load(name, error); + l->info.load_count++; + return l; +} - /* Module loaded for the first time. Insert it in the table and call the - init function if any. */ - m = g_new(LttvModule, 1); - m->module = gm; - m->ref_count = 0; - m->load_count = 0; - m->dependents = g_ptr_array_new(); - g_hash_table_insert(modules, (gpointer)module_name, m); - - if(!g_module_symbol(gm, "init", (gpointer)&init_function)) { - g_warning("module %s (%s) has no init function", name, pathname); - } - else init_function(m, argc, argv); +static void library_unload(LttvLibrary *l) +{ + guint i, len; + + GModule *gm; + + LttvModule *m; + + if(l->locked_loaded > 0) { + g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "Unload library %s: locked loaded", + l->info.name); + return; + } + + if(l->info.load_count > 0) { + g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "Unload library %s: load count %d", + l->info.name, l->info.load_count); + return; } - else { - /* Module was already opened, check that it really is the same and - undo the extra g_module_open */ + /* Check if all its modules have been released */ - g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, - "Module %s (%s) was already loaded, no need to call init function", - name, module_name); - if(m->module != gm) g_error("Two gmodules with the same pathname"); - g_module_close(gm); + for(i = 0 ; i < l->modules->len ; i++) { + m = (LttvModule *)(l->modules->pdata[i]); + if(m->info.use_count > 0) { + g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO,"Unload library %s: module %s used", + l->info.name, m->info.name); + return; + } } - - m->ref_count++; - return m; + + g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "Unload library %s: close the GModule", + l->info.name); + gm = l->gm; + library_remove(l); + if(gm != NULL) g_module_close(gm); + + /* insure that module.c will be finalized */ + + finish_destroy(); } -LttvModule * -lttv_module_load(const char *name, int argc, char **argv) +void lttv_library_unload(LttvLibrary *l) { - g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "Load module %s explicitly", name); - LttvModule *m = module_load(name, argc, argv); - if(m != NULL) m->load_count++; - return m; + l->info.load_count--; + library_unload(l); } -LttvModule * -lttv_module_require(LttvModule *m, const char *name, int argc, char **argv) +static void library_lock_loaded(LttvLibrary *l) { - LttvModule *module; - - g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, - "Load module %s, as %s is a dependent requiring it", name, - g_module_name(m->module)); - module = module_load(name, argc, argv); - if(module != NULL) g_ptr_array_add(m->dependents, module); - return module; + l->locked_loaded++; } -static void module_unload(LttvModule *m) +static void library_unlock_loaded(LttvLibrary *l) { - LttvModuleDestroy destroy_function; + l->locked_loaded--; + library_unload(l); +} - char *pathname; - guint i, len; +static LttvModule *module_require(char *name, GError **error) +{ + GError *tmp_error = NULL; - /* Decrement the reference count */ + guint i, j; - g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "Unload module %s", - g_module_name(m->module)); - m->ref_count--; - if(m->ref_count > 0) { - g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, - "Module usage count decremented to %d", m->ref_count); - return; - } + LttvModule *m, *required; + + LttvLibrary *l = NULL; + + GPtrArray *modules; + + /* Insure that module.c is initialized */ + + init(); - /* We really have to unload the module. First destroy it. */ + /* Check if the module is already loaded */ - g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, - "Call the destroy function and unload the module"); - if(!g_module_symbol(m->module, "destroy", (gpointer)&destroy_function)) { - g_warning("module (%s) has no destroy function", pathname); + modules = g_hash_table_lookup(modules_by_name, name); + + /* Try to load a library having the module name */ + + if(modules == NULL) { + l = library_load(name, error); + if(l == NULL) return NULL; + else library_lock_loaded(l); + + /* A library was found, does it contain the named module */ + + modules = g_hash_table_lookup(modules_by_name, name); + if(modules == NULL) { + g_set_error(error, lttv_module_error, LTTV_MODULE_NOT_FOUND, + "Module %s not found in library %s", name, l->info.name); + library_unlock_loaded(l); + return NULL; + } } - else destroy_function(); + m = (LttvModule *)(modules->pdata[modules->len - 1]); - /* Then release the modules required by this module */ + /* We have the module */ - len = m->dependents->len; - g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "Unload dependent modules"); + m->info.use_count++; - for(i = 0 ; i < len ; i++) { - module_unload(m->dependents->pdata[i]); + /* First use of the module. Initialize after getting the prerequisites */ + + if(m->info.use_count == 1) { + for(i = 0 ; i < m->info.prerequisites_number ; i++) { + required = module_require(m->prerequisites_names[i], &tmp_error); + + /* A prerequisite could not be found, undo everything and fail */ + + if(required == NULL) { + for(j = 0 ; j < m->prerequisites->len ; j++) { + module_release((LttvModule *)(m->prerequisites->pdata[j])); + } + g_ptr_array_set_size(m->prerequisites, 0); + if(l != NULL) library_unlock_loaded(l); + g_set_error(error, lttv_module_error, LTTV_MODULE_NOT_FOUND, + "Cannot find prerequisite for module %s: %s", name, + tmp_error->message); + g_clear_error(&tmp_error); + return NULL; + } + g_ptr_array_add(m->prerequisites, required); + } + g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "Module %s: init()", m->info.name); + m->info.init(); } - if(len != m->dependents->len) g_error("dependents list modified"); + /* Decrement the load count of the library. It will not really be + unloaded since it contains a currently used module. */ + + if(l != NULL) library_unlock_loaded(l); - /* Finally remove any trace of this module */ + return(m); +} + + +/* The require_count for a module is the number of explicit calls to + lttv_module_require, while the use_count also counts the number of times + a module is needed as a prerequisite. */ - 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); +LttvModule *lttv_module_require(char *name, GError **error) +{ + LttvModule *m = module_require(name, error); + if(m != NULL) m->info.require_count++; + return(m); } -void lttv_module_unload(LttvModule *m) +static void module_release(LttvModule *m) { - g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "Explicitly unload module %s", - g_module_name(m->module)); - if(m->load_count <= 0) { - g_error("more unload than load (%s)", g_module_name(m->module)); - return; + guint i; + + library_lock_loaded(m->info.library); + + m->info.use_count--; + if(m->info.use_count == 0) { + g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "Module %s: destroy()",m->info.name); + m->info.destroy(); + for(i = 0 ; i < m->prerequisites->len ; i++) { + module_release((LttvModule *)(m->prerequisites->pdata[i])); + } + g_ptr_array_set_size(m->prerequisites, 0); } - m->load_count--; - module_unload(m); + library_unlock_loaded(m->info.library); +} + + +void lttv_module_release(LttvModule *m) +{ + m->info.require_count--; + module_release(m); +} + + +void lttv_module_info(LttvModule *m, LttvModuleInfo *info) +{ + *info = m->info; +} + + +unsigned lttv_module_prerequisite_number(LttvModule *m) +{ + return m->prerequisites->len; +} + + +LttvModule *lttv_module_prerequisite_get(LttvModule *m, unsigned i) +{ + return (LttvModule *)(m->prerequisites->pdata[i]); +} + + +void lttv_library_info(LttvLibrary *l, LttvLibraryInfo *info) +{ + *info = l->info; +} + + +unsigned lttv_library_module_number(LttvLibrary *l) +{ + return l->modules->len; +} + + +LttvModule *lttv_library_module_get(LttvLibrary *l, unsigned i) +{ + return (LttvModule *)(l->modules->pdata[i]); +} + + +unsigned lttv_library_number() +{ + return libraries->len; } -static void -list_modules(gpointer key, gpointer value, gpointer user_data) +LttvLibrary *lttv_library_get(unsigned i) { - g_ptr_array_add((GPtrArray *)user_data, value); + return (LttvLibrary *)(libraries->pdata[i]); } -LttvModule ** -lttv_module_list(guint *nb) +void lttv_library_path_add(char *name) { - GPtrArray *list = g_ptr_array_new(); + g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "Add library path %s", name); + g_ptr_array_add(library_paths,(char*)g_strdup(name)); +} + - LttvModule **array; +void lttv_library_path_remove(char *name) +{ + guint i; - g_hash_table_foreach(modules, list_modules, list); - *nb = list->len; - array = (LttvModule **)list->pdata; - g_ptr_array_free(list, FALSE); - return array; + for(i = 0 ; i < library_paths->len ; i++) { + if(g_str_equal(name, library_paths->pdata[i])) { + g_free(library_paths->pdata[i]); + g_ptr_array_remove_index(library_paths,i); + return; + } + } } -LttvModule ** -lttv_module_info(LttvModule *m, const char **name, - guint *ref_count, guint *load_count, guint *nb_dependents) +unsigned lttv_library_path_number() { - guint i, len = m->dependents->len; + return library_paths->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; +char *lttv_library_path_get(unsigned i) +{ + return (char *)(library_paths->pdata[library_paths->len - i - 1]); } -char * -lttv_module_name(LttvModule *m) + +void lttv_module_register(struct _LttvModuleDescription *d) { - return g_module_name(m->module); + *module_next = d; + module_next = &(d->next); } -static void -list_independent(gpointer key, gpointer value, gpointer user_data) + +static void init() { - LttvModule *m = (LttvModule *)value; + if(initialized) return; + g_assert(destroyed); + + g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "Init module.c"); - if(m->load_count > 0) g_ptr_array_add((GPtrArray *)user_data, m); + initialized = TRUE; + destroyed = FALSE; + lttv_module_error = g_quark_from_string("LTTV_MODULE_ERROR"); + modules_by_name = g_hash_table_new(g_str_hash, g_str_equal); + libraries = g_ptr_array_new(); + libraries_by_g_module = g_hash_table_new(g_direct_hash, g_direct_equal); + library_paths = g_ptr_array_new(); + + if(builtin_chain == NULL) builtin_chain = module_chain; + module_chain = builtin_chain; + library_add("builtin", NULL, NULL); } -void -lttv_module_unload_all() +static finish_destroy() { guint i; + if(initialized) return; + g_assert(!destroyed); + + g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "Finish destroy module.c"); + g_hash_table_destroy(modules_by_name); + g_ptr_array_free(libraries, TRUE); + g_hash_table_destroy(libraries_by_g_module); + for(i = 0 ; i < library_paths->len ; i++) { + g_free(library_paths->pdata[i]); + } + g_ptr_array_free(library_paths, TRUE); + destroyed = TRUE; +} + + +static void destroy() +{ + guint i, j, nb; + + LttvLibrary *l, **locked_libraries; + LttvModule *m; - GPtrArray *independent_modules; + g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "Destroy module.c"); + + /* Unload all libraries */ - while(g_hash_table_size(modules) != 0) { - independent_modules = g_ptr_array_new(); - g_hash_table_foreach(modules, list_independent, independent_modules); + nb = libraries->len; + locked_libraries = g_new(LttvLibrary *, nb); - for(i = 0 ; i < independent_modules->len ; i++) { - m = (LttvModule *)independent_modules->pdata[i]; - lttv_module_unload(m); + for(i = 0 ; i < nb ; i++) { + l = (LttvLibrary *)(libraries->pdata[i]); + locked_libraries[i] = l; + library_lock_loaded(l); + for(j = 0 ; j < l->modules->len ; j++) { + m = (LttvModule *)(l->modules->pdata[j]); + while(m->info.require_count > 0) lttv_module_release(m); } - g_ptr_array_free(independent_modules, TRUE); + while(l->info.load_count > 0) lttv_library_unload(l); + } + + for(i = 0 ; i < nb ; i++) { + l = locked_libraries[i]; + library_unlock_loaded(l); } + g_free(locked_libraries); + + /* The library containing module.c may be locked by our caller */ + + g_assert(libraries->len <= 1); + + initialized = FALSE; } + +LTTV_MODULE("module", "Modules in libraries", \ + "Load libraries, list, require and initialize contained modules", \ + init, destroy) + diff --git a/ltt/branches/poly/lttv/main/option.c b/ltt/branches/poly/lttv/main/option.c index 7c80b7f6..7532073e 100644 --- a/ltt/branches/poly/lttv/main/option.c +++ b/ltt/branches/poly/lttv/main/option.c @@ -19,6 +19,7 @@ #include #include +#include #include typedef struct _LttvOption { @@ -52,32 +53,6 @@ free_option(LttvOption *option) } -void lttv_option_init(int argc, char **argv) -{ - g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "Init option.c"); - options = g_hash_table_new(g_str_hash, g_str_equal); -} - - -void lttv_option_destroy() -{ - LttvOption option; - - GPtrArray *list = g_ptr_array_new(); - - int i; - - g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "Destroy option.c"); - g_hash_table_foreach(options, list_options, list); - g_hash_table_destroy(options); - - for(i = 0 ; i < list->len ; i++) { - free_option((LttvOption *)list->pdata[i]); - } - g_ptr_array_free(list, TRUE); -} - - void lttv_option_add(const char *long_name, const char char_name, const char *description, const char *arg_description, const LttvOptionType t, void *p, @@ -251,6 +226,7 @@ void lttv_option_parse(int argc, char **argv) destroy_popts(&list, &popts, &c); } +/* CHECK */ static void show_help(LttvOption *option) { printf("--%s -%c argument: %s\n" , option->long_name, @@ -281,3 +257,31 @@ void lttv_option_show_help(void) } +static void init() +{ + g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "Init option.c"); + options = g_hash_table_new(g_str_hash, g_str_equal); +} + + +static void destroy() +{ + LttvOption option; + + GPtrArray *list = g_ptr_array_new(); + + int i; + + g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "Destroy option.c"); + g_hash_table_foreach(options, list_options, list); + g_hash_table_destroy(options); + + for(i = 0 ; i < list->len ; i++) { + free_option((LttvOption *)list->pdata[i]); + } + g_ptr_array_free(list, TRUE); +} + +LTTV_MODULE("option", "Command line options processing", \ + "Functions to add, remove and parse command line options", \ + init, destroy) diff --git a/ltt/branches/poly/lttv/main/state.c b/ltt/branches/poly/lttv/main/state.c index 5f67bf7b..c69d6a6a 100644 --- a/ltt/branches/poly/lttv/main/state.c +++ b/ltt/branches/poly/lttv/main/state.c @@ -17,6 +17,8 @@ */ +#include +#include #include #include #include @@ -150,7 +152,10 @@ init(LttvTracesetState *self, LttvTraceset *ts) tcs->save_interval = 50000; lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_SAVED_STATES_TIME, LTTV_POINTER, &v); - if(*(v.v_pointer) == NULL) *(v.v_pointer) = g_new(LttTime,1); + if(*(v.v_pointer) == NULL) { + *(v.v_pointer) = g_new(LttTime,1); + *((LttTime *)*(v.v_pointer)) = time_zero; + } tcs->max_time_state_recomputed_in_seek = (LttTime *)*(v.v_pointer); fill_name_tables(tcs); @@ -263,7 +268,9 @@ void lttv_state_write(LttvTraceState *self, LttTime t, FILE *fp) for(i = 0 ; i < nb_tracefile ; i++) { tfcs = (LttvTracefileState *)self->parent.tracefiles[i]; - fprintf(fp, " process->pid); + fprintf(fp, " process->pid, tfcs->parent.timestamp.tv_sec, + tfcs->parent.timestamp.tv_nsec); if(tfcs->parent.e == NULL) fprintf(fp,"/>\n"); else { ltt_event_position(tfcs->parent.e, ep); @@ -359,6 +366,12 @@ static void state_save(LttvTraceState *self, LttvAttribute *container) ep = ltt_event_position_new(); ltt_event_position(tfcs->parent.e, ep); *(value.v_pointer) = ep; + + guint nb_block, nb_event; + LttTracefile *tf; + ltt_event_position_get(ep, &nb_block, &nb_event, &tf); + g_debug("Block %u event %u time %lu.%lu", nb_block, nb_event, + tfcs->parent.timestamp.tv_sec, tfcs->parent.timestamp.tv_nsec); } } } @@ -583,12 +596,12 @@ static void pop_state(LttvTracefileState *tfs, LttvExecutionMode t) guint depth = process->execution_stack->len - 1; if(process->state->t != t){ - g_warning("Different execution mode type (%d.%09d): ignore it\n", + g_info("Different execution mode type (%d.%09d): ignore it\n", tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec); - g_warning("process state has %s when pop_int is %s\n", + g_info("process state has %s when pop_int is %s\n", g_quark_to_string(process->state->t), g_quark_to_string(t)); - g_warning("{ %u, %u, %s, %s }\n", + g_info("{ %u, %u, %s, %s }\n", process->pid, process->ppid, g_quark_to_string(process->name), @@ -597,7 +610,7 @@ static void pop_state(LttvTracefileState *tfs, LttvExecutionMode t) } if(depth == 0){ - g_warning("Trying to pop last state on stack (%d.%09d): ignore it\n", + g_info("Trying to pop last state on stack (%d.%09d): ignore it\n", tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec); return; } @@ -970,7 +983,7 @@ void lttv_state_remove_event_hooks(LttvTracesetState *self) } -static gboolean block_end(void *hook_data, void *call_data) +static gboolean block_start(void *hook_data, void *call_data) { LttvTracefileState *self = (LttvTracefileState *)call_data; @@ -1015,12 +1028,36 @@ static gboolean block_end(void *hook_data, void *call_data) *(value.v_time) = self->parent.timestamp; lttv_state_save(tcs, saved_state_tree); tcs->nb_event = 0; + g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec, + self->parent.timestamp.tv_nsec); } *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp; return FALSE; } +static gboolean block_end(void *hook_data, void *call_data) +{ + LttvTracefileState *self = (LttvTracefileState *)call_data; + + LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context); + + LttTracefile *tf; + + LttEventPosition *ep; + + guint nb_block, nb_event; + + ep = ltt_event_position_new(); + ltt_event_position(self->parent.e, ep); + ltt_event_position_get(ep, &nb_block, &nb_event, &tf); + tcs->nb_event += nb_event - self->saved_position + 1; + self->saved_position = 0; + *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp; + g_free(ep); +} + + void lttv_state_save_add_event_hooks(LttvTracesetState *self) { LttvTraceset *traceset = self->parent.ts; @@ -1031,13 +1068,15 @@ void lttv_state_save_add_event_hooks(LttvTracesetState *self) LttvTracefileState *tfs; - LttvTraceHook hook; + LttvTraceHook hook_start, hook_end; nb_trace = lttv_traceset_number(traceset); for(i = 0 ; i < nb_trace ; i++) { ts = (LttvTraceState *)self->parent.traces[i]; + lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL, + NULL, NULL, block_start, &hook_start); lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL, - NULL, NULL, block_end, &hook); + NULL, NULL, block_end, &hook_end); nb_tracefile = ltt_trace_control_tracefile_number(ts->parent.t) + ltt_trace_per_cpu_tracefile_number(ts->parent.t); @@ -1045,7 +1084,9 @@ void lttv_state_save_add_event_hooks(LttvTracesetState *self) for(j = 0 ; j < nb_tracefile ; j++) { tfs = LTTV_TRACEFILE_STATE(ts->parent.tracefiles[j]); lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.after_event_by_id, - hook.id), hook.h, NULL); + hook_start.id), hook_start.h, NULL); + lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.after_event_by_id, + hook_end.id), hook_end.h, NULL); } } } @@ -1061,13 +1102,16 @@ void lttv_state_save_remove_event_hooks(LttvTracesetState *self) LttvTracefileState *tfs; - LttvTraceHook hook; + LttvTraceHook hook_start, hook_end; nb_trace = lttv_traceset_number(traceset); for(i = 0 ; i < nb_trace ; i++) { ts = LTTV_TRACE_STATE(self->parent.traces[i]); + lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL, + NULL, NULL, block_start, &hook_start); + lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL, - NULL, NULL, block_end, &hook); + NULL, NULL, block_end, &hook_end); nb_tracefile = ltt_trace_control_tracefile_number(ts->parent.t) + ltt_trace_per_cpu_tracefile_number(ts->parent.t); @@ -1075,7 +1119,9 @@ void lttv_state_save_remove_event_hooks(LttvTracesetState *self) for(j = 0 ; j < nb_tracefile ; j++) { tfs = LTTV_TRACEFILE_STATE(ts->parent.tracefiles[j]); lttv_hooks_remove_data(lttv_hooks_by_id_find( - tfs->parent.after_event_by_id, hook.id), hook.h, NULL); + tfs->parent.after_event_by_id, hook_start.id), hook_start.h, NULL); + lttv_hooks_remove_data(lttv_hooks_by_id_find( + tfs->parent.after_event_by_id, hook_end.id), hook_end.h, NULL); } } } @@ -1295,7 +1341,7 @@ lttv_tracefile_state_get_type(void) } -void lttv_state_init(int argc, char **argv) +static void module_init() { LTTV_STATE_UNNAMED = g_quark_from_string("unnamed"); LTTV_STATE_MODE_UNKNOWN = g_quark_from_string("unknown execution mode"); @@ -1320,10 +1366,14 @@ void lttv_state_init(int argc, char **argv) LTTV_STATE_HOOKS = g_quark_from_string("saved state hooks"); } -void lttv_state_destroy() +static void module_destroy() { } +LTTV_MODULE("state", "State computation", \ + "Update the system state, possibly saving it at intervals", \ + module_init, module_destroy) + diff --git a/ltt/branches/poly/lttv/main/stats.c b/ltt/branches/poly/lttv/main/stats.c index c5686976..c577ab77 100644 --- a/ltt/branches/poly/lttv/main/stats.c +++ b/ltt/branches/poly/lttv/main/stats.c @@ -18,6 +18,7 @@ #include +#include #include #include #include @@ -798,27 +799,6 @@ lttv_stats_remove_event_hooks(LttvTracesetStats *self) } -void lttv_stats_init(int argc, char **argv) -{ - LTTV_STATS_PROCESS_UNKNOWN = g_quark_from_string("unknown process"); - LTTV_STATS_PROCESSES = g_quark_from_string("processes"); - LTTV_STATS_CPU = g_quark_from_string("cpu"); - LTTV_STATS_MODE_TYPES = g_quark_from_string("mode_types"); - LTTV_STATS_MODES = g_quark_from_string("modes"); - LTTV_STATS_SUBMODES = g_quark_from_string("submodes"); - LTTV_STATS_EVENT_TYPES = g_quark_from_string("event_types"); - LTTV_STATS_CPU_TIME = g_quark_from_string("cpu time"); - LTTV_STATS_ELAPSED_TIME = g_quark_from_string("elapsed time"); - LTTV_STATS_EVENTS = g_quark_from_string("events"); - LTTV_STATS_EVENTS_COUNT = g_quark_from_string("events count"); - LTTV_STATS_BEFORE_HOOKS = g_quark_from_string("saved stats before hooks"); - LTTV_STATS_AFTER_HOOKS = g_quark_from_string("saved stats after hooks"); -} - -void lttv_stats_destroy() -{ -} - void lttv_stats_save_attribute(LttvAttribute *attr, char *indent, FILE * fp) { LttvAttributeType type; @@ -1124,7 +1104,7 @@ gboolean lttv_stats_load_statistics(LttvTracesetStats *self) char filename[BUF_SIZE]; GMarkupParseContext * context; - GError * error; + GError * error = NULL; GMarkupParser markup_parser = { stats_parser_start_element, @@ -1171,3 +1151,30 @@ gboolean lttv_stats_load_statistics(LttvTracesetStats *self) return TRUE; } + + +static void module_init() +{ + LTTV_STATS_PROCESS_UNKNOWN = g_quark_from_string("unknown process"); + LTTV_STATS_PROCESSES = g_quark_from_string("processes"); + LTTV_STATS_CPU = g_quark_from_string("cpu"); + LTTV_STATS_MODE_TYPES = g_quark_from_string("mode_types"); + LTTV_STATS_MODES = g_quark_from_string("modes"); + LTTV_STATS_SUBMODES = g_quark_from_string("submodes"); + LTTV_STATS_EVENT_TYPES = g_quark_from_string("event_types"); + LTTV_STATS_CPU_TIME = g_quark_from_string("cpu time"); + LTTV_STATS_ELAPSED_TIME = g_quark_from_string("elapsed time"); + LTTV_STATS_EVENTS = g_quark_from_string("events"); + LTTV_STATS_EVENTS_COUNT = g_quark_from_string("events count"); + LTTV_STATS_BEFORE_HOOKS = g_quark_from_string("saved stats before hooks"); + LTTV_STATS_AFTER_HOOKS = g_quark_from_string("saved stats after hooks"); +} + +static void module_destroy() +{ +} + + +LTTV_MODULE("stats", "Compute processes statistics", \ + "Accumulate statistics for event types, processes and CPUs", \ + module_init, module_destroy, "state"); diff --git a/ltt/branches/poly/lttv/modules/examples/sampledep.c b/ltt/branches/poly/lttv/modules/examples/sampledep.c index dd64c9f4..305e0460 100644 --- a/ltt/branches/poly/lttv/modules/examples/sampledep.c +++ b/ltt/branches/poly/lttv/modules/examples/sampledep.c @@ -3,18 +3,19 @@ /* Created by Mathieu Desnoyers, may 2003 */ #include -#include /* Include module.h from lttv headers for module loading */ #include -G_MODULE_EXPORT void init(int argc, char * argv[], LttvModule *self) { +static void init() { g_critical("Sample module dependant init()"); - - lttv_module_require(self, "samplemodule",argc,argv); } -G_MODULE_EXPORT void destroy() { +static void destroy() { g_critical("Sample module dependant destroy()"); } - + + +LTTV_MODULE("sampledep", "Medium desc...", "Long desc...", init, destroy, \ + { "samplemodule" }) + diff --git a/ltt/branches/poly/lttv/modules/examples/samplemodule.c b/ltt/branches/poly/lttv/modules/examples/samplemodule.c index e64ab2f4..3156c9f2 100644 --- a/ltt/branches/poly/lttv/modules/examples/samplemodule.c +++ b/ltt/branches/poly/lttv/modules/examples/samplemodule.c @@ -3,13 +3,16 @@ /* Created by Mathieu Desnoyers, may 2003 */ #include -#include +#include -G_MODULE_EXPORT void init() { +static void init() { g_critical("Sample module init()"); } -G_MODULE_EXPORT void destroy() { +static void destroy() { g_critical("Sample module destroy()"); } - + + +LTTV_MODULE("sampledep", "Medium...", "Long...", init, destroy, {}) + diff --git a/ltt/branches/poly/lttv/modules/examples/samplemodule2.c b/ltt/branches/poly/lttv/modules/examples/samplemodule2.c index 3d7bb1c0..6ce8edd6 100644 --- a/ltt/branches/poly/lttv/modules/examples/samplemodule2.c +++ b/ltt/branches/poly/lttv/modules/examples/samplemodule2.c @@ -3,13 +3,16 @@ /* Created by Mathieu Desnoyers, may 2003 */ #include -#include +#include -G_MODULE_EXPORT void init() { +static void init() { g_critical("Sample module 2 init()"); } -G_MODULE_EXPORT void destroy() { +static void destroy() { g_critical("Sample module 2 destroy()"); } - + + +LTTV_MODULE("samplemodule2", "Medium...", "Long...", init, destroy, {}) + diff --git a/ltt/branches/poly/lttv/modules/gui/controlflow/module.c b/ltt/branches/poly/lttv/modules/gui/controlflow/module.c index 16068794..69694d6f 100644 --- a/ltt/branches/poly/lttv/modules/gui/controlflow/module.c +++ b/ltt/branches/poly/lttv/modules/gui/controlflow/module.c @@ -38,7 +38,6 @@ */ #include -#include #include #include #include @@ -66,16 +65,8 @@ GSList *g_control_flow_data_list = NULL ; * This function initializes the Control Flow Viewer functionnality through the * gtkTraceSet API. */ -G_MODULE_EXPORT void init(LttvModule *self, int argc, char *argv[]) { +static void init() { - Main_Win_Module = lttv_module_require(self, "mainwin", argc, argv); - - if(Main_Win_Module == NULL) - { - g_critical("Can't load Control Flow Viewer : missing mainwin\n"); - return; - } - g_info("GUI ControlFlow Viewer init()"); /* Register the toolbar insert button */ @@ -101,7 +92,7 @@ void destroy_walk(gpointer data, gpointer user_data) * This function releases the memory reserved by the module and unregisters * everything that has been registered in the gtkTraceSet API. */ -G_MODULE_EXPORT void destroy() { +static void destroy() { g_info("GUI Control Flow Viewer destroy()"); int i; @@ -116,3 +107,8 @@ G_MODULE_EXPORT void destroy() { menu_item_unreg(h_guicontrolflow); } + + +LTTV_MODULE("guicontrolflow", "Control flow viewer", \ + "Graphical module to view processes state and control flow", \ + init, destroy, "mainwin") diff --git a/ltt/branches/poly/lttv/modules/gui/detailedevents/events.c b/ltt/branches/poly/lttv/modules/gui/detailedevents/events.c index 17cc9321..43b81d03 100644 --- a/ltt/branches/poly/lttv/modules/gui/detailedevents/events.c +++ b/ltt/branches/poly/lttv/modules/gui/detailedevents/events.c @@ -40,7 +40,6 @@ #include #include -#include #include #include @@ -187,57 +186,6 @@ static gboolean parse_event(void *hook_data, void *call_data); static LttvModule *main_win_module; -/** - * plugin's init function - * - * This function initializes the Event Viewer functionnality through the - * gtkTraceSet API. - */ -G_MODULE_EXPORT void init(LttvModule *self, int argc, char *argv[]) { - - main_win_module = lttv_module_require(self, "mainwin", argc, argv); - - if(main_win_module == NULL){ - g_critical("Can't load Control Flow Viewer : missing mainwin\n"); - return; - } - - /* Register the toolbar insert button */ - toolbar_item_reg(hGuiEventsInsert_xpm, "Insert Event Viewer", h_gui_events); - - /* Register the menu item insert entry */ - menu_item_reg("/", "Insert Event Viewer", h_gui_events); - -} - -void event_destroy_walk(gpointer data, gpointer user_data) -{ - gui_events_destructor((EventViewerData*)data); -} - -/** - * plugin's destroy function - * - * This function releases the memory reserved by the module and unregisters - * everything that has been registered in the gtkTraceSet API. - */ -G_MODULE_EXPORT void destroy() { - int i; - - EventViewerData *event_viewer_data; - - if(g_event_viewer_data_list){ - g_slist_foreach(g_event_viewer_data_list, event_destroy_walk, NULL ); - g_slist_free(g_event_viewer_data_list); - } - - /* Unregister the toolbar insert button */ - toolbar_item_unreg(h_gui_events); - - /* Unregister the menu item insert entry */ - menu_item_unreg(h_gui_events); -} - /* Enumeration of the columns */ enum { @@ -1888,3 +1836,51 @@ void remove_all_items_from_queue(GQueue *q) } +/** + * plugin's init function + * + * This function initializes the Event Viewer functionnality through the + * gtkTraceSet API. + */ +static void init() { + + /* Register the toolbar insert button */ + toolbar_item_reg(hGuiEventsInsert_xpm, "Insert Event Viewer", h_gui_events); + + /* Register the menu item insert entry */ + menu_item_reg("/", "Insert Event Viewer", h_gui_events); + +} + +void event_destroy_walk(gpointer data, gpointer user_data) +{ + gui_events_destructor((EventViewerData*)data); +} + +/** + * plugin's destroy function + * + * This function releases the memory reserved by the module and unregisters + * everything that has been registered in the gtkTraceSet API. + */ +static void destroy() { + int i; + + EventViewerData *event_viewer_data; + + if(g_event_viewer_data_list){ + g_slist_foreach(g_event_viewer_data_list, event_destroy_walk, NULL ); + g_slist_free(g_event_viewer_data_list); + } + + /* Unregister the toolbar insert button */ + toolbar_item_unreg(h_gui_events); + + /* Unregister the menu item insert entry */ + menu_item_unreg(h_gui_events); +} + + +LTTV_MODULE("guievents", "Detailed events view", \ + "Graphical module to display a detailed event list", \ + init, destroy, "mainwin") diff --git a/ltt/branches/poly/lttv/modules/gui/main/src/callbacks.c b/ltt/branches/poly/lttv/modules/gui/main/src/callbacks.c index f09f7dba..08a58516 100644 --- a/ltt/branches/poly/lttv/modules/gui/main/src/callbacks.c +++ b/ltt/branches/poly/lttv/modules/gui/main/src/callbacks.c @@ -21,7 +21,6 @@ #endif #include -#include #include "callbacks.h" #include "interface.h" @@ -275,10 +274,10 @@ void create_new_window(GtkWidget* widget, gpointer user_data, gboolean clone) if(clone){ g_printf("Clone : use the same traceset\n"); - construct_main_window(parent, NULL); + construct_main_window(parent); }else{ g_printf("Empty : traceset is set to NULL\n"); - construct_main_window(NULL, parent->win_creation_data); + construct_main_window(NULL); } } @@ -1042,10 +1041,7 @@ on_load_module_activate (GtkMenuItem *menuitem, str1 = strrchr(str,'\\'); str1++; } - if(mw_data->win_creation_data) - lttv_module_load(str1, mw_data->win_creation_data->argc,mw_data->win_creation_data->argv); - else - lttv_module_load(str1, 0,NULL); + lttv_module_require(str1, NULL); g_slist_foreach(g_main_window_list, (gpointer)insert_menu_toolbar_item, NULL); g_strfreev(dir); @@ -1068,30 +1064,36 @@ on_unload_module_activate (GtkMenuItem *menuitem, gpointer user_data) { int i; - char **name, *unload_module_name; + GPtrArray *name; + char *unload_module_name; guint nb; - LttvModule ** modules, *module; + LttvLibrary *library; + LttvLibraryInfo library_info; MainWindow * mw_data = get_window_data_struct((GtkWidget*)menuitem); - modules = lttv_module_list(&nb); - name = g_new(char*, nb); + name = g_ptr_array_new(); + nb = lttv_library_number(); + for(i=0;i 0) g_ptr_array_add(name, library_info.name); } - unload_module_name =get_unload_module(name,nb); + unload_module_name =get_unload_module((char **)(name->pdata), name->len); if(unload_module_name){ for(i=0;itab = NULL; new_m_window->current_tab = NULL; new_m_window->attributes = LTTV_IATTRIBUTE(g_object_new(LTTV_ATTRIBUTE_TYPE, NULL)); - if(parent){ - new_m_window->win_creation_data = parent->win_creation_data; - }else{ - new_m_window->win_creation_data = win_creation_data; - } new_m_window->hash_menu_item = g_hash_table_new_full (g_str_hash, g_str_equal, main_window_destroy_hash_key, diff --git a/ltt/branches/poly/lttv/modules/gui/main/src/callbacks.h b/ltt/branches/poly/lttv/modules/gui/main/src/callbacks.h index 95c57c3b..c9166bda 100644 --- a/ltt/branches/poly/lttv/modules/gui/main/src/callbacks.h +++ b/ltt/branches/poly/lttv/modules/gui/main/src/callbacks.h @@ -24,7 +24,7 @@ void create_new_window(GtkWidget* widget, gpointer user_data, gboolean clone); void insert_menu_toolbar_item(MainWindow * mw, gpointer user_data); -void construct_main_window(MainWindow * parent, WindowCreationData *win_creation_data); +void construct_main_window(MainWindow * parent); void main_window_free(MainWindow * mw); void main_window_destructor(MainWindow * mw); diff --git a/ltt/branches/poly/lttv/modules/gui/main/src/init_module.c b/ltt/branches/poly/lttv/modules/gui/main/src/init_module.c index 2539ceaa..781844ad 100644 --- a/ltt/branches/poly/lttv/modules/gui/main/src/init_module.c +++ b/ltt/branches/poly/lttv/modules/gui/main/src/init_module.c @@ -45,9 +45,6 @@ #include -/* global variable */ -static WindowCreationData win_creation_data; - /** Array containing instanced objects. */ GSList * g_main_window_list = NULL ; @@ -79,8 +76,6 @@ void lttv_trace_option(void *hook_data) static gboolean window_creation_hook(void *hook_data, void *call_data) { - WindowCreationData* window_creation_data = (WindowCreationData*)hook_data; - g_debug("GUI window_creation_hook()"); #ifdef ENABLE_NLS bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR); @@ -89,20 +84,20 @@ static gboolean window_creation_hook(void *hook_data, void *call_data) #endif gtk_set_locale (); - gtk_init (&(window_creation_data->argc), &(window_creation_data->argv)); + gtk_init (<tv_argc, <tv_argv); add_pixmap_directory (PACKAGE_DATA_DIR "/" PACKAGE "/pixmaps"); add_pixmap_directory ("pixmaps"); add_pixmap_directory ("../modules/gui/main/pixmaps"); - construct_main_window(NULL, window_creation_data); + construct_main_window(NULL); gtk_main (); return FALSE; } -G_MODULE_EXPORT void init(LttvModule *self, int argc, char *argv[]) { +static void init() { LttvAttributeValue value; @@ -120,10 +115,7 @@ G_MODULE_EXPORT void init(LttvModule *self, int argc, char *argv[]) { LTTV_POINTER, &value)); g_assert((main_hooks = *(value.v_pointer)) != NULL); - win_creation_data.argc = argc; - win_creation_data.argv = argv; - - lttv_hooks_add(main_hooks, window_creation_hook, &win_creation_data); + lttv_hooks_add(main_hooks, window_creation_hook, NULL); } @@ -174,14 +166,14 @@ void main_window_destroy_walk(gpointer data, gpointer user_data) * This function releases the memory reserved by the module and unregisters * everything that has been registered in the gtkTraceSet API. */ -G_MODULE_EXPORT void destroy() { +static void destroy() { LttvAttributeValue value; LttvTrace *trace; lttv_option_remove("trace"); - lttv_hooks_remove_data(main_hooks, window_creation_hook, &win_creation_data); + lttv_hooks_remove_data(main_hooks, window_creation_hook, NULL); g_debug("GUI destroy()"); @@ -193,5 +185,6 @@ G_MODULE_EXPORT void destroy() { } - - +LTTV_MODULE("mainwin", "Viewer main window", \ + "Viewer with multiple windows, tabs and panes for graphical modules", \ + init, destroy, "stats") diff --git a/ltt/branches/poly/lttv/modules/gui/statistics/statistics.c b/ltt/branches/poly/lttv/modules/gui/statistics/statistics.c index 9bd4b8d6..101f83e9 100644 --- a/ltt/branches/poly/lttv/modules/gui/statistics/statistics.c +++ b/ltt/branches/poly/lttv/modules/gui/statistics/statistics.c @@ -17,7 +17,6 @@ */ #include -#include #include #include @@ -116,59 +115,6 @@ struct _StatisticViewerData{ }; -/** - * plugin's init function - * - * This function initializes the Statistic Viewer functionnality through the - * gtkTraceSet API. - */ -G_MODULE_EXPORT void init(LttvModule *self, int argc, char *argv[]) { - - statistic_main_win_module = lttv_module_require(self, "mainwin", argc, argv); - - if(statistic_main_win_module == NULL){ - g_critical("Can't load Statistic Viewer : missing mainwin\n"); - return; - } - - statistic_traceset = g_ptr_array_new (); - - /* Register the toolbar insert button */ - toolbar_item_reg(hGuiStatisticInsert_xpm, "Insert Statistic Viewer", h_gui_statistic); - - /* Register the menu item insert entry */ - menu_item_reg("/", "Insert Statistic Viewer", h_gui_statistic); - -} - -void statistic_destroy_walk(gpointer data, gpointer user_data) -{ - gui_statistic_destructor((StatisticViewerData*)data); -} - -/** - * plugin's destroy function - * - * This function releases the memory reserved by the module and unregisters - * everything that has been registered in the gtkTraceSet API. - */ -G_MODULE_EXPORT void destroy() { - int i; - - if(g_statistic_viewer_data_list){ - g_slist_foreach(g_statistic_viewer_data_list, statistic_destroy_walk, NULL ); - g_slist_free(g_statistic_viewer_data_list); - } - g_ptr_array_free (statistic_traceset, TRUE); - - /* Unregister the toolbar insert button */ - toolbar_item_unreg(h_gui_statistic); - - /* Unregister the menu item insert entry */ - menu_item_unreg(h_gui_statistic); -} - - void gui_statistic_free(StatisticViewerData *statistic_viewer_data) { @@ -693,3 +639,53 @@ void statistic_remove_context_hooks(StatisticViewerData * statistic_viewer_data, } +/** + * plugin's init function + * + * This function initializes the Statistic Viewer functionnality through the + * gtkTraceSet API. + */ +static void init() { + + statistic_traceset = g_ptr_array_new (); + + /* Register the toolbar insert button */ + toolbar_item_reg(hGuiStatisticInsert_xpm, "Insert Statistic Viewer", h_gui_statistic); + + /* Register the menu item insert entry */ + menu_item_reg("/", "Insert Statistic Viewer", h_gui_statistic); + +} + +void statistic_destroy_walk(gpointer data, gpointer user_data) +{ + gui_statistic_destructor((StatisticViewerData*)data); +} + +/** + * plugin's destroy function + * + * This function releases the memory reserved by the module and unregisters + * everything that has been registered in the gtkTraceSet API. + */ +static void destroy() { + int i; + + if(g_statistic_viewer_data_list){ + g_slist_foreach(g_statistic_viewer_data_list, statistic_destroy_walk, NULL ); + g_slist_free(g_statistic_viewer_data_list); + } + g_ptr_array_free (statistic_traceset, TRUE); + + /* Unregister the toolbar insert button */ + toolbar_item_unreg(h_gui_statistic); + + /* Unregister the menu item insert entry */ + menu_item_unreg(h_gui_statistic); +} + + +LTTV_MODULE("guistatistics", "Statistics viewer", \ + "Graphical module to view statistics about processes, CPUs and systems", \ + init, destroy, "mainwin") + diff --git a/ltt/branches/poly/lttv/modules/text/batchAnalysis.c b/ltt/branches/poly/lttv/modules/text/batchAnalysis.c index f26ed39a..0d8f1522 100644 --- a/ltt/branches/poly/lttv/modules/text/batchAnalysis.c +++ b/ltt/branches/poly/lttv/modules/text/batchAnalysis.c @@ -104,7 +104,7 @@ static gboolean process_traceset(void *hook_data, void *call_data) } -G_MODULE_EXPORT void init(LttvModule *self, int argc, char **argv) +static void init() { LttvAttributeValue value; @@ -167,7 +167,7 @@ G_MODULE_EXPORT void init(LttvModule *self, int argc, char **argv) } -G_MODULE_EXPORT void destroy() +static void destroy() { guint i, nb; @@ -198,3 +198,7 @@ G_MODULE_EXPORT void destroy() lttv_traceset_destroy(traceset); } + +LTTV_MODULE("batchAnalysis", "Batch processing of a trace", \ + "Run through a trace calling all the registered hooks", \ + init, destroy, "state", "stats", "option") diff --git a/ltt/branches/poly/lttv/modules/text/batchtest.c b/ltt/branches/poly/lttv/modules/text/batchtest.c new file mode 100644 index 00000000..41b5fffe --- /dev/null +++ b/ltt/branches/poly/lttv/modules/text/batchtest.c @@ -0,0 +1,569 @@ +/* This file is part of the Linux Trace Toolkit viewer + * Copyright (C) 2003-2004 Michel Dagenais + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License Version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. + */ + +/* This module inserts a hook in the program main loop. This hook processes + all the events in the main tracefile while testing the speed and + functionality of the state and stats computations. */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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; + +static char *a_dump_tracefiles; + +static char *a_save_sample; + +static int + a_sample_interval, + a_sample_number, + a_save_interval; + +static gboolean + a_test1, + a_test2, + a_test3, + a_test4, + a_test5, + a_test6, + a_test7, + a_test_all; + +typedef struct _save_state { + guint count; + FILE *fp; + guint interval; + guint position; + guint size; + LttTime *write_time; + guint version; +} SaveState; + + +static 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, lttv_trace_new(trace)); +} + +static double get_time() +{ + GTimeVal gt; + + g_get_current_time(>); + return gt.tv_sec + (double)gt.tv_usec / (double)1000000.0; +} + +static double run_one_test(LttvTracesetState *ts, LttTime start, LttTime end) +{ + double t0, t1; + + lttv_traceset_context_add_hooks(&ts->parent, + before_traceset, after_traceset, NULL, before_trace, after_trace, + NULL, before_tracefile, after_tracefile, NULL, before_event, after_event); + + t0 = get_time(); + lttv_state_traceset_seek_time_closest(ts, start); + lttv_process_traceset(&ts->parent, end, G_MAXULONG); + t1 = get_time(); + + lttv_traceset_context_remove_hooks(&ts->parent, + before_traceset, after_traceset, NULL, before_trace, after_trace, + NULL, before_tracefile, after_tracefile, NULL, before_event, after_event); + + return t1 - t0; +} + + +gboolean count_event(void *hook_data, void *call_data) +{ + guint *pcount = (guint *)hook_data; + + (*pcount)++; + return FALSE; +} + + +gboolean save_state_event(void *hook_data, void *call_data) +{ + SaveState *save_state = (SaveState *)hook_data; + + LttvTracefileState *tfs = (LttvTracefileState *)call_data; + + LttvTraceState *ts = (LttvTraceState *)tfs->parent.t_context; + + GString *filename; + + FILE *fp; + + (save_state->count)++; + if(save_state->count % save_state->interval == 0 && + save_state->position < save_state->size) { + if(a_save_sample != NULL) { + filename = g_string_new(""); + g_string_printf(filename, "%s.%u.xml.%u", a_save_sample, + save_state->position, save_state->version); + fp = fopen(filename->str, "w"); + if(fp == NULL) g_error("Cannot open %s", filename->str); + g_string_free(filename, TRUE); + lttv_state_write(ts, tfs->parent.timestamp, fp); + fclose(fp); + } else lttv_state_write(ts, tfs->parent.timestamp, save_state->fp); + + save_state->write_time[save_state->position] = tfs->parent.timestamp; + save_state->position++; + } + return FALSE; +} + + +static gboolean process_traceset(void *hook_data, void *call_data) +{ + LttvTracesetStats *tscs; + + LttvTracesetState *ts; + + LttvTracesetContext *tc; + + GString *filename; + + FILE *fp; + + double t; + + guint i, j, count, nb_control, nb_tracefile, nb_block, nb_event, nb_equal; + + LttTrace *trace; + + LttTracefile *tracefile, *tf; + + LttEvent *event; + + LttFacility *facility; + + LttType *type; + + LttEventType *event_type; + + LttTime time, previous_time; + + LttEventPosition *event_position; + + LttTime zero_time = ltt_time_zero; + + LttTime max_time = { G_MAXULONG, G_MAXULONG }; + + if(a_dump_tracefiles != NULL) { + event_position = ltt_event_position_new(); + for(i = 0 ; i < lttv_traceset_number(traceset) ; i++) { + trace = lttv_trace(lttv_traceset_get(traceset, i)); + nb_control = ltt_trace_control_tracefile_number(trace); + nb_tracefile = nb_control + ltt_trace_per_cpu_tracefile_number(trace); + for(j = 0 ; j < nb_tracefile ; j++) { + if(j < nb_control) { + tracefile = ltt_trace_control_tracefile_get(trace,j); + } + else { + tracefile = ltt_trace_per_cpu_tracefile_get(trace,j - nb_control); + } + + filename = g_string_new(""); + g_string_printf(filename, "%s.%u.%u.trace", a_dump_tracefiles, i, j); + fp = fopen(filename->str, "w"); + if(fp == NULL) g_error("Cannot open %s", filename->str); + g_string_free(filename, TRUE); + ltt_tracefile_seek_time(tracefile, zero_time); + previous_time = zero_time; + nb_equal = 0; + while((event = ltt_tracefile_read(tracefile)) != NULL) { + facility = ltt_event_facility(event); + event_type = ltt_event_eventtype(event); + time = ltt_event_time(event); + ltt_event_position(event, event_position); + ltt_event_position_get(event_position, &nb_block, &nb_event, &tf); + fprintf(fp,"%s.%s: %lu.%09lu position %u/%u\n", + ltt_facility_name(facility), ltt_eventtype_name(event_type), + (long)time.tv_sec, time.tv_nsec, nb_block, nb_event); + + if(ltt_time_compare(time, previous_time) == 0) nb_equal++; + else if(nb_equal > 0) { + g_warning("Consecutive %d events with time %lu.%lu", + nb_equal + 1, previous_time.tv_sec, previous_time.tv_nsec); + nb_equal = 0; + } + + if(ltt_time_compare(time, previous_time) < 0) { + g_warning("Time decreasing trace %d tracefile %d position %u/%u", + i, j, nb_block, nb_event); + } + previous_time = time; + } + fclose(fp); + } + } + g_free(event_position); + } + + tscs = g_object_new(LTTV_TRACESET_STATS_TYPE, NULL); + ts = &tscs->parent; + tc = &tscs->parent.parent; + + lttv_context_init(tc, traceset); + for(i = 0 ; i < lttv_traceset_number(traceset) ; i++) { + ((LttvTraceState *)(tc->traces[i]))->save_interval = a_save_interval; + } + + /* For each case compute and print the elapsed time. + The first case is simply to run through all events with a + simple counter. */ + + if(a_test1 || a_test_all) { + count = 0; + lttv_hooks_add(after_event, count_event, &count); + t = run_one_test(ts, zero_time, max_time); + lttv_hooks_remove_data(after_event, count_event, &count); + g_warning( + "Processing trace while counting events (%u events in %g seconds)", + count, t); + } + + /* Run through all events computing the state. */ + + if(a_test2 || a_test_all) { + lttv_state_add_event_hooks(ts); + t = run_one_test(ts, zero_time, max_time); + lttv_state_remove_event_hooks(ts); + g_warning("Processing trace while updating state (%g seconds)", t); + } + + /* Run through all events computing the state and writing it out + periodically. */ + + SaveState save_state; + + save_state.interval = a_sample_interval; + save_state.size = a_sample_number; + save_state.fp = stderr; + save_state.write_time = g_new(LttTime, a_sample_number); + + + if(a_test3 || a_test_all) { + for(i = 0 ; i < 2 ; i++) { + save_state.count = 0; + save_state.position = 0; + save_state.version = i; + lttv_state_add_event_hooks(ts); + lttv_hooks_add(after_event, save_state_event, &save_state); + t = run_one_test(ts, zero_time, max_time); + lttv_state_remove_event_hooks(ts); + lttv_hooks_remove_data(after_event, save_state_event, &save_state); + g_warning("Processing while updating/writing state (%g seconds)", t); + } + } + + /* Run through all events computing the stats. */ + + if(a_test4 || a_test_all) { + if(lttv_profile_memory) { + g_message("Memory summary before computing stats"); + g_mem_profile(); + } + + lttv_stats_add_event_hooks(tscs); + t = run_one_test(ts, zero_time, max_time); + lttv_stats_remove_event_hooks(tscs); + g_warning("Processing trace while counting stats (%g seconds)", t); + + if(lttv_profile_memory) { + g_message("Memory summary after computing stats"); + g_mem_profile(); + } + } + + /* Run through all events computing the state and stats. */ + + if(a_test5 || a_test_all) { + if(lttv_profile_memory) { + g_message("Memory summary before computing state and stats"); + g_mem_profile(); + } + + lttv_state_add_event_hooks(ts); + lttv_stats_add_event_hooks(tscs); + t = run_one_test(ts, zero_time, max_time); + lttv_state_remove_event_hooks(ts); + lttv_stats_remove_event_hooks(tscs); + g_warning( + "Processing trace while counting state and stats (%g seconds)", t); + + if(lttv_profile_memory) { + g_message("Memory summary after computing and state and stats"); + g_mem_profile(); + } + } + + /* Run through all events computing and saving the state. */ + + if(a_test6 || a_test_all) { + if(lttv_profile_memory) { + g_message("Memory summary before computing and saving state"); + g_mem_profile(); + } + + lttv_state_add_event_hooks(ts); + lttv_state_save_add_event_hooks(ts); + t = run_one_test(ts, zero_time, max_time); + lttv_state_remove_event_hooks(ts); + lttv_state_save_remove_event_hooks(ts); + g_warning("Processing trace while updating/saving state (%g seconds)", t); + + if(lttv_profile_memory) { + g_message("Memory summary after computing/saving state"); + g_mem_profile(); + } + } + + /* Seek a few times to each saved position */ + + if((a_test7 && a_test3) || a_test_all) { + int i, j; + + for(i = 0 ; i < 2 ; i++) { + for(j = save_state.position - 1 ; j >= 0 ; j--) { + lttv_state_add_event_hooks(ts); + t = run_one_test(ts, save_state.write_time[j], + save_state.write_time[j]); + lttv_state_remove_event_hooks(ts); + g_warning("Seeking to %lu.%lu (%g seconds)", + save_state.write_time[j].tv_sec, save_state.write_time[j].tv_nsec, + t); + + if(a_save_sample != NULL) { + filename = g_string_new(""); + g_string_printf(filename, "%s.%d.xml.bak%d", a_save_sample, j, i); + fp = fopen(filename->str, "w"); + if(fp == NULL) g_error("Cannot open %s", filename->str); + g_string_free(filename, TRUE); + lttv_state_write((LttvTraceState *)tc->traces[0], + save_state.write_time[j], fp); + fclose(fp); + } + else lttv_state_write((LttvTraceState *)tc->traces[0], + save_state.write_time[j], save_state.fp); + } + } + } + + g_free(save_state.write_time); + lttv_context_fini(tc); + g_object_unref(tscs); + + g_info("BatchTest end process traceset"); +} + + +static void init() +{ + LttvAttributeValue value; + + LttvIAttribute *attributes = LTTV_IATTRIBUTE(lttv_global_attributes()); + + g_info("Init batchtest.c"); + + lttv_option_add("trace", 't', + "add a trace to the trace set to analyse", + "pathname of the directory containing the trace", + LTTV_OPT_STRING, &a_trace, lttv_trace_option, NULL); + + a_dump_tracefiles = NULL; + lttv_option_add("dump-tracefiles", 'D', + "Write event by event the content of tracefiles", + "basename for the files where to dump events", + LTTV_OPT_STRING, &a_dump_tracefiles, NULL, NULL); + + a_save_sample = NULL; + lttv_option_add("save-sample", 's', + "Save state samples to multiple files", + "basename for the files containing the state samples", + LTTV_OPT_STRING, &a_save_sample, NULL, NULL); + + a_save_interval = 100000; + lttv_option_add("save-interval", 'i', + "Interval between saving state", + "number of events before a block start triggers saving state", + LTTV_OPT_INT, &a_save_interval, NULL, NULL); + + a_sample_interval = 100000; + lttv_option_add("sample-interval", 'S', + "Interval between sampling state", + "number of events before sampling and writing state", + LTTV_OPT_INT, &a_sample_interval, NULL, NULL); + + a_sample_number = 20; + lttv_option_add("sample-number", 'N', + "Number of state samples", + "maximum number", + LTTV_OPT_INT, &a_sample_number, NULL, NULL); + + a_test1 = FALSE; + lttv_option_add("test1", '1', "Test just counting events", "", + LTTV_OPT_NONE, &a_test1, NULL, NULL); + + a_test2 = FALSE; + lttv_option_add("test2", '2', "Test computing the state", "", + LTTV_OPT_NONE, &a_test2, NULL, NULL); + + a_test3 = FALSE; + lttv_option_add("test3", '3', "Test computing the state, writing out a few", + "", LTTV_OPT_NONE, &a_test3, NULL, NULL); + + a_test4 = FALSE; + lttv_option_add("test4", '4', "Test computing the stats", "", + LTTV_OPT_NONE, &a_test4, NULL, NULL); + + a_test5 = FALSE; + lttv_option_add("test5", '5', "Test computing the state and stats", "", + LTTV_OPT_NONE, &a_test5, NULL, NULL); + + a_test6 = FALSE; + lttv_option_add("test6", '6', "Test computing and saving the state", "", + LTTV_OPT_NONE, &a_test6, NULL, NULL); + + a_test7 = FALSE; + lttv_option_add("test7", '7', "Test seeking to positions written out in 3", + "", LTTV_OPT_NONE, &a_test7, NULL, NULL); + + a_test_all = FALSE; + lttv_option_add("testall", 'a', "Run all tests ", "", + LTTV_OPT_NONE, &a_test_all, NULL, 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); +} + + +static void destroy() +{ + guint i, nb; + + LttvTrace *trace; + + g_info("Destroy batchAnalysis.c"); + + lttv_option_remove("trace"); + lttv_option_remove("dump-tracefiles"); + lttv_option_remove("save-sample"); + lttv_option_remove("sample-interval"); + lttv_option_remove("sample-number"); + lttv_option_remove("save-interval"); + lttv_option_remove("test1"); + lttv_option_remove("test2"); + lttv_option_remove("test3"); + lttv_option_remove("test4"); + lttv_option_remove("test5"); + lttv_option_remove("test6"); + lttv_option_remove("test7"); + lttv_option_remove("testall"); + + 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); + lttv_hooks_remove_data(main_hooks, process_traceset, NULL); + + nb = lttv_traceset_number(traceset); + for(i = 0 ; i < nb ; i++) { + trace = lttv_traceset_get(traceset, i); + ltt_trace_close(lttv_trace(trace)); + lttv_trace_destroy(trace); + } + + lttv_traceset_destroy(traceset); +} + + +LTTV_MODULE("batchtest", "Batch processing of a trace for tests", \ + "Run through a trace calling all the registered hooks for tests", \ + init, destroy, "state", "stats", "option" ) diff --git a/ltt/branches/poly/lttv/modules/text/textDump.c b/ltt/branches/poly/lttv/modules/text/textDump.c index bafef11f..c105a07c 100644 --- a/ltt/branches/poly/lttv/modules/text/textDump.c +++ b/ltt/branches/poly/lttv/modules/text/textDump.c @@ -329,7 +329,7 @@ static int write_event_content(void *hook_data, void *call_data) } -G_MODULE_EXPORT void init(LttvModule *self, int argc, char **argv) +static void init() { LttvAttributeValue value; @@ -337,8 +337,6 @@ G_MODULE_EXPORT void init(LttvModule *self, int argc, char **argv) g_info("Init textDump.c"); - lttv_module_require(self, "libbatchAnalysis", argc, argv); - a_string = g_string_new(""); a_file_name = NULL; @@ -393,7 +391,7 @@ G_MODULE_EXPORT void init(LttvModule *self, int argc, char **argv) } -G_MODULE_EXPORT void destroy() +static void destroy() { g_info("Destroy textDump"); @@ -419,5 +417,10 @@ G_MODULE_EXPORT void destroy() } +LTTV_MODULE("textDump", "Print events in a file", \ + "Produce a detailed text printout of a trace", \ + init, destroy, "stats", "batchAnalysis") + + -- 2.34.1