Update the README file to mark the project as unmaintained
[lttv.git] / lttv / lttv / sync / sync_chain_unittest.c
1 /* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2009, 2010 Benjamin Poirier <benjamin.poirier@polymtl.ca>
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation, either version 2.1 of the License, or (at
7 * your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
12 * License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #define _GNU_SOURCE
19
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23
24 #include <errno.h>
25 #include <fcntl.h>
26 #include <getopt.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <sys/resource.h>
31 #include <sys/stat.h>
32 #include <sys/time.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <unistd.h>
36
37 #include "event_processing_text.h"
38 #include "event_matching_tcp.h"
39 #include "event_matching_broadcast.h"
40 #include "event_matching_distributor.h"
41 #include "event_analysis_chull.h"
42 #include "event_analysis_linreg.h"
43 #include "event_analysis_eval.h"
44 #include "factor_reduction_accuracy.h"
45 #include "sync_chain.h"
46
47
48 struct OptionsInfo
49 {
50 GArray* longOptions;
51 GString* optionString;
52 GQueue* longIndex;
53 GHashTable* shortIndex;
54 };
55
56
57 const char* processOptions(const int argc, char* const argv[]);
58 static void usage(const char* const programName);
59 static void gfPrintModuleOption(gpointer data, gpointer user_data);
60 static void nullLog(const gchar *log_domain, GLogLevelFlags log_level, const
61 gchar *message, gpointer user_data);
62 static void gfAddModuleOption(gpointer data, gpointer user_data);
63 static guint ghfCharHash(gconstpointer key);
64 static gboolean gefCharEqual(gconstpointer a, gconstpointer b);
65
66
67 static ModuleOption optionSyncStats= {
68 .shortName= 's',
69 .longName= "sync-stats",
70 .hasArg= NO_ARG,
71 .optionHelp= "Print statistics and debug messages",
72 };
73 static char graphsDir[20];
74 static ModuleOption optionSyncGraphs= {
75 .shortName= 'g',
76 .longName= "sync-graphs",
77 .hasArg= OPTIONAL_ARG,
78 .optionHelp= "Output gnuplot graph showing synchronization points",
79 };
80 static ModuleOption optionSyncAnalysis= {
81 .shortName= 'a',
82 .longName= "sync-analysis",
83 .hasArg= REQUIRED_ARG,
84 .optionHelp= "Specify which algorithm to use for event analysis",
85 };
86 static ModuleOption optionSyncReduction= {
87 .shortName= 'r',
88 .longName= "sync-reduction",
89 .hasArg= REQUIRED_ARG,
90 .optionHelp= "Specify which algorithm to use for factor reduction",
91 };
92
93
94 /*
95 * Implement a sync chain, it is mostly for unittest and it does not depend on
96 * lttv
97 *
98 * Args:
99 * argc, argv: standard argument arrays
100 *
101 * Returns:
102 * exit status from main() is always EXIT_SUCCESS
103 */
104 int main(const int argc, char* const argv[])
105 {
106 SyncState* syncState;
107 struct timeval startTime, endTime;
108 struct rusage startUsage, endUsage;
109 GList* result;
110 GArray* factors;
111 int retval;
112 bool stats;
113 const char* testCaseName;
114 GString* analysisModulesNames;
115 GString* reductionModulesNames;
116 unsigned int id;
117 AllFactors* allFactors;
118
119 /*
120 * Initialize event modules
121 * Call the "constructor" or initialization function of each event module
122 * so it can register itself. This must be done before elements in
123 * processingModules, matchingModules, analysisModules or moduleOptions
124 * are accessed.
125 */
126 registerProcessingText();
127
128 registerMatchingTCP();
129 registerMatchingBroadcast();
130 registerMatchingDistributor();
131
132 registerAnalysisCHull();
133 registerAnalysisLinReg();
134 registerAnalysisEval();
135
136 registerReductionAccuracy();
137
138 // Initialize data structures
139 syncState= malloc(sizeof(SyncState));
140
141 // Process command line arguments
142 g_assert(g_queue_get_length(&analysisModules) > 0);
143 optionSyncAnalysis.arg= ((AnalysisModule*)
144 g_queue_peek_head(&analysisModules))->name;
145 analysisModulesNames= g_string_new("Available modules: ");
146 g_queue_foreach(&analysisModules, &gfAppendAnalysisName,
147 analysisModulesNames);
148 // remove the last ", "
149 g_string_truncate(analysisModulesNames, analysisModulesNames->len - 2);
150 optionSyncAnalysis.argHelp= analysisModulesNames->str;
151
152 g_assert(g_queue_get_length(&reductionModules) > 0);
153 optionSyncReduction.arg= ((ReductionModule*)
154 g_queue_peek_head(&reductionModules))->name;
155 reductionModulesNames= g_string_new("Available modules: ");
156 g_queue_foreach(&reductionModules, &gfAppendReductionName,
157 reductionModulesNames);
158 // remove the last ", "
159 g_string_truncate(reductionModulesNames, reductionModulesNames->len - 2);
160 optionSyncReduction.argHelp= reductionModulesNames->str;
161
162 retval= snprintf(graphsDir, sizeof(graphsDir), "graphs-%d", getpid());
163 if (retval > sizeof(graphsDir) - 1)
164 {
165 graphsDir[sizeof(graphsDir) - 1]= '\0';
166 }
167 optionSyncGraphs.arg= graphsDir;
168
169 g_queue_push_head(&moduleOptions, &optionSyncReduction);
170 g_queue_push_head(&moduleOptions, &optionSyncAnalysis);
171 g_queue_push_head(&moduleOptions, &optionSyncGraphs);
172 g_queue_push_head(&moduleOptions, &optionSyncStats);
173
174 testCaseName= processOptions(argc, argv);
175
176 g_string_free(analysisModulesNames, TRUE);
177 g_string_free(reductionModulesNames, TRUE);
178
179 if (optionSyncStats.present)
180 {
181 syncState->stats= true;
182 gettimeofday(&startTime, 0);
183 getrusage(RUSAGE_SELF, &startUsage);
184 }
185 else
186 {
187 syncState->stats= false;
188 id= g_log_set_handler(NULL, G_LOG_LEVEL_DEBUG, nullLog, NULL);
189 }
190
191 if (optionSyncGraphs.present)
192 {
193 // Create the graph directory right away in case the module initialization
194 // functions have something to write in it.
195 syncState->graphsDir= optionSyncGraphs.arg;
196 syncState->graphsStream= createGraphsDir(syncState->graphsDir);
197 }
198 else
199 {
200 syncState->graphsStream= NULL;
201 syncState->graphsDir= NULL;
202 }
203
204 // Identify modules
205 syncState->processingData= NULL;
206 result= g_queue_find_custom(&processingModules, "text",
207 &gcfCompareProcessing);
208 g_assert(result != NULL);
209 syncState->processingModule= (ProcessingModule*) result->data;
210
211 syncState->matchingData= NULL;
212 result= g_queue_find_custom(&matchingModules, "TCP", &gcfCompareMatching);
213 g_assert(result != NULL);
214 syncState->matchingModule= (MatchingModule*) result->data;
215
216 syncState->analysisData= NULL;
217 result= g_queue_find_custom(&analysisModules, optionSyncAnalysis.arg,
218 &gcfCompareAnalysis);
219 if (result != NULL)
220 {
221 syncState->analysisModule= (AnalysisModule*) result->data;
222 }
223 else
224 {
225 g_error("Analysis module '%s' not found", optionSyncAnalysis.arg);
226 }
227
228 syncState->reductionData= NULL;
229 result= g_queue_find_custom(&reductionModules, optionSyncReduction.arg,
230 &gcfCompareReduction);
231 if (result != NULL)
232 {
233 syncState->reductionModule= (ReductionModule*) result->data;
234 }
235 else
236 {
237 g_error("Reduction module '%s' not found", optionSyncReduction.arg);
238 }
239
240 // Initialize modules
241 syncState->processingModule->initProcessing(syncState, testCaseName);
242 syncState->matchingModule->initMatching(syncState);
243 syncState->analysisModule->initAnalysis(syncState);
244 syncState->reductionModule->initReduction(syncState);
245
246 // Process traceset
247 allFactors= syncState->processingModule->finalizeProcessing(syncState);
248 factors= syncState->reductionModule->finalizeReduction(syncState,
249 allFactors);
250 freeAllFactors(allFactors, syncState->traceNb);
251
252 // Write graphs file
253 if (syncState->graphsStream)
254 {
255 writeGraphsScript(syncState);
256
257 if (fclose(syncState->graphsStream) != 0)
258 {
259 g_error("%s", strerror(errno));
260 }
261 }
262
263 // Print statistics
264 if (optionSyncStats.present)
265 {
266 unsigned int i;
267
268 printStats(syncState);
269
270 printf("Resulting synchronization factors:\n");
271 for (i= 0; i < factors->len; i++)
272 {
273 Factors* traceFactors= &g_array_index(factors, Factors, i);
274 printf("\ttrace %u drift= %g offset= %g\n", i,
275 traceFactors->drift, traceFactors->offset);
276 }
277 }
278
279 // Destroy modules and clean up
280 syncState->processingModule->destroyProcessing(syncState);
281 syncState->matchingModule->destroyMatching(syncState);
282 syncState->analysisModule->destroyAnalysis(syncState);
283 syncState->reductionModule->destroyReduction(syncState);
284
285 stats= syncState->stats;
286 free(syncState);
287
288 if (stats)
289 {
290 gettimeofday(&endTime, 0);
291 retval= getrusage(RUSAGE_SELF, &endUsage);
292
293 timeDiff(&endTime, &startTime);
294 timeDiff(&endUsage.ru_utime, &startUsage.ru_utime);
295 timeDiff(&endUsage.ru_stime, &startUsage.ru_stime);
296
297 printf("Synchronization time:\n");
298 printf("\treal time: %ld.%06ld\n", endTime.tv_sec, endTime.tv_usec);
299 printf("\tuser time: %ld.%06ld\n", endUsage.ru_utime.tv_sec,
300 endUsage.ru_utime.tv_usec);
301 printf("\tsystem time: %ld.%06ld\n", endUsage.ru_stime.tv_sec,
302 endUsage.ru_stime.tv_usec);
303 }
304
305 if (!optionSyncStats.present)
306 {
307 g_log_remove_handler(NULL, id);
308 }
309
310 return EXIT_SUCCESS;
311 }
312
313
314 /*
315 * Read program arguments and update ModuleOptions structures
316 *
317 * Args:
318 * argc, argv: standard argument arrays
319 *
320 * Returns:
321 * Name of the test case file (first parameter)
322 */
323 const char* processOptions(const int argc, char* const argv[])
324 {
325 int c;
326 extern char* optarg;
327 extern int optind, opterr, optopt;
328 GArray* longOptions;
329 GString* optionString;
330 GQueue* longIndex;
331 int longOption;
332 GHashTable* shortIndex;
333
334 longOptions= g_array_sized_new(TRUE, FALSE, sizeof(struct option),
335 g_queue_get_length(&moduleOptions));
336 optionString= g_string_new("");
337 longIndex= g_queue_new();
338 shortIndex= g_hash_table_new(&ghfCharHash, &gefCharEqual);
339
340 g_queue_foreach(&moduleOptions, &gfAddModuleOption, &(struct OptionsInfo)
341 {longOptions, optionString, longIndex, shortIndex});
342
343 do
344 {
345 int optionIndex= 0;
346 ModuleOption* moduleOption;
347
348 longOption= -1;
349 c= getopt_long(argc, argv, optionString->str, (struct option*)
350 longOptions->data, &optionIndex);
351
352 if (longOption >= 0 && longOption < g_queue_get_length(longIndex))
353 {
354 moduleOption= g_queue_peek_nth(longIndex, longOption);
355 }
356 else if ((moduleOption= g_hash_table_lookup(shortIndex, &c)) != NULL)
357 {
358 }
359 else if (c == -1)
360 {
361 break;
362 }
363 else if (c == '?')
364 {
365 usage(argv[0]);
366 abort();
367 }
368 else
369 {
370 g_error("Option parse error");
371 }
372
373 moduleOption->present= true;
374
375 if (moduleOption->hasArg == REQUIRED_ARG)
376 {
377 moduleOption->arg= optarg;
378 }
379 if (moduleOption->hasArg == OPTIONAL_ARG && optarg)
380 {
381 moduleOption->arg= optarg;
382 }
383 } while (c != -1);
384
385 g_array_free(longOptions, TRUE);
386 g_string_free(optionString, TRUE);
387 g_queue_free(longIndex);
388 g_hash_table_destroy(shortIndex);
389
390 if (argc <= optind)
391 {
392 fprintf(stderr, "Test file unspecified\n");
393 usage(argv[0]);
394 abort();
395 }
396
397 return argv[optind];
398 }
399
400
401 /*
402 * Print information about program options and arguments.
403 *
404 * Args:
405 * programName: name of the program, as contained in argv[0] for example
406 */
407 static void usage(const char* const programName)
408 {
409 printf(
410 "%s [options] <test file>\n"
411 "Options:\n", programName);
412
413 g_queue_foreach(&moduleOptions, &gfPrintModuleOption, NULL);
414 }
415
416
417 /*
418 * A GFunc for g_queue_foreach()
419 *
420 * Print analysis module names.
421 *
422 * Args:
423 * data: ModuleOption*, option
424 * user_data: NULL
425 */
426 static void gfPrintModuleOption(gpointer data, gpointer user_data)
427 {
428 ModuleOption* option= data;
429 int width= 0, sum= 0;
430 const int colWidth= 27;
431
432 printf("\t");
433
434 if (option->shortName)
435 {
436 printf("-%c, %n", option->shortName, &width);
437 sum+= width;
438 }
439
440 printf("--%-s%n", option->longName, &width);
441 sum+= width;
442
443 if (option->hasArg == REQUIRED_ARG || option->hasArg == OPTIONAL_ARG)
444 {
445 printf("=[..]%n", &width);
446 sum+= width;
447 }
448
449 if (option->optionHelp)
450 {
451 printf("%*s%s\n", colWidth - sum > 0 ? colWidth - sum : 0, "", option->optionHelp);
452 }
453
454 if (option->argHelp)
455 {
456 printf("\t%*s%s\n", colWidth, "", option->argHelp);
457 }
458
459 if ((option->hasArg == REQUIRED_ARG || option->hasArg == OPTIONAL_ARG) && option->arg)
460 {
461 printf("\t%*sDefault value: %s\n", colWidth, "", option->arg);
462 }
463 }
464
465
466 /*
467 * A Glib log function which does nothing.
468 */
469 static void nullLog(const gchar *log_domain, GLogLevelFlags log_level, const
470 gchar *message, gpointer user_data)
471 {}
472
473
474 /*
475 * A GFunc for g_queue_foreach()
476 *
477 * Args:
478 * data: ModuleOption*, option
479 * user_data: struct OptionsInfo*, add option to this array of struct option
480 */
481 static void gfAddModuleOption(gpointer data, gpointer user_data)
482 {
483 ModuleOption* option= data;
484 struct OptionsInfo* optionsInfo= user_data;
485 struct option newOption;
486 // "[mixing enumerations] can still be considered bad style even though it
487 // is not strictly illegal" c.faq 2.22
488 const int conversion[]= {
489 [NO_ARG]= no_argument,
490 [OPTIONAL_ARG]= optional_argument,
491 [REQUIRED_ARG]= required_argument,
492 };
493 const char* colons[]= {
494 [NO_ARG]= "",
495 [OPTIONAL_ARG]= "::",
496 [REQUIRED_ARG]= ":",
497 };
498
499 newOption.name= option->longName;
500 newOption.has_arg= conversion[option->hasArg];
501 newOption.flag= NULL;
502 newOption.val= g_queue_get_length(optionsInfo->longIndex);
503
504 g_array_append_val(optionsInfo->longOptions, newOption);
505 if (option->shortName)
506 {
507 g_string_append_c(optionsInfo->optionString, option->shortName);
508 g_string_append(optionsInfo->optionString, colons[option->hasArg]);
509
510 g_hash_table_insert(optionsInfo->shortIndex, &option->shortName,
511 option);
512 }
513 g_queue_push_tail(optionsInfo->longIndex, option);
514 }
515
516
517 /*
518 * A GHashFunc for g_hash_table_new()
519 *
520 * Args:
521 * key char*, just one character
522 */
523 static guint ghfCharHash(gconstpointer key)
524 {
525 return *(char*) key;
526 }
527
528
529 /*
530 * A GEqualFunc for g_hash_table_new()
531 *
532 * Args:
533 * a, b char*, just one character each
534 *
535 * Returns:
536 * TRUE if both values are equal
537 */
538 static gboolean gefCharEqual(gconstpointer a, gconstpointer b)
539 {
540 if (*(char*) a == *(char*) b)
541 {
542 return TRUE;
543 }
544 else
545 {
546 return FALSE;
547 }
548 }
This page took 0.039492 seconds and 5 git commands to generate.