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