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