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
#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
#include <lttv/hook.h>
#include <lttv/stats.h>
-typedef struct _WindowCreationData {
- int argc;
- char ** argv;
-} WindowCreationData;
-
-
typedef struct _TracesetInfo {
//FIXME? TracesetContext and stats in same or different variable ?
LttvTracesetStats * traceset_context;
Tab * tab;
Tab * current_tab;
- WindowCreationData * win_creation_data;
-
GHashTable * hash_menu_item;
GHashTable * hash_toolbar_item;
};
#ifndef MODULES_H
#define MODULES_H
-#include <gmodule.h>
+#include <glib.h>
-/* 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
+
+
+
+
+
+
#include <lttv/traceset.h>
#include <ltt/trace.h>
#include <stdio.h>
-#include <mcheck.h>
-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 */
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);
LttvAttributeValue value;
+ lttv_argc = argc;
+ lttv_argv = argv;
/* Before anything else, check if memory profiling is requested */
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();
/* 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 */
/* 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);
g_message("Memory summary after main");
g_mem_profile();
}
+ return 0;
}
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);
}
/*
-- 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.
+
/* This file is part of the Linux Trace Toolkit viewer
* Copyright (C) 2003-2004 Michel Dagenais
*
*/
-/* module.c : Implementation of the module loading/unloading mechanism.
- *
- */
+/* module.c : Implementation of the module loading/unloading mechanism. */
#include <lttv/module.h>
+#include <gmodule.h>
+
+
+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)
+
#include <popt.h>
#include <glib.h>
+#include <lttv/module.h>
#include <lttv/option.h>
typedef struct _LttvOption {
}
-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,
destroy_popts(&list, &popts, &c);
}
+/* CHECK */
static void show_help(LttvOption *option)
{
printf("--%s -%c argument: %s\n" , option->long_name,
}
+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)
*/
+#include <lttv/lttv.h>
+#include <lttv/module.h>
#include <lttv/state.h>
#include <ltt/facility.h>
#include <ltt/trace.h>
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);
for(i = 0 ; i < nb_tracefile ; i++) {
tfcs = (LttvTracefileState *)self->parent.tracefiles[i];
- fprintf(fp, " <TRACEFILE PID=%u", tfcs->process->pid);
+ fprintf(fp, " <TRACEFILE PID=%u TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
+ tfcs->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);
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);
}
}
}
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),
}
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;
}
}
-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;
*(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;
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);
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);
}
}
}
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);
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);
}
}
}
}
-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");
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)
+
#include <stdio.h>
+#include <lttv/module.h>
#include <lttv/stats.h>
#include <lttv/lttv.h>
#include <ltt/facility.h>
}
-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;
char filename[BUF_SIZE];
GMarkupParseContext * context;
- GError * error;
+ GError * error = NULL;
GMarkupParser markup_parser =
{
stats_parser_start_element,
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");
/* Created by Mathieu Desnoyers, may 2003 */
#include <glib.h>
-#include <gmodule.h>
/* Include module.h from lttv headers for module loading */
#include <lttv/module.h>
-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" })
+
/* Created by Mathieu Desnoyers, may 2003 */
#include <glib.h>
-#include <gmodule.h>
+#include <lttv/module.h>
-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, {})
+
/* Created by Mathieu Desnoyers, may 2003 */
#include <glib.h>
-#include <gmodule.h>
+#include <lttv/module.h>
-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, {})
+
*/
#include <glib.h>
-#include <gmodule.h>
#include <lttv/lttv.h>
#include <lttv/module.h>
#include <lttv/gtktraceset.h>
* 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 */
* 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;
menu_item_unreg(h_guicontrolflow);
}
+
+
+LTTV_MODULE("guicontrolflow", "Control flow viewer", \
+ "Graphical module to view processes state and control flow", \
+ init, destroy, "mainwin")
#include <math.h>
#include <glib.h>
-#include <gmodule.h>
#include <gtk/gtk.h>
#include <gdk/gdk.h>
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
{
}
+/**
+ * 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")
#endif
#include <gtk/gtk.h>
-#include <gmodule.h>
#include "callbacks.h"
#include "interface.h"
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);
}
}
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);
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<nb;i++){
- module = modules[i];
- name[i] = lttv_module_name(module);
+ library = lttv_library_get(i);
+ lttv_library_info(library, &library_info);
+ if(library_info.load_count > 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;i<nb;i++){
- if(strcmp(unload_module_name, name[i]) == 0){
- lttv_module_unload(modules[i]);
+ library = lttv_library_get(i);
+ lttv_library_info(library, &library_info);
+ if(strcmp(unload_module_name, library_info.name) == 0){
+ lttv_library_unload(library);
break;
}
}
}
- g_free(name);
+ g_ptr_array_free(name, TRUE);
}
case GTK_RESPONSE_ACCEPT:
case GTK_RESPONSE_OK:
dir = gtk_dir_selection_get_dir (file_selector);
- lttv_module_path_add(dir);
+ lttv_library_path_add(dir);
case GTK_RESPONSE_REJECT:
case GTK_RESPONSE_CANCEL:
default:
/* Create a main window
*/
-void construct_main_window(MainWindow * parent, WindowCreationData * win_creation_data)
+void construct_main_window(MainWindow * parent)
{
g_debug("construct_main_window()");
GtkWidget * new_window; /* New generated main window */
new_m_window->tab = 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,
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);
#include <ltt/trace.h>
-/* global variable */
-static WindowCreationData win_creation_data;
-
/** Array containing instanced objects. */
GSList * g_main_window_list = NULL ;
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);
#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;
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);
}
* 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()");
}
-
-
+LTTV_MODULE("mainwin", "Viewer main window", \
+ "Viewer with multiple windows, tabs and panes for graphical modules", \
+ init, destroy, "stats")
*/
#include <glib.h>
-#include <gmodule.h>
#include <gtk/gtk.h>
#include <gdk/gdk.h>
};
-/**
- * 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)
{
}
+/**
+ * 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")
+
}
-G_MODULE_EXPORT void init(LttvModule *self, int argc, char **argv)
+static void init()
{
LttvAttributeValue value;
}
-G_MODULE_EXPORT void destroy()
+static void destroy()
{
guint i, nb;
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")
--- /dev/null
+/* 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 <lttv/lttv.h>
+#include <lttv/attribute.h>
+#include <lttv/hook.h>
+#include <lttv/option.h>
+#include <lttv/module.h>
+#include <lttv/processTrace.h>
+#include <lttv/state.h>
+#include <lttv/stats.h>
+#include <ltt/trace.h>
+#include <ltt/event.h>
+
+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" )
}
-G_MODULE_EXPORT void init(LttvModule *self, int argc, char **argv)
+static void init()
{
LttvAttributeValue value;
g_info("Init textDump.c");
- lttv_module_require(self, "libbatchAnalysis", argc, argv);
-
a_string = g_string_new("");
a_file_name = NULL;
}
-G_MODULE_EXPORT void destroy()
+static void destroy()
{
g_info("Destroy textDump");
}
+LTTV_MODULE("textDump", "Print events in a file", \
+ "Produce a detailed text printout of a trace", \
+ init, destroy, "stats", "batchAnalysis")
+
+