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