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
;
49 const char* processOptions(const int argc
, char* const argv
[]);
50 static void usage(const char* const programName
);
51 static void gfPrintModuleOption(gpointer data
, gpointer user_data
);
52 static void nullLog(const gchar
*log_domain
, GLogLevelFlags log_level
, const
53 gchar
*message
, gpointer user_data
);
54 static void gfAddModuleOption(gpointer data
, gpointer user_data
);
57 static ModuleOption optionSyncStats
= {
59 .longName
= "sync-stats",
61 .optionHelp
= "Print statistics and debug messages",
63 static char graphsDir
[20];
64 static ModuleOption optionSyncGraphs
= {
66 .longName
= "sync-graphs",
67 .hasArg
= OPTIONAL_ARG
,
68 .optionHelp
= "Output gnuplot graph showing synchronization points",
70 static ModuleOption optionSyncAnalysis
= {
72 .longName
= "sync-analysis",
73 .hasArg
= REQUIRED_ARG
,
74 .optionHelp
= "Specify which algorithm to use for event analysis",
79 * Implement a sync chain, it is mostly for unittest and it does not depend on
83 * argc, argv: standard argument arrays
86 * exit status from main() is always EXIT_SUCCESS
88 int main(const int argc
, char* const argv
[])
91 struct timeval startTime
, endTime
;
92 struct rusage startUsage
, endUsage
;
96 const char* testCaseName
;
97 GString
* analysisModulesNames
;
99 // Initialize data structures
100 syncState
= malloc(sizeof(SyncState
));
102 // Process command line arguments
103 g_assert(g_queue_get_length(&analysisModules
) > 0);
104 optionSyncAnalysis
.arg
= ((AnalysisModule
*)
105 g_queue_peek_head(&analysisModules
))->name
;
106 analysisModulesNames
= g_string_new("Available modules: ");
107 g_queue_foreach(&analysisModules
, &gfAppendAnalysisName
,
108 analysisModulesNames
);
109 // remove the last ", "
110 g_string_truncate(analysisModulesNames
, analysisModulesNames
->len
- 2);
111 optionSyncAnalysis
.argHelp
= analysisModulesNames
->str
;
113 retval
= snprintf(graphsDir
, sizeof(graphsDir
), "graphs-%d", getpid());
114 if (retval
> sizeof(graphsDir
) - 1)
116 graphsDir
[sizeof(graphsDir
) - 1]= '\0';
118 optionSyncGraphs
.arg
= graphsDir
;
120 g_queue_push_head(&moduleOptions
, &optionSyncAnalysis
);
121 g_queue_push_head(&moduleOptions
, &optionSyncGraphs
);
122 g_queue_push_head(&moduleOptions
, &optionSyncStats
);
124 testCaseName
= processOptions(argc
, argv
);
126 g_string_free(analysisModulesNames
, TRUE
);
128 if (optionSyncStats
.present
)
130 syncState
->stats
= true;
131 gettimeofday(&startTime
, 0);
132 getrusage(RUSAGE_SELF
, &startUsage
);
136 syncState
->stats
= false;
137 g_log_set_handler(NULL
, G_LOG_LEVEL_DEBUG
, nullLog
, NULL
);
140 if (optionSyncGraphs
.present
)
142 // Create the graph directory right away in case the module initialization
143 // functions have something to write in it.
144 syncState
->graphsDir
= optionSyncGraphs
.arg
;
145 syncState
->graphsStream
= createGraphsDir(syncState
->graphsDir
);
149 syncState
->graphsStream
= NULL
;
150 syncState
->graphsDir
= NULL
;
154 syncState
->processingData
= NULL
;
155 result
= g_queue_find_custom(&processingModules
, "text",
156 &gcfCompareProcessing
);
157 g_assert(result
!= NULL
);
158 syncState
->processingModule
= (ProcessingModule
*) result
->data
;
160 syncState
->matchingData
= NULL
;
161 result
= g_queue_find_custom(&matchingModules
, "TCP", &gcfCompareMatching
);
162 g_assert(result
!= NULL
);
163 syncState
->matchingModule
= (MatchingModule
*) result
->data
;
165 syncState
->analysisData
= NULL
;
166 result
= g_queue_find_custom(&analysisModules
, optionSyncAnalysis
.arg
,
167 &gcfCompareAnalysis
);
170 syncState
->analysisModule
= (AnalysisModule
*) result
->data
;
174 g_error("Analysis module '%s' not found", optionSyncAnalysis
.arg
);
177 // Initialize modules
178 syncState
->processingModule
->initProcessing(syncState
, testCaseName
);
179 syncState
->matchingModule
->initMatching(syncState
);
180 syncState
->analysisModule
->initAnalysis(syncState
);
183 syncState
->processingModule
->finalizeProcessing(syncState
);
186 if (syncState
->graphsStream
)
188 writeGraphsScript(syncState
);
190 if (fclose(syncState
->graphsStream
) != 0)
192 g_error(strerror(errno
));
197 if (syncState
->stats
)
199 printStats(syncState
);
202 // Destroy modules and clean up
203 syncState
->processingModule
->destroyProcessing(syncState
);
204 syncState
->matchingModule
->destroyMatching(syncState
);
205 syncState
->analysisModule
->destroyAnalysis(syncState
);
207 stats
= syncState
->stats
;
212 gettimeofday(&endTime
, 0);
213 retval
= getrusage(RUSAGE_SELF
, &endUsage
);
215 timeDiff(&endTime
, &startTime
);
216 timeDiff(&endUsage
.ru_utime
, &startUsage
.ru_utime
);
217 timeDiff(&endUsage
.ru_stime
, &startUsage
.ru_stime
);
219 printf("Synchronization time:\n");
220 printf("\treal time: %ld.%06ld\n", endTime
.tv_sec
, endTime
.tv_usec
);
221 printf("\tuser time: %ld.%06ld\n", endUsage
.ru_utime
.tv_sec
,
222 endUsage
.ru_utime
.tv_usec
);
223 printf("\tsystem time: %ld.%06ld\n", endUsage
.ru_stime
.tv_sec
,
224 endUsage
.ru_stime
.tv_usec
);
232 * Read program arguments dans update ModuleOptions structures
235 * argc, argv: standard argument arrays
238 * Name of the test case file (first parameter)
240 const char* processOptions(const int argc
, char* const argv
[])
244 extern int optind
, opterr
, optopt
;
246 GString
* optionString
;
249 longOptions
= g_array_sized_new(TRUE
, FALSE
, sizeof(struct option
),
250 g_queue_get_length(&moduleOptions
));
251 optionString
= g_string_new("");
252 index
= g_queue_new();
254 g_queue_foreach(&moduleOptions
, &gfAddModuleOption
, &(struct OptionsInfo
)
255 {longOptions
, optionString
, index
});
261 c
= getopt_long(argc
, argv
, optionString
->str
, (struct option
*)
262 longOptions
->data
, &optionIndex
);
264 if (c
>= 0 && c
< g_queue_get_length(index
))
266 ModuleOption
* moduleOption
= g_queue_peek_nth(index
, c
);
268 moduleOption
->present
= true;
270 if (moduleOption
->hasArg
== REQUIRED_ARG
|| moduleOption
->hasArg
273 moduleOption
->arg
= optarg
;
287 g_error("Option parse error");
291 g_array_free(longOptions
, TRUE
);
292 g_string_free(optionString
, TRUE
);
296 fprintf(stderr
, "Test file unspecified\n");
306 * Print information about program options and arguments.
309 * programName: name of the program, as contained in argv[0] for example
311 static void usage(const char* const programName
)
314 "%s [options] <test file>\n"
315 "Options:\n", programName
);
317 g_queue_foreach(&moduleOptions
, &gfPrintModuleOption
, NULL
);
322 * A GFunc for g_queue_foreach()
324 * Print analysis module names.
327 * data: ModuleOption*, option
330 static void gfPrintModuleOption(gpointer data
, gpointer user_data
)
332 ModuleOption
* option
= data
;
333 int width
= 0, sum
= 0;
334 const int colWidth
= 27;
338 if (option
->shortName
)
340 printf("-%c, %n", option
->shortName
, &width
);
344 printf("--%-s%n", option
->longName
, &width
);
347 if (option
->hasArg
== REQUIRED_ARG
|| option
->hasArg
== OPTIONAL_ARG
)
349 printf("=[..]%n", &width
);
353 if (option
->optionHelp
)
355 printf("%*s%s\n", colWidth
- sum
> 0 ? colWidth
- sum
: 0, "", option
->optionHelp
);
360 printf("\t%*s%s\n", colWidth
, "", option
->argHelp
);
363 if ((option
->hasArg
== REQUIRED_ARG
|| option
->hasArg
== OPTIONAL_ARG
) && option
->arg
)
365 printf("\t%*sDefault value: %s\n", colWidth
, "", option
->arg
);
371 * A Glib log function which does nothing.
373 static void nullLog(const gchar
*log_domain
, GLogLevelFlags log_level
, const
374 gchar
*message
, gpointer user_data
)
379 * A GFunc for g_queue_foreach()
382 * data: ModuleOption*, option
383 * user_data: struct OptionsInfo*, add option to this array of struct option
385 static void gfAddModuleOption(gpointer data
, gpointer user_data
)
387 ModuleOption
* option
= data
;
388 struct OptionsInfo
* optionsInfo
= user_data
;
389 struct option newOption
;
390 // "[mixing enumerations] can still be considered bad style even though it
391 // is not strictly illegal" c.faq 2.22
392 const int conversion
[]= {
393 [NO_ARG
]= no_argument
,
394 [OPTIONAL_ARG
]= optional_argument
,
395 [REQUIRED_ARG
]= required_argument
,
397 const char* colons
[]= {
399 [OPTIONAL_ARG
]= "::",
403 newOption
.name
= option
->longName
;
404 newOption
.has_arg
= conversion
[option
->hasArg
];
405 newOption
.flag
= NULL
;
406 newOption
.val
= g_queue_get_length(optionsInfo
->index
);
408 g_array_append_val(optionsInfo
->longOptions
, newOption
);
409 g_string_append(optionsInfo
->optionString
, colons
[option
->hasArg
]);
410 g_queue_push_tail(optionsInfo
->index
, option
);