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