Change synchronization code license to LGPLv2.1
[lttv.git] / lttv / lttv / sync / event_processing_text.c
CommitLineData
48b641c1 1/* This file is part of the Linux Trace Toolkit viewer
277e5b53 2 * Copyright (C) 2009, 2010 Benjamin Poirier <benjamin.poirier@polymtl.ca>
48b641c1 3 *
277e5b53
BP
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.
48b641c1 8 *
277e5b53
BP
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.
48b641c1 13 *
277e5b53
BP
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/>.
48b641c1
BP
16 */
17
6ce8ceac 18#define _GNU_SOURCE
48b641c1
BP
19#define NANOSECONDS_PER_SECOND 1000000000
20#define CPU_FREQ 1e9
21
22#ifdef HAVE_CONFIG_H
23#include <config.h>
24#endif
25
26#include <errno.h>
27#include <math.h>
28#include <stdio.h>
29#include <stdlib.h>
30#include <string.h>
31
32#include "sync_chain.h"
33
34#include "event_processing_text.h"
35
36
37// Functions common to all processing modules
38static void initProcessingText(SyncState* const syncState, ...);
39static void destroyProcessingText(SyncState* const syncState);
40static void finalizeProcessingText(SyncState* const syncState);
41static void printProcessingStatsText(SyncState* const syncState);
42static void writeProcessingTraceTimeOptionsText(SyncState* const syncState,
43 const unsigned int i, const unsigned int j);
44static void writeProcessingTraceTraceOptionsText(SyncState* const syncState,
45 const unsigned int i, const unsigned int j);
46static void writeProcessingGraphVariablesText(SyncState* const syncState,
47 const unsigned int i);
48
49// Functions specific to this module
48b641c1
BP
50static unsigned int readTraceNb(FILE* testCase);
51static void skipCommentLines(FILE* testCase);
52
53
54static ProcessingModule processingModuleText = {
55 .name= "text",
56 .initProcessing= &initProcessingText,
57 .destroyProcessing= &destroyProcessingText,
58 .finalizeProcessing= &finalizeProcessingText,
59 .printProcessingStats= &printProcessingStatsText,
60 .graphFunctions= {
61 .writeVariables= &writeProcessingGraphVariablesText,
62 .writeTraceTraceOptions= &writeProcessingTraceTraceOptionsText,
63 .writeTraceTimeOptions= &writeProcessingTraceTimeOptionsText,
64 },
65};
66
67
68/*
69 * Processing Module registering function
70 */
2f961b65 71void registerProcessingText()
48b641c1
BP
72{
73 g_queue_push_tail(&processingModules, &processingModuleText);
74}
75
76
77/*
78 * Allocate and initialize data structures for synchronizing a traceset.
79 * Open test case file.
80 *
81 * Args:
82 * syncState: container for synchronization data.
83 * testCaseName: const char*, test case file name
84 */
85static void initProcessingText(SyncState* const syncState, ...)
86{
87 ProcessingDataText* processingData;
88 const char* testCaseName;
89 va_list ap;
90
91 processingData= malloc(sizeof(ProcessingDataText));
92 syncState->processingData= processingData;
93 va_start(ap, syncState);
94 testCaseName= va_arg(ap, const char*);
95 va_end(ap);
96
97 processingData->testCase= fopen(testCaseName, "r");
98 if (processingData->testCase == NULL)
99 {
100 g_error(strerror(errno));
101 }
102 syncState->traceNb= readTraceNb(processingData->testCase);
103
104 if (syncState->stats)
105 {
106 processingData->factors= NULL;
107 }
108}
109
110
111static void destroyProcessingText(SyncState* const syncState)
112{
113 ProcessingDataText* processingData= (ProcessingDataText*)
114 syncState->processingData;
115
116 if (processingData == NULL)
117 {
118 return;
119 }
120
6ce8ceac
BP
121 fclose(processingData->testCase);
122
48b641c1
BP
123 if (syncState->stats && processingData->factors)
124 {
125 g_array_free(processingData->factors, TRUE);
126 }
127
128 free(syncState->processingData);
129 syncState->processingData= NULL;
130}
131
132
133/*
134 * Read the test case file and make up events. Dispatch those events to the
135 * matching module.
136 *
137 * Args:
138 * syncState: container for synchronization data.
139 */
140static void finalizeProcessingText(SyncState* const syncState)
141{
48b641c1
BP
142 int retval;
143 unsigned int* seq;
144 GArray* factors;
145 ProcessingDataText* processingData= (ProcessingDataText*)
146 syncState->processingData;
147 FILE* testCase= processingData->testCase;
148 char* line= NULL;
6ce8ceac 149 size_t bufLen;
48b641c1
BP
150
151 seq= calloc(syncState->traceNb, sizeof(unsigned int));
152
153 skipCommentLines(testCase);
6ce8ceac 154 retval= getline(&line, &bufLen, testCase);
48b641c1
BP
155 while(!feof(testCase))
156 {
157 unsigned int sender, receiver;
158 double sendTime, recvTime;
159 char tmp;
160 unsigned int i;
161
162 if (retval == -1 && !feof(testCase))
163 {
164 g_error(strerror(errno));
165 }
166
6ce8ceac 167 if (line[retval - 1] == '\n')
48b641c1 168 {
6ce8ceac 169 line[retval - 1]= '\0';
48b641c1
BP
170 }
171
172 retval= sscanf(line, " %u %u %lf %lf %c", &sender, &receiver,
173 &sendTime, &recvTime, &tmp);
174 if (retval == EOF)
175 {
176 g_error(strerror(errno));
177 }
178 else if (retval != 4)
179 {
180 g_error("Error parsing test file while looking for data point, line was '%s'", line);
181 }
182
183 if (sender + 1 > syncState->traceNb)
184 {
185 g_error("Error parsing test file, sender is out of range, line was '%s'", line);
186 }
187
188 if (receiver + 1 > syncState->traceNb)
189 {
190 g_error("Error parsing test file, receiver is out of range, line was '%s'", line);
191 }
192
193 if (sendTime < 0)
194 {
195 g_error("Error parsing test file, send time is negative, line was '%s'", line);
196 }
197
198 if (recvTime < 0)
199 {
200 g_error("Error parsing test file, receive time is negative, line was '%s'", line);
201 }
202
203 // Generate ouput and input events
204 {
205 unsigned int addressOffset;
206 struct {
207 unsigned int traceNum;
208 double time;
209 enum Direction direction;
210 } loopValues[]= {
211 {sender, sendTime, OUT},
212 {receiver, recvTime, IN},
213 };
214
215 /* addressOffset is added to a traceNum to convert it to an address so
216 * that the address is not plainly the same as the traceNb. */
217 if (syncState->traceNb > 1)
218 {
219 addressOffset= pow(10, floor(log(syncState->traceNb - 1) /
220 log(10)) + 1);
221 }
222 else
223 {
224 addressOffset= 0;
225 }
226
227 for (i= 0; i < sizeof(loopValues) / sizeof(*loopValues); i++)
228 {
229 Event* event;
230
231 event= malloc(sizeof(Event));
232 event->traceNum= loopValues[i].traceNum;
233 event->wallTime.seconds= floor(loopValues[i].time);
234 event->wallTime.nanosec= floor((loopValues[i].time -
235 floor(loopValues[i].time)) * NANOSECONDS_PER_SECOND);
236 event->cpuTime= round(loopValues[i].time * CPU_FREQ);
237 event->type= TCP;
238 event->destroy= &destroyTCPEvent;
239 event->event.tcpEvent= malloc(sizeof(TCPEvent));
240 event->event.tcpEvent->direction= loopValues[i].direction;
241 event->event.tcpEvent->segmentKey= malloc(sizeof(SegmentKey));
242 event->event.tcpEvent->segmentKey->ihl= 5;
243 event->event.tcpEvent->segmentKey->tot_len= 40;
244 event->event.tcpEvent->segmentKey->connectionKey.saddr= sender +
245 addressOffset;
246 event->event.tcpEvent->segmentKey->connectionKey.daddr= receiver +
247 addressOffset;
248 event->event.tcpEvent->segmentKey->connectionKey.source= 57645;
249 event->event.tcpEvent->segmentKey->connectionKey.dest= 80;
250 event->event.tcpEvent->segmentKey->seq= seq[sender];
251 event->event.tcpEvent->segmentKey->ack_seq= 0;
252 event->event.tcpEvent->segmentKey->doff= 5;
253 event->event.tcpEvent->segmentKey->ack= 0;
254 event->event.tcpEvent->segmentKey->rst= 0;
255 event->event.tcpEvent->segmentKey->syn= 1;
256 event->event.tcpEvent->segmentKey->fin= 0;
257
258 syncState->matchingModule->matchEvent(syncState, event);
259 }
260 }
261
262 seq[sender]++;
263
264 skipCommentLines(testCase);
6ce8ceac 265 retval= getline(&line, &bufLen, testCase);
48b641c1
BP
266 }
267
268 free(seq);
269
270 if (line)
271 {
272 free(line);
273 }
274
275 factors= syncState->matchingModule->finalizeMatching(syncState);
276 if (syncState->stats)
277 {
278 processingData->factors= factors;
279 }
280 else
281 {
282 g_array_free(factors, TRUE);
283 }
284}
285
286
287/*
288 * Print statistics related to processing. Must be called after
289 * finalizeProcessing.
290 *
291 * Args:
292 * syncState container for synchronization data.
293 */
294static void printProcessingStatsText(SyncState* const syncState)
295{
296 unsigned int i;
297
298 printf("Resulting synchronization factors:\n");
299 for (i= 0; i < syncState->traceNb; i++)
300 {
301 Factors* factors= &g_array_index(((ProcessingDataText*)
302 syncState->processingData)->factors, Factors, i);
303
304 printf("\ttrace %u drift= %g offset= %g (%f)\n", i, factors->drift,
305 factors->offset, factors->offset / CPU_FREQ);
306 }
307}
308
309
310/*
311 * Read trace number from the test case stream. The trace number should be the
312 * first non-comment line and should be an unsigned int by itself on a line.
313 *
314 * Args:
315 * testCase: test case stream
316 *
317 * Returns:
318 * The trace number
319 */
320static unsigned int readTraceNb(FILE* testCase)
321{
322 unsigned int result;
323 int retval;
324 char* line= NULL;
325 size_t len;
326 char tmp;
327
328 skipCommentLines(testCase);
329 retval= getline(&line, &len, testCase);
330 if (retval == -1)
331 {
332 if (feof(testCase))
333 {
334 g_error("Unexpected end of file while looking for number of traces");
335 }
336 else
337 {
338 g_error(strerror(errno));
339 }
340 }
341 if (line[retval - 1] == '\n')
342 {
343 line[retval - 1]= '\0';
344 }
345
346 retval= sscanf(line, " %u %c", &result, &tmp);
347 if (retval == EOF || retval != 1)
348 {
349 g_error("Error parsing test file while looking for number of traces, line was '%s'", line);
350
351 // Not really needed but avoids warning from gcc
352 abort();
353 }
354
6ce8ceac
BP
355 if (line)
356 {
357 free(line);
358 }
359
48b641c1
BP
360 return result;
361}
362
363
364/*
365 * Advance testCase stream over empty space, empty lines and lines that begin
366 * with '#'
367 *
368 * Args:
369 * testCase: test case stream
370 */
371static void skipCommentLines(FILE* testCase)
372{
373 int firstChar;
374 ssize_t retval;
375 char* line= NULL;
376 size_t len;
377
378 do
379 {
380 firstChar= fgetc(testCase);
381 if (firstChar == (int) '#')
382 {
383 retval= getline(&line, &len, testCase);
384 if (retval == -1)
385 {
386 if (feof(testCase))
387 {
388 goto outEof;
389 }
390 else
391 {
392 g_error(strerror(errno));
393 }
394 }
395 }
396 else if (firstChar == (int) '\n' || firstChar == (int) ' ')
397 {}
398 else if (firstChar == EOF)
399 {
400 goto outEof;
401 }
402 else
403 {
404 break;
405 }
406 } while (true);
407 retval= ungetc(firstChar, testCase);
408 if (retval == EOF)
409 {
410 g_error("Error: ungetc()");
411 }
412
413outEof:
414 if (line)
415 {
416 free(line);
417 }
418}
419
420
421/*
422 * Write the processing-specific variables in the gnuplot script.
423 *
424 * Args:
425 * syncState: container for synchronization data
426 * i: trace number
427 */
428static void writeProcessingGraphVariablesText(SyncState* const syncState,
429 const unsigned int i)
430{
431 fprintf(syncState->graphsStream, "clock_freq_%u= %.3f\n", i, CPU_FREQ);
432}
433
434
435/*
436 * Write the processing-specific options in the gnuplot script.
437 *
438 * Args:
439 * syncState: container for synchronization data
440 * i: first trace number
441 * j: second trace number, garanteed to be larger than i
442 */
443static void writeProcessingTraceTraceOptionsText(SyncState* const syncState,
444 const unsigned int i, const unsigned int j)
445{
446 fprintf(syncState->graphsStream,
447 "set key inside right bottom\n"
448 "set xlabel \"Clock %1$u\"\n"
449 "set xtics nomirror\n"
450 "set ylabel \"Clock %2$u\"\n"
451 "set ytics nomirror\n"
452 "set x2label \"Clock %1$d (s)\"\n"
453 "set x2range [GPVAL_X_MIN / clock_freq_%1$u : GPVAL_X_MAX / clock_freq_%1$u]\n"
454 "set x2tics\n"
455 "set y2label \"Clock %2$d (s)\"\n"
456 "set y2range [GPVAL_Y_MIN / clock_freq_%2$u : GPVAL_Y_MAX / clock_freq_%2$u]\n"
457 "set y2tics\n", i, j);
458}
459
460
461/*
462 * Write the processing-specific options in the gnuplot script.
463 *
464 * Args:
465 * syncState: container for synchronization data
466 * i: first trace number
467 * j: second trace number, garanteed to be larger than i
468 */
469static void writeProcessingTraceTimeOptionsText(SyncState* const syncState,
470 const unsigned int i, const unsigned int j)
471{
472 fprintf(syncState->graphsStream,
473 "set key inside right bottom\n"
474 "set xlabel \"Clock %1$u\"\n"
475 "set xtics nomirror\n"
476 "set ylabel \"time (s)\"\n"
477 "set ytics nomirror\n"
478 "set x2label \"Clock %1$d (s)\"\n"
479 "set x2range [GPVAL_X_MIN / clock_freq_%1$u : GPVAL_X_MAX / clock_freq_%1$u]\n"
480 "set x2tics\n", i);
481}
This page took 0.041515 seconds and 4 git commands to generate.