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_lttv.h"
40 #define g_info(format...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, format)
45 static void destroy();
47 static void gfAppendAnalysisName(gpointer data
, gpointer user_data
);
49 static gboolean optionSync
;
50 static gboolean optionSyncStats
;
51 static gboolean optionSyncNull
;
52 static char* optionSyncAnalysis
;
53 static gboolean optionSyncGraphs
;
54 static char* optionSyncGraphsDir
;
55 static char graphsDir
[20];
57 GQueue processingModules
= G_QUEUE_INIT
;
58 GQueue matchingModules
= G_QUEUE_INIT
;
59 GQueue analysisModules
= G_QUEUE_INIT
;
63 * Module init function
65 * This function is declared to be the module initialization function. Event
66 * modules are registered with a "constructor (102)" attribute except one in
67 * each class (processing, matching, analysis) which is chosen to be the
68 * default and which is registered with a "constructor (101)" attribute.
69 * Constructors with no priority are called after constructors with
70 * priorities. The result is that the list of event modules is known when this
71 * function is executed.
75 GString
* analysisModulesNames
;
78 g_debug("\t\t\tXXXX sync init\n");
81 lttv_option_add("sync", '\0', "synchronize the time between the traces" ,
82 "none", LTTV_OPT_NONE
, &optionSync
, NULL
, NULL
);
84 optionSyncStats
= FALSE
;
85 lttv_option_add("sync-stats", '\0', "print statistics about the time "
86 "synchronization", "none", LTTV_OPT_NONE
, &optionSyncStats
, NULL
,
89 optionSyncNull
= FALSE
;
90 lttv_option_add("sync-null", '\0', "read the events but do not perform "
91 "any processing", "none", LTTV_OPT_NONE
, &optionSyncNull
, NULL
, NULL
);
93 g_assert(g_queue_get_length(&analysisModules
) > 0);
94 optionSyncAnalysis
= ((AnalysisModule
*)
95 g_queue_peek_head(&analysisModules
))->name
;
96 analysisModulesNames
= g_string_new("");
97 g_queue_foreach(&analysisModules
, &gfAppendAnalysisName
,
98 analysisModulesNames
);
99 // remove the last ", "
100 g_string_truncate(analysisModulesNames
, analysisModulesNames
->len
- 2);
101 lttv_option_add("sync-analysis", '\0', "specify the algorithm to use for "
102 "event analysis" , analysisModulesNames
->str
, LTTV_OPT_STRING
,
103 &optionSyncAnalysis
, NULL
, NULL
);
104 g_string_free(analysisModulesNames
, TRUE
);
106 optionSyncGraphs
= FALSE
;
107 lttv_option_add("sync-graphs", '\0', "output gnuplot graph showing "
108 "synchronization points", "none", LTTV_OPT_NONE
, &optionSyncGraphs
,
111 retval
= snprintf(graphsDir
, sizeof(graphsDir
), "graphs-%d", getpid());
112 if (retval
> sizeof(graphsDir
) - 1)
114 graphsDir
[sizeof(graphsDir
) - 1]= '\0';
116 optionSyncGraphsDir
= graphsDir
;
117 lttv_option_add("sync-graphs-dir", '\0', "specify the directory where to"
118 " store the graphs", graphsDir
, LTTV_OPT_STRING
, &optionSyncGraphsDir
,
124 * Module unload function
126 static void destroy()
128 g_debug("\t\t\tXXXX sync destroy\n");
130 lttv_option_remove("sync");
131 lttv_option_remove("sync-stats");
132 lttv_option_remove("sync-null");
133 lttv_option_remove("sync-analysis");
134 lttv_option_remove("sync-graphs");
135 lttv_option_remove("sync-graphs-dir");
140 * Calculate a traceset's drift and offset values based on network events
142 * The individual correction factors are written out to each trace.
145 * traceSetContext: traceset
147 void syncTraceset(LttvTracesetContext
* const traceSetContext
)
149 SyncState
* syncState
;
150 struct timeval startTime
, endTime
;
151 struct rusage startUsage
, endUsage
;
156 if (optionSync
== FALSE
)
158 g_debug("Not synchronizing traceset because option is disabled");
164 gettimeofday(&startTime
, 0);
165 getrusage(RUSAGE_SELF
, &startUsage
);
168 // Initialize data structures
169 syncState
= malloc(sizeof(SyncState
));
170 syncState
->traceNb
= lttv_traceset_number(traceSetContext
->ts
);
174 syncState
->stats
= true;
178 syncState
->stats
= false;
181 if (optionSyncGraphs
)
183 syncState
->graphs
= optionSyncGraphsDir
;
187 syncState
->graphs
= NULL
;
190 // Identify and initialize processing module
191 syncState
->processingData
= NULL
;
194 result
= g_queue_find_custom(&processingModules
, "LTTV-null",
195 &gcfCompareProcessing
);
199 result
= g_queue_find_custom(&processingModules
, "LTTV-standard",
200 &gcfCompareProcessing
);
202 g_assert(result
!= NULL
);
203 syncState
->processingModule
= (ProcessingModule
*) result
->data
;
206 if (syncState
->graphs
&&
207 syncState
->processingModule
->writeProcessingGraphsPlots
!= NULL
)
212 // Create the graph directory right away in case the module initialization
213 // functions have something to write in it.
214 cwd
= changeToGraphDir(syncState
->graphs
);
216 if ((graphsFp
= open("graphs.gnu", O_WRONLY
| O_CREAT
| O_TRUNC
, S_IRUSR
|
217 S_IWUSR
| S_IXUSR
| S_IRGRP
| S_IWGRP
| S_IXGRP
| S_IROTH
218 | S_IWOTH
| S_IXOTH
)) == -1)
220 g_error(strerror(errno
));
222 if ((graphsStream
= fdopen(graphsFp
, "w")) == NULL
)
224 g_error(strerror(errno
));
230 g_error(strerror(errno
));
235 // Identify matching and analysis modules
236 result
= g_queue_find_custom(&matchingModules
, "TCP", &gcfCompareMatching
);
237 g_assert(result
!= NULL
);
238 syncState
->matchingModule
= (MatchingModule
*) result
->data
;
240 result
= g_queue_find_custom(&analysisModules
, optionSyncAnalysis
,
241 &gcfCompareAnalysis
);
244 syncState
->analysisModule
= (AnalysisModule
*) result
->data
;
248 g_error("Analysis module '%s' not found", optionSyncAnalysis
);
251 syncState
->processingModule
->initProcessing(syncState
, traceSetContext
);
253 syncState
->matchingData
= NULL
;
254 syncState
->analysisData
= NULL
;
258 syncState
->matchingModule
->initMatching(syncState
);
259 syncState
->analysisModule
->initAnalysis(syncState
);
263 lttv_process_traceset_seek_time(traceSetContext
, ltt_time_zero
);
264 lttv_process_traceset_middle(traceSetContext
, ltt_time_infinite
,
266 lttv_process_traceset_seek_time(traceSetContext
, ltt_time_zero
);
268 syncState
->processingModule
->finalizeProcessing(syncState
);
271 if (graphsStream
!= NULL
)
275 fprintf(graphsStream
,
276 "#!/usr/bin/gnuplot\n\n"
277 "set terminal postscript eps color size 8in,6in\n");
279 // Cover the upper triangular matrix, i is the reference node.
280 for (i
= 0; i
< syncState
->traceNb
; i
++)
282 for (j
= i
+ 1; j
< syncState
->traceNb
; j
++)
286 fprintf(graphsStream
,
287 "\nset output \"%03d-%03d.eps\"\n"
290 syncState
->processingModule
->writeProcessingGraphsPlots(graphsStream
,
293 // Remove the ", \\\n" from the last graph plot line
294 fflush(graphsStream
);
295 pos
= ftell(graphsStream
);
296 if (ftruncate(fileno(graphsStream
), pos
- 4) == -1)
298 g_error(strerror(errno
));
300 if (fseek(graphsStream
, 0, SEEK_END
) == -1)
302 g_error(strerror(errno
));
305 fprintf(graphsStream
,
306 "\nset output \"%1$03d-%2$03d.eps\"\n"
307 "set key inside right bottom\n"
309 "set xlabel \"Clock %1$u\"\n"
310 "set xtics nomirror\n"
311 "set ylabel \"Clock %2$u\"\n"
312 "set ytics nomirror\n", i
, j
);
314 syncState
->processingModule
->writeProcessingGraphsOptions(graphsStream
,
317 fprintf(graphsStream
,
322 if (fclose(graphsStream
) != 0)
324 g_error(strerror(errno
));
328 if (syncState
->processingModule
->printProcessingStats
!= NULL
)
330 syncState
->processingModule
->printProcessingStats(syncState
);
333 syncState
->processingModule
->destroyProcessing(syncState
);
334 if (syncState
->matchingModule
!= NULL
)
336 syncState
->matchingModule
->destroyMatching(syncState
);
338 if (syncState
->analysisModule
!= NULL
)
340 syncState
->analysisModule
->destroyAnalysis(syncState
);
347 gettimeofday(&endTime
, 0);
348 retval
= getrusage(RUSAGE_SELF
, &endUsage
);
350 timeDiff(&endTime
, &startTime
);
351 timeDiff(&endUsage
.ru_utime
, &startUsage
.ru_utime
);
352 timeDiff(&endUsage
.ru_stime
, &startUsage
.ru_stime
);
354 printf("Synchronization time:\n");
355 printf("\treal time: %ld.%06ld\n", endTime
.tv_sec
, endTime
.tv_usec
);
356 printf("\tuser time: %ld.%06ld\n", endUsage
.ru_utime
.tv_sec
,
357 endUsage
.ru_utime
.tv_usec
);
358 printf("\tsystem time: %ld.%06ld\n", endUsage
.ru_stime
.tv_sec
,
359 endUsage
.ru_stime
.tv_usec
);
365 * Calculate the elapsed time between two timeval values
368 * end: end time, result is also stored in this structure
371 void timeDiff(struct timeval
* const end
, const struct timeval
* const start
)
373 if (end
->tv_usec
>= start
->tv_usec
)
375 end
->tv_sec
-= start
->tv_sec
;
376 end
->tv_usec
-= start
->tv_usec
;
380 end
->tv_sec
= end
->tv_sec
- start
->tv_sec
- 1;
381 end
->tv_usec
= end
->tv_usec
- start
->tv_usec
+ 1e6
;
387 * A GCompareFunc for g_slist_find_custom()
390 * a: ProcessingModule*, element's data
391 * b: char*, user data to compare against
394 * 0 if the processing module a's name is b
396 gint
gcfCompareProcessing(gconstpointer a
, gconstpointer b
)
398 const ProcessingModule
* processingModule
;
401 processingModule
= (const ProcessingModule
*) a
;
402 name
= (const char*) b
;
404 return strncmp(processingModule
->name
, name
,
405 strlen(processingModule
->name
) + 1);
410 * A GCompareFunc for g_slist_find_custom()
413 * a: MatchingModule*, element's data
414 * b: char*, user data to compare against
417 * 0 if the matching module a's name is b
419 gint
gcfCompareMatching(gconstpointer a
, gconstpointer b
)
421 const MatchingModule
* matchingModule
;
424 matchingModule
= (const MatchingModule
*) a
;
425 name
= (const char*) b
;
427 return strncmp(matchingModule
->name
, name
, strlen(matchingModule
->name
) +
433 * A GCompareFunc for g_slist_find_custom()
436 * a: AnalysisModule*, element's data
437 * b: char*, user data to compare against
440 * 0 if the analysis module a's name is b
442 gint
gcfCompareAnalysis(gconstpointer a
, gconstpointer b
)
444 const AnalysisModule
* analysisModule
;
447 analysisModule
= (const AnalysisModule
*) a
;
448 name
= (const char*) b
;
450 return strncmp(analysisModule
->name
, name
, strlen(analysisModule
->name
) +
456 * A GFunc for g_queue_foreach()
458 * Concatenate analysis module names.
461 * data: AnalysisModule*
462 * user_data: GString*, concatenated names
464 static void gfAppendAnalysisName(gpointer data
, gpointer user_data
)
466 g_string_append((GString
*) user_data
, ((AnalysisModule
*) data
)->name
);
467 g_string_append((GString
*) user_data
, ", ");
472 * Change to the directory used to hold graphs. Create it if necessary.
475 * graph: name of directory
478 * The current working directory before the execution of the function. The
479 * string must be free'd by the caller.
481 char* changeToGraphDir(char* const graphs
)
486 cwd
= getcwd(NULL
, 0);
489 g_error(strerror(errno
));
491 while ((retval
= chdir(graphs
)) != 0)
495 retval
= mkdir(graphs
, S_IRUSR
| S_IWUSR
| S_IXUSR
| S_IRGRP
|
496 S_IWGRP
| S_IXGRP
| S_IROTH
| S_IWOTH
| S_IXOTH
);
499 g_error(strerror(errno
));
504 g_error(strerror(errno
));
512 LTTV_MODULE("sync", "Synchronize traces", \
513 "Synchronizes a traceset based on the correspondance of network events", \
514 init
, destroy
, "option")