--- /dev/null
+/* This file is part of the Linux Trace Toolkit viewer
+ * Copyright (C) 2009 Benjamin Poirier <benjamin.poirier@polymtl.ca>
+ *
+ * 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 <config.h>
+#endif
+
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#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] <test file>\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);
+}
+++ /dev/null
-/* This file is part of the Linux Trace Toolkit viewer
- * Copyright (C) 2009 Benjamin Poirier <benjamin.poirier@polymtl.ca>
- *
- * 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 <config.h>
-#endif
-
-#include <errno.h>
-#include <fcntl.h>
-#include <getopt.h>
-#include <stdio.h>
-#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>
-
-#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] <test file>\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)
-{}