Add support for module options
[lttv.git] / lttv / lttv / sync / event_analysis_eval.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
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24
25 #include <arpa/inet.h>
26 #include <errno.h>
27 #include <netinet/in.h>
28 #include <stddef.h>
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <sys/socket.h>
33
34 #include "lookup3.h"
35 #include "sync_chain.h"
36
37 #include "event_analysis_eval.h"
38
39
40 // Functions common to all analysis modules
41 static void initAnalysisEval(SyncState* const syncState);
42 static void destroyAnalysisEval(SyncState* const syncState);
43
44 static void analyzeMessageEval(SyncState* const syncState, Message* const
45 message);
46 static void analyzeExchangeEval(SyncState* const syncState, Exchange* const
47 exchange);
48 static void analyzeBroadcastEval(SyncState* const syncState, Broadcast* const
49 broadcast);
50 static GArray* finalizeAnalysisEval(SyncState* const syncState);
51 static void printAnalysisStatsEval(SyncState* const syncState);
52
53 // Functions specific to this module
54 static void registerAnalysisEval() __attribute__((constructor (102)));
55 static guint ghfRttKeyHash(gconstpointer key);
56 static gboolean gefRttKeyEqual(gconstpointer a, gconstpointer b);
57 static void gdnDestroyRttKey(gpointer data);
58 static void gdnDestroyDouble(gpointer data);
59 static void readRttInfo(GHashTable* rttInfo, FILE* rttFile);
60 static void positionStream(FILE* stream);
61
62
63 static AnalysisModule analysisModuleEval= {
64 .name= "eval",
65 .initAnalysis= &initAnalysisEval,
66 .destroyAnalysis= &destroyAnalysisEval,
67 .analyzeMessage= &analyzeMessageEval,
68 .analyzeExchange= &analyzeExchangeEval,
69 .analyzeBroadcast= &analyzeBroadcastEval,
70 .finalizeAnalysis= &finalizeAnalysisEval,
71 .printAnalysisStats= &printAnalysisStatsEval,
72 .writeAnalysisGraphsPlots= NULL,
73 .writeAnalysisGraphsOptions= NULL,
74 };
75
76 static ModuleOption optionEvalRttFile= {
77 .longName= "eval-rtt-file",
78 .hasArg= REQUIRED_ARG,
79 {.arg= NULL},
80 .optionHelp= "specify the file containing rtt information",
81 .argHelp= "FILE",
82 };
83
84
85 /*
86 * Analysis module registering function
87 */
88 static void registerAnalysisEval()
89 {
90 g_queue_push_tail(&analysisModules, &analysisModuleEval);
91 g_queue_push_tail(&moduleOptions, &optionEvalRttFile);
92 }
93
94
95 /*
96 * Analysis init function
97 *
98 * This function is called at the beginning of a synchronization run for a set
99 * of traces.
100 *
101 * Args:
102 * syncState container for synchronization data.
103 */
104 static void initAnalysisEval(SyncState* const syncState)
105 {
106 AnalysisDataEval* analysisData;
107 unsigned int i;
108
109 analysisData= malloc(sizeof(AnalysisDataEval));
110 syncState->analysisData= analysisData;
111
112 analysisData->rttInfo= g_hash_table_new_full(&ghfRttKeyHash,
113 &gefRttKeyEqual, &gdnDestroyRttKey, &gdnDestroyDouble);
114 if (optionEvalRttFile.arg)
115 {
116 FILE* rttStream;
117 int retval;
118
119 rttStream= fopen(optionEvalRttFile.arg, "r");
120 if (rttStream == NULL)
121 {
122 g_error(strerror(errno));
123 }
124
125 readRttInfo(analysisData->rttInfo, rttStream);
126
127 retval= fclose(rttStream);
128 if (retval == EOF)
129 {
130 g_error(strerror(errno));
131 }
132 }
133
134 if (syncState->stats)
135 {
136 analysisData->stats= malloc(sizeof(AnalysisStatsEval));
137 analysisData->stats->broadcastDiffSum= 0.;
138
139 analysisData->stats->allStats= malloc(syncState->traceNb *
140 sizeof(TracePairStats*));
141 for (i= 0; i < syncState->traceNb; i++)
142 {
143 analysisData->stats->allStats[i]= calloc(syncState->traceNb,
144 sizeof(TracePairStats));
145 }
146 }
147 }
148
149
150 /*
151 * Analysis destroy function
152 *
153 * Free the analysis specific data structures
154 *
155 * Args:
156 * syncState container for synchronization data.
157 */
158 static void destroyAnalysisEval(SyncState* const syncState)
159 {
160 unsigned int i;
161 AnalysisDataEval* analysisData;
162
163 analysisData= (AnalysisDataEval*) syncState->analysisData;
164
165 if (analysisData == NULL || analysisData->rttInfo == NULL)
166 {
167 return;
168 }
169
170 g_hash_table_destroy(analysisData->rttInfo);
171 analysisData->rttInfo= NULL;
172
173 if (syncState->stats)
174 {
175 for (i= 0; i < syncState->traceNb; i++)
176 {
177 free(analysisData->stats->allStats[i]);
178 }
179 free(analysisData->stats->allStats);
180 free(analysisData->stats);
181 }
182
183 free(syncState->analysisData);
184 syncState->analysisData= NULL;
185 }
186
187
188 /*
189 * Perform analysis on an event pair.
190 *
191 * Args:
192 * syncState container for synchronization data
193 * message structure containing the events
194 */
195 static void analyzeMessageEval(SyncState* const syncState, Message* const message)
196 {
197 AnalysisDataEval* analysisData;
198
199 analysisData= (AnalysisDataEval*) syncState->analysisData;
200 }
201
202
203 /*
204 * Perform analysis on multiple messages
205 *
206 * Args:
207 * syncState container for synchronization data
208 * exchange structure containing the messages
209 */
210 static void analyzeExchangeEval(SyncState* const syncState, Exchange* const exchange)
211 {
212 AnalysisDataEval* analysisData;
213
214 analysisData= (AnalysisDataEval*) syncState->analysisData;
215 }
216
217
218 /*
219 * Perform analysis on muliple events
220 *
221 * Args:
222 * syncState container for synchronization data
223 * broadcast structure containing the events
224 */
225 static void analyzeBroadcastEval(SyncState* const syncState, Broadcast* const broadcast)
226 {
227 AnalysisDataEval* analysisData;
228
229 analysisData= (AnalysisDataEval*) syncState->analysisData;
230 }
231
232
233 /*
234 * Finalize the factor calculations
235 *
236 * Since this module does not really calculate factors, identity factors are
237 * returned.
238 *
239 * Args:
240 * syncState container for synchronization data.
241 *
242 * Returns:
243 * Factors[traceNb] synchronization factors for each trace
244 */
245 static GArray* finalizeAnalysisEval(SyncState* const syncState)
246 {
247 GArray* factors;
248 unsigned int i;
249
250 factors= g_array_sized_new(FALSE, FALSE, sizeof(Factors),
251 syncState->traceNb);
252 g_array_set_size(factors, syncState->traceNb);
253 for (i= 0; i < syncState->traceNb; i++)
254 {
255 Factors* e;
256
257 e= &g_array_index(factors, Factors, i);
258 e->drift= 1.;
259 e->offset= 0.;
260 }
261
262 return factors;
263 }
264
265
266 /*
267 * Print statistics related to analysis. Must be called after
268 * finalizeAnalysis.
269 *
270 * Args:
271 * syncState container for synchronization data.
272 */
273 static void printAnalysisStatsEval(SyncState* const syncState)
274 {
275 AnalysisDataEval* analysisData;
276 unsigned int i, j;
277
278 if (!syncState->stats)
279 {
280 return;
281 }
282
283 analysisData= (AnalysisDataEval*) syncState->analysisData;
284
285 printf("Synchronization evaluation analysis stats:\n");
286 printf("\tsum of broadcast differential delays: %g\n",
287 analysisData->stats->broadcastDiffSum);
288
289 printf("\tIndividual evaluation:\n"
290 "\t\tTrace pair Inversions Too fast (No RTT info)\n");
291
292 for (i= 0; i < syncState->traceNb; i++)
293 {
294 for (j= i + 1; j < syncState->traceNb; j++)
295 {
296 TracePairStats* tpStats;
297 const char* format= "\t\t%3d - %-3d %-10u %-10u %u\n";
298
299 tpStats= &analysisData->stats->allStats[i][j];
300
301 printf(format, i, j, tpStats->inversionNb, tpStats->tooFastNb,
302 tpStats->noRTTInfoNb);
303
304 tpStats= &analysisData->stats->allStats[j][i];
305
306 printf(format, j, i, tpStats->inversionNb, tpStats->tooFastNb,
307 tpStats->noRTTInfoNb);
308 }
309 }
310 }
311
312
313 /*
314 * A GHashFunc for g_hash_table_new()
315 *
316 * Args:
317 * key struct RttKey*
318 */
319 static guint ghfRttKeyHash(gconstpointer key)
320 {
321 struct RttKey* rttKey;
322 uint32_t a, b, c;
323
324 rttKey= (struct RttKey*) key;
325
326 a= rttKey->saddr;
327 b= rttKey->daddr;
328 c= 0;
329 final(a, b, c);
330
331 return c;
332 }
333
334
335 /*
336 * A GDestroyNotify function for g_hash_table_new_full()
337 *
338 * Args:
339 * data: struct RttKey*
340 */
341 static void gdnDestroyRttKey(gpointer data)
342 {
343 free(data);
344 }
345
346
347 /*
348 * A GDestroyNotify function for g_hash_table_new_full()
349 *
350 * Args:
351 * data: double*
352 */
353 static void gdnDestroyDouble(gpointer data)
354 {
355 free(data);
356 }
357
358
359 /*
360 * A GEqualFunc for g_hash_table_new()
361 *
362 * Args:
363 * a, b RttKey*
364 *
365 * Returns:
366 * TRUE if both values are equal
367 */
368 static gboolean gefRttKeyEqual(gconstpointer a, gconstpointer b)
369 {
370 const struct RttKey* rkA, * rkB;
371
372 rkA= (struct RttKey*) a;
373 rkB= (struct RttKey*) b;
374
375 if (rkA->saddr == rkB->saddr && rkA->daddr == rkB->daddr)
376 {
377 return TRUE;
378 }
379 else
380 {
381 return FALSE;
382 }
383 }
384
385
386 /*
387 * Read a file contain minimum round trip time values and fill an array with
388 * them. The file is formatted as such:
389 * <host1 IP> <host2 IP> <RTT in milliseconds>
390 * ip's should be in dotted quad format
391 *
392 * Args:
393 * rttInfo: double* rttInfo[RttKey], empty table, will be filled
394 * rttStream: stream from which to read
395 */
396 static void readRttInfo(GHashTable* rttInfo, FILE* rttStream)
397 {
398 char* line= NULL;
399 size_t len;
400 int retval;
401
402 positionStream(rttStream);
403 retval= getline(&line, &len, rttStream);
404 while(!feof(rttStream))
405 {
406 struct RttKey* rttKey;
407 char saddrDQ[20], daddrDQ[20];
408 double* rtt;
409 char tmp;
410 struct in_addr addr;
411 unsigned int i;
412 struct {
413 char* dq;
414 size_t offset;
415 } loopValues[] = {
416 {saddrDQ, offsetof(struct RttKey, saddr)},
417 {daddrDQ, offsetof(struct RttKey, daddr)}
418 };
419
420 if (retval == -1 && !feof(rttStream))
421 {
422 g_error(strerror(errno));
423 }
424
425 if (line[retval - 1] == '\n')
426 {
427 line[retval - 1]= '\0';
428 }
429
430 rtt= malloc(sizeof(double));
431 retval= sscanf(line, " %19s %19s %lf %c", saddrDQ, daddrDQ, rtt,
432 &tmp);
433 if (retval == EOF)
434 {
435 g_error(strerror(errno));
436 }
437 else if (retval != 3)
438 {
439 g_error("Error parsing RTT file, line was '%s'", line);
440 }
441
442 rttKey= malloc(sizeof(struct RttKey));
443 for (i= 0; i < sizeof(loopValues) / sizeof(*loopValues); i++)
444 {
445 retval= inet_aton(loopValues[i].dq, &addr);
446 if (retval == 0)
447 {
448 g_error("Error converting address '%s'", loopValues[i].dq);
449 }
450 *(uint32_t*) ((void*) rttKey + loopValues[i].offset)=
451 addr.s_addr;
452 }
453
454 g_hash_table_insert(rttInfo, rttKey, rtt);
455
456 positionStream(rttStream);
457 retval= getline(&line, &len, rttStream);
458 }
459
460 if (line)
461 {
462 free(line);
463 }
464 }
465
466
467 /*
468 * Advance stream over empty space, empty lines and lines that begin with '#'
469 *
470 * Args:
471 * stream: stream, at exit, will be over the first non-empty character
472 * of a line of be at EOF
473 */
474 static void positionStream(FILE* stream)
475 {
476 int firstChar;
477 ssize_t retval;
478 char* line= NULL;
479 size_t len;
480
481 do
482 {
483 firstChar= fgetc(stream);
484 if (firstChar == (int) '#')
485 {
486 retval= getline(&line, &len, stream);
487 if (retval == -1)
488 {
489 if (feof(stream))
490 {
491 goto outEof;
492 }
493 else
494 {
495 g_error(strerror(errno));
496 }
497 }
498 }
499 else if (firstChar == (int) '\n' || firstChar == (int) ' ' ||
500 firstChar == (int) '\t')
501 {}
502 else if (firstChar == EOF)
503 {
504 goto outEof;
505 }
506 else
507 {
508 break;
509 }
510 } while (true);
511 retval= ungetc(firstChar, stream);
512 if (retval == EOF)
513 {
514 g_error("Error: ungetc()");
515 }
516
517 outEof:
518 if (line)
519 {
520 free(line);
521 }
522 }
This page took 0.039934 seconds and 4 git commands to generate.