Rebuild traceset contexts after performing synchronization
[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"
2f076594 37#include "sync_chain_lttv.h"
70407e86
BP
38
39
70407e86
BP
40static void init();
41static void destroy();
42
2bd4b3e4
BP
43static void gfAddModuleOption(gpointer data, gpointer user_data);
44static void gfRemoveModuleOption(gpointer data, gpointer user_data);
70407e86 45
2bd4b3e4
BP
46static ModuleOption optionSync= {
47 .longName= "sync",
48 .hasArg= NO_ARG,
2bd4b3e4
BP
49 .optionHelp= "synchronize the time between the traces",
50};
2bd4b3e4
BP
51static ModuleOption optionSyncStats= {
52 .longName= "sync-stats",
53 .hasArg= NO_ARG,
2bd4b3e4
BP
54 .optionHelp= "print statistics about the time synchronization",
55};
56static ModuleOption optionSyncNull= {
57 .longName= "sync-null",
58 .hasArg= NO_ARG,
2bd4b3e4
BP
59 .optionHelp= "read the events but do not perform any processing",
60};
61static GString* analysisModulesNames;
62static ModuleOption optionSyncAnalysis= {
63 .longName= "sync-analysis",
64 .hasArg= REQUIRED_ARG,
65 .optionHelp= "specify the algorithm to use for event analysis",
66};
67static ModuleOption optionSyncGraphs= {
68 .longName= "sync-graphs",
69 .hasArg= NO_ARG,
2bd4b3e4
BP
70 .optionHelp= "output gnuplot graph showing synchronization points",
71};
49c335f1 72static char graphsDir[20];
2bd4b3e4
BP
73static ModuleOption optionSyncGraphsDir= {
74 .longName= "sync-graphs-dir",
75 .hasArg= REQUIRED_ARG,
76 .optionHelp= "specify the directory where to store the graphs",
77};
70407e86 78
49c335f1 79
70407e86
BP
80/*
81 * Module init function
82 *
83 * This function is declared to be the module initialization function. Event
84 * modules are registered with a "constructor (102)" attribute except one in
85 * each class (processing, matching, analysis) which is chosen to be the
86 * default and which is registered with a "constructor (101)" attribute.
87 * Constructors with no priority are called after constructors with
88 * priorities. The result is that the list of event modules is known when this
89 * function is executed.
90 */
91static void init()
92{
08365995 93 int retval;
70407e86 94
d5b038ec 95 g_debug("Sync init");
70407e86 96
70407e86 97 g_assert(g_queue_get_length(&analysisModules) > 0);
49c335f1 98 optionSyncAnalysis.arg= ((AnalysisModule*)
70407e86
BP
99 g_queue_peek_head(&analysisModules))->name;
100 analysisModulesNames= g_string_new("");
101 g_queue_foreach(&analysisModules, &gfAppendAnalysisName,
102 analysisModulesNames);
103 // remove the last ", "
104 g_string_truncate(analysisModulesNames, analysisModulesNames->len - 2);
2bd4b3e4 105 optionSyncAnalysis.argHelp= analysisModulesNames->str;
08365995
BP
106
107 retval= snprintf(graphsDir, sizeof(graphsDir), "graphs-%d", getpid());
108 if (retval > sizeof(graphsDir) - 1)
109 {
110 graphsDir[sizeof(graphsDir) - 1]= '\0';
111 }
2bd4b3e4
BP
112 optionSyncGraphsDir.arg= graphsDir;
113 optionSyncGraphsDir.argHelp= graphsDir;
114
115 g_queue_push_head(&moduleOptions, &optionSyncGraphsDir);
116 g_queue_push_head(&moduleOptions, &optionSyncGraphs);
117 g_queue_push_head(&moduleOptions, &optionSyncAnalysis);
118 g_queue_push_head(&moduleOptions, &optionSyncNull);
119 g_queue_push_head(&moduleOptions, &optionSyncStats);
120 g_queue_push_head(&moduleOptions, &optionSync);
121
122 g_queue_foreach(&moduleOptions, &gfAddModuleOption, NULL);
70407e86
BP
123}
124
125
126/*
127 * Module unload function
128 */
129static void destroy()
130{
d5b038ec 131 g_debug("Sync destroy");
70407e86 132
2bd4b3e4
BP
133 g_queue_foreach(&moduleOptions, &gfRemoveModuleOption, NULL);
134 g_string_free(analysisModulesNames, TRUE);
135
136 g_queue_clear(&processingModules);
137 g_queue_clear(&matchingModules);
138 g_queue_clear(&analysisModules);
139 g_queue_clear(&moduleOptions);
70407e86
BP
140}
141
142
143/*
144 * Calculate a traceset's drift and offset values based on network events
145 *
146 * The individual correction factors are written out to each trace.
147 *
148 * Args:
149 * traceSetContext: traceset
482fe481
BP
150 *
151 * Returns:
152 * false if synchronization was not performed, true otherwise
70407e86 153 */
482fe481 154bool syncTraceset(LttvTracesetContext* const traceSetContext)
70407e86
BP
155{
156 SyncState* syncState;
157 struct timeval startTime, endTime;
158 struct rusage startUsage, endUsage;
159 GList* result;
467066ee 160 unsigned int i;
70407e86
BP
161 int retval;
162
2bd4b3e4 163 if (!optionSync.present)
70407e86
BP
164 {
165 g_debug("Not synchronizing traceset because option is disabled");
482fe481 166 return false;
70407e86
BP
167 }
168
2bd4b3e4 169 if (optionSyncStats.present)
70407e86
BP
170 {
171 gettimeofday(&startTime, 0);
172 getrusage(RUSAGE_SELF, &startUsage);
173 }
174
175 // Initialize data structures
176 syncState= malloc(sizeof(SyncState));
70407e86 177
2bd4b3e4 178 if (optionSyncStats.present)
70407e86
BP
179 {
180 syncState->stats= true;
181 }
182 else
183 {
184 syncState->stats= false;
185 }
186
1ed11971 187 if (!optionSyncNull.present && optionSyncGraphs.present)
08365995
BP
188 {
189 // Create the graph directory right away in case the module initialization
190 // functions have something to write in it.
8d7d16dd 191 syncState->graphsDir= optionSyncGraphsDir.arg;
1d597550 192 syncState->graphsStream= createGraphsDir(syncState->graphsDir);
08365995 193 }
8d7d16dd
BP
194 else
195 {
196 syncState->graphsStream= NULL;
197 syncState->graphsDir= NULL;
198 }
08365995 199
d4721e1a
BP
200 // Identify and initialize modules
201 syncState->processingData= NULL;
202 if (optionSyncNull.present)
203 {
204 result= g_queue_find_custom(&processingModules, "LTTV-null",
205 &gcfCompareProcessing);
206 }
207 else
208 {
209 result= g_queue_find_custom(&processingModules, "LTTV-standard",
210 &gcfCompareProcessing);
211 }
212 g_assert(result != NULL);
213 syncState->processingModule= (ProcessingModule*) result->data;
214
215 syncState->matchingData= NULL;
f10c27a8
BP
216 result= g_queue_find_custom(&matchingModules, "TCP", &gcfCompareMatching);
217 g_assert(result != NULL);
218 syncState->matchingModule= (MatchingModule*) result->data;
70407e86 219
d4721e1a 220 syncState->analysisData= NULL;
2bd4b3e4 221 result= g_queue_find_custom(&analysisModules, optionSyncAnalysis.arg,
f6691532
BP
222 &gcfCompareAnalysis);
223 if (result != NULL)
70407e86 224 {
f6691532 225 syncState->analysisModule= (AnalysisModule*) result->data;
70407e86
BP
226 }
227 else
228 {
2bd4b3e4 229 g_error("Analysis module '%s' not found", optionSyncAnalysis.arg);
f6691532 230 }
70407e86 231
09857093 232 syncState->processingModule->initProcessing(syncState, traceSetContext);
2bd4b3e4 233 if (!optionSyncNull.present)
f6691532 234 {
d4721e1a 235 syncState->matchingModule->initMatching(syncState);
09857093 236 syncState->analysisModule->initAnalysis(syncState);
70407e86
BP
237 }
238
239 // Process traceset
240 lttv_process_traceset_seek_time(traceSetContext, ltt_time_zero);
241 lttv_process_traceset_middle(traceSetContext, ltt_time_infinite,
242 G_MAXULONG, NULL);
243 lttv_process_traceset_seek_time(traceSetContext, ltt_time_zero);
244
245 syncState->processingModule->finalizeProcessing(syncState);
246
08365995 247 // Write graphs file
1ed11971 248 if (!optionSyncNull.present && optionSyncGraphs.present)
08365995 249 {
467066ee 250 writeGraphsScript(syncState);
08365995 251
8d7d16dd 252 if (fclose(syncState->graphsStream) != 0)
08365995
BP
253 {
254 g_error(strerror(errno));
255 }
256 }
257
1ed11971 258 if (!optionSyncNull.present && optionSyncStats.present)
70407e86 259 {
1ed11971 260 printStats(syncState);
d6ee5003 261
d6ee5003
BP
262 printf("Resulting synchronization factors:\n");
263 for (i= 0; i < syncState->traceNb; i++)
264 {
265 LttTrace* t;
266
267 t= traceSetContext->traces[i]->t;
268
269 printf("\ttrace %u drift= %g offset= %g (%f) start time= %ld.%09ld\n",
270 i, t->drift, t->offset, (double) tsc_to_uint64(t->freq_scale,
271 t->start_freq, t->offset) / NANOSECONDS_PER_SECOND,
272 t->start_time_from_tsc.tv_sec,
273 t->start_time_from_tsc.tv_nsec);
274 }
275 }
70407e86
BP
276
277 syncState->processingModule->destroyProcessing(syncState);
278 if (syncState->matchingModule != NULL)
279 {
280 syncState->matchingModule->destroyMatching(syncState);
281 }
282 if (syncState->analysisModule != NULL)
283 {
284 syncState->analysisModule->destroyAnalysis(syncState);
285 }
286
287 free(syncState);
288
2bd4b3e4 289 if (optionSyncStats.present)
70407e86
BP
290 {
291 gettimeofday(&endTime, 0);
292 retval= getrusage(RUSAGE_SELF, &endUsage);
293
294 timeDiff(&endTime, &startTime);
295 timeDiff(&endUsage.ru_utime, &startUsage.ru_utime);
296 timeDiff(&endUsage.ru_stime, &startUsage.ru_stime);
297
298 printf("Synchronization time:\n");
299 printf("\treal time: %ld.%06ld\n", endTime.tv_sec, endTime.tv_usec);
300 printf("\tuser time: %ld.%06ld\n", endUsage.ru_utime.tv_sec,
301 endUsage.ru_utime.tv_usec);
302 printf("\tsystem time: %ld.%06ld\n", endUsage.ru_stime.tv_sec,
303 endUsage.ru_stime.tv_usec);
304 }
482fe481
BP
305
306 return true;
70407e86
BP
307}
308
309
2bd4b3e4
BP
310/*
311 * A GFunc for g_queue_foreach()
312 *
313 * Args:
314 * data: ModuleOption*
315 * user_data: NULL
316 */
317static void gfAddModuleOption(gpointer data, gpointer user_data)
318{
49c335f1 319 ModuleOption* option= data;
2bd4b3e4
BP
320 LttvOptionType conversion[]= {
321 [NO_ARG]= LTTV_OPT_NONE,
49c335f1 322 [OPTIONAL_ARG]= LTTV_OPT_NONE,
2bd4b3e4
BP
323 [REQUIRED_ARG]= LTTV_OPT_STRING,
324 };
49c335f1
BP
325 size_t fieldOffset[]= {
326 [NO_ARG]= offsetof(ModuleOption, present),
327 [REQUIRED_ARG]= offsetof(ModuleOption, arg),
328 };
329 static const char* argHelpNone= "none";
2bd4b3e4
BP
330
331 g_assert_cmpuint(sizeof(conversion) / sizeof(*conversion), ==,
332 HAS_ARG_COUNT);
49c335f1
BP
333 if (option->hasArg == OPTIONAL_ARG)
334 {
335 g_warning("Parameters with optional arguments not supported by the "
336 "lttv option scheme, parameter '%s' will not be available",
337 option->longName);
338 }
339 else
340 {
341 lttv_option_add(option->longName, '\0', option->optionHelp,
342 option->argHelp ? option->argHelp : argHelpNone,
343 conversion[option->hasArg], (void*) option + fieldOffset[option->hasArg],
344 NULL, NULL);
345 }
2bd4b3e4
BP
346}
347
348
349/*
350 * A GFunc for g_queue_foreach()
351 *
352 * Args:
353 * data: ModuleOption*
354 * user_data: NULL
355 */
356static void gfRemoveModuleOption(gpointer data, gpointer user_data)
357{
358 lttv_option_remove(((ModuleOption*) data)->longName);
359}
360
361
70407e86
BP
362LTTV_MODULE("sync", "Synchronize traces", \
363 "Synchronizes a traceset based on the correspondance of network events", \
364 init, destroy, "option")
This page took 0.039055 seconds and 4 git commands to generate.