5dd10bf9fb827deaa5ea6ea1777a2cee4a955b82
[lttv.git] / lttv / lttv / sync / sync_chain_lttv.c
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
23 #include <errno.h>
24 #include <fcntl.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <sys/resource.h>
28 #include <sys/stat.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <unistd.h>
32
33 #include <lttv/module.h>
34 #include <lttv/option.h>
35
36 #include "sync_chain.h"
37 #include "sync_chain_lttv.h"
38
39
40 static void init();
41 static void destroy();
42
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);
46
47 static char* argHelpNone= "none";
48 static ModuleOption optionSync= {
49 .longName= "sync",
50 .hasArg= NO_ARG,
51 {.present= false},
52 .optionHelp= "synchronize the time between the traces",
53 };
54 static char graphsDir[20];
55 static ModuleOption optionSyncStats= {
56 .longName= "sync-stats",
57 .hasArg= NO_ARG,
58 {.present= false},
59 .optionHelp= "print statistics about the time synchronization",
60 };
61 static ModuleOption optionSyncNull= {
62 .longName= "sync-null",
63 .hasArg= NO_ARG,
64 {.present= false},
65 .optionHelp= "read the events but do not perform any processing",
66 };
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",
72 };
73 static ModuleOption optionSyncGraphs= {
74 .longName= "sync-graphs",
75 .hasArg= NO_ARG,
76 {.present= false},
77 .optionHelp= "output gnuplot graph showing synchronization points",
78 };
79 static ModuleOption optionSyncGraphsDir= {
80 .longName= "sync-graphs-dir",
81 .hasArg= REQUIRED_ARG,
82 .optionHelp= "specify the directory where to store the graphs",
83 };
84
85 /*
86 * Module init function
87 *
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.
95 */
96 static void init()
97 {
98 int retval;
99
100 g_debug("Sync init");
101
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;
111
112 retval= snprintf(graphsDir, sizeof(graphsDir), "graphs-%d", getpid());
113 if (retval > sizeof(graphsDir) - 1)
114 {
115 graphsDir[sizeof(graphsDir) - 1]= '\0';
116 }
117 optionSyncGraphsDir.arg= graphsDir;
118 optionSyncGraphsDir.argHelp= graphsDir;
119
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);
126
127 g_queue_foreach(&moduleOptions, &gfAddModuleOption, NULL);
128
129 }
130
131
132 /*
133 * Module unload function
134 */
135 static void destroy()
136 {
137 g_debug("Sync destroy");
138
139 g_queue_foreach(&moduleOptions, &gfRemoveModuleOption, NULL);
140 g_string_free(analysisModulesNames, TRUE);
141
142 g_queue_clear(&processingModules);
143 g_queue_clear(&matchingModules);
144 g_queue_clear(&analysisModules);
145 g_queue_clear(&moduleOptions);
146 }
147
148
149 /*
150 * Calculate a traceset's drift and offset values based on network events
151 *
152 * The individual correction factors are written out to each trace.
153 *
154 * Args:
155 * traceSetContext: traceset
156 */
157 void syncTraceset(LttvTracesetContext* const traceSetContext)
158 {
159 SyncState* syncState;
160 struct timeval startTime, endTime;
161 struct rusage startUsage, endUsage;
162 GList* result;
163 unsigned int i;
164 int retval;
165
166 if (!optionSync.present)
167 {
168 g_debug("Not synchronizing traceset because option is disabled");
169 return;
170 }
171
172 if (optionSyncStats.present)
173 {
174 gettimeofday(&startTime, 0);
175 getrusage(RUSAGE_SELF, &startUsage);
176 }
177
178 // Initialize data structures
179 syncState= malloc(sizeof(SyncState));
180 syncState->traceNb= lttv_traceset_number(traceSetContext->ts);
181
182 if (optionSyncStats.present)
183 {
184 syncState->stats= true;
185 }
186 else
187 {
188 syncState->stats= false;
189 }
190
191 if (optionSyncGraphs.present)
192 {
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);
197 }
198 else
199 {
200 syncState->graphsStream= NULL;
201 syncState->graphsDir= NULL;
202 }
203
204 // Identify and initialize modules
205 syncState->processingData= NULL;
206 if (optionSyncNull.present)
207 {
208 result= g_queue_find_custom(&processingModules, "LTTV-null",
209 &gcfCompareProcessing);
210 }
211 else
212 {
213 result= g_queue_find_custom(&processingModules, "LTTV-standard",
214 &gcfCompareProcessing);
215 }
216 g_assert(result != NULL);
217 syncState->processingModule= (ProcessingModule*) result->data;
218
219 syncState->matchingData= NULL;
220 result= g_queue_find_custom(&matchingModules, "TCP", &gcfCompareMatching);
221 g_assert(result != NULL);
222 syncState->matchingModule= (MatchingModule*) result->data;
223
224 syncState->analysisData= NULL;
225 result= g_queue_find_custom(&analysisModules, optionSyncAnalysis.arg,
226 &gcfCompareAnalysis);
227 if (result != NULL)
228 {
229 syncState->analysisModule= (AnalysisModule*) result->data;
230 }
231 else
232 {
233 g_error("Analysis module '%s' not found", optionSyncAnalysis.arg);
234 }
235
236 if (!optionSyncNull.present)
237 {
238 syncState->analysisModule->initAnalysis(syncState);
239 syncState->matchingModule->initMatching(syncState);
240 }
241 syncState->processingModule->initProcessing(syncState, traceSetContext);
242
243 // Process traceset
244 lttv_process_traceset_seek_time(traceSetContext, ltt_time_zero);
245 lttv_process_traceset_middle(traceSetContext, ltt_time_infinite,
246 G_MAXULONG, NULL);
247 lttv_process_traceset_seek_time(traceSetContext, ltt_time_zero);
248
249 syncState->processingModule->finalizeProcessing(syncState);
250
251 // Write graphs file
252 if (optionSyncGraphs.present)
253 {
254 writeGraphsScript(syncState);
255
256 if (fclose(syncState->graphsStream) != 0)
257 {
258 g_error(strerror(errno));
259 }
260 }
261
262 if (syncState->processingModule->printProcessingStats != NULL)
263 {
264 syncState->processingModule->printProcessingStats(syncState);
265 }
266 if (syncState->matchingModule->printMatchingStats != NULL)
267 {
268 syncState->matchingModule->printMatchingStats(syncState);
269 }
270 if (syncState->analysisModule->printAnalysisStats != NULL)
271 {
272 syncState->analysisModule->printAnalysisStats(syncState);
273 }
274
275 if (optionSyncStats.present)
276 {
277 printf("Resulting synchronization factors:\n");
278 for (i= 0; i < syncState->traceNb; i++)
279 {
280 LttTrace* t;
281
282 t= traceSetContext->traces[i]->t;
283
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);
289 }
290 }
291
292 syncState->processingModule->destroyProcessing(syncState);
293 if (syncState->matchingModule != NULL)
294 {
295 syncState->matchingModule->destroyMatching(syncState);
296 }
297 if (syncState->analysisModule != NULL)
298 {
299 syncState->analysisModule->destroyAnalysis(syncState);
300 }
301
302 free(syncState);
303
304 if (optionSyncStats.present)
305 {
306 gettimeofday(&endTime, 0);
307 retval= getrusage(RUSAGE_SELF, &endUsage);
308
309 timeDiff(&endTime, &startTime);
310 timeDiff(&endUsage.ru_utime, &startUsage.ru_utime);
311 timeDiff(&endUsage.ru_stime, &startUsage.ru_stime);
312
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);
319 }
320 }
321
322
323 /*
324 * A GFunc for g_queue_foreach()
325 *
326 * Concatenate analysis module names.
327 *
328 * Args:
329 * data: AnalysisModule*
330 * user_data: GString*, concatenated names
331 */
332 static void gfAppendAnalysisName(gpointer data, gpointer user_data)
333 {
334 g_string_append((GString*) user_data, ((AnalysisModule*) data)->name);
335 g_string_append((GString*) user_data, ", ");
336 }
337
338
339 /*
340 * A GFunc for g_queue_foreach()
341 *
342 * Args:
343 * data: ModuleOption*
344 * user_data: NULL
345 */
346 static void gfAddModuleOption(gpointer data, gpointer user_data)
347 {
348 ModuleOption* option;
349 LttvOptionType conversion[]= {
350 [NO_ARG]= LTTV_OPT_NONE,
351 [REQUIRED_ARG]= LTTV_OPT_STRING,
352 };
353
354 g_assert_cmpuint(sizeof(conversion) / sizeof(*conversion), ==,
355 HAS_ARG_COUNT);
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);
360 }
361
362
363 /*
364 * A GFunc for g_queue_foreach()
365 *
366 * Args:
367 * data: ModuleOption*
368 * user_data: NULL
369 */
370 static void gfRemoveModuleOption(gpointer data, gpointer user_data)
371 {
372 lttv_option_remove(((ModuleOption*) data)->longName);
373 }
374
375
376 LTTV_MODULE("sync", "Synchronize traces", \
377 "Synchronizes a traceset based on the correspondance of network events", \
378 init, destroy, "option")
This page took 0.039869 seconds and 3 git commands to generate.