Make option type OPTIONAL_ARG available
[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 gfAddModuleOption(gpointer data, gpointer user_data);
44 static void gfRemoveModuleOption(gpointer data, gpointer user_data);
45
46 static ModuleOption optionSync= {
47 .longName= "sync",
48 .hasArg= NO_ARG,
49 .optionHelp= "synchronize the time between the traces",
50 };
51 static ModuleOption optionSyncStats= {
52 .longName= "sync-stats",
53 .hasArg= NO_ARG,
54 .optionHelp= "print statistics about the time synchronization",
55 };
56 static ModuleOption optionSyncNull= {
57 .longName= "sync-null",
58 .hasArg= NO_ARG,
59 .optionHelp= "read the events but do not perform any processing",
60 };
61 static GString* analysisModulesNames;
62 static ModuleOption optionSyncAnalysis= {
63 .longName= "sync-analysis",
64 .hasArg= REQUIRED_ARG,
65 .optionHelp= "specify the algorithm to use for event analysis",
66 };
67 static ModuleOption optionSyncGraphs= {
68 .longName= "sync-graphs",
69 .hasArg= NO_ARG,
70 .optionHelp= "output gnuplot graph showing synchronization points",
71 };
72 static char graphsDir[20];
73 static ModuleOption optionSyncGraphsDir= {
74 .longName= "sync-graphs-dir",
75 .hasArg= REQUIRED_ARG,
76 .optionHelp= "specify the directory where to store the graphs",
77 };
78
79
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 */
91 static void init()
92 {
93 int retval;
94
95 g_debug("Sync init");
96
97 g_assert(g_queue_get_length(&analysisModules) > 0);
98 optionSyncAnalysis.arg= ((AnalysisModule*)
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);
105 optionSyncAnalysis.argHelp= analysisModulesNames->str;
106
107 retval= snprintf(graphsDir, sizeof(graphsDir), "graphs-%d", getpid());
108 if (retval > sizeof(graphsDir) - 1)
109 {
110 graphsDir[sizeof(graphsDir) - 1]= '\0';
111 }
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);
123 }
124
125
126 /*
127 * Module unload function
128 */
129 static void destroy()
130 {
131 g_debug("Sync destroy");
132
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);
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
150 */
151 void syncTraceset(LttvTracesetContext* const traceSetContext)
152 {
153 SyncState* syncState;
154 struct timeval startTime, endTime;
155 struct rusage startUsage, endUsage;
156 GList* result;
157 unsigned int i;
158 int retval;
159
160 if (!optionSync.present)
161 {
162 g_debug("Not synchronizing traceset because option is disabled");
163 return;
164 }
165
166 if (optionSyncStats.present)
167 {
168 gettimeofday(&startTime, 0);
169 getrusage(RUSAGE_SELF, &startUsage);
170 }
171
172 // Initialize data structures
173 syncState= malloc(sizeof(SyncState));
174 syncState->traceNb= lttv_traceset_number(traceSetContext->ts);
175
176 if (optionSyncStats.present)
177 {
178 syncState->stats= true;
179 }
180 else
181 {
182 syncState->stats= false;
183 }
184
185 if (optionSyncGraphs.present)
186 {
187 // Create the graph directory right away in case the module initialization
188 // functions have something to write in it.
189 syncState->graphsDir= optionSyncGraphsDir.arg;
190 syncState->graphsStream= createGraphsDir(syncState->graphsDir);
191 }
192 else
193 {
194 syncState->graphsStream= NULL;
195 syncState->graphsDir= NULL;
196 }
197
198 // Identify and initialize modules
199 syncState->processingData= NULL;
200 if (optionSyncNull.present)
201 {
202 result= g_queue_find_custom(&processingModules, "LTTV-null",
203 &gcfCompareProcessing);
204 }
205 else
206 {
207 result= g_queue_find_custom(&processingModules, "LTTV-standard",
208 &gcfCompareProcessing);
209 }
210 g_assert(result != NULL);
211 syncState->processingModule= (ProcessingModule*) result->data;
212
213 syncState->matchingData= NULL;
214 result= g_queue_find_custom(&matchingModules, "TCP", &gcfCompareMatching);
215 g_assert(result != NULL);
216 syncState->matchingModule= (MatchingModule*) result->data;
217
218 syncState->analysisData= NULL;
219 result= g_queue_find_custom(&analysisModules, optionSyncAnalysis.arg,
220 &gcfCompareAnalysis);
221 if (result != NULL)
222 {
223 syncState->analysisModule= (AnalysisModule*) result->data;
224 }
225 else
226 {
227 g_error("Analysis module '%s' not found", optionSyncAnalysis.arg);
228 }
229
230 if (!optionSyncNull.present)
231 {
232 syncState->analysisModule->initAnalysis(syncState);
233 syncState->matchingModule->initMatching(syncState);
234 }
235 syncState->processingModule->initProcessing(syncState, traceSetContext);
236
237 // Process traceset
238 lttv_process_traceset_seek_time(traceSetContext, ltt_time_zero);
239 lttv_process_traceset_middle(traceSetContext, ltt_time_infinite,
240 G_MAXULONG, NULL);
241 lttv_process_traceset_seek_time(traceSetContext, ltt_time_zero);
242
243 syncState->processingModule->finalizeProcessing(syncState);
244
245 // Write graphs file
246 if (optionSyncGraphs.present)
247 {
248 writeGraphsScript(syncState);
249
250 if (fclose(syncState->graphsStream) != 0)
251 {
252 g_error(strerror(errno));
253 }
254 }
255
256 if (syncState->processingModule->printProcessingStats != NULL)
257 {
258 syncState->processingModule->printProcessingStats(syncState);
259 }
260 if (syncState->matchingModule->printMatchingStats != NULL)
261 {
262 syncState->matchingModule->printMatchingStats(syncState);
263 }
264 if (syncState->analysisModule->printAnalysisStats != NULL)
265 {
266 syncState->analysisModule->printAnalysisStats(syncState);
267 }
268
269 if (optionSyncStats.present)
270 {
271 printf("Resulting synchronization factors:\n");
272 for (i= 0; i < syncState->traceNb; i++)
273 {
274 LttTrace* t;
275
276 t= traceSetContext->traces[i]->t;
277
278 printf("\ttrace %u drift= %g offset= %g (%f) start time= %ld.%09ld\n",
279 i, t->drift, t->offset, (double) tsc_to_uint64(t->freq_scale,
280 t->start_freq, t->offset) / NANOSECONDS_PER_SECOND,
281 t->start_time_from_tsc.tv_sec,
282 t->start_time_from_tsc.tv_nsec);
283 }
284 }
285
286 syncState->processingModule->destroyProcessing(syncState);
287 if (syncState->matchingModule != NULL)
288 {
289 syncState->matchingModule->destroyMatching(syncState);
290 }
291 if (syncState->analysisModule != NULL)
292 {
293 syncState->analysisModule->destroyAnalysis(syncState);
294 }
295
296 free(syncState);
297
298 if (optionSyncStats.present)
299 {
300 gettimeofday(&endTime, 0);
301 retval= getrusage(RUSAGE_SELF, &endUsage);
302
303 timeDiff(&endTime, &startTime);
304 timeDiff(&endUsage.ru_utime, &startUsage.ru_utime);
305 timeDiff(&endUsage.ru_stime, &startUsage.ru_stime);
306
307 printf("Synchronization time:\n");
308 printf("\treal time: %ld.%06ld\n", endTime.tv_sec, endTime.tv_usec);
309 printf("\tuser time: %ld.%06ld\n", endUsage.ru_utime.tv_sec,
310 endUsage.ru_utime.tv_usec);
311 printf("\tsystem time: %ld.%06ld\n", endUsage.ru_stime.tv_sec,
312 endUsage.ru_stime.tv_usec);
313 }
314 }
315
316
317 /*
318 * A GFunc for g_queue_foreach()
319 *
320 * Args:
321 * data: ModuleOption*
322 * user_data: NULL
323 */
324 static void gfAddModuleOption(gpointer data, gpointer user_data)
325 {
326 ModuleOption* option= data;
327 LttvOptionType conversion[]= {
328 [NO_ARG]= LTTV_OPT_NONE,
329 [OPTIONAL_ARG]= LTTV_OPT_NONE,
330 [REQUIRED_ARG]= LTTV_OPT_STRING,
331 };
332 size_t fieldOffset[]= {
333 [NO_ARG]= offsetof(ModuleOption, present),
334 [REQUIRED_ARG]= offsetof(ModuleOption, arg),
335 };
336 static const char* argHelpNone= "none";
337
338 g_assert_cmpuint(sizeof(conversion) / sizeof(*conversion), ==,
339 HAS_ARG_COUNT);
340 if (option->hasArg == OPTIONAL_ARG)
341 {
342 g_warning("Parameters with optional arguments not supported by the "
343 "lttv option scheme, parameter '%s' will not be available",
344 option->longName);
345 }
346 else
347 {
348 lttv_option_add(option->longName, '\0', option->optionHelp,
349 option->argHelp ? option->argHelp : argHelpNone,
350 conversion[option->hasArg], (void*) option + fieldOffset[option->hasArg],
351 NULL, NULL);
352 }
353 }
354
355
356 /*
357 * A GFunc for g_queue_foreach()
358 *
359 * Args:
360 * data: ModuleOption*
361 * user_data: NULL
362 */
363 static void gfRemoveModuleOption(gpointer data, gpointer user_data)
364 {
365 lttv_option_remove(((ModuleOption*) data)->longName);
366 }
367
368
369 LTTV_MODULE("sync", "Synchronize traces", \
370 "Synchronizes a traceset based on the correspondance of network events", \
371 init, destroy, "option")
This page took 0.037171 seconds and 4 git commands to generate.