Commit | Line | Data |
---|---|---|
cdce23b3 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 | ||
2bd4b3e4 BP |
19 | #define _GNU_SOURCE |
20 | ||
cdce23b3 BP |
21 | #ifdef HAVE_CONFIG_H |
22 | #include <config.h> | |
23 | #endif | |
24 | ||
2bd4b3e4 BP |
25 | #include <arpa/inet.h> |
26 | #include <errno.h> | |
27 | #include <netinet/in.h> | |
28 | #include <stddef.h> | |
cdce23b3 | 29 | #include <stdlib.h> |
2bd4b3e4 BP |
30 | #include <stdio.h> |
31 | #include <string.h> | |
32 | #include <sys/socket.h> | |
cdce23b3 | 33 | |
2bd4b3e4 BP |
34 | #include "lookup3.h" |
35 | #include "sync_chain.h" | |
cdce23b3 BP |
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))); | |
2bd4b3e4 BP |
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); | |
cdce23b3 BP |
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 | ||
2bd4b3e4 BP |
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 | ||
cdce23b3 BP |
84 | |
85 | /* | |
86 | * Analysis module registering function | |
87 | */ | |
88 | static void registerAnalysisEval() | |
89 | { | |
90 | g_queue_push_tail(&analysisModules, &analysisModuleEval); | |
2bd4b3e4 | 91 | g_queue_push_tail(&moduleOptions, &optionEvalRttFile); |
cdce23b3 BP |
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 | ||
2bd4b3e4 BP |
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 | } | |
cdce23b3 BP |
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 | ||
2bd4b3e4 | 170 | g_hash_table_destroy(analysisData->rttInfo); |
cdce23b3 BP |
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 | } | |
2bd4b3e4 BP |
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 | } |