4ca2b932a2c303ed14186df0919bf3d9076c752f
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,
30 #include <sys/resource.h>
33 #include <sys/types.h>
37 #include "sync_chain.h"
41 #define g_info(format...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, format)
45 static void timeDiff(struct timeval
* const end
, const struct timeval
* const start
);
46 static void usage(const char* const programName
);
47 static gint
gcfCompareAnalysis(gconstpointer a
, gconstpointer b
);
48 static void gfAppendAnalysisName(gpointer data
, gpointer user_data
);
49 static unsigned int readTraceNb(FILE* testCase
);
50 static void skipCommentLines(FILE* testCase
);
51 static void processEvents(SyncState
* const syncState
, FILE* testCase
);
52 static void nullLog(const gchar
*log_domain
, GLogLevelFlags log_level
, const
53 gchar
*message
, gpointer user_data
);
55 GQueue processingModules
= G_QUEUE_INIT
;
56 GQueue matchingModules
= G_QUEUE_INIT
;
57 GQueue analysisModules
= G_QUEUE_INIT
;
59 // time values in test case files will be scaled by this factor
60 const double freq
= 1e9
;
64 * Create matching and analysis modules and feed them events read from a text
67 * Idealy, this would've been a processing module but sync_chain.c and
68 * ProcessingModule use some LTTV-specific types and functions. Unfortunately,
69 * there is some code duplication from sync_chain.c
72 int main(int argc
, char* argv
[])
76 extern int optind
, opterr
, optopt
;
77 bool optionSyncStats
= false;
78 char* optionGraphsDir
= NULL
;
82 struct timeval startTime
, endTime
;
83 struct rusage startUsage
, endUsage
;
92 syncState
= malloc(sizeof(SyncState
));
94 g_assert(g_queue_get_length(&analysisModules
) > 0);
95 syncState
->analysisModule
= g_queue_peek_head(&analysisModules
);
101 static struct option longOptions
[]=
103 {"sync-stats", no_argument
, 0, 's'},
104 {"sync-graphs", optional_argument
, 0, 'g'},
105 {"sync-analysis", required_argument
, 0, 'a'},
109 c
= getopt_long(argc
, argv
, "sg::a:", longOptions
, &optionIndex
);
118 if (!optionSyncStats
)
120 gettimeofday(&startTime
, 0);
121 getrusage(RUSAGE_SELF
, &startUsage
);
123 optionSyncStats
= true;
129 printf("xxx:%s\n", optarg
);
130 optionGraphsDir
= malloc(strlen(optarg
));
131 strcpy(optionGraphsDir
, optarg
);
135 optionGraphsDir
= malloc(20);
136 retval
= snprintf(optionGraphsDir
, 20, "graphs-%d",
140 optionGraphsDir
[20 - 1]= '\0';
146 printf("xxx:%s\n", optarg
);
147 result
= g_queue_find_custom(&analysisModules
, optarg
,
148 &gcfCompareAnalysis
);
151 syncState
->analysisModule
= (AnalysisModule
*) result
->data
;
155 g_error("Analysis module '%s' not found", optarg
);
164 g_error("Option parse error");
170 fprintf(stderr
, "Test file unspecified\n");
175 testCase
= fopen(argv
[optind
], "r");
176 if (testCase
== NULL
)
178 g_error(strerror(errno
));
181 // Initialize data structures
182 syncState
->traceNb
= readTraceNb(testCase
);
186 syncState
->stats
= true;
190 syncState
->stats
= false;
193 syncState
->graphs
= optionGraphsDir
;
195 if (!optionSyncStats
)
197 g_log_set_handler(NULL
, G_LOG_LEVEL_DEBUG
, nullLog
, NULL
);
200 // Identify and initialize matching and analysis modules
201 syncState
->matchingData
= NULL
;
202 syncState
->analysisData
= NULL
;
204 g_assert(g_queue_get_length(&matchingModules
) == 1);
205 syncState
->matchingModule
= (MatchingModule
*)
206 g_queue_peek_head(&matchingModules
);
209 if (syncState
->graphs
)
211 // Create the graph directory right away in case the module initialization
212 // functions have something to write in it.
213 cwd
= changeToGraphDir(syncState
->graphs
);
215 if (syncState
->matchingModule
->writeMatchingGraphsPlots
!= NULL
)
217 if ((graphsFp
= open("graphs.gnu", O_WRONLY
| O_CREAT
| O_TRUNC
, S_IRUSR
|
218 S_IWUSR
| S_IXUSR
| S_IRGRP
| S_IWGRP
| S_IXGRP
| S_IROTH
219 | S_IWOTH
| S_IXOTH
)) == -1)
221 g_error(strerror(errno
));
223 if ((graphsStream
= fdopen(graphsFp
, "w")) == NULL
)
225 g_error(strerror(errno
));
232 g_error(strerror(errno
));
237 syncState
->matchingModule
->initMatching(syncState
);
238 syncState
->analysisModule
->initAnalysis(syncState
);
241 processEvents(syncState
, testCase
);
243 factors
= syncState
->matchingModule
->finalizeMatching(syncState
);
246 if (graphsStream
!= NULL
)
250 fprintf(graphsStream
,
251 "#!/usr/bin/gnuplot\n\n"
252 "#set terminal postscript eps color size 8in,6in\n");
254 // Cover the upper triangular matrix, i is the reference node.
255 for (i
= 0; i
< syncState
->traceNb
; i
++)
257 for (j
= i
+ 1; j
< syncState
->traceNb
; j
++)
261 fprintf(graphsStream
,
262 "\n#set output \"%03d-%03d.eps\"\n"
265 syncState
->matchingModule
->writeMatchingGraphsPlots(graphsStream
,
268 // Remove the ", \\\n" from the last graph plot line
269 fflush(graphsStream
);
270 pos
= ftell(graphsStream
);
271 if (ftruncate(fileno(graphsStream
), pos
- 4) == -1)
273 g_error(strerror(errno
));
275 if (fseek(graphsStream
, 0, SEEK_END
) == -1)
277 g_error(strerror(errno
));
280 fprintf(graphsStream
,
281 "\nset output \"%1$03d-%2$03d.eps\"\n"
283 "set xlabel \"Clock %1$u\"\n"
284 "set xtics nomirror\n"
285 "set ylabel \"Clock %2$u\"\n"
286 "set ytics nomirror\n"
287 "set x2label \"Clock %1$u (s)\"\n"
288 "set x2range [GPVAL_X_MIN / %3$.1f : GPVAL_X_MAX / %3$.1f]\n"
290 "set y2label \"Clock %2$u (s)\"\n"
291 "set y2range [GPVAL_Y_MIN / %3$.1f: GPVAL_Y_MAX / %3$.1f]\n"
293 "set key inside right bottom\n", i
, j
, freq
);
295 syncState
->matchingModule
->writeMatchingGraphsOptions(graphsStream
,
298 fprintf(graphsStream
, "replot\n\n"
303 if (fclose(graphsStream
) != 0)
305 g_error(strerror(errno
));
310 free(optionGraphsDir
);
313 if (optionSyncStats
&& syncState
->matchingModule
->printMatchingStats
!=
318 syncState
->matchingModule
->printMatchingStats(syncState
);
320 printf("Resulting synchronization factors:\n");
321 for (i
= 0; i
< syncState
->traceNb
; i
++)
323 Factors
* traceFactors
;
325 traceFactors
= &g_array_index(factors
, Factors
, i
);
326 printf("\ttrace %u drift= %g offset= %g\n", i
,
327 traceFactors
->drift
, traceFactors
->offset
);
331 syncState
->matchingModule
->destroyMatching(syncState
);
332 syncState
->analysisModule
->destroyAnalysis(syncState
);
338 gettimeofday(&endTime
, 0);
339 retval
= getrusage(RUSAGE_SELF
, &endUsage
);
341 timeDiff(&endTime
, &startTime
);
342 timeDiff(&endUsage
.ru_utime
, &startUsage
.ru_utime
);
343 timeDiff(&endUsage
.ru_stime
, &startUsage
.ru_stime
);
345 printf("Synchronization time:\n");
346 printf("\treal time: %ld.%06ld\n", endTime
.tv_sec
, endTime
.tv_usec
);
347 printf("\tuser time: %ld.%06ld\n", endUsage
.ru_utime
.tv_sec
,
348 endUsage
.ru_utime
.tv_usec
);
349 printf("\tsystem time: %ld.%06ld\n", endUsage
.ru_stime
.tv_sec
,
350 endUsage
.ru_stime
.tv_usec
);
358 * Print information about program options and arguments.
361 * programName: name of the program, as contained in argv[0] for example
363 static void usage(const char* const programName
)
365 GString
* analysisModulesNames
;
367 analysisModulesNames
= g_string_new("");
368 g_queue_foreach(&analysisModules
, &gfAppendAnalysisName
,
369 analysisModulesNames
);
370 // remove the last ", "
371 g_string_truncate(analysisModulesNames
, analysisModulesNames
->len
- 2);
374 "%s [options] <test file>\n"
376 "\t-s, --sync-stats Print statistics and debug messages\n"
377 "\t-g, --sync-graphs[=OUPUT_DIR] Generate graphs\n"
378 "\t-a, --sync-analysis=MODULE_NAME Specify which module to use for analysis\n"
379 "\t Available modules: %s\n",
380 programName
, analysisModulesNames
->str
);
382 g_string_free(analysisModulesNames
, TRUE
);
387 * Calculate the elapsed time between two timeval values
390 * end: end time, result is also stored in this structure
393 static void timeDiff(struct timeval
* const end
, const struct timeval
* const start
)
395 if (end
->tv_usec
>= start
->tv_usec
)
397 end
->tv_sec
-= start
->tv_sec
;
398 end
->tv_usec
-= start
->tv_usec
;
402 end
->tv_sec
= end
->tv_sec
- start
->tv_sec
- 1;
403 end
->tv_usec
= end
->tv_usec
- start
->tv_usec
+ 1e6
;
409 * A GCompareFunc for g_slist_find_custom()
412 * a: AnalysisModule*, element's data
413 * b: char*, user data to compare against
416 * 0 if the analysis module a's name is b
418 static gint
gcfCompareAnalysis(gconstpointer a
, gconstpointer b
)
420 const AnalysisModule
* analysisModule
;
423 analysisModule
= (const AnalysisModule
*)a
;
424 name
= (const char*)b
;
426 return strncmp(analysisModule
->name
, name
, strlen(analysisModule
->name
) +
432 * Change to the directory used to hold graphs. Create it if necessary.
435 * graph: name of directory
438 * The current working directory before the execution of the function. The
439 * string must be free'd by the caller.
441 char* changeToGraphDir(char* const graphs
)
446 cwd
= getcwd(NULL
, 0);
449 g_error(strerror(errno
));
451 while ((retval
= chdir(graphs
)) != 0)
455 retval
= mkdir(graphs
, S_IRUSR
| S_IWUSR
| S_IXUSR
| S_IRGRP
|
456 S_IWGRP
| S_IXGRP
| S_IROTH
| S_IWOTH
| S_IXOTH
);
459 g_error(strerror(errno
));
464 g_error(strerror(errno
));
473 * A GFunc for g_queue_foreach()
475 * Concatenate analysis module names.
478 * data: AnalysisModule*
479 * user_data: GString*, concatenated names
481 static void gfAppendAnalysisName(gpointer data
, gpointer user_data
)
483 g_string_append((GString
*) user_data
, ((AnalysisModule
*) data
)->name
);
484 g_string_append((GString
*) user_data
, ", ");
489 * Read trace number from the test case stream. The trace number should be the
490 * first non-comment line and should be an unsigned int by itself on a line.
493 * testCase: test case stream
498 static unsigned int readTraceNb(FILE* testCase
)
506 skipCommentLines(testCase
);
507 retval
= getline(&line
, &len
, testCase
);
512 g_error("Unexpected end of file while looking for number of traces");
516 g_error(strerror(errno
));
519 if (line
[retval
- 1] == '\n')
521 line
[retval
- 1]= '\0';
524 retval
= sscanf(line
, " %u %c", &result
, &tmp
);
525 if (retval
== EOF
|| retval
!= 1)
527 g_error("Error parsing test file while looking for number of traces, line was '%s'", line
);
529 // Not really needed but avoids warning from gcc
538 * Advance testCase stream over empty space, empty lines and lines that begin
542 * testCase: test case stream
544 static void skipCommentLines(FILE* testCase
)
553 firstChar
= fgetc(testCase
);
554 if (firstChar
== (int) '#')
556 retval
= getline(&line
, &len
, testCase
);
565 g_error(strerror(errno
));
569 else if (firstChar
== (int) '\n' || firstChar
== (int) ' ')
571 else if (firstChar
== EOF
)
580 retval
= ungetc(firstChar
, testCase
);
583 g_error("Error: ungetc()");
595 * Make up events from the messages in the test case. Dispatch those events to
596 * the matching module.
598 static void processEvents(SyncState
* const syncState
, FILE* testCase
)
603 unsigned int addressOffset
;
606 // Trace numbers run from 0 to traceNb - 1. addressOffset is added to a
607 // traceNum to convert it to an address.
608 addressOffset
= pow(10, floor(log(syncState
->traceNb
- 1) / log(10)) + 1);
610 seq
= calloc(syncState
->traceNb
, sizeof(unsigned int));
612 skipCommentLines(testCase
);
613 retval
= getline(&line
, &len
, testCase
);
614 while(!feof(testCase
))
616 unsigned int sender
, receiver
;
617 double sendTime
, recvTime
;
621 if (retval
== -1 && !feof(testCase
))
623 g_error(strerror(errno
));
626 if (line
[len
- 1] == '\n')
631 retval
= sscanf(line
, " %u %u %lf %lf %c", &sender
, &receiver
,
632 &sendTime
, &recvTime
, &tmp
);
635 g_error(strerror(errno
));
637 else if (retval
!= 4)
639 g_error("Error parsing test file while looking for data point, line was '%s'", line
);
642 if (sender
+ 1 > syncState
->traceNb
)
644 g_error("Error parsing test file, sender is out of range, line was '%s'", line
);
647 if (receiver
+ 1 > syncState
->traceNb
)
649 g_error("Error parsing test file, receiver is out of range, line was '%s'", line
);
653 event
= malloc(sizeof(NetEvent
));
654 event
->traceNum
= sender
;
655 event
->tsc
= round(sendTime
* freq
);
657 event
->packetKey
= malloc(sizeof(PacketKey
));
658 event
->packetKey
->ihl
= 5;
659 event
->packetKey
->tot_len
= 40;
660 event
->packetKey
->connectionKey
.saddr
= sender
+ addressOffset
;
661 event
->packetKey
->connectionKey
.daddr
= receiver
+ addressOffset
;
662 event
->packetKey
->connectionKey
.source
= 57645;
663 event
->packetKey
->connectionKey
.dest
= 80;
664 event
->packetKey
->seq
= seq
[sender
];
665 event
->packetKey
->ack_seq
= 0;
666 event
->packetKey
->doff
= 5;
667 event
->packetKey
->ack
= 0;
668 event
->packetKey
->rst
= 0;
669 event
->packetKey
->syn
= 1;
670 event
->packetKey
->fin
= 0;
672 syncState
->matchingModule
->matchEvent(syncState
, event
, OUT
);
675 event
= malloc(sizeof(NetEvent
));
676 event
->traceNum
= receiver
;
677 event
->tsc
= round(recvTime
* freq
);
679 event
->packetKey
= malloc(sizeof(PacketKey
));
680 event
->packetKey
->ihl
= 5;
681 event
->packetKey
->tot_len
= 40;
682 event
->packetKey
->connectionKey
.saddr
= sender
+ addressOffset
;
683 event
->packetKey
->connectionKey
.daddr
= receiver
+ addressOffset
;
684 event
->packetKey
->connectionKey
.source
= 57645;
685 event
->packetKey
->connectionKey
.dest
= 80;
686 event
->packetKey
->seq
= seq
[sender
];
687 event
->packetKey
->ack_seq
= 0;
688 event
->packetKey
->doff
= 5;
689 event
->packetKey
->ack
= 0;
690 event
->packetKey
->rst
= 0;
691 event
->packetKey
->syn
= 1;
692 event
->packetKey
->fin
= 0;
694 syncState
->matchingModule
->matchEvent(syncState
, event
, IN
);
698 skipCommentLines(testCase
);
699 retval
= getline(&line
, &len
, testCase
);
712 * A Glib log function which does nothing.
714 static void nullLog(const gchar
*log_domain
, GLogLevelFlags log_level
, const
715 gchar
*message
, gpointer user_data
)
This page took 0.078859 seconds and 4 git commands to generate.