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