1 /* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2009, 2010 Benjamin Poirier <benjamin.poirier@polymtl.ca>
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.
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.
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/>.
18 #define _ISOC99_SOURCE
29 #include <sys/resource.h>
31 #include <sys/types.h>
35 #include <lttv/module.h>
36 #include <lttv/option.h>
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"
47 #include "factor_reduction_accuracy.h"
48 #include "sync_chain.h"
49 #include "sync_chain_lttv.h"
53 static void destroy();
55 static void gfAddModuleOption(gpointer data
, gpointer user_data
);
56 static void gfRemoveModuleOption(gpointer data
, gpointer user_data
);
58 static ModuleOption optionSync
= {
61 .optionHelp
= "synchronize the time between the traces",
63 static ModuleOption optionSyncStats
= {
64 .longName
= "sync-stats",
66 .optionHelp
= "print statistics about the time synchronization",
68 static ModuleOption optionSyncNull
= {
69 .longName
= "sync-null",
71 .optionHelp
= "read the events but do not perform any processing",
73 static GString
* analysisModulesNames
;
74 static ModuleOption optionSyncAnalysis
= {
75 .longName
= "sync-analysis",
76 .hasArg
= REQUIRED_ARG
,
77 .optionHelp
= "specify the algorithm to use for event analysis",
79 static GString
* reductionModulesNames
;
80 static ModuleOption optionSyncReduction
= {
81 .longName
= "sync-reduction",
82 .hasArg
= REQUIRED_ARG
,
83 .optionHelp
= "specify the algorithm to use for factor reduction",
85 static ModuleOption optionSyncGraphs
= {
86 .longName
= "sync-graphs",
88 .optionHelp
= "output gnuplot graph showing synchronization points",
90 static char graphsDir
[20];
91 static ModuleOption optionSyncGraphsDir
= {
92 .longName
= "sync-graphs-dir",
93 .hasArg
= REQUIRED_ARG
,
94 .optionHelp
= "specify the directory where to store the graphs",
99 * Module init function
101 * This function is declared to be the module initialization function.
110 ModuleOption
* option
;
113 void (*gfAppendName
)(gpointer data
, gpointer user_data
);
115 {&analysisModules
, &optionSyncAnalysis
, offsetof(AnalysisModule
,
116 name
), &analysisModulesNames
, &gfAppendAnalysisName
},
117 {&reductionModules
, &optionSyncReduction
, offsetof(ReductionModule
,
118 name
), &reductionModulesNames
, &gfAppendReductionName
},
121 g_debug("Sync init");
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
130 registerProcessingLTTVStandard();
131 registerProcessingLTTVNull();
133 registerMatchingTCP();
134 registerMatchingBroadcast();
135 registerMatchingDistributor();
137 registerAnalysisCHull();
138 registerAnalysisLinReg();
139 registerAnalysisEval();
141 registerReductionAccuracy();
143 // Build module names lists for option and help string
144 for (i
= 0; i
< ARRAY_SIZE(loopValues
); i
++)
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
-
156 loopValues
[i
].option
->argHelp
= (*loopValues
[i
].names
)->str
;
159 retval
= snprintf(graphsDir
, sizeof(graphsDir
), "graphs-%d", getpid());
160 if (retval
> sizeof(graphsDir
) - 1)
162 graphsDir
[sizeof(graphsDir
) - 1]= '\0';
164 optionSyncGraphsDir
.arg
= graphsDir
;
165 optionSyncGraphsDir
.argHelp
= graphsDir
;
167 g_queue_push_head(&moduleOptions
, &optionSyncGraphsDir
);
168 g_queue_push_head(&moduleOptions
, &optionSyncGraphs
);
169 g_queue_push_head(&moduleOptions
, &optionSyncReduction
);
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
);
175 g_queue_foreach(&moduleOptions
, &gfAddModuleOption
, NULL
);
180 * Module unload function
182 static void destroy()
184 g_debug("Sync destroy");
186 g_queue_foreach(&moduleOptions
, &gfRemoveModuleOption
, NULL
);
187 g_string_free(analysisModulesNames
, TRUE
);
188 g_string_free(reductionModulesNames
, TRUE
);
190 g_queue_clear(&processingModules
);
191 g_queue_clear(&matchingModules
);
192 g_queue_clear(&analysisModules
);
193 g_queue_clear(&reductionModules
);
194 g_queue_clear(&moduleOptions
);
199 * Calculate a traceset's drift and offset values based on network events
201 * The individual correction factors are written out to each trace.
204 * traceSetContext: traceset
207 * false if synchronization was not performed, true otherwise
209 bool syncTraceset(LttvTracesetContext
* const traceSetContext
)
211 SyncState
* syncState
;
212 struct timeval startTime
, endTime
;
213 struct rusage startUsage
, endUsage
;
216 AllFactors
* allFactors
;
218 double minOffset
, minDrift
;
219 unsigned int refFreqTrace
;
221 if (!optionSync
.present
)
223 g_debug("Not synchronizing traceset because option is disabled");
227 if (optionSyncStats
.present
)
229 gettimeofday(&startTime
, 0);
230 getrusage(RUSAGE_SELF
, &startUsage
);
233 // Initialize data structures
234 syncState
= malloc(sizeof(SyncState
));
236 if (optionSyncStats
.present
)
238 syncState
->stats
= true;
242 syncState
->stats
= false;
245 if (!optionSyncNull
.present
&& optionSyncGraphs
.present
)
247 // Create the graph directory right away in case the module initialization
248 // functions have something to write in it.
249 syncState
->graphsDir
= optionSyncGraphsDir
.arg
;
250 syncState
->graphsStream
= createGraphsDir(syncState
->graphsDir
);
254 syncState
->graphsStream
= NULL
;
255 syncState
->graphsDir
= NULL
;
258 // Identify and initialize modules
259 syncState
->processingData
= NULL
;
260 if (optionSyncNull
.present
)
262 result
= g_queue_find_custom(&processingModules
, "LTTV-null",
263 &gcfCompareProcessing
);
267 result
= g_queue_find_custom(&processingModules
, "LTTV-standard",
268 &gcfCompareProcessing
);
270 g_assert(result
!= NULL
);
271 syncState
->processingModule
= (ProcessingModule
*) result
->data
;
273 syncState
->matchingData
= NULL
;
274 result
= g_queue_find_custom(&matchingModules
, "TCP", &gcfCompareMatching
);
275 g_assert(result
!= NULL
);
276 syncState
->matchingModule
= (MatchingModule
*) result
->data
;
278 syncState
->analysisData
= NULL
;
279 result
= g_queue_find_custom(&analysisModules
, optionSyncAnalysis
.arg
,
280 &gcfCompareAnalysis
);
283 syncState
->analysisModule
= (AnalysisModule
*) result
->data
;
287 g_error("Analysis module '%s' not found", optionSyncAnalysis
.arg
);
290 syncState
->reductionData
= NULL
;
291 result
= g_queue_find_custom(&reductionModules
, optionSyncReduction
.arg
,
292 &gcfCompareReduction
);
295 syncState
->reductionModule
= (ReductionModule
*) result
->data
;
299 g_error("Reduction module '%s' not found", optionSyncReduction
.arg
);
302 syncState
->processingModule
->initProcessing(syncState
, traceSetContext
);
303 if (!optionSyncNull
.present
)
305 syncState
->matchingModule
->initMatching(syncState
);
306 syncState
->analysisModule
->initAnalysis(syncState
);
307 syncState
->reductionModule
->initReduction(syncState
);
311 lttv_process_traceset_seek_time(traceSetContext
, ltt_time_zero
);
312 lttv_process_traceset_middle(traceSetContext
, ltt_time_infinite
,
314 lttv_process_traceset_seek_time(traceSetContext
, ltt_time_zero
);
316 // Obtain, reduce, adjust and set correction factors
317 allFactors
= syncState
->processingModule
->finalizeProcessing(syncState
);
318 factors
= syncState
->reductionModule
->finalizeReduction(syncState
,
320 freeAllFactors(allFactors
, syncState
->traceNb
);
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
328 for (i
= 0; i
< syncState
->traceNb
; i
++)
330 minOffset
= MIN(g_array_index(factors
, Factors
, i
).offset
, minOffset
);
333 for (i
= 0; i
< syncState
->traceNb
; i
++)
335 g_array_index(factors
, Factors
, i
).offset
-= minOffset
;
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
344 for (i
= 0; i
< syncState
->traceNb
; i
++)
346 if (g_array_index(factors
, Factors
, i
).drift
< minDrift
)
348 minDrift
= g_array_index(factors
, Factors
, i
).drift
;
352 g_assert(syncState
->traceNb
== 0 || minDrift
!= INFINITY
);
354 // Write the factors to the LttTrace structures
355 for (i
= 0; i
< syncState
->traceNb
; i
++)
358 Factors
* traceFactors
;
360 t
= traceSetContext
->traces
[i
]->t
;
361 traceFactors
= &g_array_index(factors
, Factors
, i
);
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
));
372 g_array_free(factors
, TRUE
);
374 lttv_traceset_context_compute_time_span(traceSetContext
,
375 &traceSetContext
->time_span
);
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
);
384 if (!optionSyncNull
.present
&& optionSyncGraphs
.present
)
386 writeGraphsScript(syncState
);
388 if (fclose(syncState
->graphsStream
) != 0)
390 g_error("%s", strerror(errno
));
394 if (!optionSyncNull
.present
&& optionSyncStats
.present
)
396 printStats(syncState
);
398 printf("Resulting synchronization factors:\n");
399 for (i
= 0; i
< syncState
->traceNb
; i
++)
403 t
= traceSetContext
->traces
[i
]->t
;
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
);
413 syncState
->processingModule
->destroyProcessing(syncState
);
414 if (syncState
->matchingModule
!= NULL
)
416 syncState
->matchingModule
->destroyMatching(syncState
);
418 if (syncState
->analysisModule
!= NULL
)
420 syncState
->analysisModule
->destroyAnalysis(syncState
);
422 if (syncState
->reductionModule
!= NULL
)
424 syncState
->reductionModule
->destroyReduction(syncState
);
429 if (optionSyncStats
.present
)
431 gettimeofday(&endTime
, 0);
432 getrusage(RUSAGE_SELF
, &endUsage
);
434 timeDiff(&endTime
, &startTime
);
435 timeDiff(&endUsage
.ru_utime
, &startUsage
.ru_utime
);
436 timeDiff(&endUsage
.ru_stime
, &startUsage
.ru_stime
);
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
);
451 * A GFunc for g_queue_foreach()
454 * data: ModuleOption*
457 static void gfAddModuleOption(gpointer data
, gpointer user_data
)
459 ModuleOption
* option
= data
;
460 LttvOptionType conversion
[]= {
461 [NO_ARG
]= LTTV_OPT_NONE
,
462 [OPTIONAL_ARG
]= LTTV_OPT_NONE
,
463 [REQUIRED_ARG
]= LTTV_OPT_STRING
,
465 size_t fieldOffset
[]= {
466 [NO_ARG
]= offsetof(ModuleOption
, present
),
467 [REQUIRED_ARG
]= offsetof(ModuleOption
, arg
),
469 static const char* argHelpNone
= "none";
471 g_assert_cmpuint(sizeof(conversion
) / sizeof(*conversion
), ==,
473 if (option
->hasArg
== OPTIONAL_ARG
)
475 g_warning("Parameters with optional arguments not supported by the "
476 "lttv option scheme, parameter '%s' will not be available",
481 lttv_option_add(option
->longName
, '\0', option
->optionHelp
,
482 option
->argHelp
? option
->argHelp
: argHelpNone
,
483 conversion
[option
->hasArg
], (void*) option
+ fieldOffset
[option
->hasArg
],
490 * A GFunc for g_queue_foreach()
493 * data: ModuleOption*
496 static void gfRemoveModuleOption(gpointer data
, gpointer user_data
)
498 lttv_option_remove(((ModuleOption
*) data
)->longName
);
502 LTTV_MODULE("sync", "Synchronize traces", \
503 "Synchronizes a traceset based on the correspondance of network events", \
504 init
, destroy
, "option")