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