Commit | Line | Data |
---|---|---|
cdce23b3 | 1 | /* This file is part of the Linux Trace Toolkit viewer |
277e5b53 | 2 | * Copyright (C) 2009, 2010 Benjamin Poirier <benjamin.poirier@polymtl.ca> |
cdce23b3 | 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. | |
cdce23b3 | 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. | |
cdce23b3 | 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/>. | |
cdce23b3 BP |
16 | */ |
17 | ||
2bd4b3e4 | 18 | #define _GNU_SOURCE |
d4721e1a | 19 | #define _ISOC99_SOURCE |
2bd4b3e4 | 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> | |
76be6fc2 | 27 | #include <math.h> |
2bd4b3e4 BP |
28 | #include <netinet/in.h> |
29 | #include <stddef.h> | |
cdce23b3 | 30 | #include <stdlib.h> |
2bd4b3e4 BP |
31 | #include <stdio.h> |
32 | #include <string.h> | |
33 | #include <sys/socket.h> | |
4ee223e5 | 34 | #include <unistd.h> |
cdce23b3 | 35 | |
2bd4b3e4 BP |
36 | #include "lookup3.h" |
37 | #include "sync_chain.h" | |
cdce23b3 BP |
38 | |
39 | #include "event_analysis_eval.h" | |
40 | ||
41 | ||
66eaf2eb | 42 | struct WriteHistogramInfo |
e072e1ab BP |
43 | { |
44 | GHashTable* rttInfo; | |
45 | FILE* graphsStream; | |
46 | }; | |
47 | ||
cdce23b3 BP |
48 | // Functions common to all analysis modules |
49 | static void initAnalysisEval(SyncState* const syncState); | |
50 | static void destroyAnalysisEval(SyncState* const syncState); | |
51 | ||
52 | static void analyzeMessageEval(SyncState* const syncState, Message* const | |
53 | message); | |
54 | static void analyzeExchangeEval(SyncState* const syncState, Exchange* const | |
55 | exchange); | |
56 | static void analyzeBroadcastEval(SyncState* const syncState, Broadcast* const | |
57 | broadcast); | |
0a87ec9a | 58 | static AllFactors* finalizeAnalysisEval(SyncState* const syncState); |
cdce23b3 BP |
59 | static void printAnalysisStatsEval(SyncState* const syncState); |
60 | ||
61 | // Functions specific to this module | |
2bd4b3e4 BP |
62 | static guint ghfRttKeyHash(gconstpointer key); |
63 | static gboolean gefRttKeyEqual(gconstpointer a, gconstpointer b); | |
64 | static void gdnDestroyRttKey(gpointer data); | |
65 | static void gdnDestroyDouble(gpointer data); | |
66 | static void readRttInfo(GHashTable* rttInfo, FILE* rttFile); | |
67 | static void positionStream(FILE* stream); | |
cdce23b3 | 68 | |
76be6fc2 BP |
69 | static void gfSum(gpointer data, gpointer userData); |
70 | static void gfSumSquares(gpointer data, gpointer userData); | |
66eaf2eb BP |
71 | static void ghfPrintExchangeRtt(gpointer key, gpointer value, gpointer |
72 | user_data); | |
76be6fc2 | 73 | |
e072e1ab | 74 | static void hitBin(struct Bins* const bins, const double value); |
4ee223e5 BP |
75 | static unsigned int binNum(const double value) __attribute__((pure)); |
76 | static double binStart(const unsigned int binNum) __attribute__((pure)); | |
77 | static double binEnd(const unsigned int binNum) __attribute__((pure)); | |
467066ee | 78 | static uint32_t normalTotal(struct Bins* const bins) __attribute__((const)); |
4ee223e5 | 79 | |
66eaf2eb | 80 | static AnalysisHistogramEval* constructAnalysisHistogramEval(const char* const |
e072e1ab | 81 | graphsDir, const struct RttKey* const rttKey); |
66eaf2eb BP |
82 | static void destroyAnalysisHistogramEval(AnalysisHistogramEval* const |
83 | histogram); | |
84 | static void gdnDestroyAnalysisHistogramEval(gpointer data); | |
85 | static void ghfWriteHistogram(gpointer key, gpointer value, gpointer | |
86 | user_data); | |
e072e1ab BP |
87 | static void dumpBinToFile(const struct Bins* const bins, FILE* const file); |
88 | static void writeHistogram(FILE* graphsStream, const struct RttKey* rttKey, | |
66eaf2eb BP |
89 | double* minRtt, AnalysisHistogramEval* const histogram); |
90 | ||
c6356aa7 BP |
91 | static void updateBounds(Bounds** const bounds, Event* const e1, Event* const |
92 | e2); | |
66eaf2eb | 93 | |
4ee223e5 | 94 | |
66eaf2eb | 95 | // initialized in registerAnalysisEval() |
4ee223e5 | 96 | double binBase; |
cdce23b3 BP |
97 | |
98 | static AnalysisModule analysisModuleEval= { | |
99 | .name= "eval", | |
100 | .initAnalysis= &initAnalysisEval, | |
101 | .destroyAnalysis= &destroyAnalysisEval, | |
102 | .analyzeMessage= &analyzeMessageEval, | |
103 | .analyzeExchange= &analyzeExchangeEval, | |
104 | .analyzeBroadcast= &analyzeBroadcastEval, | |
105 | .finalizeAnalysis= &finalizeAnalysisEval, | |
106 | .printAnalysisStats= &printAnalysisStatsEval, | |
ab6edc6a | 107 | .graphFunctions= {} |
cdce23b3 BP |
108 | }; |
109 | ||
2bd4b3e4 BP |
110 | static ModuleOption optionEvalRttFile= { |
111 | .longName= "eval-rtt-file", | |
112 | .hasArg= REQUIRED_ARG, | |
4ee223e5 | 113 | .optionHelp= "specify the file containing RTT information", |
2bd4b3e4 BP |
114 | .argHelp= "FILE", |
115 | }; | |
116 | ||
cdce23b3 BP |
117 | |
118 | /* | |
119 | * Analysis module registering function | |
120 | */ | |
2f961b65 | 121 | void registerAnalysisEval() |
cdce23b3 | 122 | { |
66eaf2eb BP |
123 | binBase= exp10(6. / (BIN_NB - 3)); |
124 | ||
cdce23b3 | 125 | g_queue_push_tail(&analysisModules, &analysisModuleEval); |
2bd4b3e4 | 126 | g_queue_push_tail(&moduleOptions, &optionEvalRttFile); |
cdce23b3 BP |
127 | } |
128 | ||
129 | ||
130 | /* | |
131 | * Analysis init function | |
132 | * | |
133 | * This function is called at the beginning of a synchronization run for a set | |
134 | * of traces. | |
135 | * | |
136 | * Args: | |
137 | * syncState container for synchronization data. | |
138 | */ | |
139 | static void initAnalysisEval(SyncState* const syncState) | |
140 | { | |
141 | AnalysisDataEval* analysisData; | |
66eaf2eb | 142 | unsigned int i, j; |
cdce23b3 BP |
143 | |
144 | analysisData= malloc(sizeof(AnalysisDataEval)); | |
145 | syncState->analysisData= analysisData; | |
146 | ||
2bd4b3e4 BP |
147 | analysisData->rttInfo= g_hash_table_new_full(&ghfRttKeyHash, |
148 | &gefRttKeyEqual, &gdnDestroyRttKey, &gdnDestroyDouble); | |
149 | if (optionEvalRttFile.arg) | |
150 | { | |
151 | FILE* rttStream; | |
152 | int retval; | |
153 | ||
154 | rttStream= fopen(optionEvalRttFile.arg, "r"); | |
155 | if (rttStream == NULL) | |
156 | { | |
157 | g_error(strerror(errno)); | |
158 | } | |
159 | ||
160 | readRttInfo(analysisData->rttInfo, rttStream); | |
161 | ||
162 | retval= fclose(rttStream); | |
163 | if (retval == EOF) | |
164 | { | |
165 | g_error(strerror(errno)); | |
166 | } | |
167 | } | |
cdce23b3 BP |
168 | |
169 | if (syncState->stats) | |
170 | { | |
76be6fc2 | 171 | analysisData->stats= calloc(1, sizeof(AnalysisStatsEval)); |
2849af52 BP |
172 | analysisData->stats->broadcastRangeMin= INFINITY; |
173 | analysisData->stats->broadcastRangeMax= -INFINITY; | |
cdce23b3 | 174 | |
76be6fc2 BP |
175 | analysisData->stats->messageStats= malloc(syncState->traceNb * |
176 | sizeof(MessageStats*)); | |
cdce23b3 BP |
177 | for (i= 0; i < syncState->traceNb; i++) |
178 | { | |
76be6fc2 BP |
179 | analysisData->stats->messageStats[i]= calloc(syncState->traceNb, |
180 | sizeof(MessageStats)); | |
cdce23b3 | 181 | } |
d4721e1a BP |
182 | |
183 | analysisData->stats->exchangeRtt= | |
184 | g_hash_table_new_full(&ghfRttKeyHash, &gefRttKeyEqual, | |
185 | &gdnDestroyRttKey, &gdnDestroyDouble); | |
cdce23b3 | 186 | } |
4ee223e5 | 187 | |
8d7d16dd | 188 | if (syncState->graphsStream) |
4ee223e5 | 189 | { |
66eaf2eb BP |
190 | AnalysisGraphsEval* graphs= malloc(sizeof(AnalysisGraphsEval)); |
191 | ||
192 | analysisData->graphs= graphs; | |
193 | ||
194 | graphs->histograms= g_hash_table_new_full(&ghfRttKeyHash, | |
195 | &gefRttKeyEqual, &gdnDestroyRttKey, | |
196 | &gdnDestroyAnalysisHistogramEval); | |
197 | ||
198 | graphs->bounds= malloc(syncState->traceNb * sizeof(Bounds*)); | |
199 | for (i= 0; i < syncState->traceNb; i++) | |
200 | { | |
201 | graphs->bounds[i]= malloc(i * sizeof(Bounds)); | |
202 | for (j= 0; j < i; j++) | |
203 | { | |
204 | graphs->bounds[i][j].min= UINT64_MAX; | |
205 | graphs->bounds[i][j].max= 0; | |
206 | } | |
207 | } | |
4ee223e5 BP |
208 | } |
209 | } | |
210 | ||
211 | ||
212 | /* | |
e072e1ab BP |
213 | * Create and open files used to store histogram points to generate graphs. |
214 | * Create data structures to store histogram points during analysis. | |
4ee223e5 BP |
215 | * |
216 | * Args: | |
e072e1ab BP |
217 | * graphsDir: folder where to write files |
218 | * rttKey: host pair, make sure saddr < daddr | |
4ee223e5 | 219 | */ |
66eaf2eb | 220 | static AnalysisHistogramEval* constructAnalysisHistogramEval(const char* const |
e072e1ab | 221 | graphsDir, const struct RttKey* const rttKey) |
4ee223e5 | 222 | { |
4ee223e5 | 223 | int retval; |
e072e1ab | 224 | unsigned int i; |
4ee223e5 | 225 | char* cwd; |
e072e1ab | 226 | char name[60], saddr[16], daddr[16]; |
66eaf2eb | 227 | AnalysisHistogramEval* histogram= calloc(1, sizeof(*histogram)); |
e072e1ab BP |
228 | const struct { |
229 | size_t pointsOffset; | |
230 | const char* fileName; | |
231 | const char* host1, *host2; | |
232 | } loopValues[]= { | |
66eaf2eb BP |
233 | {offsetof(AnalysisHistogramEval, ttSendPoints), |
234 | "analysis_eval_tt-%s_to_%s.data", saddr, daddr}, | |
235 | {offsetof(AnalysisHistogramEval, ttRecvPoints), | |
236 | "analysis_eval_tt-%s_to_%s.data", daddr, saddr}, | |
237 | {offsetof(AnalysisHistogramEval, hrttPoints), | |
238 | "analysis_eval_hrtt-%s_and_%s.data", saddr, daddr}, | |
e072e1ab BP |
239 | }; |
240 | ||
66eaf2eb BP |
241 | histogram->ttSendBins.min= BIN_NB - 1; |
242 | histogram->ttRecvBins.min= BIN_NB - 1; | |
243 | histogram->hrttBins.min= BIN_NB - 1; | |
e072e1ab BP |
244 | |
245 | convertIP(saddr, rttKey->saddr); | |
246 | convertIP(daddr, rttKey->daddr); | |
247 | ||
1d597550 | 248 | cwd= changeToGraphsDir(graphsDir); |
e072e1ab BP |
249 | |
250 | for (i= 0; i < sizeof(loopValues) / sizeof(*loopValues); i++) | |
4ee223e5 | 251 | { |
e072e1ab BP |
252 | retval= snprintf(name, sizeof(name), loopValues[i].fileName, |
253 | loopValues[i].host1, loopValues[i].host2); | |
254 | if (retval > sizeof(name) - 1) | |
4ee223e5 | 255 | { |
e072e1ab | 256 | name[sizeof(name) - 1]= '\0'; |
4ee223e5 | 257 | } |
66eaf2eb | 258 | if ((*(FILE**)((void*) histogram + loopValues[i].pointsOffset)= |
e072e1ab | 259 | fopen(name, "w")) == NULL) |
4ee223e5 | 260 | { |
e072e1ab | 261 | g_error(strerror(errno)); |
4ee223e5 BP |
262 | } |
263 | } | |
264 | ||
265 | retval= chdir(cwd); | |
266 | if (retval == -1) | |
267 | { | |
268 | g_error(strerror(errno)); | |
269 | } | |
270 | free(cwd); | |
e072e1ab | 271 | |
66eaf2eb | 272 | return histogram; |
4ee223e5 BP |
273 | } |
274 | ||
275 | ||
276 | /* | |
e072e1ab | 277 | * Close files used to store histogram points to generate graphs. |
4ee223e5 BP |
278 | * |
279 | * Args: | |
e072e1ab BP |
280 | * graphsDir: folder where to write files |
281 | * rttKey: host pair, make sure saddr < daddr | |
4ee223e5 | 282 | */ |
66eaf2eb BP |
283 | static void destroyAnalysisHistogramEval(AnalysisHistogramEval* const |
284 | histogram) | |
4ee223e5 | 285 | { |
e072e1ab BP |
286 | unsigned int i; |
287 | int retval; | |
288 | const struct { | |
289 | size_t pointsOffset; | |
290 | } loopValues[]= { | |
66eaf2eb BP |
291 | {offsetof(AnalysisHistogramEval, ttSendPoints)}, |
292 | {offsetof(AnalysisHistogramEval, ttRecvPoints)}, | |
293 | {offsetof(AnalysisHistogramEval, hrttPoints)}, | |
e072e1ab BP |
294 | }; |
295 | ||
296 | for (i= 0; i < sizeof(loopValues) / sizeof(*loopValues); i++) | |
4ee223e5 | 297 | { |
66eaf2eb | 298 | retval= fclose(*(FILE**)((void*) histogram + loopValues[i].pointsOffset)); |
e072e1ab | 299 | if (retval != 0) |
4ee223e5 | 300 | { |
e072e1ab | 301 | g_error(strerror(errno)); |
4ee223e5 BP |
302 | } |
303 | } | |
66eaf2eb BP |
304 | |
305 | free(histogram); | |
4ee223e5 BP |
306 | } |
307 | ||
308 | ||
e072e1ab BP |
309 | /* |
310 | * A GDestroyNotify function for g_hash_table_new_full() | |
311 | * | |
312 | * Args: | |
66eaf2eb | 313 | * data: AnalysisHistogramEval* |
e072e1ab | 314 | */ |
66eaf2eb | 315 | static void gdnDestroyAnalysisHistogramEval(gpointer data) |
e072e1ab | 316 | { |
66eaf2eb | 317 | destroyAnalysisHistogramEval(data); |
e072e1ab BP |
318 | } |
319 | ||
320 | ||
321 | /* | |
322 | * A GHFunc for g_hash_table_foreach() | |
323 | * | |
324 | * Args: | |
325 | * key: RttKey* where saddr < daddr | |
66eaf2eb BP |
326 | * value: AnalysisHistogramEval* |
327 | * user_data struct WriteHistogramInfo* | |
e072e1ab | 328 | */ |
66eaf2eb | 329 | static void ghfWriteHistogram(gpointer key, gpointer value, gpointer user_data) |
e072e1ab BP |
330 | { |
331 | double* rtt1, * rtt2; | |
332 | struct RttKey* rttKey= key; | |
333 | struct RttKey oppositeRttKey= {.saddr= rttKey->daddr, .daddr= | |
334 | rttKey->saddr}; | |
66eaf2eb BP |
335 | AnalysisHistogramEval* histogram= value; |
336 | struct WriteHistogramInfo* info= user_data; | |
e072e1ab BP |
337 | |
338 | rtt1= g_hash_table_lookup(info->rttInfo, rttKey); | |
339 | rtt2= g_hash_table_lookup(info->rttInfo, &oppositeRttKey); | |
340 | ||
341 | if (rtt1 == NULL) | |
342 | { | |
343 | rtt1= rtt2; | |
344 | } | |
345 | else if (rtt2 != NULL) | |
346 | { | |
347 | rtt1= MIN(rtt1, rtt2); | |
348 | } | |
349 | ||
66eaf2eb BP |
350 | dumpBinToFile(&histogram->ttSendBins, histogram->ttSendPoints); |
351 | dumpBinToFile(&histogram->ttRecvBins, histogram->ttRecvPoints); | |
352 | dumpBinToFile(&histogram->hrttBins, histogram->hrttPoints); | |
353 | writeHistogram(info->graphsStream, rttKey, rtt1, histogram); | |
e072e1ab BP |
354 | } |
355 | ||
356 | ||
4ee223e5 BP |
357 | /* |
358 | * Write the content of one bin in a histogram point file | |
359 | * | |
360 | * Args: | |
361 | * bin: array of values that make up a histogram | |
e072e1ab | 362 | * file: FILE*, write to this file |
4ee223e5 | 363 | */ |
e072e1ab | 364 | static void dumpBinToFile(const struct Bins* const bins, FILE* const file) |
4ee223e5 BP |
365 | { |
366 | unsigned int i; | |
367 | ||
e072e1ab BP |
368 | // The first and last bins are skipped, see struct Bins |
369 | for (i= 1; i < BIN_NB - 1; i++) | |
4ee223e5 | 370 | { |
e072e1ab | 371 | if (bins->bin[i] > 0) |
4ee223e5 | 372 | { |
e072e1ab BP |
373 | fprintf(file, "%20.9f %20.9f %20.9f\n", (binStart(i) + binEnd(i)) |
374 | / 2., (double) bins->bin[i] / ((binEnd(i) - binStart(i)) * | |
375 | bins->total), binEnd(i) - binStart(i)); | |
4ee223e5 BP |
376 | } |
377 | } | |
378 | } | |
379 | ||
380 | ||
381 | /* | |
e072e1ab | 382 | * Write the analysis-specific plot in the gnuplot script. |
4ee223e5 BP |
383 | * |
384 | * Args: | |
e072e1ab BP |
385 | * graphsStream: write to this file |
386 | * rttKey: must be sorted such that saddr < daddr | |
387 | * minRtt: if available, else NULL | |
66eaf2eb | 388 | * histogram: struct that contains the bins for the pair of traces |
467066ee | 389 | * identified by rttKey |
4ee223e5 | 390 | */ |
e072e1ab | 391 | static void writeHistogram(FILE* graphsStream, const struct RttKey* rttKey, |
66eaf2eb | 392 | double* minRtt, AnalysisHistogramEval* const histogram) |
4ee223e5 | 393 | { |
e072e1ab | 394 | char saddr[16], daddr[16]; |
4ee223e5 | 395 | |
e072e1ab BP |
396 | convertIP(saddr, rttKey->saddr); |
397 | convertIP(daddr, rttKey->daddr); | |
4ee223e5 | 398 | |
e072e1ab | 399 | fprintf(graphsStream, |
66eaf2eb | 400 | "\nreset\n" |
e072e1ab BP |
401 | "set output \"histogram-%s-%s.eps\"\n" |
402 | "set title \"\"\n" | |
403 | "set xlabel \"Message Latency (s)\"\n" | |
404 | "set ylabel \"Proportion of messages per second\"\n", saddr, daddr); | |
4ee223e5 | 405 | |
e072e1ab | 406 | if (minRtt != NULL) |
4ee223e5 | 407 | { |
e072e1ab BP |
408 | fprintf(graphsStream, |
409 | "set arrow from %.9f, 0 rto 0, graph 1 " | |
467066ee BP |
410 | "nohead linetype 3 linewidth 3 linecolor rgb \"black\"\n", *minRtt |
411 | / 2); | |
4ee223e5 | 412 | } |
4ee223e5 | 413 | |
66eaf2eb BP |
414 | if (normalTotal(&histogram->ttSendBins) || |
415 | normalTotal(&histogram->ttRecvBins) || | |
416 | normalTotal(&histogram->hrttBins)) | |
467066ee BP |
417 | { |
418 | fprintf(graphsStream, "plot \\\n"); | |
419 | ||
66eaf2eb | 420 | if (normalTotal(&histogram->hrttBins)) |
467066ee BP |
421 | { |
422 | fprintf(graphsStream, | |
423 | "\t\"analysis_eval_hrtt-%s_and_%s.data\" " | |
424 | "title \"RTT/2\" with linespoints linetype 1 linewidth 2 " | |
425 | "linecolor rgb \"black\" pointtype 6 pointsize 1,\\\n", | |
426 | saddr, daddr); | |
427 | } | |
428 | ||
66eaf2eb | 429 | if (normalTotal(&histogram->ttSendBins)) |
467066ee BP |
430 | { |
431 | fprintf(graphsStream, | |
432 | "\t\"analysis_eval_tt-%1$s_to_%2$s.data\" " | |
433 | "title \"%1$s to %2$s\" with linespoints linetype 4 linewidth 2 " | |
434 | "linecolor rgb \"gray60\" pointtype 6 pointsize 1,\\\n", | |
435 | saddr, daddr); | |
436 | } | |
437 | ||
66eaf2eb | 438 | if (normalTotal(&histogram->ttRecvBins)) |
467066ee BP |
439 | { |
440 | fprintf(graphsStream, | |
441 | "\t\"analysis_eval_tt-%1$s_to_%2$s.data\" " | |
442 | "title \"%1$s to %2$s\" with linespoints linetype 4 linewidth 2 " | |
443 | "linecolor rgb \"gray30\" pointtype 6 pointsize 1,\\\n", | |
444 | daddr, saddr); | |
445 | } | |
446 | ||
447 | // Remove the ",\\\n" from the last graph plot line | |
448 | if (ftruncate(fileno(graphsStream), ftell(graphsStream) - 3) == -1) | |
449 | { | |
450 | g_error(strerror(errno)); | |
451 | } | |
452 | if (fseek(graphsStream, 0, SEEK_END) == -1) | |
453 | { | |
454 | g_error(strerror(errno)); | |
455 | } | |
456 | fprintf(graphsStream, "\n"); | |
457 | } | |
cdce23b3 BP |
458 | } |
459 | ||
460 | ||
461 | /* | |
462 | * Analysis destroy function | |
463 | * | |
464 | * Free the analysis specific data structures | |
465 | * | |
466 | * Args: | |
467 | * syncState container for synchronization data. | |
468 | */ | |
469 | static void destroyAnalysisEval(SyncState* const syncState) | |
470 | { | |
05a840df | 471 | unsigned int i; |
cdce23b3 BP |
472 | AnalysisDataEval* analysisData; |
473 | ||
474 | analysisData= (AnalysisDataEval*) syncState->analysisData; | |
475 | ||
66eaf2eb | 476 | if (analysisData == NULL) |
cdce23b3 BP |
477 | { |
478 | return; | |
479 | } | |
480 | ||
2bd4b3e4 | 481 | g_hash_table_destroy(analysisData->rttInfo); |
cdce23b3 BP |
482 | |
483 | if (syncState->stats) | |
484 | { | |
66eaf2eb BP |
485 | AnalysisStatsEval* stats= analysisData->stats; |
486 | ||
487 | for (i= 0; i < syncState->traceNb; i++) | |
488 | { | |
489 | free(stats->messageStats[i]); | |
490 | } | |
491 | free(stats->messageStats); | |
492 | ||
493 | g_hash_table_destroy(stats->exchangeRtt); | |
494 | ||
66eaf2eb BP |
495 | free(stats); |
496 | } | |
497 | ||
498 | if (syncState->graphsStream) | |
499 | { | |
500 | AnalysisGraphsEval* graphs= analysisData->graphs; | |
501 | ||
502 | if (graphs->histograms) | |
503 | { | |
504 | g_hash_table_destroy(graphs->histograms); | |
505 | } | |
506 | ||
cdce23b3 BP |
507 | for (i= 0; i < syncState->traceNb; i++) |
508 | { | |
66eaf2eb BP |
509 | free(graphs->bounds[i]); |
510 | } | |
511 | free(graphs->bounds); | |
512 | ||
66eaf2eb | 513 | free(graphs); |
cdce23b3 BP |
514 | } |
515 | ||
516 | free(syncState->analysisData); | |
517 | syncState->analysisData= NULL; | |
518 | } | |
519 | ||
520 | ||
521 | /* | |
522 | * Perform analysis on an event pair. | |
523 | * | |
76be6fc2 BP |
524 | * Check if there is message inversion or messages that are too fast. |
525 | * | |
cdce23b3 BP |
526 | * Args: |
527 | * syncState container for synchronization data | |
528 | * message structure containing the events | |
529 | */ | |
66eaf2eb BP |
530 | static void analyzeMessageEval(SyncState* const syncState, Message* const |
531 | message) | |
cdce23b3 | 532 | { |
e072e1ab | 533 | AnalysisDataEval* analysisData= syncState->analysisData; |
7e39acc6 | 534 | MessageStats* messageStats; |
d4721e1a | 535 | double* rtt; |
76be6fc2 BP |
536 | double tt; |
537 | struct RttKey rttKey; | |
538 | ||
e072e1ab | 539 | g_assert(message->inE->type == TCP); |
76be6fc2 | 540 | |
66eaf2eb BP |
541 | if (syncState->stats) |
542 | { | |
7e39acc6 BP |
543 | messageStats= |
544 | &analysisData->stats->messageStats[message->outE->traceNum][message->inE->traceNum]; | |
66eaf2eb BP |
545 | messageStats->total++; |
546 | } | |
76be6fc2 BP |
547 | |
548 | tt= wallTimeSub(&message->inE->wallTime, &message->outE->wallTime); | |
549 | if (tt <= 0) | |
550 | { | |
66eaf2eb BP |
551 | if (syncState->stats) |
552 | { | |
553 | messageStats->inversionNb++; | |
554 | } | |
76be6fc2 | 555 | } |
8d7d16dd | 556 | else if (syncState->graphsStream) |
4ee223e5 | 557 | { |
e072e1ab BP |
558 | struct RttKey rttKey= { |
559 | .saddr=MIN(message->inE->event.tcpEvent->segmentKey->connectionKey.saddr, | |
560 | message->inE->event.tcpEvent->segmentKey->connectionKey.daddr), | |
561 | .daddr=MAX(message->inE->event.tcpEvent->segmentKey->connectionKey.saddr, | |
562 | message->inE->event.tcpEvent->segmentKey->connectionKey.daddr), | |
563 | }; | |
66eaf2eb BP |
564 | AnalysisHistogramEval* histogram= |
565 | g_hash_table_lookup(analysisData->graphs->histograms, &rttKey); | |
e072e1ab | 566 | |
66eaf2eb | 567 | if (histogram == NULL) |
e072e1ab BP |
568 | { |
569 | struct RttKey* tableKey= malloc(sizeof(*tableKey)); | |
570 | ||
66eaf2eb | 571 | histogram= constructAnalysisHistogramEval(syncState->graphsDir, &rttKey); |
e072e1ab | 572 | memcpy(tableKey, &rttKey, sizeof(*tableKey)); |
66eaf2eb | 573 | g_hash_table_insert(analysisData->graphs->histograms, tableKey, histogram); |
e072e1ab BP |
574 | } |
575 | ||
576 | if (message->inE->event.udpEvent->datagramKey->saddr < | |
577 | message->inE->event.udpEvent->datagramKey->daddr) | |
578 | { | |
66eaf2eb | 579 | hitBin(&histogram->ttSendBins, tt); |
e072e1ab BP |
580 | } |
581 | else | |
582 | { | |
66eaf2eb | 583 | hitBin(&histogram->ttRecvBins, tt); |
e072e1ab | 584 | } |
4ee223e5 | 585 | } |
76be6fc2 | 586 | |
66eaf2eb | 587 | if (syncState->stats) |
76be6fc2 | 588 | { |
66eaf2eb BP |
589 | rttKey.saddr= |
590 | message->inE->event.tcpEvent->segmentKey->connectionKey.saddr; | |
591 | rttKey.daddr= | |
592 | message->inE->event.tcpEvent->segmentKey->connectionKey.daddr; | |
593 | rtt= g_hash_table_lookup(analysisData->rttInfo, &rttKey); | |
594 | g_debug("rttInfo, looking up (%u, %u)->(%f)", rttKey.saddr, | |
595 | rttKey.daddr, rtt ? *rtt : NAN); | |
596 | ||
597 | if (rtt) | |
76be6fc2 | 598 | { |
66eaf2eb BP |
599 | g_debug("rttInfo, tt: %f rtt / 2: %f", tt, *rtt / 2.); |
600 | if (tt < *rtt / 2.) | |
601 | { | |
602 | messageStats->tooFastNb++; | |
603 | } | |
604 | } | |
605 | else | |
606 | { | |
607 | messageStats->noRTTInfoNb++; | |
76be6fc2 BP |
608 | } |
609 | } | |
66eaf2eb BP |
610 | |
611 | if (syncState->graphsStream) | |
612 | { | |
613 | updateBounds(analysisData->graphs->bounds, message->inE, | |
614 | message->outE); | |
615 | } | |
cdce23b3 BP |
616 | } |
617 | ||
618 | ||
619 | /* | |
620 | * Perform analysis on multiple messages | |
621 | * | |
76be6fc2 BP |
622 | * Measure the RTT |
623 | * | |
cdce23b3 BP |
624 | * Args: |
625 | * syncState container for synchronization data | |
626 | * exchange structure containing the messages | |
627 | */ | |
66eaf2eb BP |
628 | static void analyzeExchangeEval(SyncState* const syncState, Exchange* const |
629 | exchange) | |
cdce23b3 | 630 | { |
d4721e1a BP |
631 | AnalysisDataEval* analysisData= syncState->analysisData; |
632 | Message* m1= g_queue_peek_tail(exchange->acks); | |
633 | Message* m2= exchange->message; | |
634 | struct RttKey* rttKey; | |
635 | double* rtt, * exchangeRtt; | |
cdce23b3 | 636 | |
e072e1ab BP |
637 | g_assert(m1->inE->type == TCP); |
638 | ||
d4721e1a BP |
639 | // (T2 - T1) - (T3 - T4) |
640 | rtt= malloc(sizeof(double)); | |
641 | *rtt= wallTimeSub(&m1->inE->wallTime, &m1->outE->wallTime) - | |
642 | wallTimeSub(&m2->outE->wallTime, &m2->inE->wallTime); | |
643 | ||
d4721e1a BP |
644 | rttKey= malloc(sizeof(struct RttKey)); |
645 | rttKey->saddr= | |
646 | MIN(m1->inE->event.tcpEvent->segmentKey->connectionKey.saddr, | |
647 | m1->inE->event.tcpEvent->segmentKey->connectionKey.daddr); | |
648 | rttKey->daddr= | |
649 | MAX(m1->inE->event.tcpEvent->segmentKey->connectionKey.saddr, | |
650 | m1->inE->event.tcpEvent->segmentKey->connectionKey.daddr); | |
e072e1ab BP |
651 | |
652 | if (syncState->graphsStream) | |
653 | { | |
66eaf2eb BP |
654 | AnalysisHistogramEval* histogram= |
655 | g_hash_table_lookup(analysisData->graphs->histograms, rttKey); | |
e072e1ab | 656 | |
66eaf2eb | 657 | if (histogram == NULL) |
e072e1ab BP |
658 | { |
659 | struct RttKey* tableKey= malloc(sizeof(*tableKey)); | |
660 | ||
66eaf2eb BP |
661 | histogram= constructAnalysisHistogramEval(syncState->graphsDir, |
662 | rttKey); | |
e072e1ab | 663 | memcpy(tableKey, rttKey, sizeof(*tableKey)); |
66eaf2eb BP |
664 | g_hash_table_insert(analysisData->graphs->histograms, tableKey, |
665 | histogram); | |
e072e1ab BP |
666 | } |
667 | ||
66eaf2eb | 668 | hitBin(&histogram->hrttBins, *rtt / 2); |
e072e1ab BP |
669 | } |
670 | ||
66eaf2eb | 671 | if (syncState->stats) |
d4721e1a | 672 | { |
66eaf2eb BP |
673 | exchangeRtt= g_hash_table_lookup(analysisData->stats->exchangeRtt, |
674 | rttKey); | |
675 | ||
676 | if (exchangeRtt) | |
d4721e1a | 677 | { |
66eaf2eb BP |
678 | if (*rtt < *exchangeRtt) |
679 | { | |
680 | g_hash_table_replace(analysisData->stats->exchangeRtt, rttKey, rtt); | |
681 | } | |
682 | else | |
683 | { | |
684 | free(rttKey); | |
685 | free(rtt); | |
686 | } | |
687 | } | |
688 | else | |
689 | { | |
690 | g_hash_table_insert(analysisData->stats->exchangeRtt, rttKey, rtt); | |
d4721e1a BP |
691 | } |
692 | } | |
693 | else | |
694 | { | |
66eaf2eb BP |
695 | free(rttKey); |
696 | free(rtt); | |
d4721e1a | 697 | } |
cdce23b3 BP |
698 | } |
699 | ||
700 | ||
701 | /* | |
702 | * Perform analysis on muliple events | |
703 | * | |
76be6fc2 BP |
704 | * Sum the broadcast differential delays |
705 | * | |
cdce23b3 BP |
706 | * Args: |
707 | * syncState container for synchronization data | |
708 | * broadcast structure containing the events | |
709 | */ | |
66eaf2eb BP |
710 | static void analyzeBroadcastEval(SyncState* const syncState, Broadcast* const |
711 | broadcast) | |
cdce23b3 | 712 | { |
66eaf2eb | 713 | AnalysisDataEval* analysisData= syncState->analysisData; |
76be6fc2 | 714 | |
66eaf2eb | 715 | if (syncState->stats) |
76be6fc2 | 716 | { |
66eaf2eb BP |
717 | double sum= 0, squaresSum= 0; |
718 | double y; | |
cdce23b3 | 719 | |
66eaf2eb BP |
720 | g_queue_foreach(broadcast->events, &gfSum, &sum); |
721 | g_queue_foreach(broadcast->events, &gfSumSquares, &squaresSum); | |
76be6fc2 | 722 | |
66eaf2eb BP |
723 | analysisData->stats->broadcastNb++; |
724 | // Because of numerical errors, this can at times be < 0 | |
725 | y= squaresSum / g_queue_get_length(broadcast->events) - pow(sum / | |
726 | g_queue_get_length(broadcast->events), 2.); | |
727 | if (y > 0) | |
728 | { | |
2849af52 BP |
729 | analysisData->stats->broadcastStdevSum+= sqrt(y); |
730 | } | |
731 | ||
732 | if (syncState->traceNb == 2 && g_queue_get_length(broadcast->events) | |
733 | == 2) | |
734 | { | |
735 | Event* e0, * e1; | |
736 | double dd; | |
737 | ||
738 | e0= g_queue_peek_head(broadcast->events); | |
739 | e1= g_queue_peek_tail(broadcast->events); | |
740 | if (e0->traceNum > e1->traceNum) | |
741 | { | |
742 | Event* tmp; | |
743 | ||
744 | tmp= e0; | |
745 | e0= e1; | |
746 | e1= tmp; | |
747 | } | |
748 | ||
749 | dd= wallTimeSub(&e1->wallTime, &e0->wallTime); | |
750 | ||
751 | analysisData->stats->broadcastPairNb++; | |
752 | if (dd < analysisData->stats->broadcastRangeMin) | |
753 | { | |
754 | analysisData->stats->broadcastRangeMin= dd; | |
755 | } | |
756 | if (dd > analysisData->stats->broadcastRangeMax) | |
757 | { | |
758 | analysisData->stats->broadcastRangeMax= dd; | |
759 | } | |
760 | ||
761 | analysisData->stats->broadcastSum+= dd; | |
762 | analysisData->stats->broadcastSumSquares+= pow(dd, 2); | |
66eaf2eb BP |
763 | } |
764 | } | |
76be6fc2 | 765 | |
66eaf2eb | 766 | if (syncState->graphsStream) |
76be6fc2 | 767 | { |
66eaf2eb BP |
768 | unsigned int i, j; |
769 | GArray* events; | |
770 | unsigned int eventNb= broadcast->events->length; | |
771 | ||
772 | events= g_array_sized_new(FALSE, FALSE, sizeof(Event*), eventNb); | |
773 | g_queue_foreach(broadcast->events, &gfAddEventToArray, events); | |
774 | ||
775 | for (i= 0; i < eventNb; i++) | |
776 | { | |
777 | for (j= 0; j < eventNb; j++) | |
778 | { | |
779 | Event* eventI= g_array_index(events, Event*, i), * eventJ= | |
780 | g_array_index(events, Event*, j); | |
781 | ||
782 | if (eventI->traceNum < eventJ->traceNum) | |
783 | { | |
784 | updateBounds(analysisData->graphs->bounds, eventI, eventJ); | |
785 | } | |
786 | } | |
787 | } | |
788 | ||
789 | g_array_free(events, TRUE); | |
76be6fc2 | 790 | } |
cdce23b3 BP |
791 | } |
792 | ||
793 | ||
794 | /* | |
66eaf2eb | 795 | * Finalize the factor calculations. Since this module does not really |
0a87ec9a | 796 | * calculate factors, absent factors are returned. Instead, histograms are |
66eaf2eb | 797 | * written out and histogram structures are freed. |
cdce23b3 BP |
798 | * |
799 | * Args: | |
800 | * syncState container for synchronization data. | |
801 | * | |
802 | * Returns: | |
0a87ec9a | 803 | * AllFactors* synchronization factors for each trace pair |
cdce23b3 | 804 | */ |
0a87ec9a | 805 | static AllFactors* finalizeAnalysisEval(SyncState* const syncState) |
cdce23b3 | 806 | { |
4ee223e5 BP |
807 | AnalysisDataEval* analysisData= syncState->analysisData; |
808 | ||
66eaf2eb | 809 | if (syncState->graphsStream && analysisData->graphs->histograms) |
4ee223e5 | 810 | { |
66eaf2eb BP |
811 | g_hash_table_foreach(analysisData->graphs->histograms, |
812 | &ghfWriteHistogram, &(struct WriteHistogramInfo) {.rttInfo= | |
813 | analysisData->rttInfo, .graphsStream= syncState->graphsStream}); | |
814 | g_hash_table_destroy(analysisData->graphs->histograms); | |
815 | analysisData->graphs->histograms= NULL; | |
4ee223e5 | 816 | } |
cdce23b3 | 817 | |
0a87ec9a | 818 | return createAllFactors(syncState->traceNb); |
cdce23b3 BP |
819 | } |
820 | ||
821 | ||
822 | /* | |
823 | * Print statistics related to analysis. Must be called after | |
824 | * finalizeAnalysis. | |
825 | * | |
826 | * Args: | |
827 | * syncState container for synchronization data. | |
828 | */ | |
829 | static void printAnalysisStatsEval(SyncState* const syncState) | |
830 | { | |
831 | AnalysisDataEval* analysisData; | |
f109919b BP |
832 | unsigned int i, j, k; |
833 | unsigned int totInversion= 0, totTooFast= 0, totNoInfo= 0, totTotal= 0; | |
834 | int charNb; | |
cdce23b3 BP |
835 | |
836 | if (!syncState->stats) | |
837 | { | |
838 | return; | |
839 | } | |
840 | ||
841 | analysisData= (AnalysisDataEval*) syncState->analysisData; | |
842 | ||
843 | printf("Synchronization evaluation analysis stats:\n"); | |
ffa21cfd BP |
844 | if (analysisData->stats->broadcastNb) |
845 | { | |
2849af52 BP |
846 | printf("\tBroadcast differential delay:\n"); |
847 | printf("\t\tsum of standard deviations: %g\n", | |
848 | analysisData->stats->broadcastStdevSum); | |
849 | printf("\t\taverage standard deviation: %g\n", | |
850 | analysisData->stats->broadcastStdevSum / | |
ffa21cfd | 851 | analysisData->stats->broadcastNb); |
2849af52 BP |
852 | |
853 | if (syncState->traceNb == 2) | |
854 | { | |
855 | printf("\t\tdifferential delay range: [ %g .. %g ]\n", | |
856 | analysisData->stats->broadcastRangeMin, | |
857 | analysisData->stats->broadcastRangeMax); | |
858 | printf("\t\tdifferential delay average: %g\n", | |
859 | analysisData->stats->broadcastSum / | |
860 | analysisData->stats->broadcastPairNb); | |
861 | printf("\t\tdifferential delay standard deviation: %g\n", | |
862 | sqrt(analysisData->stats->broadcastSumSquares / | |
863 | analysisData->stats->broadcastPairNb - | |
864 | pow(analysisData->stats->broadcastSum / | |
865 | analysisData->stats->broadcastPairNb, 2))); | |
866 | } | |
ffa21cfd | 867 | } |
cdce23b3 BP |
868 | |
869 | printf("\tIndividual evaluation:\n" | |
f109919b | 870 | "\t\tTrace pair Inversions Too fast No RTT info Total\n"); |
cdce23b3 BP |
871 | |
872 | for (i= 0; i < syncState->traceNb; i++) | |
873 | { | |
874 | for (j= i + 1; j < syncState->traceNb; j++) | |
875 | { | |
76be6fc2 | 876 | MessageStats* messageStats; |
f109919b BP |
877 | struct { |
878 | unsigned int t1, t2; | |
879 | } loopValues[]= { | |
880 | {i, j}, | |
881 | {j, i} | |
882 | }; | |
883 | ||
884 | for (k= 0; k < sizeof(loopValues) / sizeof(*loopValues); k++) | |
885 | { | |
886 | messageStats= | |
887 | &analysisData->stats->messageStats[loopValues[k].t1][loopValues[k].t2]; | |
888 | ||
889 | printf("\t\t%3d - %-3d ", loopValues[k].t1, loopValues[k].t2); | |
2849af52 BP |
890 | printf("%u (%.2f%%)%n", messageStats->inversionNb, (double) |
891 | messageStats->inversionNb / messageStats->total * 100, | |
892 | &charNb); | |
f109919b | 893 | printf("%*s", 17 - charNb > 0 ? 17 - charNb + 1: 1, " "); |
2849af52 BP |
894 | printf("%u (%.2f%%)%n", messageStats->tooFastNb, (double) |
895 | messageStats->tooFastNb / messageStats->total * 100, | |
896 | &charNb); | |
f109919b BP |
897 | printf("%*s%-10u %u\n", 17 - charNb > 0 ? 17 - charNb + 1: |
898 | 1, " ", messageStats->noRTTInfoNb, messageStats->total); | |
899 | ||
900 | totInversion+= messageStats->inversionNb; | |
901 | totTooFast+= messageStats->tooFastNb; | |
902 | totNoInfo+= messageStats->noRTTInfoNb; | |
903 | totTotal+= messageStats->total; | |
904 | } | |
cdce23b3 BP |
905 | } |
906 | } | |
d4721e1a | 907 | |
f109919b | 908 | printf("\t\t total "); |
2849af52 BP |
909 | printf("%u (%.2f%%)%n", totInversion, (double) totInversion / totTotal * |
910 | 100, &charNb); | |
f109919b | 911 | printf("%*s", 17 - charNb > 0 ? 17 - charNb + 1: 1, " "); |
2849af52 BP |
912 | printf("%u (%.2f%%)%n", totTooFast, (double) totTooFast / totTotal * 100, |
913 | &charNb); | |
f109919b BP |
914 | printf("%*s%-10u %u\n", 17 - charNb > 0 ? 17 - charNb + 1: 1, " ", |
915 | totNoInfo, totTotal); | |
916 | ||
d4721e1a BP |
917 | printf("\tRound-trip times:\n" |
918 | "\t\tHost pair RTT from exchanges RTTs from file (ms)\n"); | |
919 | g_hash_table_foreach(analysisData->stats->exchangeRtt, | |
920 | &ghfPrintExchangeRtt, analysisData->rttInfo); | |
921 | } | |
922 | ||
923 | ||
924 | /* | |
925 | * A GHFunc for g_hash_table_foreach() | |
926 | * | |
927 | * Args: | |
928 | * key: RttKey* where saddr < daddr | |
929 | * value: double*, RTT estimated from exchanges | |
930 | * user_data GHashTable* rttInfo | |
931 | */ | |
66eaf2eb BP |
932 | static void ghfPrintExchangeRtt(gpointer key, gpointer value, gpointer |
933 | user_data) | |
d4721e1a BP |
934 | { |
935 | char addr1[16], addr2[16]; | |
936 | struct RttKey* rttKey1= key; | |
937 | struct RttKey rttKey2= {rttKey1->daddr, rttKey1->saddr}; | |
938 | double* fileRtt1, *fileRtt2; | |
939 | GHashTable* rttInfo= user_data; | |
940 | ||
941 | convertIP(addr1, rttKey1->saddr); | |
942 | convertIP(addr2, rttKey1->daddr); | |
943 | ||
944 | fileRtt1= g_hash_table_lookup(rttInfo, rttKey1); | |
945 | fileRtt2= g_hash_table_lookup(rttInfo, &rttKey2); | |
946 | ||
947 | printf("\t\t(%15s, %-15s) %-18.3f ", addr1, addr2, *(double*) value * 1e3); | |
948 | ||
949 | if (fileRtt1 || fileRtt2) | |
950 | { | |
951 | if (fileRtt1) | |
952 | { | |
953 | printf("%.3f", *fileRtt1 * 1e3); | |
954 | } | |
955 | if (fileRtt1 && fileRtt2) | |
956 | { | |
957 | printf(", "); | |
958 | } | |
959 | if (fileRtt2) | |
960 | { | |
961 | printf("%.3f", *fileRtt2 * 1e3); | |
962 | } | |
963 | } | |
964 | else | |
965 | { | |
966 | printf("-"); | |
967 | } | |
968 | printf("\n"); | |
cdce23b3 | 969 | } |
2bd4b3e4 BP |
970 | |
971 | ||
972 | /* | |
973 | * A GHashFunc for g_hash_table_new() | |
974 | * | |
975 | * Args: | |
976 | * key struct RttKey* | |
977 | */ | |
978 | static guint ghfRttKeyHash(gconstpointer key) | |
979 | { | |
980 | struct RttKey* rttKey; | |
981 | uint32_t a, b, c; | |
982 | ||
983 | rttKey= (struct RttKey*) key; | |
984 | ||
985 | a= rttKey->saddr; | |
986 | b= rttKey->daddr; | |
987 | c= 0; | |
988 | final(a, b, c); | |
989 | ||
990 | return c; | |
991 | } | |
992 | ||
993 | ||
994 | /* | |
995 | * A GDestroyNotify function for g_hash_table_new_full() | |
996 | * | |
997 | * Args: | |
998 | * data: struct RttKey* | |
999 | */ | |
1000 | static void gdnDestroyRttKey(gpointer data) | |
1001 | { | |
1002 | free(data); | |
1003 | } | |
1004 | ||
1005 | ||
1006 | /* | |
1007 | * A GDestroyNotify function for g_hash_table_new_full() | |
1008 | * | |
1009 | * Args: | |
1010 | * data: double* | |
1011 | */ | |
1012 | static void gdnDestroyDouble(gpointer data) | |
1013 | { | |
1014 | free(data); | |
1015 | } | |
1016 | ||
1017 | ||
1018 | /* | |
1019 | * A GEqualFunc for g_hash_table_new() | |
1020 | * | |
1021 | * Args: | |
1022 | * a, b RttKey* | |
1023 | * | |
1024 | * Returns: | |
1025 | * TRUE if both values are equal | |
1026 | */ | |
1027 | static gboolean gefRttKeyEqual(gconstpointer a, gconstpointer b) | |
1028 | { | |
1029 | const struct RttKey* rkA, * rkB; | |
1030 | ||
1031 | rkA= (struct RttKey*) a; | |
1032 | rkB= (struct RttKey*) b; | |
1033 | ||
1034 | if (rkA->saddr == rkB->saddr && rkA->daddr == rkB->daddr) | |
1035 | { | |
1036 | return TRUE; | |
1037 | } | |
1038 | else | |
1039 | { | |
1040 | return FALSE; | |
1041 | } | |
1042 | } | |
1043 | ||
1044 | ||
1045 | /* | |
1046 | * Read a file contain minimum round trip time values and fill an array with | |
1047 | * them. The file is formatted as such: | |
1048 | * <host1 IP> <host2 IP> <RTT in milliseconds> | |
1049 | * ip's should be in dotted quad format | |
1050 | * | |
1051 | * Args: | |
1052 | * rttInfo: double* rttInfo[RttKey], empty table, will be filled | |
1053 | * rttStream: stream from which to read | |
1054 | */ | |
1055 | static void readRttInfo(GHashTable* rttInfo, FILE* rttStream) | |
1056 | { | |
1057 | char* line= NULL; | |
1058 | size_t len; | |
1059 | int retval; | |
1060 | ||
1061 | positionStream(rttStream); | |
1062 | retval= getline(&line, &len, rttStream); | |
1063 | while(!feof(rttStream)) | |
1064 | { | |
1065 | struct RttKey* rttKey; | |
1066 | char saddrDQ[20], daddrDQ[20]; | |
1067 | double* rtt; | |
1068 | char tmp; | |
1069 | struct in_addr addr; | |
1070 | unsigned int i; | |
1071 | struct { | |
1072 | char* dq; | |
1073 | size_t offset; | |
1074 | } loopValues[] = { | |
1075 | {saddrDQ, offsetof(struct RttKey, saddr)}, | |
1076 | {daddrDQ, offsetof(struct RttKey, daddr)} | |
1077 | }; | |
1078 | ||
1079 | if (retval == -1 && !feof(rttStream)) | |
1080 | { | |
1081 | g_error(strerror(errno)); | |
1082 | } | |
1083 | ||
1084 | if (line[retval - 1] == '\n') | |
1085 | { | |
1086 | line[retval - 1]= '\0'; | |
1087 | } | |
1088 | ||
1089 | rtt= malloc(sizeof(double)); | |
1090 | retval= sscanf(line, " %19s %19s %lf %c", saddrDQ, daddrDQ, rtt, | |
1091 | &tmp); | |
1092 | if (retval == EOF) | |
1093 | { | |
1094 | g_error(strerror(errno)); | |
1095 | } | |
1096 | else if (retval != 3) | |
1097 | { | |
1098 | g_error("Error parsing RTT file, line was '%s'", line); | |
1099 | } | |
1100 | ||
1101 | rttKey= malloc(sizeof(struct RttKey)); | |
1102 | for (i= 0; i < sizeof(loopValues) / sizeof(*loopValues); i++) | |
1103 | { | |
1104 | retval= inet_aton(loopValues[i].dq, &addr); | |
1105 | if (retval == 0) | |
1106 | { | |
1107 | g_error("Error converting address '%s'", loopValues[i].dq); | |
1108 | } | |
1109 | *(uint32_t*) ((void*) rttKey + loopValues[i].offset)= | |
1110 | addr.s_addr; | |
1111 | } | |
1112 | ||
76be6fc2 | 1113 | *rtt/= 1e3; |
d4721e1a BP |
1114 | g_debug("rttInfo, Inserting (%u, %u)->(%f)", rttKey->saddr, |
1115 | rttKey->daddr, *rtt); | |
2bd4b3e4 BP |
1116 | g_hash_table_insert(rttInfo, rttKey, rtt); |
1117 | ||
1118 | positionStream(rttStream); | |
1119 | retval= getline(&line, &len, rttStream); | |
1120 | } | |
1121 | ||
1122 | if (line) | |
1123 | { | |
1124 | free(line); | |
1125 | } | |
1126 | } | |
1127 | ||
1128 | ||
1129 | /* | |
1130 | * Advance stream over empty space, empty lines and lines that begin with '#' | |
1131 | * | |
1132 | * Args: | |
1133 | * stream: stream, at exit, will be over the first non-empty character | |
1134 | * of a line of be at EOF | |
1135 | */ | |
1136 | static void positionStream(FILE* stream) | |
1137 | { | |
1138 | int firstChar; | |
1139 | ssize_t retval; | |
1140 | char* line= NULL; | |
1141 | size_t len; | |
1142 | ||
1143 | do | |
1144 | { | |
1145 | firstChar= fgetc(stream); | |
1146 | if (firstChar == (int) '#') | |
1147 | { | |
1148 | retval= getline(&line, &len, stream); | |
1149 | if (retval == -1) | |
1150 | { | |
1151 | if (feof(stream)) | |
1152 | { | |
1153 | goto outEof; | |
1154 | } | |
1155 | else | |
1156 | { | |
1157 | g_error(strerror(errno)); | |
1158 | } | |
1159 | } | |
1160 | } | |
1161 | else if (firstChar == (int) '\n' || firstChar == (int) ' ' || | |
1162 | firstChar == (int) '\t') | |
1163 | {} | |
1164 | else if (firstChar == EOF) | |
1165 | { | |
1166 | goto outEof; | |
1167 | } | |
1168 | else | |
1169 | { | |
1170 | break; | |
1171 | } | |
1172 | } while (true); | |
1173 | retval= ungetc(firstChar, stream); | |
1174 | if (retval == EOF) | |
1175 | { | |
1176 | g_error("Error: ungetc()"); | |
1177 | } | |
1178 | ||
1179 | outEof: | |
1180 | if (line) | |
1181 | { | |
1182 | free(line); | |
1183 | } | |
1184 | } | |
76be6fc2 BP |
1185 | |
1186 | ||
1187 | /* | |
1188 | * A GFunc for g_queue_foreach() | |
1189 | * | |
1190 | * Args: | |
1191 | * data Event*, a UDP broadcast event | |
1192 | * user_data double*, the running sum | |
1193 | * | |
1194 | * Returns: | |
1195 | * Adds the time of the event to the sum | |
1196 | */ | |
1197 | static void gfSum(gpointer data, gpointer userData) | |
1198 | { | |
1199 | Event* event= (Event*) data; | |
1200 | ||
1201 | *(double*) userData+= event->wallTime.seconds + event->wallTime.nanosec / | |
1202 | 1e9; | |
1203 | } | |
1204 | ||
1205 | ||
1206 | /* | |
1207 | * A GFunc for g_queue_foreach() | |
1208 | * | |
1209 | * Args: | |
1210 | * data Event*, a UDP broadcast event | |
1211 | * user_data double*, the running sum | |
1212 | * | |
1213 | * Returns: | |
1214 | * Adds the square of the time of the event to the sum | |
1215 | */ | |
1216 | static void gfSumSquares(gpointer data, gpointer userData) | |
1217 | { | |
1218 | Event* event= (Event*) data; | |
1219 | ||
1220 | *(double*) userData+= pow(event->wallTime.seconds + event->wallTime.nanosec | |
1221 | / 1e9, 2.); | |
1222 | } | |
4ee223e5 BP |
1223 | |
1224 | ||
e072e1ab BP |
1225 | /* |
1226 | * Update a struct Bins according to a new value | |
1227 | * | |
1228 | * Args: | |
1229 | * bins: the structure containing bins to build a histrogram | |
1230 | * value: the new value | |
1231 | */ | |
1232 | static void hitBin(struct Bins* const bins, const double value) | |
1233 | { | |
1234 | unsigned int binN= binNum(value); | |
1235 | ||
1236 | if (binN < bins->min) | |
1237 | { | |
1238 | bins->min= binN; | |
1239 | } | |
1240 | else if (binN > bins->max) | |
1241 | { | |
1242 | bins->max= binN; | |
1243 | } | |
1244 | ||
1245 | bins->total++; | |
1246 | ||
1247 | bins->bin[binN]++; | |
1248 | } | |
1249 | ||
1250 | ||
4ee223e5 BP |
1251 | /* |
1252 | * Figure out the bin in a histogram to which a value belongs. | |
1253 | * | |
1254 | * This uses exponentially sized bins that go from 0 to infinity. | |
1255 | * | |
1256 | * Args: | |
e072e1ab BP |
1257 | * value: in the range -INFINITY to INFINITY |
1258 | * | |
1259 | * Returns: | |
1260 | * The number of the bin in a struct Bins.bin | |
4ee223e5 BP |
1261 | */ |
1262 | static unsigned int binNum(const double value) | |
1263 | { | |
e072e1ab | 1264 | if (value <= 0) |
4ee223e5 BP |
1265 | { |
1266 | return 0; | |
1267 | } | |
e072e1ab BP |
1268 | else if (value < binEnd(1)) |
1269 | { | |
1270 | return 1; | |
1271 | } | |
1272 | else if (value >= binStart(BIN_NB - 1)) | |
1273 | { | |
1274 | return BIN_NB - 1; | |
1275 | } | |
4ee223e5 BP |
1276 | else |
1277 | { | |
e072e1ab | 1278 | return floor(log(value) / log(binBase)) + BIN_NB + 1; |
4ee223e5 BP |
1279 | } |
1280 | } | |
1281 | ||
1282 | ||
1283 | /* | |
e072e1ab BP |
1284 | * Figure out the start of the interval of a bin in a histogram. See struct |
1285 | * Bins. | |
4ee223e5 BP |
1286 | * |
1287 | * This uses exponentially sized bins that go from 0 to infinity. | |
1288 | * | |
1289 | * Args: | |
1290 | * binNum: bin number | |
e072e1ab BP |
1291 | * |
1292 | * Return: | |
1293 | * The start of the interval, this value is included in the interval (except | |
1294 | * for -INFINITY, naturally) | |
4ee223e5 BP |
1295 | */ |
1296 | static double binStart(const unsigned int binNum) | |
1297 | { | |
e072e1ab | 1298 | g_assert_cmpuint(binNum, <, BIN_NB); |
4ee223e5 BP |
1299 | |
1300 | if (binNum == 0) | |
1301 | { | |
e072e1ab BP |
1302 | return -INFINITY; |
1303 | } | |
1304 | else if (binNum == 1) | |
1305 | { | |
1306 | return 0.; | |
4ee223e5 BP |
1307 | } |
1308 | else | |
1309 | { | |
e072e1ab | 1310 | return pow(binBase, (double) binNum - BIN_NB + 1); |
4ee223e5 BP |
1311 | } |
1312 | } | |
1313 | ||
1314 | ||
1315 | /* | |
e072e1ab BP |
1316 | * Figure out the end of the interval of a bin in a histogram. See struct |
1317 | * Bins. | |
4ee223e5 BP |
1318 | * |
1319 | * This uses exponentially sized bins that go from 0 to infinity. | |
1320 | * | |
1321 | * Args: | |
1322 | * binNum: bin number | |
e072e1ab BP |
1323 | * |
1324 | * Return: | |
1325 | * The end of the interval, this value is not included in the interval | |
4ee223e5 BP |
1326 | */ |
1327 | static double binEnd(const unsigned int binNum) | |
1328 | { | |
e072e1ab | 1329 | g_assert_cmpuint(binNum, <, BIN_NB); |
4ee223e5 | 1330 | |
e072e1ab | 1331 | if (binNum == 0) |
4ee223e5 | 1332 | { |
e072e1ab BP |
1333 | return 0.; |
1334 | } | |
1335 | else if (binNum < BIN_NB - 1) | |
1336 | { | |
1337 | return pow(binBase, (double) binNum - BIN_NB + 2); | |
4ee223e5 BP |
1338 | } |
1339 | else | |
1340 | { | |
1341 | return INFINITY; | |
1342 | } | |
1343 | } | |
467066ee BP |
1344 | |
1345 | ||
1346 | /* | |
1347 | * Return the total number of elements in the "normal" bins (not underflow or | |
1348 | * overflow) | |
1349 | * | |
1350 | * Args: | |
1351 | * bins: the structure containing bins to build a histrogram | |
1352 | */ | |
1353 | static uint32_t normalTotal(struct Bins* const bins) | |
1354 | { | |
1355 | return bins->total - bins->bin[0] - bins->bin[BIN_NB - 1]; | |
1356 | } | |
66eaf2eb BP |
1357 | |
1358 | ||
1359 | /* Update the bounds between two traces | |
1360 | * | |
1361 | * Args: | |
1362 | * bounds: the array containing all the trace-pair bounds | |
1363 | * e1, e2: the two related events | |
1364 | */ | |
c6356aa7 BP |
1365 | static void updateBounds(Bounds** const bounds, Event* const e1, Event* const |
1366 | e2) | |
66eaf2eb BP |
1367 | { |
1368 | unsigned int traceI, traceJ; | |
1369 | uint64_t messageTime; | |
1370 | Bounds* tpBounds; | |
1371 | ||
1372 | if (e1->traceNum < e2->traceNum) | |
1373 | { | |
1374 | traceI= e2->traceNum; | |
1375 | traceJ= e1->traceNum; | |
1376 | messageTime= e1->cpuTime; | |
1377 | } | |
1378 | else | |
1379 | { | |
1380 | traceI= e1->traceNum; | |
1381 | traceJ= e2->traceNum; | |
1382 | messageTime= e2->cpuTime; | |
1383 | } | |
1384 | tpBounds= &bounds[traceI][traceJ]; | |
1385 | ||
1386 | if (messageTime < tpBounds->min) | |
1387 | { | |
1388 | tpBounds->min= messageTime; | |
1389 | } | |
1390 | if (messageTime > tpBounds->max) | |
1391 | { | |
1392 | tpBounds->max= messageTime; | |
1393 | } | |
1394 | } |