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,
20 #define NANOSECONDS_PER_SECOND 1000000000
33 #include "sync_chain.h"
35 #include "event_processing_text.h"
38 // Functions common to all processing modules
39 static void initProcessingText(SyncState
* const syncState
, ...);
40 static void destroyProcessingText(SyncState
* const syncState
);
41 static void finalizeProcessingText(SyncState
* const syncState
);
42 static void printProcessingStatsText(SyncState
* const syncState
);
43 static void writeProcessingTraceTimeOptionsText(SyncState
* const syncState
,
44 const unsigned int i
, const unsigned int j
);
45 static void writeProcessingTraceTraceOptionsText(SyncState
* const syncState
,
46 const unsigned int i
, const unsigned int j
);
47 static void writeProcessingGraphVariablesText(SyncState
* const syncState
,
48 const unsigned int i
);
50 // Functions specific to this module
51 static void registerProcessingText() __attribute__((constructor (102)));
53 static unsigned int readTraceNb(FILE* testCase
);
54 static void skipCommentLines(FILE* testCase
);
57 static ProcessingModule processingModuleText
= {
59 .initProcessing
= &initProcessingText
,
60 .destroyProcessing
= &destroyProcessingText
,
61 .finalizeProcessing
= &finalizeProcessingText
,
62 .printProcessingStats
= &printProcessingStatsText
,
64 .writeVariables
= &writeProcessingGraphVariablesText
,
65 .writeTraceTraceOptions
= &writeProcessingTraceTraceOptionsText
,
66 .writeTraceTimeOptions
= &writeProcessingTraceTimeOptionsText
,
72 * Processing Module registering function
74 static void registerProcessingText()
76 g_queue_push_tail(&processingModules
, &processingModuleText
);
81 * Allocate and initialize data structures for synchronizing a traceset.
82 * Open test case file.
85 * syncState: container for synchronization data.
86 * testCaseName: const char*, test case file name
88 static void initProcessingText(SyncState
* const syncState
, ...)
90 ProcessingDataText
* processingData
;
91 const char* testCaseName
;
94 processingData
= malloc(sizeof(ProcessingDataText
));
95 syncState
->processingData
= processingData
;
96 va_start(ap
, syncState
);
97 testCaseName
= va_arg(ap
, const char*);
100 processingData
->testCase
= fopen(testCaseName
, "r");
101 if (processingData
->testCase
== NULL
)
103 g_error(strerror(errno
));
105 syncState
->traceNb
= readTraceNb(processingData
->testCase
);
107 if (syncState
->stats
)
109 processingData
->factors
= NULL
;
114 static void destroyProcessingText(SyncState
* const syncState
)
116 ProcessingDataText
* processingData
= (ProcessingDataText
*)
117 syncState
->processingData
;
119 if (processingData
== NULL
)
124 fclose(processingData
->testCase
);
126 if (syncState
->stats
&& processingData
->factors
)
128 g_array_free(processingData
->factors
, TRUE
);
131 free(syncState
->processingData
);
132 syncState
->processingData
= NULL
;
137 * Read the test case file and make up events. Dispatch those events to the
141 * syncState: container for synchronization data.
143 static void finalizeProcessingText(SyncState
* const syncState
)
148 ProcessingDataText
* processingData
= (ProcessingDataText
*)
149 syncState
->processingData
;
150 FILE* testCase
= processingData
->testCase
;
154 seq
= calloc(syncState
->traceNb
, sizeof(unsigned int));
156 skipCommentLines(testCase
);
157 retval
= getline(&line
, &bufLen
, testCase
);
158 while(!feof(testCase
))
160 unsigned int sender
, receiver
;
161 double sendTime
, recvTime
;
165 if (retval
== -1 && !feof(testCase
))
167 g_error(strerror(errno
));
170 if (line
[retval
- 1] == '\n')
172 line
[retval
- 1]= '\0';
175 retval
= sscanf(line
, " %u %u %lf %lf %c", &sender
, &receiver
,
176 &sendTime
, &recvTime
, &tmp
);
179 g_error(strerror(errno
));
181 else if (retval
!= 4)
183 g_error("Error parsing test file while looking for data point, line was '%s'", line
);
186 if (sender
+ 1 > syncState
->traceNb
)
188 g_error("Error parsing test file, sender is out of range, line was '%s'", line
);
191 if (receiver
+ 1 > syncState
->traceNb
)
193 g_error("Error parsing test file, receiver is out of range, line was '%s'", line
);
198 g_error("Error parsing test file, send time is negative, line was '%s'", line
);
203 g_error("Error parsing test file, receive time is negative, line was '%s'", line
);
206 // Generate ouput and input events
208 unsigned int addressOffset
;
210 unsigned int traceNum
;
212 enum Direction direction
;
214 {sender
, sendTime
, OUT
},
215 {receiver
, recvTime
, IN
},
218 /* addressOffset is added to a traceNum to convert it to an address so
219 * that the address is not plainly the same as the traceNb. */
220 if (syncState
->traceNb
> 1)
222 addressOffset
= pow(10, floor(log(syncState
->traceNb
- 1) /
230 for (i
= 0; i
< sizeof(loopValues
) / sizeof(*loopValues
); i
++)
234 event
= malloc(sizeof(Event
));
235 event
->traceNum
= loopValues
[i
].traceNum
;
236 event
->wallTime
.seconds
= floor(loopValues
[i
].time
);
237 event
->wallTime
.nanosec
= floor((loopValues
[i
].time
-
238 floor(loopValues
[i
].time
)) * NANOSECONDS_PER_SECOND
);
239 event
->cpuTime
= round(loopValues
[i
].time
* CPU_FREQ
);
241 event
->destroy
= &destroyTCPEvent
;
242 event
->event
.tcpEvent
= malloc(sizeof(TCPEvent
));
243 event
->event
.tcpEvent
->direction
= loopValues
[i
].direction
;
244 event
->event
.tcpEvent
->segmentKey
= malloc(sizeof(SegmentKey
));
245 event
->event
.tcpEvent
->segmentKey
->ihl
= 5;
246 event
->event
.tcpEvent
->segmentKey
->tot_len
= 40;
247 event
->event
.tcpEvent
->segmentKey
->connectionKey
.saddr
= sender
+
249 event
->event
.tcpEvent
->segmentKey
->connectionKey
.daddr
= receiver
+
251 event
->event
.tcpEvent
->segmentKey
->connectionKey
.source
= 57645;
252 event
->event
.tcpEvent
->segmentKey
->connectionKey
.dest
= 80;
253 event
->event
.tcpEvent
->segmentKey
->seq
= seq
[sender
];
254 event
->event
.tcpEvent
->segmentKey
->ack_seq
= 0;
255 event
->event
.tcpEvent
->segmentKey
->doff
= 5;
256 event
->event
.tcpEvent
->segmentKey
->ack
= 0;
257 event
->event
.tcpEvent
->segmentKey
->rst
= 0;
258 event
->event
.tcpEvent
->segmentKey
->syn
= 1;
259 event
->event
.tcpEvent
->segmentKey
->fin
= 0;
261 syncState
->matchingModule
->matchEvent(syncState
, event
);
267 skipCommentLines(testCase
);
268 retval
= getline(&line
, &bufLen
, testCase
);
278 factors
= syncState
->matchingModule
->finalizeMatching(syncState
);
279 if (syncState
->stats
)
281 processingData
->factors
= factors
;
285 g_array_free(factors
, TRUE
);
291 * Print statistics related to processing. Must be called after
292 * finalizeProcessing.
295 * syncState container for synchronization data.
297 static void printProcessingStatsText(SyncState
* const syncState
)
301 printf("Resulting synchronization factors:\n");
302 for (i
= 0; i
< syncState
->traceNb
; i
++)
304 Factors
* factors
= &g_array_index(((ProcessingDataText
*)
305 syncState
->processingData
)->factors
, Factors
, i
);
307 printf("\ttrace %u drift= %g offset= %g (%f)\n", i
, factors
->drift
,
308 factors
->offset
, factors
->offset
/ CPU_FREQ
);
314 * Read trace number from the test case stream. The trace number should be the
315 * first non-comment line and should be an unsigned int by itself on a line.
318 * testCase: test case stream
323 static unsigned int readTraceNb(FILE* testCase
)
331 skipCommentLines(testCase
);
332 retval
= getline(&line
, &len
, testCase
);
337 g_error("Unexpected end of file while looking for number of traces");
341 g_error(strerror(errno
));
344 if (line
[retval
- 1] == '\n')
346 line
[retval
- 1]= '\0';
349 retval
= sscanf(line
, " %u %c", &result
, &tmp
);
350 if (retval
== EOF
|| retval
!= 1)
352 g_error("Error parsing test file while looking for number of traces, line was '%s'", line
);
354 // Not really needed but avoids warning from gcc
368 * Advance testCase stream over empty space, empty lines and lines that begin
372 * testCase: test case stream
374 static void skipCommentLines(FILE* testCase
)
383 firstChar
= fgetc(testCase
);
384 if (firstChar
== (int) '#')
386 retval
= getline(&line
, &len
, testCase
);
395 g_error(strerror(errno
));
399 else if (firstChar
== (int) '\n' || firstChar
== (int) ' ')
401 else if (firstChar
== EOF
)
410 retval
= ungetc(firstChar
, testCase
);
413 g_error("Error: ungetc()");
425 * Write the processing-specific variables in the gnuplot script.
428 * syncState: container for synchronization data
431 static void writeProcessingGraphVariablesText(SyncState
* const syncState
,
432 const unsigned int i
)
434 fprintf(syncState
->graphsStream
, "clock_freq_%u= %.3f\n", i
, CPU_FREQ
);
439 * Write the processing-specific options in the gnuplot script.
442 * syncState: container for synchronization data
443 * i: first trace number
444 * j: second trace number, garanteed to be larger than i
446 static void writeProcessingTraceTraceOptionsText(SyncState
* const syncState
,
447 const unsigned int i
, const unsigned int j
)
449 fprintf(syncState
->graphsStream
,
450 "set key inside right bottom\n"
451 "set xlabel \"Clock %1$u\"\n"
452 "set xtics nomirror\n"
453 "set ylabel \"Clock %2$u\"\n"
454 "set ytics nomirror\n"
455 "set x2label \"Clock %1$d (s)\"\n"
456 "set x2range [GPVAL_X_MIN / clock_freq_%1$u : GPVAL_X_MAX / clock_freq_%1$u]\n"
458 "set y2label \"Clock %2$d (s)\"\n"
459 "set y2range [GPVAL_Y_MIN / clock_freq_%2$u : GPVAL_Y_MAX / clock_freq_%2$u]\n"
460 "set y2tics\n", i
, j
);
465 * Write the processing-specific options in the gnuplot script.
468 * syncState: container for synchronization data
469 * i: first trace number
470 * j: second trace number, garanteed to be larger than i
472 static void writeProcessingTraceTimeOptionsText(SyncState
* const syncState
,
473 const unsigned int i
, const unsigned int j
)
475 fprintf(syncState
->graphsStream
,
476 "set key inside right bottom\n"
477 "set xlabel \"Clock %1$u\"\n"
478 "set xtics nomirror\n"
479 "set ylabel \"time (s)\"\n"
480 "set ytics nomirror\n"
481 "set x2label \"Clock %1$d (s)\"\n"
482 "set x2range [GPVAL_X_MIN / clock_freq_%1$u : GPVAL_X_MAX / clock_freq_%1$u]\n"