From 9a9ca632e32af79f5f77894ef6e981ac0138102a Mon Sep 17 00:00:00 2001 From: Benjamin Poirier Date: Tue, 27 Oct 2009 13:56:25 -0400 Subject: [PATCH] Add a batchanalysis module to build and run a sync chain This is mostly to build a sync chain with an analysis module that evaluates the quality of synchronization. It does not modifiy the time correction factors in the traces. Signed-off-by: Benjamin Poirier --- lttv/lttv/iattribute.c | 4 +- lttv/lttv/iattribute.h | 2 +- lttv/lttv/sync/README | 2 + .../lttv/sync/event_processing_lttng_common.h | 1 + .../sync/event_processing_lttng_standard.c | 4 +- lttv/lttv/sync/sync_chain_lttv.c | 63 ++- lttv/lttv/sync/sync_chain_lttv.h | 6 + lttv/modules/text/Makefile.am | 3 +- lttv/modules/text/sync_chain_batch.c | 507 ++++++++++++++++++ runlttv | 5 +- 10 files changed, 568 insertions(+), 29 deletions(-) create mode 100644 lttv/modules/text/sync_chain_batch.c diff --git a/lttv/lttv/iattribute.c b/lttv/lttv/iattribute.c index 0271dddb..fe50fb63 100644 --- a/lttv/lttv/iattribute.c +++ b/lttv/lttv/iattribute.c @@ -146,7 +146,7 @@ gboolean lttv_iattribute_find(LttvIAttribute *self, LttvAttributeName name, /* Trees of attribute tables may be accessed using a hierarchical path with components separated by /, like in filesystems */ -gboolean lttv_iattribute_find_by_path(LttvIAttribute *self, char *path, +gboolean lttv_iattribute_find_by_path(LttvIAttribute *self, const char *path, LttvAttributeType t, LttvAttributeValue *v) { LttvIAttribute *node = self; @@ -177,7 +177,7 @@ gboolean lttv_iattribute_find_by_path(LttvIAttribute *self, char *path, if(found_type == LTTV_NONE) { node = lttv_iattribute_find_subdir(node, name); } - else if(found_type == LTTV_GOBJECT && + else if(found_type == LTTV_GOBJECT && LTTV_IS_IATTRIBUTE(*(v->v_gobject))) { node = LTTV_IATTRIBUTE(*(v->v_gobject)); } diff --git a/lttv/lttv/iattribute.h b/lttv/lttv/iattribute.h index cbda045f..29227090 100644 --- a/lttv/lttv/iattribute.h +++ b/lttv/lttv/iattribute.h @@ -179,7 +179,7 @@ gboolean lttv_iattribute_find(LttvIAttribute *self, LttvAttributeName name, /* Trees of attribute tables may be accessed using a hierarchical path with components separated by /, like in filesystems */ -gboolean lttv_iattribute_find_by_path(LttvIAttribute *self, char *path, +gboolean lttv_iattribute_find_by_path(LttvIAttribute *self, const char *path, LttvAttributeType t, LttvAttributeValue *v); diff --git a/lttv/lttv/sync/README b/lttv/lttv/sync/README index 25f9a719..6310db87 100644 --- a/lttv/lttv/sync/README +++ b/lttv/lttv/sync/README @@ -34,6 +34,8 @@ to make sure the following markers are enabled: * dev_xmit_extended * tcpv4_rcv_extended * udpv4_rcv_extended +You can use the 'ltt-armall' and 'ltt-armnetsync' scripts for this. + You also have to make sure there is some TCP traffic between the traced nodes. ++ Viewing traces diff --git a/lttv/lttv/sync/event_processing_lttng_common.h b/lttv/lttv/sync/event_processing_lttng_common.h index 14ed7c15..7a710f74 100644 --- a/lttv/lttv/sync/event_processing_lttng_common.h +++ b/lttv/lttv/sync/event_processing_lttng_common.h @@ -20,6 +20,7 @@ #define EVENT_PROCESSING_LTTNG_COMMON_H #include +#include #include diff --git a/lttv/lttv/sync/event_processing_lttng_standard.c b/lttv/lttv/sync/event_processing_lttng_standard.c index a8c08aaf..489dec5f 100644 --- a/lttv/lttv/sync/event_processing_lttng_standard.c +++ b/lttv/lttv/sync/event_processing_lttng_standard.c @@ -380,12 +380,12 @@ static gboolean processEventLTTVStandard(void* hookData, void* callData) traceHook= (LttvTraceHook*) hookData; tfc= (LttvTracefileContext*) callData; + trace= tfc->t_context->t; syncState= (SyncState*) traceHook->hook_data; processingData= (ProcessingDataLTTVStandard*) syncState->processingData; event= ltt_tracefile_get_event(tfc->tf); time= ltt_event_time(event); - tsc= ltt_event_cycle_count(event); - trace= tfc->t_context->t; + tsc= trace->drift * ltt_event_cycle_count(event) + trace->offset; info= marker_get_info_from_id(tfc->tf->mdata, event->event_id); g_assert(g_hash_table_lookup_extended(processingData->traceNumTable, diff --git a/lttv/lttv/sync/sync_chain_lttv.c b/lttv/lttv/sync/sync_chain_lttv.c index 2479512f..2003e95f 100644 --- a/lttv/lttv/sync/sync_chain_lttv.c +++ b/lttv/lttv/sync/sync_chain_lttv.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include @@ -45,10 +44,6 @@ static void init(); static void destroy(); -static void timeDiff(struct timeval* const end, const struct timeval* const start); - -static gint gcfCompareAnalysis(gconstpointer a, gconstpointer b); -static gint gcfCompareProcessing(gconstpointer a, gconstpointer b); static void gfAppendAnalysisName(gpointer data, gpointer user_data); static gboolean optionSync; @@ -155,9 +150,7 @@ void syncTraceset(LttvTracesetContext* const traceSetContext) struct timeval startTime, endTime; struct rusage startUsage, endUsage; GList* result; - char* cwd; FILE* graphsStream; - int graphsFp; int retval; if (optionSync == FALSE) @@ -213,6 +206,9 @@ void syncTraceset(LttvTracesetContext* const traceSetContext) if (syncState->graphs && syncState->processingModule->writeProcessingGraphsPlots != NULL) { + char* cwd; + int graphsFp; + // Create the graph directory right away in case the module initialization // functions have something to write in it. cwd= changeToGraphDir(syncState->graphs); @@ -372,7 +368,7 @@ void syncTraceset(LttvTracesetContext* const traceSetContext) * end: end time, result is also stored in this structure * start: start time */ -static void timeDiff(struct timeval* const end, const struct timeval* const start) +void timeDiff(struct timeval* const end, const struct timeval* const start) { if (end->tv_usec >= start->tv_usec) { @@ -391,21 +387,44 @@ static void timeDiff(struct timeval* const end, const struct timeval* const star * A GCompareFunc for g_slist_find_custom() * * Args: - * a: AnalysisModule*, element's data + * a: ProcessingModule*, element's data * b: char*, user data to compare against * * Returns: - * 0 if the analysis module a's name is b + * 0 if the processing module a's name is b */ -static gint gcfCompareAnalysis(gconstpointer a, gconstpointer b) +gint gcfCompareProcessing(gconstpointer a, gconstpointer b) { - const AnalysisModule* analysisModule; + const ProcessingModule* processingModule; const char* name; - analysisModule= (const AnalysisModule*)a; - name= (const char*)b; + processingModule= (const ProcessingModule*) a; + name= (const char*) b; - return strncmp(analysisModule->name, name, strlen(analysisModule->name) + + return strncmp(processingModule->name, name, + strlen(processingModule->name) + 1); +} + + +/* + * A GCompareFunc for g_slist_find_custom() + * + * Args: + * a: MatchingModule*, element's data + * b: char*, user data to compare against + * + * Returns: + * 0 if the matching module a's name is b + */ +gint gcfCompareMatching(gconstpointer a, gconstpointer b) +{ + const MatchingModule* matchingModule; + const char* name; + + matchingModule= (const MatchingModule*) a; + name= (const char*) b; + + return strncmp(matchingModule->name, name, strlen(matchingModule->name) + 1); } @@ -414,22 +433,22 @@ static gint gcfCompareAnalysis(gconstpointer a, gconstpointer b) * A GCompareFunc for g_slist_find_custom() * * Args: - * a: ProcessingModule*, element's data + * a: AnalysisModule*, element's data * b: char*, user data to compare against * * Returns: * 0 if the analysis module a's name is b */ -static gint gcfCompareProcessing(gconstpointer a, gconstpointer b) +gint gcfCompareAnalysis(gconstpointer a, gconstpointer b) { - const ProcessingModule* processingModule; + const AnalysisModule* analysisModule; const char* name; - processingModule= (const ProcessingModule*)a; - name= (const char*)b; + analysisModule= (const AnalysisModule*) a; + name= (const char*) b; - return strncmp(processingModule->name, name, - strlen(processingModule->name) + 1); + return strncmp(analysisModule->name, name, strlen(analysisModule->name) + + 1); } diff --git a/lttv/lttv/sync/sync_chain_lttv.h b/lttv/lttv/sync/sync_chain_lttv.h index a6a460b0..1f7a273b 100644 --- a/lttv/lttv/sync/sync_chain_lttv.h +++ b/lttv/lttv/sync/sync_chain_lttv.h @@ -20,6 +20,7 @@ #define SYNC_CHAIN_LTTV_H #include +#include #include "event_processing.h" #include "event_matching.h" @@ -47,5 +48,10 @@ extern GQueue analysisModules; void syncTraceset(LttvTracesetContext* const traceSetContext); char* changeToGraphDir(char* const graphs); +void timeDiff(struct timeval* const end, const struct timeval* const start); + +gint gcfCompareProcessing(gconstpointer a, gconstpointer b); +gint gcfCompareMatching(gconstpointer a, gconstpointer b); +gint gcfCompareAnalysis(gconstpointer a, gconstpointer b); #endif diff --git a/lttv/modules/text/Makefile.am b/lttv/modules/text/Makefile.am index aa34737d..29e89905 100644 --- a/lttv/modules/text/Makefile.am +++ b/lttv/modules/text/Makefile.am @@ -3,13 +3,14 @@ AM_LDFLAGS = $(MODULE_LDFLAGS) libdir = ${lttvplugindir} -lib_LTLIBRARIES = libtextDump.la libbatchAnalysis.la libtextFilter.la libprecomputeState.la libdepanalysis.la +lib_LTLIBRARIES = libtextDump.la libbatchAnalysis.la libtextFilter.la libprecomputeState.la libdepanalysis.la libsync_chain_batch.la libtextDump_la_SOURCES = textDump.c libbatchAnalysis_la_SOURCES = batchAnalysis.c libtextFilter_la_SOURCES = textFilter.c libprecomputeState_la_SOURCES = precomputeState.c libdepanalysis_la_SOURCES = depanalysis.c sstack.c +libsync_chain_batch_la_SOURCES = sync_chain_batch.c noinst_HEADERS = \ batchanalysis.h \ diff --git a/lttv/modules/text/sync_chain_batch.c b/lttv/modules/text/sync_chain_batch.c new file mode 100644 index 00000000..376a696a --- /dev/null +++ b/lttv/modules/text/sync_chain_batch.c @@ -0,0 +1,507 @@ +/* This file is part of the Linux Trace Toolkit viewer + * Copyright (C) 2009 Benjamin Poirier + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +struct TracesetChainState { + // uint64_t* eventNbs[LttvTraceContext*] + GHashTable* eventNbs; + + SyncState* syncState; + struct timeval startTime; + struct rusage startUsage; + FILE* graphsStream; +}; + +static LttvHooks* before_traceset, * before_trace, * event_hook, * after_traceset; + + +static void init(); +static void destroy(); + +static gboolean tracesetStart(void *hook_data, void *call_data); +static gboolean traceStart(void *hook_data, void *call_data); +static int processEveryEvent(void *hook_data, void *call_data); +static gboolean tracesetEnd(void *hook_data, void *call_data); + +static void setupSyncChain(LttvTracesetContext* const traceSetContext); +static void teardownSyncChain(LttvTracesetContext* const traceSetContext); + +void ghfPrintEventCount(gpointer key, gpointer value, gpointer user_data); +void gdnDestroyUint64(gpointer data); + +// struct TracesetChainState* tracesetChainStates[LttvTracesetContext*] +static GHashTable* tracesetChainStates; + +static LttvHooks* before_traceset, * before_trace, * event_hook, * after_traceset; +static const struct { + const char const *path; + LttvHooks **hook; + LttvHook function; +} batchAnalysisHooks[] = { + {"hooks/traceset/before", &before_traceset, &tracesetStart}, + {"hooks/trace/before", &before_trace, &traceStart}, + {"hooks/event", &event_hook, &processEveryEvent}, + {"hooks/traceset/after", &after_traceset, &tracesetEnd}, +}; + +static gboolean optionEvalGraphs; +static char* optionEvalGraphsDir; +static char graphsDir[20]; + + +/* + * Module init function + */ +static void init() +{ + gboolean result; + unsigned int i; + LttvAttributeValue value; + int retval; + LttvIAttribute* attributes= LTTV_IATTRIBUTE(lttv_global_attributes()); + + tracesetChainStates= g_hash_table_new(NULL, NULL); + + for (i= 0; i < sizeof(batchAnalysisHooks) / sizeof(*batchAnalysisHooks); + i++) + { + result= lttv_iattribute_find_by_path(attributes, + batchAnalysisHooks[i].path, LTTV_POINTER, &value); + g_assert(result); + *batchAnalysisHooks[i].hook= *(value.v_pointer); + g_assert(*batchAnalysisHooks[i].hook); + lttv_hooks_add(*batchAnalysisHooks[i].hook, + batchAnalysisHooks[i].function, NULL, LTTV_PRIO_DEFAULT); + } + + optionEvalGraphs= FALSE; + lttv_option_add("eval-graphs", '\0', "output gnuplot graph showing " + "synchronization points", "none", LTTV_OPT_NONE, &optionEvalGraphs, + NULL, NULL); + + retval= snprintf(graphsDir, sizeof(graphsDir), "graphs-%d", getpid()); + if (retval > sizeof(graphsDir) - 1) + { + graphsDir[sizeof(graphsDir) - 1]= '\0'; + } + optionEvalGraphsDir= graphsDir; + lttv_option_add("eval-graphs-dir", '\0', "specify the directory where to" + " store the graphs", graphsDir, LTTV_OPT_STRING, &optionEvalGraphsDir, + NULL, NULL); +} + + +/* + * Module destroy function + */ +static void destroy() +{ + unsigned int i; + + g_assert_cmpuint(g_hash_table_size(tracesetChainStates), ==, 0); + g_hash_table_destroy(tracesetChainStates); + + for (i= 0; i < sizeof(batchAnalysisHooks) / sizeof(*batchAnalysisHooks); + i++) + { + lttv_hooks_remove_data(*batchAnalysisHooks[i].hook, + batchAnalysisHooks[i].function, NULL); + } + + lttv_option_remove("eval-graphs"); + lttv_option_remove("eval-graphs-dir"); +} + + +/* + * Lttv hook function that will be called before a traceset is processed + * + * Args: + * hookData: NULL + * callData: LttvTracesetContext* at that moment + * + * Returns: + * FALSE Always returns FALSE, meaning to keep processing hooks + */ +static gboolean tracesetStart(void *hook_data, void *call_data) +{ + struct TracesetChainState* tracesetChainState; + LttvTracesetContext *tsc= (LttvTracesetContext *) call_data; + + tracesetChainState= malloc(sizeof(struct TracesetChainState)); + g_hash_table_insert(tracesetChainStates, tsc, tracesetChainState); + tracesetChainState->eventNbs= g_hash_table_new_full(&g_direct_hash, + &g_direct_equal, NULL, &gdnDestroyUint64); + + gettimeofday(&tracesetChainState->startTime, 0); + getrusage(RUSAGE_SELF, &tracesetChainState->startUsage); + + setupSyncChain(tsc); + + return FALSE; +} + + +/* + * Lttv hook function that will be called before a trace is processed + * + * Args: + * hookData: NULL + * callData: LttvTraceContext* at that moment + * + * Returns: + * FALSE Always returns FALSE, meaning to keep processing hooks + */ +static gboolean traceStart(void *hook_data, void *call_data) +{ + struct TracesetChainState* tracesetChainState; + uint64_t* eventNb; + LttvTraceContext* tc= (LttvTraceContext*) call_data; + LttvTracesetContext* tsc= tc->ts_context; + + tracesetChainState= g_hash_table_lookup(tracesetChainStates, tsc); + eventNb= malloc(sizeof(uint64_t)); + *eventNb= 0; + g_hash_table_insert(tracesetChainState->eventNbs, tc, eventNb); + + return FALSE; +} + + +/* + * Lttv hook function that is called for every event + * + * Args: + * hookData: NULL + * callData: LttvTracefileContext* at the moment of the event + * + * Returns: + * FALSE Always returns FALSE, meaning to keep processing hooks for + * this event + */ +static int processEveryEvent(void *hook_data, void *call_data) +{ + LttvTracefileContext* tfc= (LttvTracefileContext*) call_data; + LttvTraceContext* tc= tfc->t_context; + LttvTracesetContext* tsc= tc->ts_context; + struct TracesetChainState* tracesetChainState; + uint64_t* eventNb; + + tracesetChainState= g_hash_table_lookup(tracesetChainStates, tsc); + eventNb= g_hash_table_lookup(tracesetChainState->eventNbs, tc); + + (*eventNb)++; + + return FALSE; +} + + +/* + * Lttv hook function that is called after a traceset has been processed + * + * Args: + * hookData: NULL + * callData: LttvTracefileContext* at that moment + * + * Returns: + * FALSE Always returns FALSE, meaning to keep processing hooks + */ +static gboolean tracesetEnd(void *hook_data, void *call_data) +{ + struct TracesetChainState* tracesetChainState; + LttvTracesetContext* tsc= (LttvTracesetContext*) call_data; + uint64_t sum= 0; + + tracesetChainState= g_hash_table_lookup(tracesetChainStates, tsc); + printf("Event count (%u traces):\n", + g_hash_table_size(tracesetChainState->eventNbs)); + g_hash_table_foreach(tracesetChainState->eventNbs, &ghfPrintEventCount, + &sum); + printf("\ttotal events: %" PRIu64 "\n", sum); + g_hash_table_destroy(tracesetChainState->eventNbs); + + teardownSyncChain(tsc); + + g_hash_table_remove(tracesetChainStates, tsc); + + return FALSE; +} + + +/* + * Initialize modules in a sync chain. Use modules that will check + * the precision of time synchronization between a group of traces. + * + * Args: + * traceSetContext: traceset + */ +void setupSyncChain(LttvTracesetContext* const traceSetContext) +{ + struct TracesetChainState* tracesetChainState; + SyncState* syncState; + GList* result; + int retval; + + tracesetChainState= g_hash_table_lookup(tracesetChainStates, traceSetContext); + syncState= malloc(sizeof(SyncState)); + tracesetChainState->syncState= syncState; + syncState->traceNb= lttv_traceset_number(traceSetContext->ts); + + syncState->stats= true; + + if (optionEvalGraphs) + { + syncState->graphs= optionEvalGraphsDir; + } + else + { + syncState->graphs= NULL; + } + + syncState->processingData= NULL; + result= g_queue_find_custom(&processingModules, "LTTV-standard", + &gcfCompareProcessing); + syncState->processingModule= (ProcessingModule*) result->data; + + tracesetChainState->graphsStream= NULL; + if (syncState->graphs && + syncState->processingModule->writeProcessingGraphsPlots != NULL) + { + char* cwd; + int graphsFp; + + // Create the graph directory right away in case the module initialization + // functions have something to write in it. + cwd= changeToGraphDir(syncState->graphs); + + if ((graphsFp= open("graphs.gnu", O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | + S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH + | S_IWOTH | S_IXOTH)) == -1) + { + g_error(strerror(errno)); + } + if ((tracesetChainState->graphsStream= fdopen(graphsFp, "w")) == NULL) + { + g_error(strerror(errno)); + } + + retval= chdir(cwd); + if (retval == -1) + { + g_error(strerror(errno)); + } + free(cwd); + } + + syncState->matchingData= NULL; + result= g_queue_find_custom(&matchingModules, "TCP", &gcfCompareMatching); + syncState->matchingModule= (MatchingModule*) result->data; + + syncState->analysisData= NULL; + result= g_queue_find_custom(&analysisModules, "chull", &gcfCompareAnalysis); + syncState->analysisModule= (AnalysisModule*) result->data; + + syncState->processingModule->initProcessing(syncState, traceSetContext); + syncState->matchingModule->initMatching(syncState); + syncState->analysisModule->initAnalysis(syncState); +} + + +/* + * Destroy modules in a sync chain + * + * Args: + * traceSetContext: traceset + */ +void teardownSyncChain(LttvTracesetContext* const traceSetContext) +{ + struct TracesetChainState* tracesetChainState; + SyncState* syncState; + struct timeval endTime; + struct rusage endUsage; + int retval; + + tracesetChainState= g_hash_table_lookup(tracesetChainStates, traceSetContext); + syncState= tracesetChainState->syncState; + + syncState->processingModule->finalizeProcessing(syncState); + + // Write graphs file + if (tracesetChainState->graphsStream != NULL) + { + unsigned int i, j; + + fprintf(tracesetChainState->graphsStream, + "#!/usr/bin/gnuplot\n\n" + "set terminal postscript eps color size 8in,6in\n"); + + // Cover the upper triangular matrix, i is the reference node. + for (i= 0; i < syncState->traceNb; i++) + { + for (j= i + 1; j < syncState->traceNb; j++) + { + long pos; + + fprintf(tracesetChainState->graphsStream, + "\nset output \"%03d-%03d.eps\"\n" + "plot \\\n", i, j); + + syncState->processingModule->writeProcessingGraphsPlots(tracesetChainState->graphsStream, + syncState, i, j); + + // Remove the ", \\\n" from the last graph plot line + fflush(tracesetChainState->graphsStream); + pos= ftell(tracesetChainState->graphsStream); + if (ftruncate(fileno(tracesetChainState->graphsStream), pos - 4) == -1) + { + g_error(strerror(errno)); + } + if (fseek(tracesetChainState->graphsStream, 0, SEEK_END) == -1) + { + g_error(strerror(errno)); + } + + fprintf(tracesetChainState->graphsStream, + "\nset output \"%1$03d-%2$03d.eps\"\n" + "set key inside right bottom\n" + "set title \"\"\n" + "set xlabel \"Clock %1$u\"\n" + "set xtics nomirror\n" + "set ylabel \"Clock %2$u\"\n" + "set ytics nomirror\n", i, j); + + syncState->processingModule->writeProcessingGraphsOptions(tracesetChainState->graphsStream, + syncState, i, j); + + fprintf(tracesetChainState->graphsStream, + "replot\n"); + } + } + + if (fclose(tracesetChainState->graphsStream) != 0) + { + g_error(strerror(errno)); + } + } + + if (syncState->processingModule->printProcessingStats != NULL) + { + syncState->processingModule->printProcessingStats(syncState); + } + + syncState->processingModule->destroyProcessing(syncState); + if (syncState->matchingModule != NULL) + { + syncState->matchingModule->destroyMatching(syncState); + } + if (syncState->analysisModule != NULL) + { + syncState->analysisModule->destroyAnalysis(syncState); + } + + free(syncState); + + gettimeofday(&endTime, 0); + retval= getrusage(RUSAGE_SELF, &endUsage); + + timeDiff(&endTime, &tracesetChainState->startTime); + timeDiff(&endUsage.ru_utime, &tracesetChainState->startUsage.ru_utime); + timeDiff(&endUsage.ru_stime, &tracesetChainState->startUsage.ru_stime); + + printf("Evaluation time:\n"); + printf("\treal time: %ld.%06ld\n", endTime.tv_sec, endTime.tv_usec); + printf("\tuser time: %ld.%06ld\n", endUsage.ru_utime.tv_sec, + endUsage.ru_utime.tv_usec); + printf("\tsystem time: %ld.%06ld\n", endUsage.ru_stime.tv_sec, + endUsage.ru_stime.tv_usec); + + g_hash_table_remove(tracesetChainStates, traceSetContext); + free(tracesetChainState); +} + + + +/* + * A GHFunc function for g_hash_table_foreach() + * + * Args: + * key: LttvTraceContext * + * value: uint64_t *, event count for this trace + * user_data: uint64_t *, sum of the event counts + * + * Returns: + * Updates the sum in user_data + */ +void ghfPrintEventCount(gpointer key, gpointer value, gpointer user_data) +{ + LttvTraceContext *tc = (LttvTraceContext *) key; + uint64_t *eventNb = (uint64_t *)value; + uint64_t *sum = (uint64_t *)user_data; + + printf("\t%s: %" PRIu64 "\n", g_quark_to_string(ltt_trace_name(tc->t)), + *eventNb); + *sum += *eventNb; +} + + +/* + * A GDestroyNotify function for g_hash_table_new_full() + * + * Args: + * data: TsetStats * + */ +void gdnDestroyUint64(gpointer data) +{ + free((uint64_t *) data); +} + + +LTTV_MODULE("sync_chain_batch", "Execute synchronization modules in a "\ + "post-processing step.", "This can be used to quantify the precision "\ + "with which a group of trace is synchronized.", init, destroy,\ + "batchAnalysis", "option", "sync") diff --git a/runlttv b/runlttv index 6c8c8f9d..5a3e2722 100755 --- a/runlttv +++ b/runlttv @@ -14,6 +14,7 @@ PROGNAME=$0 BUILDPATH=$(dirname $0) RCFILE="$(dirname $0)/.runlttvrc" TEXTLIBS="-L ${BUILDPATH}/lttv/modules/text/.libs -m textDump" +EVALLIBS="-L ${BUILDPATH}/lttv/modules/text/.libs -m sync_chain_batch" GRAPHLIBS="-L ${BUILDPATH}/lttv/modules/gui/lttvwindow/lttvwindow/.libs -m lttvwindow "\ "-L ${BUILDPATH}/lttv/modules/gui/controlflow/.libs -m guicontrolflow "\ "-L ${BUILDPATH}/lttv/modules/gui/detailedevents/.libs -m guievents "\ @@ -29,7 +30,7 @@ usage () { echo "Usage: $0 [OPTION]... [TRACE]..." >/dev/stderr echo "" >/dev/stderr echo "Options:" >/dev/stderr - printf "\t-m MODE Output mode (modes: text, gui)\n" >/dev/stderr + printf "\t-m MODE Output mode (modes: text, eval, gui)\n" >/dev/stderr printf "\t-H HELPER Invoke LTTV through a helper program\n" >/dev/stderr printf "\t (helpers: gdb, valgrind, massif, strace)\n" >/dev/stderr printf "\t-b OPTIONS LTTV options to specify before the module list\n" >/dev/stderr @@ -75,6 +76,8 @@ fi if [ "$MODE" = "text" ]; then LIBS="$TEXTLIBS" +elif [ "$MODE" = "eval" ]; then + LIBS="$EVALLIBS" elif [ "$MODE" = "gui" ]; then LIBS="$GRAPHLIBS" else -- 2.34.1