Add sync_chain_unittest
[lttv.git] / lttv / lttv / sync / sync_chain_unittest.c
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
41 struct OptionsInfo
42 {
43 GArray* longOptions;
44 GString* optionString;
45 GQueue* index;
46 };
47
48
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);
55
56
57 static ModuleOption optionSyncStats= {
58 .shortName= 's',
59 .longName= "sync-stats",
60 .hasArg= NO_ARG,
61 .optionHelp= "Print statistics and debug messages",
62 };
63 static char graphsDir[20];
64 static ModuleOption optionSyncGraphs= {
65 .shortName= 'g',
66 .longName= "sync-graphs",
67 .hasArg= OPTIONAL_ARG,
68 .optionHelp= "Output gnuplot graph showing synchronization points",
69 };
70 static ModuleOption optionSyncAnalysis= {
71 .shortName= 'a',
72 .longName= "sync-analysis",
73 .hasArg= REQUIRED_ARG,
74 .optionHelp= "Specify which algorithm to use for event analysis",
75 };
76
77
78 /*
79 * Implement a sync chain, it is mostly for unittest and it does not depend on
80 * lttv
81 *
82 * Args:
83 * argc, argv: standard argument arrays
84 *
85 * Returns:
86 * exit status from main() is always EXIT_SUCCESS
87 */
88 int main(const int argc, char* const argv[])
89 {
90 SyncState* syncState;
91 struct timeval startTime, endTime;
92 struct rusage startUsage, endUsage;
93 GList* result;
94 int retval;
95 bool stats;
96 const char* testCaseName;
97 GString* analysisModulesNames;
98
99 // Initialize data structures
100 syncState= malloc(sizeof(SyncState));
101
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;
112
113 retval= snprintf(graphsDir, sizeof(graphsDir), "graphs-%d", getpid());
114 if (retval > sizeof(graphsDir) - 1)
115 {
116 graphsDir[sizeof(graphsDir) - 1]= '\0';
117 }
118 optionSyncGraphs.arg= graphsDir;
119
120 g_queue_push_head(&moduleOptions, &optionSyncAnalysis);
121 g_queue_push_head(&moduleOptions, &optionSyncGraphs);
122 g_queue_push_head(&moduleOptions, &optionSyncStats);
123
124 testCaseName= processOptions(argc, argv);
125
126 g_string_free(analysisModulesNames, TRUE);
127
128 if (optionSyncStats.present)
129 {
130 syncState->stats= true;
131 gettimeofday(&startTime, 0);
132 getrusage(RUSAGE_SELF, &startUsage);
133 }
134 else
135 {
136 syncState->stats= false;
137 g_log_set_handler(NULL, G_LOG_LEVEL_DEBUG, nullLog, NULL);
138 }
139
140 if (optionSyncGraphs.present)
141 {
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);
146 }
147 else
148 {
149 syncState->graphsStream= NULL;
150 syncState->graphsDir= NULL;
151 }
152
153 // Identify modules
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;
159
160 syncState->matchingData= NULL;
161 result= g_queue_find_custom(&matchingModules, "TCP", &gcfCompareMatching);
162 g_assert(result != NULL);
163 syncState->matchingModule= (MatchingModule*) result->data;
164
165 syncState->analysisData= NULL;
166 result= g_queue_find_custom(&analysisModules, optionSyncAnalysis.arg,
167 &gcfCompareAnalysis);
168 if (result != NULL)
169 {
170 syncState->analysisModule= (AnalysisModule*) result->data;
171 }
172 else
173 {
174 g_error("Analysis module '%s' not found", optionSyncAnalysis.arg);
175 }
176
177 // Initialize modules
178 syncState->processingModule->initProcessing(syncState, testCaseName);
179 syncState->matchingModule->initMatching(syncState);
180 syncState->analysisModule->initAnalysis(syncState);
181
182 // Process traceset
183 syncState->processingModule->finalizeProcessing(syncState);
184
185 // Write graphs file
186 if (syncState->graphsStream)
187 {
188 writeGraphsScript(syncState);
189
190 if (fclose(syncState->graphsStream) != 0)
191 {
192 g_error(strerror(errno));
193 }
194 }
195
196 // Print statistics
197 if (syncState->stats)
198 {
199 printStats(syncState);
200 }
201
202 // Destroy modules and clean up
203 syncState->processingModule->destroyProcessing(syncState);
204 syncState->matchingModule->destroyMatching(syncState);
205 syncState->analysisModule->destroyAnalysis(syncState);
206
207 stats= syncState->stats;
208 free(syncState);
209
210 if (stats)
211 {
212 gettimeofday(&endTime, 0);
213 retval= getrusage(RUSAGE_SELF, &endUsage);
214
215 timeDiff(&endTime, &startTime);
216 timeDiff(&endUsage.ru_utime, &startUsage.ru_utime);
217 timeDiff(&endUsage.ru_stime, &startUsage.ru_stime);
218
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);
225 }
226
227 return EXIT_SUCCESS;
228 }
229
230
231 /*
232 * Read program arguments dans update ModuleOptions structures
233 *
234 * Args:
235 * argc, argv: standard argument arrays
236 *
237 * Returns:
238 * Name of the test case file (first parameter)
239 */
240 const char* processOptions(const int argc, char* const argv[])
241 {
242 int c;
243 extern char* optarg;
244 extern int optind, opterr, optopt;
245 GArray* longOptions;
246 GString* optionString;
247 GQueue* index;
248
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();
253
254 g_queue_foreach(&moduleOptions, &gfAddModuleOption, &(struct OptionsInfo)
255 {longOptions, optionString, index});
256
257 do
258 {
259 int optionIndex= 0;
260
261 c= getopt_long(argc, argv, optionString->str, (struct option*)
262 longOptions->data, &optionIndex);
263
264 if (c >= 0 && c < g_queue_get_length(index))
265 {
266 ModuleOption* moduleOption= g_queue_peek_nth(index, c);
267
268 moduleOption->present= true;
269
270 if (moduleOption->hasArg == REQUIRED_ARG || moduleOption->hasArg
271 == OPTIONAL_ARG)
272 {
273 moduleOption->arg= optarg;
274 }
275 }
276 else if (c == -1)
277 {
278 break;
279 }
280 else if (c == '?')
281 {
282 usage(argv[0]);
283 abort();
284 }
285 else
286 {
287 g_error("Option parse error");
288 }
289 } while (c != -1);
290
291 g_array_free(longOptions, TRUE);
292 g_string_free(optionString, TRUE);
293
294 if (argc <= optind)
295 {
296 fprintf(stderr, "Test file unspecified\n");
297 usage(argv[0]);
298 abort();
299 }
300
301 return argv[optind];
302 }
303
304
305 /*
306 * Print information about program options and arguments.
307 *
308 * Args:
309 * programName: name of the program, as contained in argv[0] for example
310 */
311 static void usage(const char* const programName)
312 {
313 printf(
314 "%s [options] <test file>\n"
315 "Options:\n", programName);
316
317 g_queue_foreach(&moduleOptions, &gfPrintModuleOption, NULL);
318 }
319
320
321 /*
322 * A GFunc for g_queue_foreach()
323 *
324 * Print analysis module names.
325 *
326 * Args:
327 * data: ModuleOption*, option
328 * user_data: NULL
329 */
330 static void gfPrintModuleOption(gpointer data, gpointer user_data)
331 {
332 ModuleOption* option= data;
333 int width= 0, sum= 0;
334 const int colWidth= 27;
335
336 printf("\t");
337
338 if (option->shortName)
339 {
340 printf("-%c, %n", option->shortName, &width);
341 sum+= width;
342 }
343
344 printf("--%-s%n", option->longName, &width);
345 sum+= width;
346
347 if (option->hasArg == REQUIRED_ARG || option->hasArg == OPTIONAL_ARG)
348 {
349 printf("=[..]%n", &width);
350 sum+= width;
351 }
352
353 if (option->optionHelp)
354 {
355 printf("%*s%s\n", colWidth - sum > 0 ? colWidth - sum : 0, "", option->optionHelp);
356 }
357
358 if (option->argHelp)
359 {
360 printf("\t%*s%s\n", colWidth, "", option->argHelp);
361 }
362
363 if ((option->hasArg == REQUIRED_ARG || option->hasArg == OPTIONAL_ARG) && option->arg)
364 {
365 printf("\t%*sDefault value: %s\n", colWidth, "", option->arg);
366 }
367 }
368
369
370 /*
371 * A Glib log function which does nothing.
372 */
373 static void nullLog(const gchar *log_domain, GLogLevelFlags log_level, const
374 gchar *message, gpointer user_data)
375 {}
376
377
378 /*
379 * A GFunc for g_queue_foreach()
380 *
381 * Args:
382 * data: ModuleOption*, option
383 * user_data: struct OptionsInfo*, add option to this array of struct option
384 */
385 static void gfAddModuleOption(gpointer data, gpointer user_data)
386 {
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,
396 };
397 const char* colons[]= {
398 [NO_ARG]= "",
399 [OPTIONAL_ARG]= "::",
400 [REQUIRED_ARG]= ":",
401 };
402
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);
407
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);
411 }
This page took 0.037278 seconds and 4 git commands to generate.