Add support for module options
[lttv.git] / lttv / lttv / sync / sync_chain_lttv.c
CommitLineData
70407e86
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#ifdef HAVE_CONFIG_H
20#include <config.h>
21#endif
22
08365995
BP
23#include <errno.h>
24#include <fcntl.h>
25#include <stdio.h>
70407e86 26#include <stdlib.h>
70407e86 27#include <sys/resource.h>
08365995 28#include <sys/stat.h>
08365995
BP
29#include <sys/types.h>
30#include <sys/stat.h>
31#include <unistd.h>
70407e86
BP
32
33#include <lttv/module.h>
34#include <lttv/option.h>
35
2bd4b3e4 36#include "sync_chain.h"
70407e86
BP
37
38
39#ifndef g_info
40#define g_info(format...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, format)
41#endif
42
43
44static void init();
45static void destroy();
46
70407e86 47static void gfAppendAnalysisName(gpointer data, gpointer user_data);
2bd4b3e4
BP
48static void gfAddModuleOption(gpointer data, gpointer user_data);
49static void gfRemoveModuleOption(gpointer data, gpointer user_data);
70407e86
BP
50
51GQueue processingModules= G_QUEUE_INIT;
52GQueue matchingModules= G_QUEUE_INIT;
53GQueue analysisModules= G_QUEUE_INIT;
2bd4b3e4
BP
54GQueue moduleOptions= G_QUEUE_INIT;
55
56static char* argHelpNone= "none";
57static ModuleOption optionSync= {
58 .longName= "sync",
59 .hasArg= NO_ARG,
60 {.present= false},
61 .optionHelp= "synchronize the time between the traces",
62};
63static char graphsDir[20];
64static ModuleOption optionSyncStats= {
65 .longName= "sync-stats",
66 .hasArg= NO_ARG,
67 {.present= false},
68 .optionHelp= "print statistics about the time synchronization",
69};
70static ModuleOption optionSyncNull= {
71 .longName= "sync-null",
72 .hasArg= NO_ARG,
73 {.present= false},
74 .optionHelp= "read the events but do not perform any processing",
75};
76static GString* analysisModulesNames;
77static ModuleOption optionSyncAnalysis= {
78 .longName= "sync-analysis",
79 .hasArg= REQUIRED_ARG,
80 .optionHelp= "specify the algorithm to use for event analysis",
81};
82static ModuleOption optionSyncGraphs= {
83 .longName= "sync-graphs",
84 .hasArg= NO_ARG,
85 {.present= false},
86 .optionHelp= "output gnuplot graph showing synchronization points",
87};
88static ModuleOption optionSyncGraphsDir= {
89 .longName= "sync-graphs-dir",
90 .hasArg= REQUIRED_ARG,
91 .optionHelp= "specify the directory where to store the graphs",
92};
70407e86
BP
93
94/*
95 * Module init function
96 *
97 * This function is declared to be the module initialization function. Event
98 * modules are registered with a "constructor (102)" attribute except one in
99 * each class (processing, matching, analysis) which is chosen to be the
100 * default and which is registered with a "constructor (101)" attribute.
101 * Constructors with no priority are called after constructors with
102 * priorities. The result is that the list of event modules is known when this
103 * function is executed.
104 */
105static void init()
106{
08365995 107 int retval;
70407e86
BP
108
109 g_debug("\t\t\tXXXX sync init\n");
110
70407e86 111 g_assert(g_queue_get_length(&analysisModules) > 0);
2bd4b3e4 112 optionSyncAnalysis.arg = ((AnalysisModule*)
70407e86
BP
113 g_queue_peek_head(&analysisModules))->name;
114 analysisModulesNames= g_string_new("");
115 g_queue_foreach(&analysisModules, &gfAppendAnalysisName,
116 analysisModulesNames);
117 // remove the last ", "
118 g_string_truncate(analysisModulesNames, analysisModulesNames->len - 2);
2bd4b3e4 119 optionSyncAnalysis.argHelp= analysisModulesNames->str;
08365995
BP
120
121 retval= snprintf(graphsDir, sizeof(graphsDir), "graphs-%d", getpid());
122 if (retval > sizeof(graphsDir) - 1)
123 {
124 graphsDir[sizeof(graphsDir) - 1]= '\0';
125 }
2bd4b3e4
BP
126 optionSyncGraphsDir.arg= graphsDir;
127 optionSyncGraphsDir.argHelp= graphsDir;
128
129 g_queue_push_head(&moduleOptions, &optionSyncGraphsDir);
130 g_queue_push_head(&moduleOptions, &optionSyncGraphs);
131 g_queue_push_head(&moduleOptions, &optionSyncAnalysis);
132 g_queue_push_head(&moduleOptions, &optionSyncNull);
133 g_queue_push_head(&moduleOptions, &optionSyncStats);
134 g_queue_push_head(&moduleOptions, &optionSync);
135
136 g_queue_foreach(&moduleOptions, &gfAddModuleOption, NULL);
137
70407e86
BP
138}
139
140
141/*
142 * Module unload function
143 */
144static void destroy()
145{
146 g_debug("\t\t\tXXXX sync destroy\n");
147
2bd4b3e4
BP
148 g_queue_foreach(&moduleOptions, &gfRemoveModuleOption, NULL);
149 g_string_free(analysisModulesNames, TRUE);
150
151 g_queue_clear(&processingModules);
152 g_queue_clear(&matchingModules);
153 g_queue_clear(&analysisModules);
154 g_queue_clear(&moduleOptions);
70407e86
BP
155}
156
157
158/*
159 * Calculate a traceset's drift and offset values based on network events
160 *
161 * The individual correction factors are written out to each trace.
162 *
163 * Args:
164 * traceSetContext: traceset
165 */
166void syncTraceset(LttvTracesetContext* const traceSetContext)
167{
168 SyncState* syncState;
169 struct timeval startTime, endTime;
170 struct rusage startUsage, endUsage;
171 GList* result;
08365995 172 FILE* graphsStream;
70407e86
BP
173 int retval;
174
2bd4b3e4 175 if (!optionSync.present)
70407e86
BP
176 {
177 g_debug("Not synchronizing traceset because option is disabled");
178 return;
179 }
180
2bd4b3e4 181 if (optionSyncStats.present)
70407e86
BP
182 {
183 gettimeofday(&startTime, 0);
184 getrusage(RUSAGE_SELF, &startUsage);
185 }
186
187 // Initialize data structures
188 syncState= malloc(sizeof(SyncState));
189 syncState->traceNb= lttv_traceset_number(traceSetContext->ts);
190
2bd4b3e4 191 if (optionSyncStats.present)
70407e86
BP
192 {
193 syncState->stats= true;
194 }
195 else
196 {
197 syncState->stats= false;
198 }
199
2bd4b3e4 200 if (optionSyncGraphs.present)
08365995 201 {
2bd4b3e4 202 syncState->graphs= optionSyncGraphsDir.arg;
08365995
BP
203 }
204 else
205 {
206 syncState->graphs= NULL;
207 }
208
209 // Identify and initialize processing module
70407e86 210 syncState->processingData= NULL;
2bd4b3e4 211 if (optionSyncNull.present)
70407e86
BP
212 {
213 result= g_queue_find_custom(&processingModules, "LTTV-null",
214 &gcfCompareProcessing);
215 }
216 else
217 {
218 result= g_queue_find_custom(&processingModules, "LTTV-standard",
219 &gcfCompareProcessing);
220 }
221 g_assert(result != NULL);
222 syncState->processingModule= (ProcessingModule*) result->data;
08365995
BP
223
224 graphsStream= NULL;
f6691532
BP
225 if (syncState->graphs &&
226 syncState->processingModule->writeProcessingGraphsPlots != NULL)
08365995 227 {
9a9ca632
BP
228 char* cwd;
229 int graphsFp;
230
08365995
BP
231 // Create the graph directory right away in case the module initialization
232 // functions have something to write in it.
233 cwd= changeToGraphDir(syncState->graphs);
234
f6691532
BP
235 if ((graphsFp= open("graphs.gnu", O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR |
236 S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH
237 | S_IWOTH | S_IXOTH)) == -1)
08365995 238 {
f6691532
BP
239 g_error(strerror(errno));
240 }
241 if ((graphsStream= fdopen(graphsFp, "w")) == NULL)
242 {
243 g_error(strerror(errno));
08365995
BP
244 }
245
246 retval= chdir(cwd);
247 if (retval == -1)
248 {
249 g_error(strerror(errno));
250 }
251 free(cwd);
252 }
253
f6691532 254 // Identify matching and analysis modules
f10c27a8
BP
255 result= g_queue_find_custom(&matchingModules, "TCP", &gcfCompareMatching);
256 g_assert(result != NULL);
257 syncState->matchingModule= (MatchingModule*) result->data;
70407e86 258
2bd4b3e4 259 result= g_queue_find_custom(&analysisModules, optionSyncAnalysis.arg,
f6691532
BP
260 &gcfCompareAnalysis);
261 if (result != NULL)
70407e86 262 {
f6691532 263 syncState->analysisModule= (AnalysisModule*) result->data;
70407e86
BP
264 }
265 else
266 {
2bd4b3e4 267 g_error("Analysis module '%s' not found", optionSyncAnalysis.arg);
f6691532 268 }
70407e86 269
f6691532
BP
270 syncState->processingModule->initProcessing(syncState, traceSetContext);
271
272 syncState->matchingData= NULL;
273 syncState->analysisData= NULL;
274
2bd4b3e4 275 if (!optionSyncNull.present)
f6691532
BP
276 {
277 syncState->matchingModule->initMatching(syncState);
278 syncState->analysisModule->initAnalysis(syncState);
70407e86
BP
279 }
280
281 // Process traceset
282 lttv_process_traceset_seek_time(traceSetContext, ltt_time_zero);
283 lttv_process_traceset_middle(traceSetContext, ltt_time_infinite,
284 G_MAXULONG, NULL);
285 lttv_process_traceset_seek_time(traceSetContext, ltt_time_zero);
286
287 syncState->processingModule->finalizeProcessing(syncState);
288
08365995
BP
289 // Write graphs file
290 if (graphsStream != NULL)
291 {
292 unsigned int i, j;
293
294 fprintf(graphsStream,
295 "#!/usr/bin/gnuplot\n\n"
296 "set terminal postscript eps color size 8in,6in\n");
297
298 // Cover the upper triangular matrix, i is the reference node.
299 for (i= 0; i < syncState->traceNb; i++)
300 {
301 for (j= i + 1; j < syncState->traceNb; j++)
302 {
303 long pos;
304
305 fprintf(graphsStream,
306 "\nset output \"%03d-%03d.eps\"\n"
307 "plot \\\n", i, j);
308
309 syncState->processingModule->writeProcessingGraphsPlots(graphsStream,
310 syncState, i, j);
311
312 // Remove the ", \\\n" from the last graph plot line
313 fflush(graphsStream);
314 pos= ftell(graphsStream);
315 if (ftruncate(fileno(graphsStream), pos - 4) == -1)
316 {
317 g_error(strerror(errno));
318 }
319 if (fseek(graphsStream, 0, SEEK_END) == -1)
320 {
321 g_error(strerror(errno));
322 }
323
324 fprintf(graphsStream,
325 "\nset output \"%1$03d-%2$03d.eps\"\n"
326 "set key inside right bottom\n"
327 "set title \"\"\n"
328 "set xlabel \"Clock %1$u\"\n"
329 "set xtics nomirror\n"
330 "set ylabel \"Clock %2$u\"\n"
331 "set ytics nomirror\n", i, j);
332
333 syncState->processingModule->writeProcessingGraphsOptions(graphsStream,
334 syncState, i, j);
335
336 fprintf(graphsStream,
337 "replot\n");
338 }
339 }
340
341 if (fclose(graphsStream) != 0)
342 {
343 g_error(strerror(errno));
344 }
345 }
346
70407e86
BP
347 if (syncState->processingModule->printProcessingStats != NULL)
348 {
349 syncState->processingModule->printProcessingStats(syncState);
350 }
351
352 syncState->processingModule->destroyProcessing(syncState);
353 if (syncState->matchingModule != NULL)
354 {
355 syncState->matchingModule->destroyMatching(syncState);
356 }
357 if (syncState->analysisModule != NULL)
358 {
359 syncState->analysisModule->destroyAnalysis(syncState);
360 }
361
362 free(syncState);
363
2bd4b3e4 364 if (optionSyncStats.present)
70407e86
BP
365 {
366 gettimeofday(&endTime, 0);
367 retval= getrusage(RUSAGE_SELF, &endUsage);
368
369 timeDiff(&endTime, &startTime);
370 timeDiff(&endUsage.ru_utime, &startUsage.ru_utime);
371 timeDiff(&endUsage.ru_stime, &startUsage.ru_stime);
372
373 printf("Synchronization time:\n");
374 printf("\treal time: %ld.%06ld\n", endTime.tv_sec, endTime.tv_usec);
375 printf("\tuser time: %ld.%06ld\n", endUsage.ru_utime.tv_sec,
376 endUsage.ru_utime.tv_usec);
377 printf("\tsystem time: %ld.%06ld\n", endUsage.ru_stime.tv_sec,
378 endUsage.ru_stime.tv_usec);
379 }
380}
381
382
383/*
384 * Calculate the elapsed time between two timeval values
385 *
386 * Args:
387 * end: end time, result is also stored in this structure
388 * start: start time
389 */
9a9ca632 390void timeDiff(struct timeval* const end, const struct timeval* const start)
70407e86
BP
391{
392 if (end->tv_usec >= start->tv_usec)
393 {
394 end->tv_sec-= start->tv_sec;
395 end->tv_usec-= start->tv_usec;
396 }
397 else
398 {
399 end->tv_sec= end->tv_sec - start->tv_sec - 1;
400 end->tv_usec= end->tv_usec - start->tv_usec + 1e6;
401 }
402}
403
404
405/*
406 * A GCompareFunc for g_slist_find_custom()
407 *
408 * Args:
9a9ca632 409 * a: ProcessingModule*, element's data
70407e86
BP
410 * b: char*, user data to compare against
411 *
412 * Returns:
9a9ca632 413 * 0 if the processing module a's name is b
70407e86 414 */
9a9ca632 415gint gcfCompareProcessing(gconstpointer a, gconstpointer b)
70407e86 416{
9a9ca632 417 const ProcessingModule* processingModule;
70407e86
BP
418 const char* name;
419
9a9ca632
BP
420 processingModule= (const ProcessingModule*) a;
421 name= (const char*) b;
70407e86 422
9a9ca632
BP
423 return strncmp(processingModule->name, name,
424 strlen(processingModule->name) + 1);
425}
426
427
428/*
429 * A GCompareFunc for g_slist_find_custom()
430 *
431 * Args:
432 * a: MatchingModule*, element's data
433 * b: char*, user data to compare against
434 *
435 * Returns:
436 * 0 if the matching module a's name is b
437 */
438gint gcfCompareMatching(gconstpointer a, gconstpointer b)
439{
440 const MatchingModule* matchingModule;
441 const char* name;
442
443 matchingModule= (const MatchingModule*) a;
444 name= (const char*) b;
445
446 return strncmp(matchingModule->name, name, strlen(matchingModule->name) +
70407e86
BP
447 1);
448}
449
450
451/*
452 * A GCompareFunc for g_slist_find_custom()
453 *
454 * Args:
9a9ca632 455 * a: AnalysisModule*, element's data
70407e86
BP
456 * b: char*, user data to compare against
457 *
458 * Returns:
459 * 0 if the analysis module a's name is b
460 */
9a9ca632 461gint gcfCompareAnalysis(gconstpointer a, gconstpointer b)
70407e86 462{
9a9ca632 463 const AnalysisModule* analysisModule;
70407e86
BP
464 const char* name;
465
9a9ca632
BP
466 analysisModule= (const AnalysisModule*) a;
467 name= (const char*) b;
70407e86 468
9a9ca632
BP
469 return strncmp(analysisModule->name, name, strlen(analysisModule->name) +
470 1);
70407e86
BP
471}
472
473
474/*
475 * A GFunc for g_queue_foreach()
476 *
477 * Concatenate analysis module names.
478 *
479 * Args:
480 * data: AnalysisModule*
481 * user_data: GString*, concatenated names
482 */
483static void gfAppendAnalysisName(gpointer data, gpointer user_data)
484{
485 g_string_append((GString*) user_data, ((AnalysisModule*) data)->name);
486 g_string_append((GString*) user_data, ", ");
487}
488
489
08365995
BP
490/*
491 * Change to the directory used to hold graphs. Create it if necessary.
492 *
493 * Args:
494 * graph: name of directory
495 *
496 * Returns:
497 * The current working directory before the execution of the function. The
498 * string must be free'd by the caller.
499 */
2bd4b3e4 500char* changeToGraphDir(const char* const graphs)
08365995
BP
501{
502 int retval;
503 char* cwd;
504
505 cwd= getcwd(NULL, 0);
506 if (cwd == NULL)
507 {
508 g_error(strerror(errno));
509 }
510 while ((retval= chdir(graphs)) != 0)
511 {
512 if (errno == ENOENT)
513 {
514 retval= mkdir(graphs, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP |
515 S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH);
516 if (retval != 0)
517 {
518 g_error(strerror(errno));
519 }
520 }
521 else
522 {
523 g_error(strerror(errno));
524 }
525 }
526
527 return cwd;
528}
529
530
2bd4b3e4
BP
531/*
532 * A GFunc for g_queue_foreach()
533 *
534 * Args:
535 * data: ModuleOption*
536 * user_data: NULL
537 */
538static void gfAddModuleOption(gpointer data, gpointer user_data)
539{
540 ModuleOption* option;
541 LttvOptionType conversion[]= {
542 [NO_ARG]= LTTV_OPT_NONE,
543 [REQUIRED_ARG]= LTTV_OPT_STRING,
544 };
545
546 g_assert_cmpuint(sizeof(conversion) / sizeof(*conversion), ==,
547 HAS_ARG_COUNT);
548 option= (ModuleOption*) data;
549 lttv_option_add(option->longName, '\0', option->optionHelp,
550 option->argHelp ? option->argHelp : argHelpNone,
551 conversion[option->hasArg], &option->arg, NULL, NULL);
552}
553
554
555/*
556 * A GFunc for g_queue_foreach()
557 *
558 * Args:
559 * data: ModuleOption*
560 * user_data: NULL
561 */
562static void gfRemoveModuleOption(gpointer data, gpointer user_data)
563{
564 lttv_option_remove(((ModuleOption*) data)->longName);
565}
566
567
70407e86
BP
568LTTV_MODULE("sync", "Synchronize traces", \
569 "Synchronizes a traceset based on the correspondance of network events", \
570 init, destroy, "option")
This page took 0.045846 seconds and 4 git commands to generate.