Remove warning generated by newer gcc (4.6)
[lttv.git] / lttv / lttv / sync / sync_chain_lttv.c
CommitLineData
70407e86 1/* This file is part of the Linux Trace Toolkit viewer
277e5b53 2 * Copyright (C) 2009, 2010 Benjamin Poirier <benjamin.poirier@polymtl.ca>
70407e86 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.
70407e86 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.
70407e86 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/>.
70407e86
BP
16 */
17
9c7696b8
BP
18#define _ISOC99_SOURCE
19
70407e86
BP
20#ifdef HAVE_CONFIG_H
21#include <config.h>
22#endif
23
08365995
BP
24#include <errno.h>
25#include <fcntl.h>
9c7696b8 26#include <math.h>
08365995 27#include <stdio.h>
70407e86 28#include <stdlib.h>
70407e86 29#include <sys/resource.h>
08365995 30#include <sys/stat.h>
08365995
BP
31#include <sys/types.h>
32#include <sys/stat.h>
33#include <unistd.h>
70407e86
BP
34
35#include <lttv/module.h>
36#include <lttv/option.h>
37
2f961b65
BP
38
39#include "event_processing_lttng_standard.h"
40#include "event_processing_lttng_null.h"
41#include "event_matching_tcp.h"
42#include "event_matching_broadcast.h"
43#include "event_matching_distributor.h"
44#include "event_analysis_chull.h"
45#include "event_analysis_linreg.h"
46#include "event_analysis_eval.h"
b2da0724 47#include "factor_reduction_accuracy.h"
2bd4b3e4 48#include "sync_chain.h"
2f076594 49#include "sync_chain_lttv.h"
70407e86
BP
50
51
70407e86
BP
52static void init();
53static void destroy();
54
2bd4b3e4
BP
55static void gfAddModuleOption(gpointer data, gpointer user_data);
56static void gfRemoveModuleOption(gpointer data, gpointer user_data);
70407e86 57
2bd4b3e4
BP
58static ModuleOption optionSync= {
59 .longName= "sync",
60 .hasArg= NO_ARG,
2bd4b3e4
BP
61 .optionHelp= "synchronize the time between the traces",
62};
2bd4b3e4
BP
63static ModuleOption optionSyncStats= {
64 .longName= "sync-stats",
65 .hasArg= NO_ARG,
2bd4b3e4
BP
66 .optionHelp= "print statistics about the time synchronization",
67};
68static ModuleOption optionSyncNull= {
69 .longName= "sync-null",
70 .hasArg= NO_ARG,
2bd4b3e4
BP
71 .optionHelp= "read the events but do not perform any processing",
72};
73static GString* analysisModulesNames;
74static ModuleOption optionSyncAnalysis= {
75 .longName= "sync-analysis",
76 .hasArg= REQUIRED_ARG,
77 .optionHelp= "specify the algorithm to use for event analysis",
78};
b2da0724
BP
79static GString* reductionModulesNames;
80static ModuleOption optionSyncReduction= {
81 .longName= "sync-reduction",
82 .hasArg= REQUIRED_ARG,
83 .optionHelp= "specify the algorithm to use for factor reduction",
84};
2bd4b3e4
BP
85static ModuleOption optionSyncGraphs= {
86 .longName= "sync-graphs",
87 .hasArg= NO_ARG,
2bd4b3e4
BP
88 .optionHelp= "output gnuplot graph showing synchronization points",
89};
49c335f1 90static char graphsDir[20];
2bd4b3e4
BP
91static ModuleOption optionSyncGraphsDir= {
92 .longName= "sync-graphs-dir",
93 .hasArg= REQUIRED_ARG,
94 .optionHelp= "specify the directory where to store the graphs",
95};
70407e86 96
49c335f1 97
70407e86
BP
98/*
99 * Module init function
100 *
2f961b65 101 * This function is declared to be the module initialization function.
70407e86
BP
102 */
103static void init()
104{
08365995 105 int retval;
b2da0724
BP
106 unsigned int i;
107 const struct
108 {
109 GQueue* modules;
110 ModuleOption* option;
111 size_t nameOffset;
112 GString** names;
113 void (*gfAppendName)(gpointer data, gpointer user_data);
114 } loopValues[]= {
115 {&analysisModules, &optionSyncAnalysis, offsetof(AnalysisModule,
116 name), &analysisModulesNames, &gfAppendAnalysisName},
117 {&reductionModules, &optionSyncReduction, offsetof(ReductionModule,
118 name), &reductionModulesNames, &gfAppendReductionName},
119 };
70407e86 120
d5b038ec 121 g_debug("Sync init");
70407e86 122
2f961b65
BP
123 /*
124 * Initialize event modules
125 * Call the "constructor" or initialization function of each event module
126 * so it can register itself. This must be done before elements in
127 * processingModules, matchingModules, analysisModules or moduleOptions
128 * are accessed.
129 */
130 registerProcessingLTTVStandard();
131 registerProcessingLTTVNull();
132
133 registerMatchingTCP();
134 registerMatchingBroadcast();
135 registerMatchingDistributor();
136
137 registerAnalysisCHull();
138 registerAnalysisLinReg();
139 registerAnalysisEval();
140
b2da0724
BP
141 registerReductionAccuracy();
142
143 // Build module names lists for option and help string
144 for (i= 0; i < ARRAY_SIZE(loopValues); i++)
145 {
146 g_assert(g_queue_get_length(loopValues[i].modules) > 0);
147 loopValues[i].option->arg= (char*)(*(void**)
148 g_queue_peek_head(loopValues[i].modules) +
149 loopValues[i].nameOffset);
150 *loopValues[i].names= g_string_new("");
151 g_queue_foreach(loopValues[i].modules, loopValues[i].gfAppendName,
152 *loopValues[i].names);
153 // remove the last ", "
154 g_string_truncate(*loopValues[i].names, (*loopValues[i].names)->len -
155 2);
156 loopValues[i].option->argHelp= (*loopValues[i].names)->str;
157 }
08365995
BP
158
159 retval= snprintf(graphsDir, sizeof(graphsDir), "graphs-%d", getpid());
160 if (retval > sizeof(graphsDir) - 1)
161 {
162 graphsDir[sizeof(graphsDir) - 1]= '\0';
163 }
2bd4b3e4
BP
164 optionSyncGraphsDir.arg= graphsDir;
165 optionSyncGraphsDir.argHelp= graphsDir;
166
167 g_queue_push_head(&moduleOptions, &optionSyncGraphsDir);
168 g_queue_push_head(&moduleOptions, &optionSyncGraphs);
b2da0724 169 g_queue_push_head(&moduleOptions, &optionSyncReduction);
2bd4b3e4
BP
170 g_queue_push_head(&moduleOptions, &optionSyncAnalysis);
171 g_queue_push_head(&moduleOptions, &optionSyncNull);
172 g_queue_push_head(&moduleOptions, &optionSyncStats);
173 g_queue_push_head(&moduleOptions, &optionSync);
174
175 g_queue_foreach(&moduleOptions, &gfAddModuleOption, NULL);
70407e86
BP
176}
177
178
179/*
180 * Module unload function
181 */
182static void destroy()
183{
d5b038ec 184 g_debug("Sync destroy");
70407e86 185
2bd4b3e4
BP
186 g_queue_foreach(&moduleOptions, &gfRemoveModuleOption, NULL);
187 g_string_free(analysisModulesNames, TRUE);
b2da0724 188 g_string_free(reductionModulesNames, TRUE);
2bd4b3e4
BP
189
190 g_queue_clear(&processingModules);
191 g_queue_clear(&matchingModules);
192 g_queue_clear(&analysisModules);
b2da0724 193 g_queue_clear(&reductionModules);
2bd4b3e4 194 g_queue_clear(&moduleOptions);
70407e86
BP
195}
196
197
198/*
199 * Calculate a traceset's drift and offset values based on network events
200 *
201 * The individual correction factors are written out to each trace.
202 *
203 * Args:
204 * traceSetContext: traceset
482fe481
BP
205 *
206 * Returns:
207 * false if synchronization was not performed, true otherwise
70407e86 208 */
482fe481 209bool syncTraceset(LttvTracesetContext* const traceSetContext)
70407e86
BP
210{
211 SyncState* syncState;
212 struct timeval startTime, endTime;
213 struct rusage startUsage, endUsage;
214 GList* result;
467066ee 215 unsigned int i;
0a87ec9a 216 AllFactors* allFactors;
9c7696b8
BP
217 GArray* factors;
218 double minOffset, minDrift;
219 unsigned int refFreqTrace;
70407e86 220
2bd4b3e4 221 if (!optionSync.present)
70407e86
BP
222 {
223 g_debug("Not synchronizing traceset because option is disabled");
482fe481 224 return false;
70407e86
BP
225 }
226
2bd4b3e4 227 if (optionSyncStats.present)
70407e86
BP
228 {
229 gettimeofday(&startTime, 0);
230 getrusage(RUSAGE_SELF, &startUsage);
231 }
232
233 // Initialize data structures
234 syncState= malloc(sizeof(SyncState));
70407e86 235
2bd4b3e4 236 if (optionSyncStats.present)
70407e86
BP
237 {
238 syncState->stats= true;
239 }
240 else
241 {
242 syncState->stats= false;
243 }
244
1ed11971 245 if (!optionSyncNull.present && optionSyncGraphs.present)
08365995
BP
246 {
247 // Create the graph directory right away in case the module initialization
248 // functions have something to write in it.
8d7d16dd 249 syncState->graphsDir= optionSyncGraphsDir.arg;
1d597550 250 syncState->graphsStream= createGraphsDir(syncState->graphsDir);
08365995 251 }
8d7d16dd
BP
252 else
253 {
254 syncState->graphsStream= NULL;
255 syncState->graphsDir= NULL;
256 }
08365995 257
d4721e1a
BP
258 // Identify and initialize modules
259 syncState->processingData= NULL;
260 if (optionSyncNull.present)
261 {
262 result= g_queue_find_custom(&processingModules, "LTTV-null",
263 &gcfCompareProcessing);
264 }
265 else
266 {
267 result= g_queue_find_custom(&processingModules, "LTTV-standard",
268 &gcfCompareProcessing);
269 }
270 g_assert(result != NULL);
271 syncState->processingModule= (ProcessingModule*) result->data;
272
273 syncState->matchingData= NULL;
f10c27a8
BP
274 result= g_queue_find_custom(&matchingModules, "TCP", &gcfCompareMatching);
275 g_assert(result != NULL);
276 syncState->matchingModule= (MatchingModule*) result->data;
70407e86 277
d4721e1a 278 syncState->analysisData= NULL;
2bd4b3e4 279 result= g_queue_find_custom(&analysisModules, optionSyncAnalysis.arg,
f6691532
BP
280 &gcfCompareAnalysis);
281 if (result != NULL)
70407e86 282 {
f6691532 283 syncState->analysisModule= (AnalysisModule*) result->data;
70407e86
BP
284 }
285 else
286 {
2bd4b3e4 287 g_error("Analysis module '%s' not found", optionSyncAnalysis.arg);
f6691532 288 }
70407e86 289
b2da0724
BP
290 syncState->reductionData= NULL;
291 result= g_queue_find_custom(&reductionModules, optionSyncReduction.arg,
292 &gcfCompareReduction);
293 if (result != NULL)
294 {
295 syncState->reductionModule= (ReductionModule*) result->data;
296 }
297 else
298 {
299 g_error("Reduction module '%s' not found", optionSyncReduction.arg);
300 }
301
09857093 302 syncState->processingModule->initProcessing(syncState, traceSetContext);
2bd4b3e4 303 if (!optionSyncNull.present)
f6691532 304 {
d4721e1a 305 syncState->matchingModule->initMatching(syncState);
09857093 306 syncState->analysisModule->initAnalysis(syncState);
b2da0724 307 syncState->reductionModule->initReduction(syncState);
70407e86
BP
308 }
309
310 // Process traceset
311 lttv_process_traceset_seek_time(traceSetContext, ltt_time_zero);
312 lttv_process_traceset_middle(traceSetContext, ltt_time_infinite,
313 G_MAXULONG, NULL);
314 lttv_process_traceset_seek_time(traceSetContext, ltt_time_zero);
315
0a87ec9a
BP
316 // Obtain, reduce, adjust and set correction factors
317 allFactors= syncState->processingModule->finalizeProcessing(syncState);
b2da0724
BP
318 factors= syncState->reductionModule->finalizeReduction(syncState,
319 allFactors);
320 freeAllFactors(allFactors, syncState->traceNb);
9c7696b8
BP
321
322 /* The offsets are adjusted so the lowest one is 0. This is done because
323 * of a Lttv specific limitation: events cannot have negative times. By
324 * having non-negative offsets, events cannot be moved backwards to
325 * negative times.
326 */
327 minOffset= 0;
328 for (i= 0; i < syncState->traceNb; i++)
329 {
330 minOffset= MIN(g_array_index(factors, Factors, i).offset, minOffset);
331 }
332
333 for (i= 0; i < syncState->traceNb; i++)
334 {
335 g_array_index(factors, Factors, i).offset-= minOffset;
336 }
337
338 /* Because the timestamps are corrected at the TSC level (not at the
339 * LttTime level) all trace frequencies must be made equal. We use the
340 * frequency of the system with the lowest drift
341 */
342 minDrift= INFINITY;
343 refFreqTrace= 0;
344 for (i= 0; i < syncState->traceNb; i++)
345 {
346 if (g_array_index(factors, Factors, i).drift < minDrift)
347 {
348 minDrift= g_array_index(factors, Factors, i).drift;
349 refFreqTrace= i;
350 }
351 }
352 g_assert(syncState->traceNb == 0 || minDrift != INFINITY);
353
354 // Write the factors to the LttTrace structures
355 for (i= 0; i < syncState->traceNb; i++)
356 {
357 LttTrace* t;
358 Factors* traceFactors;
359
360 t= traceSetContext->traces[i]->t;
361 traceFactors= &g_array_index(factors, Factors, i);
362
363 t->drift= traceFactors->drift;
364 t->offset= traceFactors->offset;
365 t->start_freq= traceSetContext->traces[refFreqTrace]->t->start_freq;
366 t->freq_scale= traceSetContext->traces[refFreqTrace]->t->freq_scale;
367 t->start_time_from_tsc =
368 ltt_time_from_uint64(tsc_to_uint64(t->freq_scale, t->start_freq,
369 t->drift * t->start_tsc + t->offset));
370 }
371
372 g_array_free(factors, TRUE);
373
374 lttv_traceset_context_compute_time_span(traceSetContext,
375 &traceSetContext->time_span);
376
377 g_debug("traceset start %ld.%09ld end %ld.%09ld",
378 traceSetContext->time_span.start_time.tv_sec,
379 traceSetContext->time_span.start_time.tv_nsec,
380 traceSetContext->time_span.end_time.tv_sec,
381 traceSetContext->time_span.end_time.tv_nsec);
70407e86 382
08365995 383 // Write graphs file
1ed11971 384 if (!optionSyncNull.present && optionSyncGraphs.present)
08365995 385 {
467066ee 386 writeGraphsScript(syncState);
08365995 387
8d7d16dd 388 if (fclose(syncState->graphsStream) != 0)
08365995 389 {
df64b316 390 g_error("%s", strerror(errno));
08365995
BP
391 }
392 }
393
1ed11971 394 if (!optionSyncNull.present && optionSyncStats.present)
70407e86 395 {
1ed11971 396 printStats(syncState);
d6ee5003 397
d6ee5003
BP
398 printf("Resulting synchronization factors:\n");
399 for (i= 0; i < syncState->traceNb; i++)
400 {
401 LttTrace* t;
402
403 t= traceSetContext->traces[i]->t;
404
405 printf("\ttrace %u drift= %g offset= %g (%f) start time= %ld.%09ld\n",
406 i, t->drift, t->offset, (double) tsc_to_uint64(t->freq_scale,
407 t->start_freq, t->offset) / NANOSECONDS_PER_SECOND,
408 t->start_time_from_tsc.tv_sec,
409 t->start_time_from_tsc.tv_nsec);
410 }
411 }
70407e86
BP
412
413 syncState->processingModule->destroyProcessing(syncState);
414 if (syncState->matchingModule != NULL)
415 {
416 syncState->matchingModule->destroyMatching(syncState);
417 }
418 if (syncState->analysisModule != NULL)
419 {
420 syncState->analysisModule->destroyAnalysis(syncState);
421 }
b2da0724
BP
422 if (syncState->reductionModule != NULL)
423 {
424 syncState->reductionModule->destroyReduction(syncState);
425 }
70407e86
BP
426
427 free(syncState);
428
2bd4b3e4 429 if (optionSyncStats.present)
70407e86
BP
430 {
431 gettimeofday(&endTime, 0);
e865422c 432 getrusage(RUSAGE_SELF, &endUsage);
70407e86
BP
433
434 timeDiff(&endTime, &startTime);
435 timeDiff(&endUsage.ru_utime, &startUsage.ru_utime);
436 timeDiff(&endUsage.ru_stime, &startUsage.ru_stime);
437
438 printf("Synchronization time:\n");
439 printf("\treal time: %ld.%06ld\n", endTime.tv_sec, endTime.tv_usec);
440 printf("\tuser time: %ld.%06ld\n", endUsage.ru_utime.tv_sec,
441 endUsage.ru_utime.tv_usec);
442 printf("\tsystem time: %ld.%06ld\n", endUsage.ru_stime.tv_sec,
443 endUsage.ru_stime.tv_usec);
444 }
482fe481
BP
445
446 return true;
70407e86
BP
447}
448
449
2bd4b3e4
BP
450/*
451 * A GFunc for g_queue_foreach()
452 *
453 * Args:
454 * data: ModuleOption*
455 * user_data: NULL
456 */
457static void gfAddModuleOption(gpointer data, gpointer user_data)
458{
49c335f1 459 ModuleOption* option= data;
2bd4b3e4
BP
460 LttvOptionType conversion[]= {
461 [NO_ARG]= LTTV_OPT_NONE,
49c335f1 462 [OPTIONAL_ARG]= LTTV_OPT_NONE,
2bd4b3e4
BP
463 [REQUIRED_ARG]= LTTV_OPT_STRING,
464 };
49c335f1
BP
465 size_t fieldOffset[]= {
466 [NO_ARG]= offsetof(ModuleOption, present),
467 [REQUIRED_ARG]= offsetof(ModuleOption, arg),
468 };
469 static const char* argHelpNone= "none";
2bd4b3e4
BP
470
471 g_assert_cmpuint(sizeof(conversion) / sizeof(*conversion), ==,
472 HAS_ARG_COUNT);
49c335f1
BP
473 if (option->hasArg == OPTIONAL_ARG)
474 {
475 g_warning("Parameters with optional arguments not supported by the "
476 "lttv option scheme, parameter '%s' will not be available",
477 option->longName);
478 }
479 else
480 {
481 lttv_option_add(option->longName, '\0', option->optionHelp,
482 option->argHelp ? option->argHelp : argHelpNone,
483 conversion[option->hasArg], (void*) option + fieldOffset[option->hasArg],
484 NULL, NULL);
485 }
2bd4b3e4
BP
486}
487
488
489/*
490 * A GFunc for g_queue_foreach()
491 *
492 * Args:
493 * data: ModuleOption*
494 * user_data: NULL
495 */
496static void gfRemoveModuleOption(gpointer data, gpointer user_data)
497{
498 lttv_option_remove(((ModuleOption*) data)->longName);
499}
500
501
70407e86
BP
502LTTV_MODULE("sync", "Synchronize traces", \
503 "Synchronizes a traceset based on the correspondance of network events", \
504 init, destroy, "option")
This page took 0.07949 seconds and 4 git commands to generate.