1 /* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2009, 2010 Benjamin Poirier <benjamin.poirier@polymtl.ca>
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation, either version 2.1 of the License, or (at
7 * your option) any later version.
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
12 * License for more details.
14 * You should have received a copy of the GNU Lesser General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #define NANOSECONDS_PER_SECOND 1000000000
32 #include "sync_chain.h"
34 #include "event_processing_text.h"
37 // Functions common to all processing modules
38 static void initProcessingText(SyncState
* const syncState
, ...);
39 static void destroyProcessingText(SyncState
* const syncState
);
40 static AllFactors
* finalizeProcessingText(SyncState
* const syncState
);
41 static void writeProcessingTraceTimeOptionsText(SyncState
* const syncState
,
42 const unsigned int i
, const unsigned int j
);
43 static void writeProcessingTraceTraceOptionsText(SyncState
* const syncState
,
44 const unsigned int i
, const unsigned int j
);
45 static void writeProcessingGraphVariablesText(SyncState
* const syncState
,
46 const unsigned int i
);
48 // Functions specific to this module
49 static unsigned int readTraceNb(FILE* testCase
);
50 static void skipCommentLines(FILE* testCase
);
53 static ProcessingModule processingModuleText
= {
55 .initProcessing
= &initProcessingText
,
56 .destroyProcessing
= &destroyProcessingText
,
57 .finalizeProcessing
= &finalizeProcessingText
,
59 .writeVariables
= &writeProcessingGraphVariablesText
,
60 .writeTraceTraceOptions
= &writeProcessingTraceTraceOptionsText
,
61 .writeTraceTimeOptions
= &writeProcessingTraceTimeOptionsText
,
67 * Processing Module registering function
69 void registerProcessingText()
71 g_queue_push_tail(&processingModules
, &processingModuleText
);
76 * Allocate and initialize data structures for synchronizing a traceset.
77 * Open test case file.
80 * syncState: container for synchronization data.
81 * testCaseName: const char*, test case file name
83 static void initProcessingText(SyncState
* const syncState
, ...)
85 ProcessingDataText
* processingData
;
86 const char* testCaseName
;
89 processingData
= malloc(sizeof(ProcessingDataText
));
90 syncState
->processingData
= processingData
;
91 va_start(ap
, syncState
);
92 testCaseName
= va_arg(ap
, const char*);
95 processingData
->testCase
= fopen(testCaseName
, "r");
96 if (processingData
->testCase
== NULL
)
98 g_error("%s", strerror(errno
));
100 syncState
->traceNb
= readTraceNb(processingData
->testCase
);
102 if (syncState
->stats
)
104 processingData
->factors
= NULL
;
109 static void destroyProcessingText(SyncState
* const syncState
)
111 ProcessingDataText
* processingData
= (ProcessingDataText
*)
112 syncState
->processingData
;
114 if (processingData
== NULL
)
119 fclose(processingData
->testCase
);
121 if (syncState
->stats
&& processingData
->factors
)
123 freeAllFactors(processingData
->factors
, syncState
->traceNb
);
126 free(syncState
->processingData
);
127 syncState
->processingData
= NULL
;
132 * Read the test case file and make up events. Dispatch those events to the
136 * syncState: container for synchronization data.
139 * AllFactors synchronization factors for each trace pair
141 static AllFactors
* finalizeProcessingText(SyncState
* const syncState
)
146 ProcessingDataText
* processingData
= (ProcessingDataText
*)
147 syncState
->processingData
;
148 FILE* testCase
= processingData
->testCase
;
152 seq
= calloc(syncState
->traceNb
, sizeof(unsigned int));
154 skipCommentLines(testCase
);
155 retval
= getline(&line
, &bufLen
, testCase
);
156 while(!feof(testCase
))
158 unsigned int sender
, receiver
;
159 double sendTime
, recvTime
;
163 if (retval
== -1 && !feof(testCase
))
165 g_error("%s", strerror(errno
));
168 if (line
[retval
- 1] == '\n')
170 line
[retval
- 1]= '\0';
173 retval
= sscanf(line
, " %u %u %lf %lf %c", &sender
, &receiver
,
174 &sendTime
, &recvTime
, &tmp
);
177 g_error("%s", strerror(errno
));
179 else if (retval
!= 4)
181 g_error("Error parsing test file while looking for data point, line was '%s'", line
);
184 if (sender
+ 1 > syncState
->traceNb
)
186 g_error("Error parsing test file, sender is out of range, line was '%s'", line
);
189 if (receiver
+ 1 > syncState
->traceNb
)
191 g_error("Error parsing test file, receiver is out of range, line was '%s'", line
);
196 g_error("Error parsing test file, send time is negative, line was '%s'", line
);
201 g_error("Error parsing test file, receive time is negative, line was '%s'", line
);
204 // Generate ouput and input events
206 unsigned int addressOffset
;
208 unsigned int traceNum
;
210 enum Direction direction
;
212 {sender
, sendTime
, OUT
},
213 {receiver
, recvTime
, IN
},
216 /* addressOffset is added to a traceNum to convert it to an address so
217 * that the address is not plainly the same as the traceNb. */
218 if (syncState
->traceNb
> 1)
220 addressOffset
= pow(10, floor(log(syncState
->traceNb
- 1) /
228 for (i
= 0; i
< sizeof(loopValues
) / sizeof(*loopValues
); i
++)
232 event
= malloc(sizeof(Event
));
233 event
->traceNum
= loopValues
[i
].traceNum
;
234 event
->wallTime
.seconds
= floor(loopValues
[i
].time
);
235 event
->wallTime
.nanosec
= floor((loopValues
[i
].time
-
236 floor(loopValues
[i
].time
)) * NANOSECONDS_PER_SECOND
);
237 event
->cpuTime
= round(loopValues
[i
].time
* CPU_FREQ
);
239 event
->destroy
= &destroyTCPEvent
;
240 event
->event
.tcpEvent
= malloc(sizeof(TCPEvent
));
241 event
->event
.tcpEvent
->direction
= loopValues
[i
].direction
;
242 event
->event
.tcpEvent
->segmentKey
= malloc(sizeof(SegmentKey
));
243 event
->event
.tcpEvent
->segmentKey
->ihl
= 5;
244 event
->event
.tcpEvent
->segmentKey
->tot_len
= 40;
245 event
->event
.tcpEvent
->segmentKey
->connectionKey
.saddr
= sender
+
247 event
->event
.tcpEvent
->segmentKey
->connectionKey
.daddr
= receiver
+
249 event
->event
.tcpEvent
->segmentKey
->connectionKey
.source
= 57645;
250 event
->event
.tcpEvent
->segmentKey
->connectionKey
.dest
= 80;
251 event
->event
.tcpEvent
->segmentKey
->seq
= seq
[sender
];
252 event
->event
.tcpEvent
->segmentKey
->ack_seq
= 0;
253 event
->event
.tcpEvent
->segmentKey
->doff
= 5;
254 event
->event
.tcpEvent
->segmentKey
->ack
= 0;
255 event
->event
.tcpEvent
->segmentKey
->rst
= 0;
256 event
->event
.tcpEvent
->segmentKey
->syn
= 1;
257 event
->event
.tcpEvent
->segmentKey
->fin
= 0;
259 syncState
->matchingModule
->matchEvent(syncState
, event
);
265 skipCommentLines(testCase
);
266 retval
= getline(&line
, &bufLen
, testCase
);
276 factors
= syncState
->matchingModule
->finalizeMatching(syncState
);
277 if (syncState
->stats
)
279 processingData
->factors
= factors
;
287 * Read trace number from the test case stream. The trace number should be the
288 * first non-comment line and should be an unsigned int by itself on a line.
291 * testCase: test case stream
296 static unsigned int readTraceNb(FILE* testCase
)
304 skipCommentLines(testCase
);
305 retval
= getline(&line
, &len
, testCase
);
310 g_error("Unexpected end of file while looking for number of traces");
314 g_error("%s", strerror(errno
));
317 if (line
[retval
- 1] == '\n')
319 line
[retval
- 1]= '\0';
322 retval
= sscanf(line
, " %u %c", &result
, &tmp
);
323 if (retval
== EOF
|| retval
!= 1)
325 g_error("Error parsing test file while looking for number of traces, line was '%s'", line
);
327 // Not really needed but avoids warning from gcc
341 * Advance testCase stream over empty space, empty lines and lines that begin
345 * testCase: test case stream
347 static void skipCommentLines(FILE* testCase
)
356 firstChar
= fgetc(testCase
);
357 if (firstChar
== (int) '#')
359 retval
= getline(&line
, &len
, testCase
);
368 g_error("%s", strerror(errno
));
372 else if (firstChar
== (int) '\n' || firstChar
== (int) ' ')
374 else if (firstChar
== EOF
)
383 retval
= ungetc(firstChar
, testCase
);
386 g_error("Error: ungetc()");
398 * Write the processing-specific variables in the gnuplot script.
401 * syncState: container for synchronization data
404 static void writeProcessingGraphVariablesText(SyncState
* const syncState
,
405 const unsigned int i
)
407 fprintf(syncState
->graphsStream
, "clock_freq_%u= %.3f\n", i
, CPU_FREQ
);
412 * Write the processing-specific options in the gnuplot script.
415 * syncState: container for synchronization data
416 * i: first trace number
417 * j: second trace number, garanteed to be larger than i
419 static void writeProcessingTraceTraceOptionsText(SyncState
* const syncState
,
420 const unsigned int i
, const unsigned int j
)
422 fprintf(syncState
->graphsStream
,
423 "set key inside right bottom\n"
424 "set xlabel \"Clock %1$u\"\n"
425 "set xtics nomirror\n"
426 "set ylabel \"Clock %2$u\"\n"
427 "set ytics nomirror\n"
428 "set x2label \"Clock %1$d (s)\"\n"
429 "set x2range [GPVAL_X_MIN / clock_freq_%1$u : GPVAL_X_MAX / clock_freq_%1$u]\n"
431 "set y2label \"Clock %2$d (s)\"\n"
432 "set y2range [GPVAL_Y_MIN / clock_freq_%2$u : GPVAL_Y_MAX / clock_freq_%2$u]\n"
433 "set y2tics\n", i
, j
);
438 * Write the processing-specific options in the gnuplot script.
441 * syncState: container for synchronization data
442 * i: first trace number
443 * j: second trace number, garanteed to be larger than i
445 static void writeProcessingTraceTimeOptionsText(SyncState
* const syncState
,
446 const unsigned int i
, const unsigned int j
)
448 fprintf(syncState
->graphsStream
,
449 "set key inside right bottom\n"
450 "set xlabel \"Clock %1$u\"\n"
451 "set xtics nomirror\n"
452 "set ylabel \"time (s)\"\n"
453 "set ytics nomirror\n"
454 "set x2label \"Clock %1$d (s)\"\n"
455 "set x2range [GPVAL_X_MIN / clock_freq_%1$u : GPVAL_X_MAX / clock_freq_%1$u]\n"