Add a batchanalysis module to build and run a sync chain
authorBenjamin Poirier <benjamin.poirier@polymtl.ca>
Tue, 27 Oct 2009 17:56:25 +0000 (13:56 -0400)
committerBenjamin Poirier <benjamin.poirier@polymtl.ca>
Fri, 18 Dec 2009 19:03:25 +0000 (14:03 -0500)
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 <benjamin.poirier@polymtl.ca>
lttv/lttv/iattribute.c
lttv/lttv/iattribute.h
lttv/lttv/sync/README
lttv/lttv/sync/event_processing_lttng_common.h
lttv/lttv/sync/event_processing_lttng_standard.c
lttv/lttv/sync/sync_chain_lttv.c
lttv/lttv/sync/sync_chain_lttv.h
lttv/modules/text/Makefile.am
lttv/modules/text/sync_chain_batch.c [new file with mode: 0644]
runlttv

index 0271dddb65d3836e10932c31539e1bc5a6a398b6..fe50fb63a3617b6b5b3fa48a98b5a8f0660c4042 100644 (file)
@@ -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));
       }
index cbda045f4bba5db151a75c11d99d3de82f01d5c2..292270908163022e711f3222c5e152ee4acde9f0 100644 (file)
@@ -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);
 
 
index 25f9a71959af26b2728dae64cb16d230ca5f91e5..6310db875e28efdfd43cdf82658ce670b0ee7ba0 100644 (file)
@@ -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
index 14ed7c150a62730a73b84a8829390fe710495783..7a710f74c79efc13b44d9e00b4f32bf63bdbdbd9 100644 (file)
@@ -20,6 +20,7 @@
 #define EVENT_PROCESSING_LTTNG_COMMON_H
 
 #include <glib.h>
+#include <stdbool.h>
 
 #include <lttv/tracecontext.h>
 
index a8c08aaf05a1e2924d194e12c64933ba6a503965..489dec5fd6e60481b377cf514a9ca4c3efd1aed2 100644 (file)
@@ -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,
index 2479512fed5ddb083ef170fabda3b154f56199d7..2003e95fd7ca24d29481a7775dcad2f60901329a 100644 (file)
@@ -26,7 +26,6 @@
 #include <stdlib.h>
 #include <sys/resource.h>
 #include <sys/stat.h>
-#include <sys/time.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
 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);
 }
 
 
index a6a460b0723e4da8ef619c2598a37075f9a51ce0..1f7a273b693884d637abd4b0d179b1b3fb688740 100644 (file)
@@ -20,6 +20,7 @@
 #define SYNC_CHAIN_LTTV_H
 
 #include <glib.h>
+#include <sys/time.h>
 
 #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
index aa34737d9ece16d7e707a85fae8f289aa502c434..29e899051930b63f5fd714aa8714a661ffea6b6d 100644 (file)
@@ -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 (file)
index 0000000..376a696
--- /dev/null
@@ -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 <config.h>
+#endif
+
+#include <errno.h>
+#include <fcntl.h>
+#include <glib.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/resource.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <lttv/attribute.h>
+#include <lttv/filter.h>
+#include <lttv/hook.h>
+#include <lttv/iattribute.h>
+#include <lttv/lttv.h>
+#include <lttv/module.h>
+#include <lttv/option.h>
+#include <lttv/print.h>
+#include <lttv/sync/sync_chain_lttv.h>
+#include <ltt/ltt.h>
+#include <ltt/event.h>
+#include <ltt/trace.h>
+
+
+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 6c8c8f9df02530066684ccd6c41a35ca03d8755b..5a3e2722d9db4c68b10023d1661467378eadd7cf 100755 (executable)
--- 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
This page took 0.034961 seconds and 4 git commands to generate.