From: Benjamin Poirier Date: Thu, 26 Nov 2009 22:03:06 +0000 (-0500) Subject: Add sync_chain_unittest X-Git-Tag: v0.12.26~18 X-Git-Url: https://git.lttng.org/?p=lttv.git;a=commitdiff_plain;h=b670bb7cf8ff6e781462434a2273e47e055e54db Add sync_chain_unittest Makes the former unitest program more compliant with the current architecture. Signed-off-by: Benjamin Poirier --- diff --git a/lttv/lttv/sync/Makefile.am b/lttv/lttv/sync/Makefile.am index 84562f98..cd08bb8d 100644 --- a/lttv/lttv/sync/Makefile.am +++ b/lttv/lttv/sync/Makefile.am @@ -1,11 +1,13 @@ AM_CFLAGS= $(PACKAGE_CFLAGS) -LDADD = $(M_LIBS) +LDADD = $(M_LIBS) $(GLPK_LIBS) check_PROGRAMS = unittest unittest_SOURCES = \ - unittest.c\ data_structures.c\ + graph_functions.c\ + sync_chain.c\ + sync_chain_unittest.c\ event_matching_broadcast.c\ event_matching_distributor.c\ event_matching_tcp.c\ diff --git a/lttv/lttv/sync/README b/lttv/lttv/sync/README index ada0210b..4e6b19ce 100644 --- a/lttv/lttv/sync/README +++ b/lttv/lttv/sync/README @@ -192,9 +192,11 @@ This reads parameters, creates SyncState and calls the processing init function. The "sync chain" is the set of event-* modules. At the moment there is only one module at each stage. However, as more module are added, it will become relevant to have many modules at the same stage simultaneously. This -will require some modifications. I've kept this possibility at the back of my -mind while designing. It is already partly supported at the matching stage -through encapsulation of other matching modules. +will require some modifications. It is already partly supported at the +matching stage through encapsulation of other matching modules. + +sync_chain_unitest provides a fairly simple example of sync chain +implementation. ++ Stage 1: Event processing Specific to the tracing data source. diff --git a/lttv/lttv/sync/sync_chain.h b/lttv/lttv/sync/sync_chain.h index d999c9ce..5d10a08b 100644 --- a/lttv/lttv/sync/sync_chain.h +++ b/lttv/lttv/sync/sync_chain.h @@ -43,7 +43,7 @@ typedef struct _SyncState typedef struct { - const char shortName; + char shortName; const char* longName; enum { NO_ARG, diff --git a/lttv/lttv/sync/sync_chain_unittest.c b/lttv/lttv/sync/sync_chain_unittest.c new file mode 100644 index 00000000..3a6de571 --- /dev/null +++ b/lttv/lttv/sync/sync_chain_unittest.c @@ -0,0 +1,411 @@ +/* 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. + */ + +#define _GNU_SOURCE + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sync_chain.h" + + +struct OptionsInfo +{ + GArray* longOptions; + GString* optionString; + GQueue* index; +}; + + +const char* processOptions(const int argc, char* const argv[]); +static void usage(const char* const programName); +static void gfPrintModuleOption(gpointer data, gpointer user_data); +static void nullLog(const gchar *log_domain, GLogLevelFlags log_level, const + gchar *message, gpointer user_data); +static void gfAddModuleOption(gpointer data, gpointer user_data); + + +static ModuleOption optionSyncStats= { + .shortName= 's', + .longName= "sync-stats", + .hasArg= NO_ARG, + .optionHelp= "Print statistics and debug messages", +}; +static char graphsDir[20]; +static ModuleOption optionSyncGraphs= { + .shortName= 'g', + .longName= "sync-graphs", + .hasArg= OPTIONAL_ARG, + .optionHelp= "Output gnuplot graph showing synchronization points", +}; +static ModuleOption optionSyncAnalysis= { + .shortName= 'a', + .longName= "sync-analysis", + .hasArg= REQUIRED_ARG, + .optionHelp= "Specify which algorithm to use for event analysis", +}; + + +/* + * Implement a sync chain, it is mostly for unittest and it does not depend on + * lttv + * + * Args: + * argc, argv: standard argument arrays + * + * Returns: + * exit status from main() is always EXIT_SUCCESS + */ +int main(const int argc, char* const argv[]) +{ + SyncState* syncState; + struct timeval startTime, endTime; + struct rusage startUsage, endUsage; + GList* result; + int retval; + bool stats; + const char* testCaseName; + GString* analysisModulesNames; + + // Initialize data structures + syncState= malloc(sizeof(SyncState)); + + // Process command line arguments + g_assert(g_queue_get_length(&analysisModules) > 0); + optionSyncAnalysis.arg= ((AnalysisModule*) + g_queue_peek_head(&analysisModules))->name; + analysisModulesNames= g_string_new("Available modules: "); + g_queue_foreach(&analysisModules, &gfAppendAnalysisName, + analysisModulesNames); + // remove the last ", " + g_string_truncate(analysisModulesNames, analysisModulesNames->len - 2); + optionSyncAnalysis.argHelp= analysisModulesNames->str; + + retval= snprintf(graphsDir, sizeof(graphsDir), "graphs-%d", getpid()); + if (retval > sizeof(graphsDir) - 1) + { + graphsDir[sizeof(graphsDir) - 1]= '\0'; + } + optionSyncGraphs.arg= graphsDir; + + g_queue_push_head(&moduleOptions, &optionSyncAnalysis); + g_queue_push_head(&moduleOptions, &optionSyncGraphs); + g_queue_push_head(&moduleOptions, &optionSyncStats); + + testCaseName= processOptions(argc, argv); + + g_string_free(analysisModulesNames, TRUE); + + if (optionSyncStats.present) + { + syncState->stats= true; + gettimeofday(&startTime, 0); + getrusage(RUSAGE_SELF, &startUsage); + } + else + { + syncState->stats= false; + g_log_set_handler(NULL, G_LOG_LEVEL_DEBUG, nullLog, NULL); + } + + if (optionSyncGraphs.present) + { + // Create the graph directory right away in case the module initialization + // functions have something to write in it. + syncState->graphsDir= optionSyncGraphs.arg; + syncState->graphsStream= createGraphsDir(syncState->graphsDir); + } + else + { + syncState->graphsStream= NULL; + syncState->graphsDir= NULL; + } + + // Identify modules + syncState->processingData= NULL; + result= g_queue_find_custom(&processingModules, "text", + &gcfCompareProcessing); + g_assert(result != NULL); + syncState->processingModule= (ProcessingModule*) result->data; + + syncState->matchingData= NULL; + result= g_queue_find_custom(&matchingModules, "TCP", &gcfCompareMatching); + g_assert(result != NULL); + syncState->matchingModule= (MatchingModule*) result->data; + + syncState->analysisData= NULL; + result= g_queue_find_custom(&analysisModules, optionSyncAnalysis.arg, + &gcfCompareAnalysis); + if (result != NULL) + { + syncState->analysisModule= (AnalysisModule*) result->data; + } + else + { + g_error("Analysis module '%s' not found", optionSyncAnalysis.arg); + } + + // Initialize modules + syncState->processingModule->initProcessing(syncState, testCaseName); + syncState->matchingModule->initMatching(syncState); + syncState->analysisModule->initAnalysis(syncState); + + // Process traceset + syncState->processingModule->finalizeProcessing(syncState); + + // Write graphs file + if (syncState->graphsStream) + { + writeGraphsScript(syncState); + + if (fclose(syncState->graphsStream) != 0) + { + g_error(strerror(errno)); + } + } + + // Print statistics + if (syncState->stats) + { + printStats(syncState); + } + + // Destroy modules and clean up + syncState->processingModule->destroyProcessing(syncState); + syncState->matchingModule->destroyMatching(syncState); + syncState->analysisModule->destroyAnalysis(syncState); + + stats= syncState->stats; + free(syncState); + + if (stats) + { + gettimeofday(&endTime, 0); + retval= getrusage(RUSAGE_SELF, &endUsage); + + timeDiff(&endTime, &startTime); + timeDiff(&endUsage.ru_utime, &startUsage.ru_utime); + timeDiff(&endUsage.ru_stime, &startUsage.ru_stime); + + printf("Synchronization 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); + } + + return EXIT_SUCCESS; +} + + +/* + * Read program arguments dans update ModuleOptions structures + * + * Args: + * argc, argv: standard argument arrays + * + * Returns: + * Name of the test case file (first parameter) + */ +const char* processOptions(const int argc, char* const argv[]) +{ + int c; + extern char* optarg; + extern int optind, opterr, optopt; + GArray* longOptions; + GString* optionString; + GQueue* index; + + longOptions= g_array_sized_new(TRUE, FALSE, sizeof(struct option), + g_queue_get_length(&moduleOptions)); + optionString= g_string_new(""); + index= g_queue_new(); + + g_queue_foreach(&moduleOptions, &gfAddModuleOption, &(struct OptionsInfo) + {longOptions, optionString, index}); + + do + { + int optionIndex= 0; + + c= getopt_long(argc, argv, optionString->str, (struct option*) + longOptions->data, &optionIndex); + + if (c >= 0 && c < g_queue_get_length(index)) + { + ModuleOption* moduleOption= g_queue_peek_nth(index, c); + + moduleOption->present= true; + + if (moduleOption->hasArg == REQUIRED_ARG || moduleOption->hasArg + == OPTIONAL_ARG) + { + moduleOption->arg= optarg; + } + } + else if (c == -1) + { + break; + } + else if (c == '?') + { + usage(argv[0]); + abort(); + } + else + { + g_error("Option parse error"); + } + } while (c != -1); + + g_array_free(longOptions, TRUE); + g_string_free(optionString, TRUE); + + if (argc <= optind) + { + fprintf(stderr, "Test file unspecified\n"); + usage(argv[0]); + abort(); + } + + return argv[optind]; +} + + +/* + * Print information about program options and arguments. + * + * Args: + * programName: name of the program, as contained in argv[0] for example + */ +static void usage(const char* const programName) +{ + printf( + "%s [options] \n" + "Options:\n", programName); + + g_queue_foreach(&moduleOptions, &gfPrintModuleOption, NULL); +} + + +/* + * A GFunc for g_queue_foreach() + * + * Print analysis module names. + * + * Args: + * data: ModuleOption*, option + * user_data: NULL + */ +static void gfPrintModuleOption(gpointer data, gpointer user_data) +{ + ModuleOption* option= data; + int width= 0, sum= 0; + const int colWidth= 27; + + printf("\t"); + + if (option->shortName) + { + printf("-%c, %n", option->shortName, &width); + sum+= width; + } + + printf("--%-s%n", option->longName, &width); + sum+= width; + + if (option->hasArg == REQUIRED_ARG || option->hasArg == OPTIONAL_ARG) + { + printf("=[..]%n", &width); + sum+= width; + } + + if (option->optionHelp) + { + printf("%*s%s\n", colWidth - sum > 0 ? colWidth - sum : 0, "", option->optionHelp); + } + + if (option->argHelp) + { + printf("\t%*s%s\n", colWidth, "", option->argHelp); + } + + if ((option->hasArg == REQUIRED_ARG || option->hasArg == OPTIONAL_ARG) && option->arg) + { + printf("\t%*sDefault value: %s\n", colWidth, "", option->arg); + } +} + + +/* + * A Glib log function which does nothing. + */ +static void nullLog(const gchar *log_domain, GLogLevelFlags log_level, const + gchar *message, gpointer user_data) +{} + + +/* + * A GFunc for g_queue_foreach() + * + * Args: + * data: ModuleOption*, option + * user_data: struct OptionsInfo*, add option to this array of struct option + */ +static void gfAddModuleOption(gpointer data, gpointer user_data) +{ + ModuleOption* option= data; + struct OptionsInfo* optionsInfo= user_data; + struct option newOption; + // "[mixing enumerations] can still be considered bad style even though it + // is not strictly illegal" c.faq 2.22 + const int conversion[]= { + [NO_ARG]= no_argument, + [OPTIONAL_ARG]= optional_argument, + [REQUIRED_ARG]= required_argument, + }; + const char* colons[]= { + [NO_ARG]= "", + [OPTIONAL_ARG]= "::", + [REQUIRED_ARG]= ":", + }; + + newOption.name= option->longName; + newOption.has_arg= conversion[option->hasArg]; + newOption.flag= NULL; + newOption.val= g_queue_get_length(optionsInfo->index); + + g_array_append_val(optionsInfo->longOptions, newOption); + g_string_append(optionsInfo->optionString, colons[option->hasArg]); + g_queue_push_tail(optionsInfo->index, option); +} diff --git a/lttv/lttv/sync/unittest.c b/lttv/lttv/sync/unittest.c deleted file mode 100644 index 9b99d32b..00000000 --- a/lttv/lttv/sync/unittest.c +++ /dev/null @@ -1,717 +0,0 @@ -/* 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. - */ - -#define _GNU_SOURCE - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "sync_chain.h" - - -static void timeDiff(struct timeval* const end, const struct timeval* const start); -static void usage(const char* const programName); -static gint gcfCompareAnalysis(gconstpointer a, gconstpointer b); -static void gfAppendAnalysisName(gpointer data, gpointer user_data); -static unsigned int readTraceNb(FILE* testCase); -static void skipCommentLines(FILE* testCase); -static void processEvents(SyncState* const syncState, FILE* testCase); -static void nullLog(const gchar *log_domain, GLogLevelFlags log_level, const - gchar *message, gpointer user_data); - -GQueue processingModules= G_QUEUE_INIT; -GQueue matchingModules= G_QUEUE_INIT; -GQueue analysisModules= G_QUEUE_INIT; - -// time values in test case files will be scaled by this factor -const double freq= 1e9; - - -/* - * Create matching and analysis modules and feed them events read from a text - * file. - * - * Idealy, this would've been a processing module but sync_chain.c and - * ProcessingModule use some LTTV-specific types and functions. Unfortunately, - * there is some code duplication from sync_chain.c - * - */ -int main(int argc, char* argv[]) -{ - int c; - extern char* optarg; - extern int optind, opterr, optopt; - bool optionSyncStats= false; - char* optionGraphsDir= NULL; - FILE* testCase= NULL; - - SyncState* syncState; - struct timeval startTime, endTime; - struct rusage startUsage, endUsage; - GList* result; - char* cwd; - FILE* graphsStream; - int graphsFp; - GArray* factors; - - int retval; - - syncState= malloc(sizeof(SyncState)); - - g_assert(g_queue_get_length(&analysisModules) > 0); - syncState->analysisModule= g_queue_peek_head(&analysisModules); - - do - { - int optionIndex= 0; - - static struct option longOptions[]= - { - {"sync-stats", no_argument, 0, 's'}, - {"sync-graphs", optional_argument, 0, 'g'}, - {"sync-analysis", required_argument, 0, 'a'}, - {0, 0, 0, 0} - }; - - c= getopt_long(argc, argv, "sg::a:", longOptions, &optionIndex); - - switch (c) - { - case -1: - case 0: - break; - - case 's': - if (!optionSyncStats) - { - gettimeofday(&startTime, 0); - getrusage(RUSAGE_SELF, &startUsage); - } - optionSyncStats= true; - break; - - case 'g': - if (optarg) - { - printf("xxx:%s\n", optarg); - optionGraphsDir= malloc(strlen(optarg)); - strcpy(optionGraphsDir, optarg); - } - else - { - optionGraphsDir= malloc(20); - retval= snprintf(optionGraphsDir, 20, "graphs-%d", - getpid()); - if (retval > 20 - 1) - { - optionGraphsDir[20 - 1]= '\0'; - } - } - break; - - case 'a': - printf("xxx:%s\n", optarg); - result= g_queue_find_custom(&analysisModules, optarg, - &gcfCompareAnalysis); - if (result != NULL) - { - syncState->analysisModule= (AnalysisModule*) result->data; - } - else - { - g_error("Analysis module '%s' not found", optarg); - } - break; - - case '?': - usage(argv[0]); - abort(); - - default: - g_error("Option parse error"); - } - } while (c != -1); - - if (argc <= optind) - { - fprintf(stderr, "Test file unspecified\n"); - usage(argv[0]); - abort(); - } - - testCase= fopen(argv[optind], "r"); - if (testCase == NULL) - { - g_error(strerror(errno)); - } - - // Initialize data structures - syncState->traceNb= readTraceNb(testCase); - - if (optionSyncStats) - { - syncState->stats= true; - } - else - { - syncState->stats= false; - } - - syncState->graphs= optionGraphsDir; - - if (!optionSyncStats) - { - g_log_set_handler(NULL, G_LOG_LEVEL_DEBUG, nullLog, NULL); - } - - // Identify and initialize matching and analysis modules - syncState->matchingData= NULL; - syncState->analysisData= NULL; - - g_assert(g_queue_get_length(&matchingModules) == 1); - syncState->matchingModule= (MatchingModule*) - g_queue_peek_head(&matchingModules); - - graphsStream= NULL; - if (syncState->graphs) - { - // Create the graph directory right away in case the module initialization - // functions have something to write in it. - cwd= changeToGraphDir(syncState->graphs); - - if (syncState->matchingModule->writeMatchingGraphsPlots != NULL) - { - 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 ((graphsStream= fdopen(graphsFp, "w")) == NULL) - { - g_error(strerror(errno)); - } - } - - retval= chdir(cwd); - if (retval == -1) - { - g_error(strerror(errno)); - } - free(cwd); - } - - syncState->matchingModule->initMatching(syncState); - syncState->analysisModule->initAnalysis(syncState); - - // Process traceset - processEvents(syncState, testCase); - - factors= syncState->matchingModule->finalizeMatching(syncState); - - // Write graphs file - if (graphsStream != NULL) - { - unsigned int i, j; - - fprintf(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(graphsStream, - "\n#set output \"%03d-%03d.eps\"\n" - "plot \\\n", i, j); - - syncState->matchingModule->writeMatchingGraphsPlots(graphsStream, - syncState, i, j); - - // Remove the ", \\\n" from the last graph plot line - fflush(graphsStream); - pos= ftell(graphsStream); - if (ftruncate(fileno(graphsStream), pos - 4) == -1) - { - g_error(strerror(errno)); - } - if (fseek(graphsStream, 0, SEEK_END) == -1) - { - g_error(strerror(errno)); - } - - fprintf(graphsStream, - "\nset output \"%1$03d-%2$03d.eps\"\n" - "set title \"\"\n" - "set xlabel \"Clock %1$u\"\n" - "set xtics nomirror\n" - "set ylabel \"Clock %2$u\"\n" - "set ytics nomirror\n" - "set x2label \"Clock %1$u (s)\"\n" - "set x2range [GPVAL_X_MIN / %3$.1f : GPVAL_X_MAX / %3$.1f]\n" - "set x2tics\n" - "set y2label \"Clock %2$u (s)\"\n" - "set y2range [GPVAL_Y_MIN / %3$.1f: GPVAL_Y_MAX / %3$.1f]\n" - "set y2tics\n" - "set key inside right bottom\n", i, j, freq); - - syncState->matchingModule->writeMatchingGraphsOptions(graphsStream, - syncState, i, j); - - fprintf(graphsStream, "replot\n\n" - "pause -1\n"); - } - } - - if (fclose(graphsStream) != 0) - { - g_error(strerror(errno)); - } - } - if (optionGraphsDir) - { - free(optionGraphsDir); - } - - if (optionSyncStats && syncState->matchingModule->printMatchingStats != - NULL) - { - unsigned int i; - - syncState->matchingModule->printMatchingStats(syncState); - - printf("Resulting synchronization factors:\n"); - for (i= 0; i < syncState->traceNb; i++) - { - Factors* traceFactors; - - traceFactors= &g_array_index(factors, Factors, i); - printf("\ttrace %u drift= %g offset= %g\n", i, - traceFactors->drift, traceFactors->offset); - } - } - - syncState->matchingModule->destroyMatching(syncState); - syncState->analysisModule->destroyAnalysis(syncState); - - free(syncState); - - if (optionSyncStats) - { - gettimeofday(&endTime, 0); - retval= getrusage(RUSAGE_SELF, &endUsage); - - timeDiff(&endTime, &startTime); - timeDiff(&endUsage.ru_utime, &startUsage.ru_utime); - timeDiff(&endUsage.ru_stime, &startUsage.ru_stime); - - printf("Synchronization 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); - } - - return EXIT_SUCCESS; -} - - -/* - * Print information about program options and arguments. - * - * Args: - * programName: name of the program, as contained in argv[0] for example - */ -static void usage(const char* const programName) -{ - GString* analysisModulesNames; - - analysisModulesNames= g_string_new(""); - g_queue_foreach(&analysisModules, &gfAppendAnalysisName, - analysisModulesNames); - // remove the last ", " - g_string_truncate(analysisModulesNames, analysisModulesNames->len - 2); - - printf( - "%s [options] \n" - "Options:\n" - "\t-s, --sync-stats Print statistics and debug messages\n" - "\t-g, --sync-graphs[=OUPUT_DIR] Generate graphs\n" - "\t-a, --sync-analysis=MODULE_NAME Specify which module to use for analysis\n" - "\t Available modules: %s\n", - programName, analysisModulesNames->str); - - g_string_free(analysisModulesNames, TRUE); -} - - -/* - * Calculate the elapsed time between two timeval values - * - * Args: - * 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) -{ - if (end->tv_usec >= start->tv_usec) - { - end->tv_sec-= start->tv_sec; - end->tv_usec-= start->tv_usec; - } - else - { - end->tv_sec= end->tv_sec - start->tv_sec - 1; - end->tv_usec= end->tv_usec - start->tv_usec + 1e6; - } -} - - -/* - * A GCompareFunc for g_slist_find_custom() - * - * Args: - * 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 gcfCompareAnalysis(gconstpointer a, gconstpointer b) -{ - const AnalysisModule* analysisModule; - const char* name; - - analysisModule= (const AnalysisModule*)a; - name= (const char*)b; - - return strncmp(analysisModule->name, name, strlen(analysisModule->name) + - 1); -} - - -/* - * Change to the directory used to hold graphs. Create it if necessary. - * - * Args: - * graph: name of directory - * - * Returns: - * The current working directory before the execution of the function. The - * string must be free'd by the caller. - */ -char* changeToGraphDir(char* const graphs) -{ - int retval; - char* cwd; - - cwd= getcwd(NULL, 0); - if (cwd == NULL) - { - g_error(strerror(errno)); - } - while ((retval= chdir(graphs)) != 0) - { - if (errno == ENOENT) - { - retval= mkdir(graphs, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | - S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH); - if (retval != 0) - { - g_error(strerror(errno)); - } - } - else - { - g_error(strerror(errno)); - } - } - - return cwd; -} - - -/* - * A GFunc for g_queue_foreach() - * - * Concatenate analysis module names. - * - * Args: - * data: AnalysisModule* - * user_data: GString*, concatenated names - */ -static void gfAppendAnalysisName(gpointer data, gpointer user_data) -{ - g_string_append((GString*) user_data, ((AnalysisModule*) data)->name); - g_string_append((GString*) user_data, ", "); -} - - -/* - * Read trace number from the test case stream. The trace number should be the - * first non-comment line and should be an unsigned int by itself on a line. - * - * Args: - * testCase: test case stream - * - * Returns: - * The trace number - */ -static unsigned int readTraceNb(FILE* testCase) -{ - unsigned int result; - int retval; - char* line= NULL; - size_t len; - char tmp; - - skipCommentLines(testCase); - retval= getline(&line, &len, testCase); - if (retval == -1) - { - if (feof(testCase)) - { - g_error("Unexpected end of file while looking for number of traces"); - } - else - { - g_error(strerror(errno)); - } - } - if (line[retval - 1] == '\n') - { - line[retval - 1]= '\0'; - } - - retval= sscanf(line, " %u %c", &result, &tmp); - if (retval == EOF || retval != 1) - { - g_error("Error parsing test file while looking for number of traces, line was '%s'", line); - - // Not really needed but avoids warning from gcc - abort(); - } - - return result; -} - - -/* - * Advance testCase stream over empty space, empty lines and lines that begin - * with '#' - * - * Args: - * testCase: test case stream - */ -static void skipCommentLines(FILE* testCase) -{ - int firstChar; - ssize_t retval; - char* line= NULL; - size_t len; - - do - { - firstChar= fgetc(testCase); - if (firstChar == (int) '#') - { - retval= getline(&line, &len, testCase); - if (retval == -1) - { - if (feof(testCase)) - { - goto outEof; - } - else - { - g_error(strerror(errno)); - } - } - } - else if (firstChar == (int) '\n' || firstChar == (int) ' ') - {} - else if (firstChar == EOF) - { - goto outEof; - } - else - { - break; - } - } while (true); - retval= ungetc(firstChar, testCase); - if (retval == EOF) - { - g_error("Error: ungetc()"); - } - -outEof: - if (line) - { - free(line); - } -} - - -/* - * Make up events from the messages in the test case. Dispatch those events to - * the matching module. - */ -static void processEvents(SyncState* const syncState, FILE* testCase) -{ - char* line= NULL; - size_t len; - int retval; - unsigned int addressOffset; - unsigned int* seq; - - // Trace numbers run from 0 to traceNb - 1. addressOffset is added to a - // traceNum to convert it to an address. - addressOffset= pow(10, floor(log(syncState->traceNb - 1) / log(10)) + 1); - - seq= calloc(syncState->traceNb, sizeof(unsigned int)); - - skipCommentLines(testCase); - retval= getline(&line, &len, testCase); - while(!feof(testCase)) - { - unsigned int sender, receiver; - double sendTime, recvTime; - char tmp; - Event* event; - - if (retval == -1 && !feof(testCase)) - { - g_error(strerror(errno)); - } - - if (line[len - 1] == '\n') - { - line[len - 1]= '\0'; - } - - retval= sscanf(line, " %u %u %lf %lf %c", &sender, &receiver, - &sendTime, &recvTime, &tmp); - if (retval == EOF) - { - g_error(strerror(errno)); - } - else if (retval != 4) - { - g_error("Error parsing test file while looking for data point, line was '%s'", line); - } - - if (sender + 1 > syncState->traceNb) - { - g_error("Error parsing test file, sender is out of range, line was '%s'", line); - } - - if (receiver + 1 > syncState->traceNb) - { - g_error("Error parsing test file, receiver is out of range, line was '%s'", line); - } - - // Output event - event= malloc(sizeof(Event)); - event->traceNum= sender; - event->time= round(sendTime * freq); - event->type= TCP; - event->destroy= &destroyTCPEvent; - event->event.tcpEvent= malloc(sizeof(TCPEvent)); - event->event.tcpEvent->direction= OUT; - event->event.tcpEvent->segmentKey= malloc(sizeof(SegmentKey)); - event->event.tcpEvent->segmentKey->ihl= 5; - event->event.tcpEvent->segmentKey->tot_len= 40; - event->event.tcpEvent->segmentKey->connectionKey.saddr= sender + addressOffset; - event->event.tcpEvent->segmentKey->connectionKey.daddr= receiver + addressOffset; - event->event.tcpEvent->segmentKey->connectionKey.source= 57645; - event->event.tcpEvent->segmentKey->connectionKey.dest= 80; - event->event.tcpEvent->segmentKey->seq= seq[sender]; - event->event.tcpEvent->segmentKey->ack_seq= 0; - event->event.tcpEvent->segmentKey->doff= 5; - event->event.tcpEvent->segmentKey->ack= 0; - event->event.tcpEvent->segmentKey->rst= 0; - event->event.tcpEvent->segmentKey->syn= 1; - event->event.tcpEvent->segmentKey->fin= 0; - - syncState->matchingModule->matchEvent(syncState, event); - - // Input event - event= malloc(sizeof(Event)); - event->traceNum= receiver; - event->time= round(recvTime * freq); - event->type= TCP; - event->destroy= &destroyTCPEvent; - event->event.tcpEvent= malloc(sizeof(TCPEvent)); - event->event.tcpEvent->direction= IN; - event->event.tcpEvent->segmentKey= malloc(sizeof(SegmentKey)); - event->event.tcpEvent->segmentKey->ihl= 5; - event->event.tcpEvent->segmentKey->tot_len= 40; - event->event.tcpEvent->segmentKey->connectionKey.saddr= sender + addressOffset; - event->event.tcpEvent->segmentKey->connectionKey.daddr= receiver + addressOffset; - event->event.tcpEvent->segmentKey->connectionKey.source= 57645; - event->event.tcpEvent->segmentKey->connectionKey.dest= 80; - event->event.tcpEvent->segmentKey->seq= seq[sender]; - event->event.tcpEvent->segmentKey->ack_seq= 0; - event->event.tcpEvent->segmentKey->doff= 5; - event->event.tcpEvent->segmentKey->ack= 0; - event->event.tcpEvent->segmentKey->rst= 0; - event->event.tcpEvent->segmentKey->syn= 1; - event->event.tcpEvent->segmentKey->fin= 0; - - syncState->matchingModule->matchEvent(syncState, event); - - seq[sender]++; - - skipCommentLines(testCase); - retval= getline(&line, &len, testCase); - } - - free(seq); - - if (line) - { - free(line); - } -} - - -/* - * A Glib log function which does nothing. - */ -static void nullLog(const gchar *log_domain, GLogLevelFlags log_level, const - gchar *message, gpointer user_data) -{}