1 /* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2009 Benjamin Poirier <benjamin.poirier@polymtl.ca>
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;
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.
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,
27 #include <sys/resource.h>
29 #include <sys/types.h>
33 #include <lttv/module.h>
34 #include <lttv/option.h>
36 #include "sync_chain.h"
37 #include "sync_chain_lttv.h"
41 static void destroy();
43 static void gfAppendAnalysisName(gpointer data
, gpointer user_data
);
44 static void gfAddModuleOption(gpointer data
, gpointer user_data
);
45 static void gfRemoveModuleOption(gpointer data
, gpointer user_data
);
47 static char* argHelpNone
= "none";
48 static ModuleOption optionSync
= {
52 .optionHelp
= "synchronize the time between the traces",
54 static char graphsDir
[20];
55 static ModuleOption optionSyncStats
= {
56 .longName
= "sync-stats",
59 .optionHelp
= "print statistics about the time synchronization",
61 static ModuleOption optionSyncNull
= {
62 .longName
= "sync-null",
65 .optionHelp
= "read the events but do not perform any processing",
67 static GString
* analysisModulesNames
;
68 static ModuleOption optionSyncAnalysis
= {
69 .longName
= "sync-analysis",
70 .hasArg
= REQUIRED_ARG
,
71 .optionHelp
= "specify the algorithm to use for event analysis",
73 static ModuleOption optionSyncGraphs
= {
74 .longName
= "sync-graphs",
77 .optionHelp
= "output gnuplot graph showing synchronization points",
79 static ModuleOption optionSyncGraphsDir
= {
80 .longName
= "sync-graphs-dir",
81 .hasArg
= REQUIRED_ARG
,
82 .optionHelp
= "specify the directory where to store the graphs",
86 * Module init function
88 * This function is declared to be the module initialization function. Event
89 * modules are registered with a "constructor (102)" attribute except one in
90 * each class (processing, matching, analysis) which is chosen to be the
91 * default and which is registered with a "constructor (101)" attribute.
92 * Constructors with no priority are called after constructors with
93 * priorities. The result is that the list of event modules is known when this
94 * function is executed.
100 g_debug("Sync init");
102 g_assert(g_queue_get_length(&analysisModules
) > 0);
103 optionSyncAnalysis
.arg
= ((AnalysisModule
*)
104 g_queue_peek_head(&analysisModules
))->name
;
105 analysisModulesNames
= g_string_new("");
106 g_queue_foreach(&analysisModules
, &gfAppendAnalysisName
,
107 analysisModulesNames
);
108 // remove the last ", "
109 g_string_truncate(analysisModulesNames
, analysisModulesNames
->len
- 2);
110 optionSyncAnalysis
.argHelp
= analysisModulesNames
->str
;
112 retval
= snprintf(graphsDir
, sizeof(graphsDir
), "graphs-%d", getpid());
113 if (retval
> sizeof(graphsDir
) - 1)
115 graphsDir
[sizeof(graphsDir
) - 1]= '\0';
117 optionSyncGraphsDir
.arg
= graphsDir
;
118 optionSyncGraphsDir
.argHelp
= graphsDir
;
120 g_queue_push_head(&moduleOptions
, &optionSyncGraphsDir
);
121 g_queue_push_head(&moduleOptions
, &optionSyncGraphs
);
122 g_queue_push_head(&moduleOptions
, &optionSyncAnalysis
);
123 g_queue_push_head(&moduleOptions
, &optionSyncNull
);
124 g_queue_push_head(&moduleOptions
, &optionSyncStats
);
125 g_queue_push_head(&moduleOptions
, &optionSync
);
127 g_queue_foreach(&moduleOptions
, &gfAddModuleOption
, NULL
);
133 * Module unload function
135 static void destroy()
137 g_debug("Sync destroy");
139 g_queue_foreach(&moduleOptions
, &gfRemoveModuleOption
, NULL
);
140 g_string_free(analysisModulesNames
, TRUE
);
142 g_queue_clear(&processingModules
);
143 g_queue_clear(&matchingModules
);
144 g_queue_clear(&analysisModules
);
145 g_queue_clear(&moduleOptions
);
150 * Calculate a traceset's drift and offset values based on network events
152 * The individual correction factors are written out to each trace.
155 * traceSetContext: traceset
157 void syncTraceset(LttvTracesetContext
* const traceSetContext
)
159 SyncState
* syncState
;
160 struct timeval startTime
, endTime
;
161 struct rusage startUsage
, endUsage
;
166 if (!optionSync
.present
)
168 g_debug("Not synchronizing traceset because option is disabled");
172 if (optionSyncStats
.present
)
174 gettimeofday(&startTime
, 0);
175 getrusage(RUSAGE_SELF
, &startUsage
);
178 // Initialize data structures
179 syncState
= malloc(sizeof(SyncState
));
180 syncState
->traceNb
= lttv_traceset_number(traceSetContext
->ts
);
182 if (optionSyncStats
.present
)
184 syncState
->stats
= true;
188 syncState
->stats
= false;
191 if (optionSyncGraphs
.present
)
193 // Create the graph directory right away in case the module initialization
194 // functions have something to write in it.
195 syncState
->graphsDir
= optionSyncGraphsDir
.arg
;
196 syncState
->graphsStream
= createGraphsDir(syncState
->graphsDir
);
200 syncState
->graphsStream
= NULL
;
201 syncState
->graphsDir
= NULL
;
204 // Identify and initialize modules
205 syncState
->processingData
= NULL
;
206 if (optionSyncNull
.present
)
208 result
= g_queue_find_custom(&processingModules
, "LTTV-null",
209 &gcfCompareProcessing
);
213 result
= g_queue_find_custom(&processingModules
, "LTTV-standard",
214 &gcfCompareProcessing
);
216 g_assert(result
!= NULL
);
217 syncState
->processingModule
= (ProcessingModule
*) result
->data
;
219 syncState
->matchingData
= NULL
;
220 result
= g_queue_find_custom(&matchingModules
, "TCP", &gcfCompareMatching
);
221 g_assert(result
!= NULL
);
222 syncState
->matchingModule
= (MatchingModule
*) result
->data
;
224 syncState
->analysisData
= NULL
;
225 result
= g_queue_find_custom(&analysisModules
, optionSyncAnalysis
.arg
,
226 &gcfCompareAnalysis
);
229 syncState
->analysisModule
= (AnalysisModule
*) result
->data
;
233 g_error("Analysis module '%s' not found", optionSyncAnalysis
.arg
);
236 if (!optionSyncNull
.present
)
238 syncState
->analysisModule
->initAnalysis(syncState
);
239 syncState
->matchingModule
->initMatching(syncState
);
241 syncState
->processingModule
->initProcessing(syncState
, traceSetContext
);
244 lttv_process_traceset_seek_time(traceSetContext
, ltt_time_zero
);
245 lttv_process_traceset_middle(traceSetContext
, ltt_time_infinite
,
247 lttv_process_traceset_seek_time(traceSetContext
, ltt_time_zero
);
249 syncState
->processingModule
->finalizeProcessing(syncState
);
252 if (optionSyncGraphs
.present
)
254 writeGraphsScript(syncState
);
256 if (fclose(syncState
->graphsStream
) != 0)
258 g_error(strerror(errno
));
262 if (syncState
->processingModule
->printProcessingStats
!= NULL
)
264 syncState
->processingModule
->printProcessingStats(syncState
);
266 if (syncState
->matchingModule
->printMatchingStats
!= NULL
)
268 syncState
->matchingModule
->printMatchingStats(syncState
);
270 if (syncState
->analysisModule
->printAnalysisStats
!= NULL
)
272 syncState
->analysisModule
->printAnalysisStats(syncState
);
275 if (optionSyncStats
.present
)
277 printf("Resulting synchronization factors:\n");
278 for (i
= 0; i
< syncState
->traceNb
; i
++)
282 t
= traceSetContext
->traces
[i
]->t
;
284 printf("\ttrace %u drift= %g offset= %g (%f) start time= %ld.%09ld\n",
285 i
, t
->drift
, t
->offset
, (double) tsc_to_uint64(t
->freq_scale
,
286 t
->start_freq
, t
->offset
) / NANOSECONDS_PER_SECOND
,
287 t
->start_time_from_tsc
.tv_sec
,
288 t
->start_time_from_tsc
.tv_nsec
);
292 syncState
->processingModule
->destroyProcessing(syncState
);
293 if (syncState
->matchingModule
!= NULL
)
295 syncState
->matchingModule
->destroyMatching(syncState
);
297 if (syncState
->analysisModule
!= NULL
)
299 syncState
->analysisModule
->destroyAnalysis(syncState
);
304 if (optionSyncStats
.present
)
306 gettimeofday(&endTime
, 0);
307 retval
= getrusage(RUSAGE_SELF
, &endUsage
);
309 timeDiff(&endTime
, &startTime
);
310 timeDiff(&endUsage
.ru_utime
, &startUsage
.ru_utime
);
311 timeDiff(&endUsage
.ru_stime
, &startUsage
.ru_stime
);
313 printf("Synchronization time:\n");
314 printf("\treal time: %ld.%06ld\n", endTime
.tv_sec
, endTime
.tv_usec
);
315 printf("\tuser time: %ld.%06ld\n", endUsage
.ru_utime
.tv_sec
,
316 endUsage
.ru_utime
.tv_usec
);
317 printf("\tsystem time: %ld.%06ld\n", endUsage
.ru_stime
.tv_sec
,
318 endUsage
.ru_stime
.tv_usec
);
324 * A GFunc for g_queue_foreach()
326 * Concatenate analysis module names.
329 * data: AnalysisModule*
330 * user_data: GString*, concatenated names
332 static void gfAppendAnalysisName(gpointer data
, gpointer user_data
)
334 g_string_append((GString
*) user_data
, ((AnalysisModule
*) data
)->name
);
335 g_string_append((GString
*) user_data
, ", ");
340 * A GFunc for g_queue_foreach()
343 * data: ModuleOption*
346 static void gfAddModuleOption(gpointer data
, gpointer user_data
)
348 ModuleOption
* option
;
349 LttvOptionType conversion
[]= {
350 [NO_ARG
]= LTTV_OPT_NONE
,
351 [REQUIRED_ARG
]= LTTV_OPT_STRING
,
354 g_assert_cmpuint(sizeof(conversion
) / sizeof(*conversion
), ==,
356 option
= (ModuleOption
*) data
;
357 lttv_option_add(option
->longName
, '\0', option
->optionHelp
,
358 option
->argHelp
? option
->argHelp
: argHelpNone
,
359 conversion
[option
->hasArg
], &option
->arg
, NULL
, NULL
);
364 * A GFunc for g_queue_foreach()
367 * data: ModuleOption*
370 static void gfRemoveModuleOption(gpointer data
, gpointer user_data
)
372 lttv_option_remove(((ModuleOption
*) data
)->longName
);
376 LTTV_MODULE("sync", "Synchronize traces", \
377 "Synchronizes a traceset based on the correspondance of network events", \
378 init
, destroy
, "option")