Fix leaks and invalid memory accesses
[lttv.git] / lttv / lttv / sync / sync_chain_unittest.c
CommitLineData
b670bb7c
BP
1/* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2009 Benjamin Poirier <benjamin.poirier@polymtl.ca>
3 *
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;
7 *
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.
12 *
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,
16 * MA 02111-1307, USA.
17 */
18
19#define _GNU_SOURCE
20
21#ifdef HAVE_CONFIG_H
22#include <config.h>
23#endif
24
25#include <errno.h>
26#include <fcntl.h>
27#include <getopt.h>
28#include <stdio.h>
29#include <stdlib.h>
30#include <string.h>
31#include <sys/resource.h>
32#include <sys/stat.h>
33#include <sys/time.h>
34#include <sys/types.h>
35#include <sys/stat.h>
36#include <unistd.h>
37
38#include "sync_chain.h"
39
40
41struct OptionsInfo
42{
43 GArray* longOptions;
44 GString* optionString;
48b641c1
BP
45 GQueue* longIndex;
46 GHashTable* shortIndex;
b670bb7c
BP
47};
48
49
50const char* processOptions(const int argc, char* const argv[]);
51static void usage(const char* const programName);
52static void gfPrintModuleOption(gpointer data, gpointer user_data);
53static void nullLog(const gchar *log_domain, GLogLevelFlags log_level, const
54 gchar *message, gpointer user_data);
55static void gfAddModuleOption(gpointer data, gpointer user_data);
48b641c1
BP
56static guint ghfCharHash(gconstpointer key);
57static gboolean gefCharEqual(gconstpointer a, gconstpointer b);
b670bb7c
BP
58
59
60static ModuleOption optionSyncStats= {
61 .shortName= 's',
62 .longName= "sync-stats",
63 .hasArg= NO_ARG,
64 .optionHelp= "Print statistics and debug messages",
65};
66static char graphsDir[20];
67static ModuleOption optionSyncGraphs= {
68 .shortName= 'g',
69 .longName= "sync-graphs",
70 .hasArg= OPTIONAL_ARG,
71 .optionHelp= "Output gnuplot graph showing synchronization points",
72};
73static ModuleOption optionSyncAnalysis= {
74 .shortName= 'a',
75 .longName= "sync-analysis",
76 .hasArg= REQUIRED_ARG,
77 .optionHelp= "Specify which algorithm to use for event analysis",
78};
79
80
81/*
82 * Implement a sync chain, it is mostly for unittest and it does not depend on
83 * lttv
84 *
85 * Args:
86 * argc, argv: standard argument arrays
87 *
88 * Returns:
89 * exit status from main() is always EXIT_SUCCESS
90 */
91int main(const int argc, char* const argv[])
92{
93 SyncState* syncState;
94 struct timeval startTime, endTime;
95 struct rusage startUsage, endUsage;
96 GList* result;
97 int retval;
98 bool stats;
99 const char* testCaseName;
100 GString* analysisModulesNames;
6ce8ceac 101 unsigned int id;
b670bb7c
BP
102
103 // Initialize data structures
104 syncState= malloc(sizeof(SyncState));
105
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;
116
117 retval= snprintf(graphsDir, sizeof(graphsDir), "graphs-%d", getpid());
118 if (retval > sizeof(graphsDir) - 1)
119 {
120 graphsDir[sizeof(graphsDir) - 1]= '\0';
121 }
122 optionSyncGraphs.arg= graphsDir;
123
124 g_queue_push_head(&moduleOptions, &optionSyncAnalysis);
125 g_queue_push_head(&moduleOptions, &optionSyncGraphs);
126 g_queue_push_head(&moduleOptions, &optionSyncStats);
127
128 testCaseName= processOptions(argc, argv);
129
130 g_string_free(analysisModulesNames, TRUE);
131
132 if (optionSyncStats.present)
133 {
134 syncState->stats= true;
135 gettimeofday(&startTime, 0);
136 getrusage(RUSAGE_SELF, &startUsage);
137 }
138 else
139 {
140 syncState->stats= false;
6ce8ceac 141 id= g_log_set_handler(NULL, G_LOG_LEVEL_DEBUG, nullLog, NULL);
b670bb7c
BP
142 }
143
144 if (optionSyncGraphs.present)
145 {
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);
150 }
151 else
152 {
153 syncState->graphsStream= NULL;
154 syncState->graphsDir= NULL;
155 }
156
157 // Identify modules
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;
163
164 syncState->matchingData= NULL;
165 result= g_queue_find_custom(&matchingModules, "TCP", &gcfCompareMatching);
166 g_assert(result != NULL);
167 syncState->matchingModule= (MatchingModule*) result->data;
168
169 syncState->analysisData= NULL;
170 result= g_queue_find_custom(&analysisModules, optionSyncAnalysis.arg,
171 &gcfCompareAnalysis);
172 if (result != NULL)
173 {
174 syncState->analysisModule= (AnalysisModule*) result->data;
175 }
176 else
177 {
178 g_error("Analysis module '%s' not found", optionSyncAnalysis.arg);
179 }
180
181 // Initialize modules
182 syncState->processingModule->initProcessing(syncState, testCaseName);
183 syncState->matchingModule->initMatching(syncState);
184 syncState->analysisModule->initAnalysis(syncState);
185
186 // Process traceset
187 syncState->processingModule->finalizeProcessing(syncState);
188
189 // Write graphs file
190 if (syncState->graphsStream)
191 {
192 writeGraphsScript(syncState);
193
194 if (fclose(syncState->graphsStream) != 0)
195 {
196 g_error(strerror(errno));
197 }
198 }
199
200 // Print statistics
201 if (syncState->stats)
202 {
203 printStats(syncState);
204 }
205
206 // Destroy modules and clean up
207 syncState->processingModule->destroyProcessing(syncState);
208 syncState->matchingModule->destroyMatching(syncState);
209 syncState->analysisModule->destroyAnalysis(syncState);
210
211 stats= syncState->stats;
212 free(syncState);
213
214 if (stats)
215 {
216 gettimeofday(&endTime, 0);
217 retval= getrusage(RUSAGE_SELF, &endUsage);
218
219 timeDiff(&endTime, &startTime);
220 timeDiff(&endUsage.ru_utime, &startUsage.ru_utime);
221 timeDiff(&endUsage.ru_stime, &startUsage.ru_stime);
222
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);
229 }
230
6ce8ceac
BP
231 if (!optionSyncStats.present)
232 {
233 g_log_remove_handler(NULL, id);
234 }
235
b670bb7c
BP
236 return EXIT_SUCCESS;
237}
238
239
240/*
241 * Read program arguments dans update ModuleOptions structures
242 *
243 * Args:
244 * argc, argv: standard argument arrays
245 *
246 * Returns:
247 * Name of the test case file (first parameter)
248 */
249const char* processOptions(const int argc, char* const argv[])
250{
251 int c;
252 extern char* optarg;
253 extern int optind, opterr, optopt;
254 GArray* longOptions;
255 GString* optionString;
48b641c1
BP
256 GQueue* longIndex;
257 int longOption;
258 GHashTable* shortIndex;
b670bb7c
BP
259
260 longOptions= g_array_sized_new(TRUE, FALSE, sizeof(struct option),
261 g_queue_get_length(&moduleOptions));
262 optionString= g_string_new("");
48b641c1
BP
263 longIndex= g_queue_new();
264 shortIndex= g_hash_table_new(&ghfCharHash, &gefCharEqual);
b670bb7c
BP
265
266 g_queue_foreach(&moduleOptions, &gfAddModuleOption, &(struct OptionsInfo)
48b641c1 267 {longOptions, optionString, longIndex, shortIndex});
b670bb7c
BP
268
269 do
270 {
271 int optionIndex= 0;
48b641c1 272 ModuleOption* moduleOption;
b670bb7c 273
48b641c1 274 longOption= -1;
b670bb7c
BP
275 c= getopt_long(argc, argv, optionString->str, (struct option*)
276 longOptions->data, &optionIndex);
277
48b641c1
BP
278 if (longOption >= 0 && longOption < g_queue_get_length(longIndex))
279 {
280 moduleOption= g_queue_peek_nth(longIndex, longOption);
281 }
282 else if ((moduleOption= g_hash_table_lookup(shortIndex, &c)) != NULL)
b670bb7c 283 {
b670bb7c
BP
284 }
285 else if (c == -1)
286 {
287 break;
288 }
289 else if (c == '?')
290 {
291 usage(argv[0]);
292 abort();
293 }
294 else
295 {
296 g_error("Option parse error");
297 }
48b641c1
BP
298
299 moduleOption->present= true;
300
301 if (moduleOption->hasArg == REQUIRED_ARG)
302 {
303 moduleOption->arg= optarg;
304 }
305 if (moduleOption->hasArg == OPTIONAL_ARG && optarg)
306 {
307 moduleOption->arg= optarg;
308 }
b670bb7c
BP
309 } while (c != -1);
310
311 g_array_free(longOptions, TRUE);
312 g_string_free(optionString, TRUE);
48b641c1
BP
313 g_queue_free(longIndex);
314 g_hash_table_destroy(shortIndex);
b670bb7c
BP
315
316 if (argc <= optind)
317 {
318 fprintf(stderr, "Test file unspecified\n");
319 usage(argv[0]);
320 abort();
321 }
322
323 return argv[optind];
324}
325
326
327/*
328 * Print information about program options and arguments.
329 *
330 * Args:
331 * programName: name of the program, as contained in argv[0] for example
332 */
333static void usage(const char* const programName)
334{
335 printf(
336 "%s [options] <test file>\n"
337 "Options:\n", programName);
338
339 g_queue_foreach(&moduleOptions, &gfPrintModuleOption, NULL);
340}
341
342
343/*
344 * A GFunc for g_queue_foreach()
345 *
346 * Print analysis module names.
347 *
348 * Args:
349 * data: ModuleOption*, option
350 * user_data: NULL
351 */
352static void gfPrintModuleOption(gpointer data, gpointer user_data)
353{
354 ModuleOption* option= data;
355 int width= 0, sum= 0;
356 const int colWidth= 27;
357
358 printf("\t");
359
360 if (option->shortName)
361 {
362 printf("-%c, %n", option->shortName, &width);
363 sum+= width;
364 }
365
366 printf("--%-s%n", option->longName, &width);
367 sum+= width;
368
369 if (option->hasArg == REQUIRED_ARG || option->hasArg == OPTIONAL_ARG)
370 {
371 printf("=[..]%n", &width);
372 sum+= width;
373 }
374
375 if (option->optionHelp)
376 {
377 printf("%*s%s\n", colWidth - sum > 0 ? colWidth - sum : 0, "", option->optionHelp);
378 }
379
380 if (option->argHelp)
381 {
382 printf("\t%*s%s\n", colWidth, "", option->argHelp);
383 }
384
385 if ((option->hasArg == REQUIRED_ARG || option->hasArg == OPTIONAL_ARG) && option->arg)
386 {
387 printf("\t%*sDefault value: %s\n", colWidth, "", option->arg);
388 }
389}
390
391
392/*
393 * A Glib log function which does nothing.
394 */
395static void nullLog(const gchar *log_domain, GLogLevelFlags log_level, const
396 gchar *message, gpointer user_data)
397{}
398
399
400/*
401 * A GFunc for g_queue_foreach()
402 *
403 * Args:
404 * data: ModuleOption*, option
405 * user_data: struct OptionsInfo*, add option to this array of struct option
406 */
407static void gfAddModuleOption(gpointer data, gpointer user_data)
408{
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,
418 };
419 const char* colons[]= {
420 [NO_ARG]= "",
421 [OPTIONAL_ARG]= "::",
422 [REQUIRED_ARG]= ":",
423 };
424
425 newOption.name= option->longName;
426 newOption.has_arg= conversion[option->hasArg];
427 newOption.flag= NULL;
48b641c1 428 newOption.val= g_queue_get_length(optionsInfo->longIndex);
b670bb7c
BP
429
430 g_array_append_val(optionsInfo->longOptions, newOption);
48b641c1
BP
431 if (option->shortName)
432 {
433 g_string_append_c(optionsInfo->optionString, option->shortName);
434 g_string_append(optionsInfo->optionString, colons[option->hasArg]);
435
436 g_hash_table_insert(optionsInfo->shortIndex, &option->shortName,
437 option);
438 }
439 g_queue_push_tail(optionsInfo->longIndex, option);
440}
441
442
443/*
444 * A GHashFunc for g_hash_table_new()
445 *
446 * Args:
447 * key char*, just one character
448 */
449static guint ghfCharHash(gconstpointer key)
450{
451 return *(char*) key;
452}
453
454
455/*
456 * A GEqualFunc for g_hash_table_new()
457 *
458 * Args:
459 * a, b char*, just one character each
460 *
461 * Returns:
462 * TRUE if both values are equal
463 */
464static gboolean gefCharEqual(gconstpointer a, gconstpointer b)
465{
466 if (*(char*) a == *(char*) b)
467 {
468 return TRUE;
469 }
470 else
471 {
472 return FALSE;
473 }
b670bb7c 474}
This page took 0.040278 seconds and 4 git commands to generate.