Processing of UDP events
[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
BP
28#include <sys/stat.h>
29#include <sys/time.h>
30#include <sys/types.h>
31#include <sys/stat.h>
32#include <unistd.h>
70407e86
BP
33
34#include <lttv/module.h>
35#include <lttv/option.h>
36
10341d26 37#include "sync_chain_lttv.h"
70407e86
BP
38
39
40#ifndef g_info
41#define g_info(format...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, format)
42#endif
43
44
45static void init();
46static void destroy();
47
48static void timeDiff(struct timeval* const end, const struct timeval* const start);
08365995 49
70407e86
BP
50static gint gcfCompareAnalysis(gconstpointer a, gconstpointer b);
51static gint gcfCompareProcessing(gconstpointer a, gconstpointer b);
52static void gfAppendAnalysisName(gpointer data, gpointer user_data);
53
54static gboolean optionSync;
55static gboolean optionSyncStats;
56static gboolean optionSyncNull;
57static char* optionSyncAnalysis;
08365995
BP
58static gboolean optionSyncGraphs;
59static char* optionSyncGraphsDir;
60static char graphsDir[20];
70407e86
BP
61
62GQueue processingModules= G_QUEUE_INIT;
63GQueue matchingModules= G_QUEUE_INIT;
64GQueue analysisModules= G_QUEUE_INIT;
65
66
67/*
68 * Module init function
69 *
70 * This function is declared to be the module initialization function. Event
71 * modules are registered with a "constructor (102)" attribute except one in
72 * each class (processing, matching, analysis) which is chosen to be the
73 * default and which is registered with a "constructor (101)" attribute.
74 * Constructors with no priority are called after constructors with
75 * priorities. The result is that the list of event modules is known when this
76 * function is executed.
77 */
78static void init()
79{
80 GString* analysisModulesNames;
08365995 81 int retval;
70407e86
BP
82
83 g_debug("\t\t\tXXXX sync init\n");
84
85 optionSync= FALSE;
86 lttv_option_add("sync", '\0', "synchronize the time between the traces" ,
87 "none", LTTV_OPT_NONE, &optionSync, NULL, NULL);
88
89 optionSyncStats= FALSE;
90 lttv_option_add("sync-stats", '\0', "print statistics about the time "
91 "synchronization", "none", LTTV_OPT_NONE, &optionSyncStats, NULL,
92 NULL);
93
94 optionSyncNull= FALSE;
95 lttv_option_add("sync-null", '\0', "read the events but do not perform "
96 "any processing", "none", LTTV_OPT_NONE, &optionSyncNull, NULL, NULL);
97
98 g_assert(g_queue_get_length(&analysisModules) > 0);
99 optionSyncAnalysis= ((AnalysisModule*)
100 g_queue_peek_head(&analysisModules))->name;
101 analysisModulesNames= g_string_new("");
102 g_queue_foreach(&analysisModules, &gfAppendAnalysisName,
103 analysisModulesNames);
104 // remove the last ", "
105 g_string_truncate(analysisModulesNames, analysisModulesNames->len - 2);
106 lttv_option_add("sync-analysis", '\0', "specify the algorithm to use for "
107 "event analysis" , analysisModulesNames->str, LTTV_OPT_STRING,
108 &optionSyncAnalysis, NULL, NULL);
109 g_string_free(analysisModulesNames, TRUE);
08365995
BP
110
111 optionSyncGraphs= FALSE;
112 lttv_option_add("sync-graphs", '\0', "output gnuplot graph showing "
113 "synchronization points", "none", LTTV_OPT_NONE, &optionSyncGraphs,
114 NULL, NULL);
115
116 retval= snprintf(graphsDir, sizeof(graphsDir), "graphs-%d", getpid());
117 if (retval > sizeof(graphsDir) - 1)
118 {
119 graphsDir[sizeof(graphsDir) - 1]= '\0';
120 }
121 optionSyncGraphsDir= graphsDir;
122 lttv_option_add("sync-graphs-dir", '\0', "specify the directory where to"
123 " store the graphs", graphsDir, LTTV_OPT_STRING, &optionSyncGraphsDir,
124 NULL, NULL);
70407e86
BP
125}
126
127
128/*
129 * Module unload function
130 */
131static void destroy()
132{
133 g_debug("\t\t\tXXXX sync destroy\n");
134
135 lttv_option_remove("sync");
136 lttv_option_remove("sync-stats");
137 lttv_option_remove("sync-null");
138 lttv_option_remove("sync-analysis");
08365995
BP
139 lttv_option_remove("sync-graphs");
140 lttv_option_remove("sync-graphs-dir");
70407e86
BP
141}
142
143
144/*
145 * Calculate a traceset's drift and offset values based on network events
146 *
147 * The individual correction factors are written out to each trace.
148 *
149 * Args:
150 * traceSetContext: traceset
151 */
152void syncTraceset(LttvTracesetContext* const traceSetContext)
153{
154 SyncState* syncState;
155 struct timeval startTime, endTime;
156 struct rusage startUsage, endUsage;
157 GList* result;
08365995
BP
158 char* cwd;
159 FILE* graphsStream;
160 int graphsFp;
70407e86
BP
161 int retval;
162
163 if (optionSync == FALSE)
164 {
165 g_debug("Not synchronizing traceset because option is disabled");
166 return;
167 }
168
169 if (optionSyncStats)
170 {
171 gettimeofday(&startTime, 0);
172 getrusage(RUSAGE_SELF, &startUsage);
173 }
174
175 // Initialize data structures
176 syncState= malloc(sizeof(SyncState));
177 syncState->traceNb= lttv_traceset_number(traceSetContext->ts);
178
179 if (optionSyncStats)
180 {
181 syncState->stats= true;
182 }
183 else
184 {
185 syncState->stats= false;
186 }
187
08365995
BP
188 if (optionSyncGraphs)
189 {
190 syncState->graphs= optionSyncGraphsDir;
191 }
192 else
193 {
194 syncState->graphs= NULL;
195 }
196
197 // Identify and initialize processing module
70407e86
BP
198 syncState->processingData= NULL;
199 if (optionSyncNull)
200 {
201 result= g_queue_find_custom(&processingModules, "LTTV-null",
202 &gcfCompareProcessing);
203 }
204 else
205 {
206 result= g_queue_find_custom(&processingModules, "LTTV-standard",
207 &gcfCompareProcessing);
208 }
209 g_assert(result != NULL);
210 syncState->processingModule= (ProcessingModule*) result->data;
08365995
BP
211
212 graphsStream= NULL;
f6691532
BP
213 if (syncState->graphs &&
214 syncState->processingModule->writeProcessingGraphsPlots != NULL)
08365995
BP
215 {
216 // Create the graph directory right away in case the module initialization
217 // functions have something to write in it.
218 cwd= changeToGraphDir(syncState->graphs);
219
f6691532
BP
220 if ((graphsFp= open("graphs.gnu", O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR |
221 S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH
222 | S_IWOTH | S_IXOTH)) == -1)
08365995 223 {
f6691532
BP
224 g_error(strerror(errno));
225 }
226 if ((graphsStream= fdopen(graphsFp, "w")) == NULL)
227 {
228 g_error(strerror(errno));
08365995
BP
229 }
230
231 retval= chdir(cwd);
232 if (retval == -1)
233 {
234 g_error(strerror(errno));
235 }
236 free(cwd);
237 }
238
f6691532
BP
239 // Identify matching and analysis modules
240 g_assert(g_queue_get_length(&matchingModules) == 1);
241 syncState->matchingModule= (MatchingModule*)
242 g_queue_peek_head(&matchingModules);
70407e86 243
f6691532
BP
244 result= g_queue_find_custom(&analysisModules, optionSyncAnalysis,
245 &gcfCompareAnalysis);
246 if (result != NULL)
70407e86 247 {
f6691532 248 syncState->analysisModule= (AnalysisModule*) result->data;
70407e86
BP
249 }
250 else
251 {
f6691532
BP
252 g_error("Analysis module '%s' not found", optionSyncAnalysis);
253 }
70407e86 254
f6691532
BP
255 syncState->processingModule->initProcessing(syncState, traceSetContext);
256
257 syncState->matchingData= NULL;
258 syncState->analysisData= NULL;
259
260 if (!optionSyncNull)
261 {
262 syncState->matchingModule->initMatching(syncState);
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
272 syncState->processingModule->finalizeProcessing(syncState);
273
08365995
BP
274 // Write graphs file
275 if (graphsStream != NULL)
276 {
277 unsigned int i, j;
278
279 fprintf(graphsStream,
280 "#!/usr/bin/gnuplot\n\n"
281 "set terminal postscript eps color size 8in,6in\n");
282
283 // Cover the upper triangular matrix, i is the reference node.
284 for (i= 0; i < syncState->traceNb; i++)
285 {
286 for (j= i + 1; j < syncState->traceNb; j++)
287 {
288 long pos;
289
290 fprintf(graphsStream,
291 "\nset output \"%03d-%03d.eps\"\n"
292 "plot \\\n", i, j);
293
294 syncState->processingModule->writeProcessingGraphsPlots(graphsStream,
295 syncState, i, j);
296
297 // Remove the ", \\\n" from the last graph plot line
298 fflush(graphsStream);
299 pos= ftell(graphsStream);
300 if (ftruncate(fileno(graphsStream), pos - 4) == -1)
301 {
302 g_error(strerror(errno));
303 }
304 if (fseek(graphsStream, 0, SEEK_END) == -1)
305 {
306 g_error(strerror(errno));
307 }
308
309 fprintf(graphsStream,
310 "\nset output \"%1$03d-%2$03d.eps\"\n"
311 "set key inside right bottom\n"
312 "set title \"\"\n"
313 "set xlabel \"Clock %1$u\"\n"
314 "set xtics nomirror\n"
315 "set ylabel \"Clock %2$u\"\n"
316 "set ytics nomirror\n", i, j);
317
318 syncState->processingModule->writeProcessingGraphsOptions(graphsStream,
319 syncState, i, j);
320
321 fprintf(graphsStream,
322 "replot\n");
323 }
324 }
325
326 if (fclose(graphsStream) != 0)
327 {
328 g_error(strerror(errno));
329 }
330 }
331
70407e86
BP
332 if (syncState->processingModule->printProcessingStats != NULL)
333 {
334 syncState->processingModule->printProcessingStats(syncState);
335 }
336
337 syncState->processingModule->destroyProcessing(syncState);
338 if (syncState->matchingModule != NULL)
339 {
340 syncState->matchingModule->destroyMatching(syncState);
341 }
342 if (syncState->analysisModule != NULL)
343 {
344 syncState->analysisModule->destroyAnalysis(syncState);
345 }
346
347 free(syncState);
348
349 if (optionSyncStats)
350 {
351 gettimeofday(&endTime, 0);
352 retval= getrusage(RUSAGE_SELF, &endUsage);
353
354 timeDiff(&endTime, &startTime);
355 timeDiff(&endUsage.ru_utime, &startUsage.ru_utime);
356 timeDiff(&endUsage.ru_stime, &startUsage.ru_stime);
357
358 printf("Synchronization time:\n");
359 printf("\treal time: %ld.%06ld\n", endTime.tv_sec, endTime.tv_usec);
360 printf("\tuser time: %ld.%06ld\n", endUsage.ru_utime.tv_sec,
361 endUsage.ru_utime.tv_usec);
362 printf("\tsystem time: %ld.%06ld\n", endUsage.ru_stime.tv_sec,
363 endUsage.ru_stime.tv_usec);
364 }
365}
366
367
368/*
369 * Calculate the elapsed time between two timeval values
370 *
371 * Args:
372 * end: end time, result is also stored in this structure
373 * start: start time
374 */
375static void timeDiff(struct timeval* const end, const struct timeval* const start)
376{
377 if (end->tv_usec >= start->tv_usec)
378 {
379 end->tv_sec-= start->tv_sec;
380 end->tv_usec-= start->tv_usec;
381 }
382 else
383 {
384 end->tv_sec= end->tv_sec - start->tv_sec - 1;
385 end->tv_usec= end->tv_usec - start->tv_usec + 1e6;
386 }
387}
388
389
390/*
391 * A GCompareFunc for g_slist_find_custom()
392 *
393 * Args:
394 * a: AnalysisModule*, element's data
395 * b: char*, user data to compare against
396 *
397 * Returns:
398 * 0 if the analysis module a's name is b
399 */
400static gint gcfCompareAnalysis(gconstpointer a, gconstpointer b)
401{
402 const AnalysisModule* analysisModule;
403 const char* name;
404
405 analysisModule= (const AnalysisModule*)a;
406 name= (const char*)b;
407
408 return strncmp(analysisModule->name, name, strlen(analysisModule->name) +
409 1);
410}
411
412
413/*
414 * A GCompareFunc for g_slist_find_custom()
415 *
416 * Args:
417 * a: ProcessingModule*, element's data
418 * b: char*, user data to compare against
419 *
420 * Returns:
421 * 0 if the analysis module a's name is b
422 */
423static gint gcfCompareProcessing(gconstpointer a, gconstpointer b)
424{
425 const ProcessingModule* processingModule;
426 const char* name;
427
428 processingModule= (const ProcessingModule*)a;
429 name= (const char*)b;
430
431 return strncmp(processingModule->name, name,
432 strlen(processingModule->name) + 1);
433}
434
435
436/*
437 * A GFunc for g_queue_foreach()
438 *
439 * Concatenate analysis module names.
440 *
441 * Args:
442 * data: AnalysisModule*
443 * user_data: GString*, concatenated names
444 */
445static void gfAppendAnalysisName(gpointer data, gpointer user_data)
446{
447 g_string_append((GString*) user_data, ((AnalysisModule*) data)->name);
448 g_string_append((GString*) user_data, ", ");
449}
450
451
08365995
BP
452/*
453 * Change to the directory used to hold graphs. Create it if necessary.
454 *
455 * Args:
456 * graph: name of directory
457 *
458 * Returns:
459 * The current working directory before the execution of the function. The
460 * string must be free'd by the caller.
461 */
462char* changeToGraphDir(char* const graphs)
463{
464 int retval;
465 char* cwd;
466
467 cwd= getcwd(NULL, 0);
468 if (cwd == NULL)
469 {
470 g_error(strerror(errno));
471 }
472 while ((retval= chdir(graphs)) != 0)
473 {
474 if (errno == ENOENT)
475 {
476 retval= mkdir(graphs, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP |
477 S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH);
478 if (retval != 0)
479 {
480 g_error(strerror(errno));
481 }
482 }
483 else
484 {
485 g_error(strerror(errno));
486 }
487 }
488
489 return cwd;
490}
491
492
70407e86
BP
493LTTV_MODULE("sync", "Synchronize traces", \
494 "Synchronizes a traceset based on the correspondance of network events", \
495 init, destroy, "option")
This page took 0.041267 seconds and 4 git commands to generate.