1 /* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2009 Benjamin Poirier <benjamin.poirier@polymtl.ca>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License Version 2 as
6 * published by the Free Software Foundation;
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
31 #include <sys/resource.h>
34 #include <sys/types.h>
38 #include "sync_chain.h"
44 GString
* optionString
;
46 GHashTable
* shortIndex
;
50 const char* processOptions(const int argc
, char* const argv
[]);
51 static void usage(const char* const programName
);
52 static void gfPrintModuleOption(gpointer data
, gpointer user_data
);
53 static void nullLog(const gchar
*log_domain
, GLogLevelFlags log_level
, const
54 gchar
*message
, gpointer user_data
);
55 static void gfAddModuleOption(gpointer data
, gpointer user_data
);
56 static guint
ghfCharHash(gconstpointer key
);
57 static gboolean
gefCharEqual(gconstpointer a
, gconstpointer b
);
60 static ModuleOption optionSyncStats
= {
62 .longName
= "sync-stats",
64 .optionHelp
= "Print statistics and debug messages",
66 static char graphsDir
[20];
67 static ModuleOption optionSyncGraphs
= {
69 .longName
= "sync-graphs",
70 .hasArg
= OPTIONAL_ARG
,
71 .optionHelp
= "Output gnuplot graph showing synchronization points",
73 static ModuleOption optionSyncAnalysis
= {
75 .longName
= "sync-analysis",
76 .hasArg
= REQUIRED_ARG
,
77 .optionHelp
= "Specify which algorithm to use for event analysis",
82 * Implement a sync chain, it is mostly for unittest and it does not depend on
86 * argc, argv: standard argument arrays
89 * exit status from main() is always EXIT_SUCCESS
91 int main(const int argc
, char* const argv
[])
94 struct timeval startTime
, endTime
;
95 struct rusage startUsage
, endUsage
;
99 const char* testCaseName
;
100 GString
* analysisModulesNames
;
103 // Initialize data structures
104 syncState
= malloc(sizeof(SyncState
));
106 // Process command line arguments
107 g_assert(g_queue_get_length(&analysisModules
) > 0);
108 optionSyncAnalysis
.arg
= ((AnalysisModule
*)
109 g_queue_peek_head(&analysisModules
))->name
;
110 analysisModulesNames
= g_string_new("Available modules: ");
111 g_queue_foreach(&analysisModules
, &gfAppendAnalysisName
,
112 analysisModulesNames
);
113 // remove the last ", "
114 g_string_truncate(analysisModulesNames
, analysisModulesNames
->len
- 2);
115 optionSyncAnalysis
.argHelp
= analysisModulesNames
->str
;
117 retval
= snprintf(graphsDir
, sizeof(graphsDir
), "graphs-%d", getpid());
118 if (retval
> sizeof(graphsDir
) - 1)
120 graphsDir
[sizeof(graphsDir
) - 1]= '\0';
122 optionSyncGraphs
.arg
= graphsDir
;
124 g_queue_push_head(&moduleOptions
, &optionSyncAnalysis
);
125 g_queue_push_head(&moduleOptions
, &optionSyncGraphs
);
126 g_queue_push_head(&moduleOptions
, &optionSyncStats
);
128 testCaseName
= processOptions(argc
, argv
);
130 g_string_free(analysisModulesNames
, TRUE
);
132 if (optionSyncStats
.present
)
134 syncState
->stats
= true;
135 gettimeofday(&startTime
, 0);
136 getrusage(RUSAGE_SELF
, &startUsage
);
140 syncState
->stats
= false;
141 id
= g_log_set_handler(NULL
, G_LOG_LEVEL_DEBUG
, nullLog
, NULL
);
144 if (optionSyncGraphs
.present
)
146 // Create the graph directory right away in case the module initialization
147 // functions have something to write in it.
148 syncState
->graphsDir
= optionSyncGraphs
.arg
;
149 syncState
->graphsStream
= createGraphsDir(syncState
->graphsDir
);
153 syncState
->graphsStream
= NULL
;
154 syncState
->graphsDir
= NULL
;
158 syncState
->processingData
= NULL
;
159 result
= g_queue_find_custom(&processingModules
, "text",
160 &gcfCompareProcessing
);
161 g_assert(result
!= NULL
);
162 syncState
->processingModule
= (ProcessingModule
*) result
->data
;
164 syncState
->matchingData
= NULL
;
165 result
= g_queue_find_custom(&matchingModules
, "TCP", &gcfCompareMatching
);
166 g_assert(result
!= NULL
);
167 syncState
->matchingModule
= (MatchingModule
*) result
->data
;
169 syncState
->analysisData
= NULL
;
170 result
= g_queue_find_custom(&analysisModules
, optionSyncAnalysis
.arg
,
171 &gcfCompareAnalysis
);
174 syncState
->analysisModule
= (AnalysisModule
*) result
->data
;
178 g_error("Analysis module '%s' not found", optionSyncAnalysis
.arg
);
181 // Initialize modules
182 syncState
->processingModule
->initProcessing(syncState
, testCaseName
);
183 syncState
->matchingModule
->initMatching(syncState
);
184 syncState
->analysisModule
->initAnalysis(syncState
);
187 syncState
->processingModule
->finalizeProcessing(syncState
);
190 if (syncState
->graphsStream
)
192 writeGraphsScript(syncState
);
194 if (fclose(syncState
->graphsStream
) != 0)
196 g_error(strerror(errno
));
201 if (syncState
->stats
)
203 printStats(syncState
);
206 // Destroy modules and clean up
207 syncState
->processingModule
->destroyProcessing(syncState
);
208 syncState
->matchingModule
->destroyMatching(syncState
);
209 syncState
->analysisModule
->destroyAnalysis(syncState
);
211 stats
= syncState
->stats
;
216 gettimeofday(&endTime
, 0);
217 retval
= getrusage(RUSAGE_SELF
, &endUsage
);
219 timeDiff(&endTime
, &startTime
);
220 timeDiff(&endUsage
.ru_utime
, &startUsage
.ru_utime
);
221 timeDiff(&endUsage
.ru_stime
, &startUsage
.ru_stime
);
223 printf("Synchronization time:\n");
224 printf("\treal time: %ld.%06ld\n", endTime
.tv_sec
, endTime
.tv_usec
);
225 printf("\tuser time: %ld.%06ld\n", endUsage
.ru_utime
.tv_sec
,
226 endUsage
.ru_utime
.tv_usec
);
227 printf("\tsystem time: %ld.%06ld\n", endUsage
.ru_stime
.tv_sec
,
228 endUsage
.ru_stime
.tv_usec
);
231 if (!optionSyncStats
.present
)
233 g_log_remove_handler(NULL
, id
);
241 * Read program arguments dans update ModuleOptions structures
244 * argc, argv: standard argument arrays
247 * Name of the test case file (first parameter)
249 const char* processOptions(const int argc
, char* const argv
[])
253 extern int optind
, opterr
, optopt
;
255 GString
* optionString
;
258 GHashTable
* shortIndex
;
260 longOptions
= g_array_sized_new(TRUE
, FALSE
, sizeof(struct option
),
261 g_queue_get_length(&moduleOptions
));
262 optionString
= g_string_new("");
263 longIndex
= g_queue_new();
264 shortIndex
= g_hash_table_new(&ghfCharHash
, &gefCharEqual
);
266 g_queue_foreach(&moduleOptions
, &gfAddModuleOption
, &(struct OptionsInfo
)
267 {longOptions
, optionString
, longIndex
, shortIndex
});
272 ModuleOption
* moduleOption
;
275 c
= getopt_long(argc
, argv
, optionString
->str
, (struct option
*)
276 longOptions
->data
, &optionIndex
);
278 if (longOption
>= 0 && longOption
< g_queue_get_length(longIndex
))
280 moduleOption
= g_queue_peek_nth(longIndex
, longOption
);
282 else if ((moduleOption
= g_hash_table_lookup(shortIndex
, &c
)) != NULL
)
296 g_error("Option parse error");
299 moduleOption
->present
= true;
301 if (moduleOption
->hasArg
== REQUIRED_ARG
)
303 moduleOption
->arg
= optarg
;
305 if (moduleOption
->hasArg
== OPTIONAL_ARG
&& optarg
)
307 moduleOption
->arg
= optarg
;
311 g_array_free(longOptions
, TRUE
);
312 g_string_free(optionString
, TRUE
);
313 g_queue_free(longIndex
);
314 g_hash_table_destroy(shortIndex
);
318 fprintf(stderr
, "Test file unspecified\n");
328 * Print information about program options and arguments.
331 * programName: name of the program, as contained in argv[0] for example
333 static void usage(const char* const programName
)
336 "%s [options] <test file>\n"
337 "Options:\n", programName
);
339 g_queue_foreach(&moduleOptions
, &gfPrintModuleOption
, NULL
);
344 * A GFunc for g_queue_foreach()
346 * Print analysis module names.
349 * data: ModuleOption*, option
352 static void gfPrintModuleOption(gpointer data
, gpointer user_data
)
354 ModuleOption
* option
= data
;
355 int width
= 0, sum
= 0;
356 const int colWidth
= 27;
360 if (option
->shortName
)
362 printf("-%c, %n", option
->shortName
, &width
);
366 printf("--%-s%n", option
->longName
, &width
);
369 if (option
->hasArg
== REQUIRED_ARG
|| option
->hasArg
== OPTIONAL_ARG
)
371 printf("=[..]%n", &width
);
375 if (option
->optionHelp
)
377 printf("%*s%s\n", colWidth
- sum
> 0 ? colWidth
- sum
: 0, "", option
->optionHelp
);
382 printf("\t%*s%s\n", colWidth
, "", option
->argHelp
);
385 if ((option
->hasArg
== REQUIRED_ARG
|| option
->hasArg
== OPTIONAL_ARG
) && option
->arg
)
387 printf("\t%*sDefault value: %s\n", colWidth
, "", option
->arg
);
393 * A Glib log function which does nothing.
395 static void nullLog(const gchar
*log_domain
, GLogLevelFlags log_level
, const
396 gchar
*message
, gpointer user_data
)
401 * A GFunc for g_queue_foreach()
404 * data: ModuleOption*, option
405 * user_data: struct OptionsInfo*, add option to this array of struct option
407 static void gfAddModuleOption(gpointer data
, gpointer user_data
)
409 ModuleOption
* option
= data
;
410 struct OptionsInfo
* optionsInfo
= user_data
;
411 struct option newOption
;
412 // "[mixing enumerations] can still be considered bad style even though it
413 // is not strictly illegal" c.faq 2.22
414 const int conversion
[]= {
415 [NO_ARG
]= no_argument
,
416 [OPTIONAL_ARG
]= optional_argument
,
417 [REQUIRED_ARG
]= required_argument
,
419 const char* colons
[]= {
421 [OPTIONAL_ARG
]= "::",
425 newOption
.name
= option
->longName
;
426 newOption
.has_arg
= conversion
[option
->hasArg
];
427 newOption
.flag
= NULL
;
428 newOption
.val
= g_queue_get_length(optionsInfo
->longIndex
);
430 g_array_append_val(optionsInfo
->longOptions
, newOption
);
431 if (option
->shortName
)
433 g_string_append_c(optionsInfo
->optionString
, option
->shortName
);
434 g_string_append(optionsInfo
->optionString
, colons
[option
->hasArg
]);
436 g_hash_table_insert(optionsInfo
->shortIndex
, &option
->shortName
,
439 g_queue_push_tail(optionsInfo
->longIndex
, option
);
444 * A GHashFunc for g_hash_table_new()
447 * key char*, just one character
449 static guint
ghfCharHash(gconstpointer key
)
456 * A GEqualFunc for g_hash_table_new()
459 * a, b char*, just one character each
462 * TRUE if both values are equal
464 static gboolean
gefCharEqual(gconstpointer a
, gconstpointer b
)
466 if (*(char*) a
== *(char*) b
)