1 /* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2009 Benjamin Poirier <benjamin.poirier@polymtl.ca>
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;
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.
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,
20 #define _ISOC99_SOURCE
26 #include <arpa/inet.h>
29 #include <netinet/in.h>
34 #include <sys/socket.h>
38 #include "sync_chain.h"
40 #include "event_analysis_eval.h"
50 // Functions common to all analysis modules
51 static void initAnalysisEval(SyncState
* const syncState
);
52 static void destroyAnalysisEval(SyncState
* const syncState
);
54 static void analyzeMessageEval(SyncState
* const syncState
, Message
* const
56 static void analyzeExchangeEval(SyncState
* const syncState
, Exchange
* const
58 static void analyzeBroadcastEval(SyncState
* const syncState
, Broadcast
* const
60 static GArray
* finalizeAnalysisEval(SyncState
* const syncState
);
61 static void printAnalysisStatsEval(SyncState
* const syncState
);
63 // Functions specific to this module
64 static void registerAnalysisEval() __attribute__((constructor (102)));
65 static guint
ghfRttKeyHash(gconstpointer key
);
66 static gboolean
gefRttKeyEqual(gconstpointer a
, gconstpointer b
);
67 static void gdnDestroyRttKey(gpointer data
);
68 static void gdnDestroyDouble(gpointer data
);
69 static void readRttInfo(GHashTable
* rttInfo
, FILE* rttFile
);
70 static void positionStream(FILE* stream
);
72 static void gfSum(gpointer data
, gpointer userData
);
73 static void gfSumSquares(gpointer data
, gpointer userData
);
74 static void ghfPrintExchangeRtt(gpointer key
, gpointer value
, gpointer user_data
);
76 static void hitBin(struct Bins
* const bins
, const double value
);
77 static unsigned int binNum(const double value
) __attribute__((pure
));
78 static double binStart(const unsigned int binNum
) __attribute__((pure
));
79 static double binEnd(const unsigned int binNum
) __attribute__((pure
));
81 static AnalysisGraphEval
* constructAnalysisGraphEval(const char* const
82 graphsDir
, const struct RttKey
* const rttKey
);
83 static void destroyAnalysisGraphEval(AnalysisGraphEval
* const graph
);
84 static void gdnDestroyAnalysisGraphEval(gpointer data
);
85 static void ghfWriteGraph(gpointer key
, gpointer value
, gpointer user_data
);
86 static void dumpBinToFile(const struct Bins
* const bins
, FILE* const file
);
87 static void writeHistogram(FILE* graphsStream
, const struct RttKey
* rttKey
,
93 static AnalysisModule analysisModuleEval
= {
95 .initAnalysis
= &initAnalysisEval
,
96 .destroyAnalysis
= &destroyAnalysisEval
,
97 .analyzeMessage
= &analyzeMessageEval
,
98 .analyzeExchange
= &analyzeExchangeEval
,
99 .analyzeBroadcast
= &analyzeBroadcastEval
,
100 .finalizeAnalysis
= &finalizeAnalysisEval
,
101 .printAnalysisStats
= &printAnalysisStatsEval
,
102 .writeAnalysisGraphsPlots
= NULL
,
103 .writeAnalysisGraphsOptions
= NULL
,
106 static ModuleOption optionEvalRttFile
= {
107 .longName
= "eval-rtt-file",
108 .hasArg
= REQUIRED_ARG
,
110 .optionHelp
= "specify the file containing RTT information",
116 * Analysis module registering function
118 static void registerAnalysisEval()
120 g_queue_push_tail(&analysisModules
, &analysisModuleEval
);
121 g_queue_push_tail(&moduleOptions
, &optionEvalRttFile
);
126 * Analysis init function
128 * This function is called at the beginning of a synchronization run for a set
132 * syncState container for synchronization data.
134 static void initAnalysisEval(SyncState
* const syncState
)
136 AnalysisDataEval
* analysisData
;
139 analysisData
= malloc(sizeof(AnalysisDataEval
));
140 syncState
->analysisData
= analysisData
;
142 analysisData
->rttInfo
= g_hash_table_new_full(&ghfRttKeyHash
,
143 &gefRttKeyEqual
, &gdnDestroyRttKey
, &gdnDestroyDouble
);
144 if (optionEvalRttFile
.arg
)
149 rttStream
= fopen(optionEvalRttFile
.arg
, "r");
150 if (rttStream
== NULL
)
152 g_error(strerror(errno
));
155 readRttInfo(analysisData
->rttInfo
, rttStream
);
157 retval
= fclose(rttStream
);
160 g_error(strerror(errno
));
164 if (syncState
->stats
)
166 analysisData
->stats
= calloc(1, sizeof(AnalysisStatsEval
));
167 analysisData
->stats
->broadcastDiffSum
= 0.;
169 analysisData
->stats
->messageStats
= malloc(syncState
->traceNb
*
170 sizeof(MessageStats
*));
171 for (i
= 0; i
< syncState
->traceNb
; i
++)
173 analysisData
->stats
->messageStats
[i
]= calloc(syncState
->traceNb
,
174 sizeof(MessageStats
));
177 analysisData
->stats
->exchangeRtt
=
178 g_hash_table_new_full(&ghfRttKeyHash
, &gefRttKeyEqual
,
179 &gdnDestroyRttKey
, &gdnDestroyDouble
);
182 if (syncState
->graphsStream
)
184 binBase
= exp10(6. / (BIN_NB
- 3));
185 analysisData
->graphs
= g_hash_table_new_full(&ghfRttKeyHash
,
186 &gefRttKeyEqual
, &gdnDestroyRttKey
, &gdnDestroyAnalysisGraphEval
);
192 * Create and open files used to store histogram points to generate graphs.
193 * Create data structures to store histogram points during analysis.
196 * graphsDir: folder where to write files
197 * rttKey: host pair, make sure saddr < daddr
199 static AnalysisGraphEval
* constructAnalysisGraphEval(const char* const
200 graphsDir
, const struct RttKey
* const rttKey
)
205 char name
[60], saddr
[16], daddr
[16];
206 AnalysisGraphEval
* graph
= calloc(1, sizeof(*graph
));
209 const char* fileName
;
210 const char* host1
, *host2
;
212 {offsetof(AnalysisGraphEval
, ttSendPoints
), "analysis_eval_tt-%s_to_%s.data",
214 {offsetof(AnalysisGraphEval
, ttRecvPoints
), "analysis_eval_tt-%s_to_%s.data",
216 {offsetof(AnalysisGraphEval
, hrttPoints
), "analysis_eval_hrtt-%s_and_%s.data",
220 graph
->ttSendBins
.max
= BIN_NB
- 1;
221 graph
->ttRecvBins
.max
= BIN_NB
- 1;
222 graph
->hrttBins
.max
= BIN_NB
- 1;
224 convertIP(saddr
, rttKey
->saddr
);
225 convertIP(daddr
, rttKey
->daddr
);
227 cwd
= changeToGraphDir(graphsDir
);
229 for (i
= 0; i
< sizeof(loopValues
) / sizeof(*loopValues
); i
++)
231 retval
= snprintf(name
, sizeof(name
), loopValues
[i
].fileName
,
232 loopValues
[i
].host1
, loopValues
[i
].host2
);
233 if (retval
> sizeof(name
) - 1)
235 name
[sizeof(name
) - 1]= '\0';
237 if ((*(FILE**)((void*) graph
+ loopValues
[i
].pointsOffset
)=
238 fopen(name
, "w")) == NULL
)
240 g_error(strerror(errno
));
247 g_error(strerror(errno
));
256 * Close files used to store histogram points to generate graphs.
259 * graphsDir: folder where to write files
260 * rttKey: host pair, make sure saddr < daddr
262 static void destroyAnalysisGraphEval(AnalysisGraphEval
* const graph
)
269 {offsetof(AnalysisGraphEval
, ttSendPoints
)},
270 {offsetof(AnalysisGraphEval
, ttRecvPoints
)},
271 {offsetof(AnalysisGraphEval
, hrttPoints
)},
274 for (i
= 0; i
< sizeof(loopValues
) / sizeof(*loopValues
); i
++)
276 retval
= fclose(*(FILE**)((void*) graph
+ loopValues
[i
].pointsOffset
));
279 g_error(strerror(errno
));
286 * A GDestroyNotify function for g_hash_table_new_full()
289 * data: AnalysisGraphEval*
291 static void gdnDestroyAnalysisGraphEval(gpointer data
)
293 destroyAnalysisGraphEval(data
);
298 * A GHFunc for g_hash_table_foreach()
301 * key: RttKey* where saddr < daddr
302 * value: AnalysisGraphEval*
303 * user_data struct WriteGraphInfo*
305 static void ghfWriteGraph(gpointer key
, gpointer value
, gpointer user_data
)
307 double* rtt1
, * rtt2
;
308 struct RttKey
* rttKey
= key
;
309 struct RttKey oppositeRttKey
= {.saddr
= rttKey
->daddr
, .daddr
=
311 AnalysisGraphEval
* graph
= value
;
312 struct WriteGraphInfo
* info
= user_data
;
314 rtt1
= g_hash_table_lookup(info
->rttInfo
, rttKey
);
315 rtt2
= g_hash_table_lookup(info
->rttInfo
, &oppositeRttKey
);
321 else if (rtt2
!= NULL
)
323 rtt1
= MIN(rtt1
, rtt2
);
326 dumpBinToFile(&graph
->ttSendBins
, graph
->ttSendPoints
);
327 dumpBinToFile(&graph
->ttRecvBins
, graph
->ttRecvPoints
);
328 dumpBinToFile(&graph
->hrttBins
, graph
->hrttPoints
);
329 writeHistogram(info
->graphsStream
, rttKey
, rtt1
);
334 * Write the content of one bin in a histogram point file
337 * bin: array of values that make up a histogram
338 * file: FILE*, write to this file
340 static void dumpBinToFile(const struct Bins
* const bins
, FILE* const file
)
344 // The first and last bins are skipped, see struct Bins
345 for (i
= 1; i
< BIN_NB
- 1; i
++)
347 if (bins
->bin
[i
] > 0)
349 fprintf(file
, "%20.9f %20.9f %20.9f\n", (binStart(i
) + binEnd(i
))
350 / 2., (double) bins
->bin
[i
] / ((binEnd(i
) - binStart(i
)) *
351 bins
->total
), binEnd(i
) - binStart(i
));
358 * Write the analysis-specific plot in the gnuplot script.
361 * graphsStream: write to this file
362 * rttKey: must be sorted such that saddr < daddr
363 * minRtt: if available, else NULL
365 static void writeHistogram(FILE* graphsStream
, const struct RttKey
* rttKey
,
368 char saddr
[16], daddr
[16];
370 convertIP(saddr
, rttKey
->saddr
);
371 convertIP(daddr
, rttKey
->daddr
);
373 fprintf(graphsStream
,
375 "set output \"histogram-%s-%s.eps\"\n"
377 "set xlabel \"Message Latency (s)\"\n"
378 "set ylabel \"Proportion of messages per second\"\n", saddr
, daddr
);
382 fprintf(graphsStream
,
383 "set arrow from %.9f, 0 rto 0, graph 1 "
384 "nohead linetype 3 linewidth 3 linecolor rgb \"black\"\n", *minRtt
/ 2);
387 fprintf(graphsStream
,
389 "\t\"analysis_eval_hrtt-%1$s_and_%2$s.data\" "
390 "title \"RTT/2\" with linespoints linetype 1 linewidth 2 "
391 "linecolor rgb \"black\" pointtype 6 pointsize 1,\\\n"
392 "\t\"analysis_eval_tt-%1$s_to_%2$s.data\" "
393 "title \"%1$s to %2$s\" with linespoints linetype 4 linewidth 2 "
394 "linecolor rgb \"gray60\" pointtype 6 pointsize 1,\\\n"
395 "\t\"analysis_eval_tt-%2$s_to_%1$s.data\" "
396 "title \"%2$s to %1$s\" with linespoints linetype 4 linewidth 2 "
397 "linecolor rgb \"gray30\" pointtype 6 pointsize 1\n", saddr
, daddr
);
402 * Analysis destroy function
404 * Free the analysis specific data structures
407 * syncState container for synchronization data.
409 static void destroyAnalysisEval(SyncState
* const syncState
)
412 AnalysisDataEval
* analysisData
;
414 analysisData
= (AnalysisDataEval
*) syncState
->analysisData
;
416 if (analysisData
== NULL
|| analysisData
->rttInfo
== NULL
)
421 g_hash_table_destroy(analysisData
->rttInfo
);
422 analysisData
->rttInfo
= NULL
;
424 if (syncState
->stats
)
426 for (i
= 0; i
< syncState
->traceNb
; i
++)
428 free(analysisData
->stats
->messageStats
[i
]);
430 free(analysisData
->stats
->messageStats
);
432 g_hash_table_destroy(analysisData
->stats
->exchangeRtt
);
434 free(analysisData
->stats
);
437 if (syncState
->graphsStream
&& analysisData
->graphs
)
439 g_hash_table_destroy(analysisData
->graphs
);
442 free(syncState
->analysisData
);
443 syncState
->analysisData
= NULL
;
448 * Perform analysis on an event pair.
450 * Check if there is message inversion or messages that are too fast.
453 * syncState container for synchronization data
454 * message structure containing the events
456 static void analyzeMessageEval(SyncState
* const syncState
, Message
* const message
)
458 AnalysisDataEval
* analysisData
= syncState
->analysisData
;
459 MessageStats
* messageStats
=
460 &analysisData
->stats
->messageStats
[message
->outE
->traceNum
][message
->inE
->traceNum
];;
463 struct RttKey rttKey
;
465 if (!syncState
->stats
)
470 g_assert(message
->inE
->type
== TCP
);
472 messageStats
->total
++;
474 tt
= wallTimeSub(&message
->inE
->wallTime
, &message
->outE
->wallTime
);
477 messageStats
->inversionNb
++;
479 else if (syncState
->graphsStream
)
481 struct RttKey rttKey
= {
482 .saddr
=MIN(message
->inE
->event
.tcpEvent
->segmentKey
->connectionKey
.saddr
,
483 message
->inE
->event
.tcpEvent
->segmentKey
->connectionKey
.daddr
),
484 .daddr
=MAX(message
->inE
->event
.tcpEvent
->segmentKey
->connectionKey
.saddr
,
485 message
->inE
->event
.tcpEvent
->segmentKey
->connectionKey
.daddr
),
487 AnalysisGraphEval
* graph
= g_hash_table_lookup(analysisData
->graphs
,
492 struct RttKey
* tableKey
= malloc(sizeof(*tableKey
));
494 graph
= constructAnalysisGraphEval(syncState
->graphsDir
, &rttKey
);
495 memcpy(tableKey
, &rttKey
, sizeof(*tableKey
));
496 g_hash_table_insert(analysisData
->graphs
, tableKey
, graph
);
499 if (message
->inE
->event
.udpEvent
->datagramKey
->saddr
<
500 message
->inE
->event
.udpEvent
->datagramKey
->daddr
)
502 hitBin(&graph
->ttSendBins
, tt
);
506 hitBin(&graph
->ttRecvBins
, tt
);
511 message
->inE
->event
.tcpEvent
->segmentKey
->connectionKey
.saddr
;
513 message
->inE
->event
.tcpEvent
->segmentKey
->connectionKey
.daddr
;
514 rtt
= g_hash_table_lookup(analysisData
->rttInfo
, &rttKey
);
515 g_debug("rttInfo, looking up (%u, %u)->(%f)", rttKey
.saddr
,
516 rttKey
.daddr
, rtt
? *rtt
: NAN
);
520 g_debug("rttInfo, tt: %f rtt / 2: %f", tt
, *rtt
/ 2.);
523 messageStats
->tooFastNb
++;
528 messageStats
->noRTTInfoNb
++;
534 * Perform analysis on multiple messages
539 * syncState container for synchronization data
540 * exchange structure containing the messages
542 static void analyzeExchangeEval(SyncState
* const syncState
, Exchange
* const exchange
)
544 AnalysisDataEval
* analysisData
= syncState
->analysisData
;
545 Message
* m1
= g_queue_peek_tail(exchange
->acks
);
546 Message
* m2
= exchange
->message
;
547 struct RttKey
* rttKey
;
548 double* rtt
, * exchangeRtt
;
550 if (!syncState
->stats
)
555 g_assert(m1
->inE
->type
== TCP
);
557 // (T2 - T1) - (T3 - T4)
558 rtt
= malloc(sizeof(double));
559 *rtt
= wallTimeSub(&m1
->inE
->wallTime
, &m1
->outE
->wallTime
) -
560 wallTimeSub(&m2
->outE
->wallTime
, &m2
->inE
->wallTime
);
562 rttKey
= malloc(sizeof(struct RttKey
));
564 MIN(m1
->inE
->event
.tcpEvent
->segmentKey
->connectionKey
.saddr
,
565 m1
->inE
->event
.tcpEvent
->segmentKey
->connectionKey
.daddr
);
567 MAX(m1
->inE
->event
.tcpEvent
->segmentKey
->connectionKey
.saddr
,
568 m1
->inE
->event
.tcpEvent
->segmentKey
->connectionKey
.daddr
);
570 if (syncState
->graphsStream
)
572 AnalysisGraphEval
* graph
= g_hash_table_lookup(analysisData
->graphs
,
577 struct RttKey
* tableKey
= malloc(sizeof(*tableKey
));
579 graph
= constructAnalysisGraphEval(syncState
->graphsDir
, rttKey
);
580 memcpy(tableKey
, rttKey
, sizeof(*tableKey
));
581 g_hash_table_insert(analysisData
->graphs
, tableKey
, graph
);
584 hitBin(&graph
->hrttBins
, *rtt
/ 2);
587 exchangeRtt
= g_hash_table_lookup(analysisData
->stats
->exchangeRtt
,
592 if (*rtt
< *exchangeRtt
)
594 g_hash_table_replace(analysisData
->stats
->exchangeRtt
, rttKey
, rtt
);
599 g_hash_table_insert(analysisData
->stats
->exchangeRtt
, rttKey
, rtt
);
605 * Perform analysis on muliple events
607 * Sum the broadcast differential delays
610 * syncState container for synchronization data
611 * broadcast structure containing the events
613 static void analyzeBroadcastEval(SyncState
* const syncState
, Broadcast
* const broadcast
)
615 AnalysisDataEval
* analysisData
;
616 double sum
= 0, squaresSum
= 0;
619 if (!syncState
->stats
)
624 analysisData
= (AnalysisDataEval
*) syncState
->analysisData
;
626 g_queue_foreach(broadcast
->events
, &gfSum
, &sum
);
627 g_queue_foreach(broadcast
->events
, &gfSumSquares
, &squaresSum
);
629 analysisData
->stats
->broadcastNb
++;
630 // Because of numerical errors, this can at times be < 0
631 y
= squaresSum
/ g_queue_get_length(broadcast
->events
) - pow(sum
/
632 g_queue_get_length(broadcast
->events
), 2.);
635 analysisData
->stats
->broadcastDiffSum
+= sqrt(y
);
641 * Finalize the factor calculations
643 * Since this module does not really calculate factors, identity factors are
647 * syncState container for synchronization data.
650 * Factors[traceNb] identity factors for each trace
652 static GArray
* finalizeAnalysisEval(SyncState
* const syncState
)
656 AnalysisDataEval
* analysisData
= syncState
->analysisData
;
658 if (syncState
->graphsStream
&& analysisData
->graphs
)
660 g_hash_table_foreach(analysisData
->graphs
, &ghfWriteGraph
, &(struct
661 WriteGraphInfo
) {.rttInfo
= analysisData
->rttInfo
,
662 .graphsStream
= syncState
->graphsStream
});
663 g_hash_table_destroy(analysisData
->graphs
);
664 analysisData
->graphs
= NULL
;
667 factors
= g_array_sized_new(FALSE
, FALSE
, sizeof(Factors
),
669 g_array_set_size(factors
, syncState
->traceNb
);
670 for (i
= 0; i
< syncState
->traceNb
; i
++)
674 e
= &g_array_index(factors
, Factors
, i
);
684 * Print statistics related to analysis. Must be called after
688 * syncState container for synchronization data.
690 static void printAnalysisStatsEval(SyncState
* const syncState
)
692 AnalysisDataEval
* analysisData
;
693 unsigned int i
, j
, k
;
694 unsigned int totInversion
= 0, totTooFast
= 0, totNoInfo
= 0, totTotal
= 0;
697 if (!syncState
->stats
)
702 analysisData
= (AnalysisDataEval
*) syncState
->analysisData
;
704 printf("Synchronization evaluation analysis stats:\n");
705 if (analysisData
->stats
->broadcastNb
)
707 printf("\tsum of broadcast differential delays: %g\n",
708 analysisData
->stats
->broadcastDiffSum
);
709 printf("\taverage broadcast differential delays: %g\n",
710 analysisData
->stats
->broadcastDiffSum
/
711 analysisData
->stats
->broadcastNb
);
714 printf("\tIndividual evaluation:\n"
715 "\t\tTrace pair Inversions Too fast No RTT info Total\n");
717 for (i
= 0; i
< syncState
->traceNb
; i
++)
719 for (j
= i
+ 1; j
< syncState
->traceNb
; j
++)
721 MessageStats
* messageStats
;
729 for (k
= 0; k
< sizeof(loopValues
) / sizeof(*loopValues
); k
++)
732 &analysisData
->stats
->messageStats
[loopValues
[k
].t1
][loopValues
[k
].t2
];
734 printf("\t\t%3d - %-3d ", loopValues
[k
].t1
, loopValues
[k
].t2
);
735 printf("%u (%u%%)%n", messageStats
->inversionNb
, (unsigned
736 int) ceil((double) messageStats
->inversionNb
/
737 messageStats
->total
* 100), &charNb
);
738 printf("%*s", 17 - charNb
> 0 ? 17 - charNb
+ 1: 1, " ");
739 printf("%u (%u%%)%n", messageStats
->tooFastNb
, (unsigned int)
740 ceil((double) messageStats
->tooFastNb
/
741 messageStats
->total
* 100), &charNb
);
742 printf("%*s%-10u %u\n", 17 - charNb
> 0 ? 17 - charNb
+ 1:
743 1, " ", messageStats
->noRTTInfoNb
, messageStats
->total
);
745 totInversion
+= messageStats
->inversionNb
;
746 totTooFast
+= messageStats
->tooFastNb
;
747 totNoInfo
+= messageStats
->noRTTInfoNb
;
748 totTotal
+= messageStats
->total
;
753 printf("\t\t total ");
754 printf("%u (%u%%)%n", totInversion
, (unsigned int) ceil((double)
755 totInversion
/ totTotal
* 100), &charNb
);
756 printf("%*s", 17 - charNb
> 0 ? 17 - charNb
+ 1: 1, " ");
757 printf("%u (%u%%)%n", totTooFast
, (unsigned int) ceil((double) totTooFast
758 / totTotal
* 100), &charNb
);
759 printf("%*s%-10u %u\n", 17 - charNb
> 0 ? 17 - charNb
+ 1: 1, " ",
760 totNoInfo
, totTotal
);
762 printf("\tRound-trip times:\n"
763 "\t\tHost pair RTT from exchanges RTTs from file (ms)\n");
764 g_hash_table_foreach(analysisData
->stats
->exchangeRtt
,
765 &ghfPrintExchangeRtt
, analysisData
->rttInfo
);
770 * A GHFunc for g_hash_table_foreach()
773 * key: RttKey* where saddr < daddr
774 * value: double*, RTT estimated from exchanges
775 * user_data GHashTable* rttInfo
777 static void ghfPrintExchangeRtt(gpointer key
, gpointer value
, gpointer user_data
)
779 char addr1
[16], addr2
[16];
780 struct RttKey
* rttKey1
= key
;
781 struct RttKey rttKey2
= {rttKey1
->daddr
, rttKey1
->saddr
};
782 double* fileRtt1
, *fileRtt2
;
783 GHashTable
* rttInfo
= user_data
;
785 convertIP(addr1
, rttKey1
->saddr
);
786 convertIP(addr2
, rttKey1
->daddr
);
788 fileRtt1
= g_hash_table_lookup(rttInfo
, rttKey1
);
789 fileRtt2
= g_hash_table_lookup(rttInfo
, &rttKey2
);
791 printf("\t\t(%15s, %-15s) %-18.3f ", addr1
, addr2
, *(double*) value
* 1e3
);
793 if (fileRtt1
|| fileRtt2
)
797 printf("%.3f", *fileRtt1
* 1e3
);
799 if (fileRtt1
&& fileRtt2
)
805 printf("%.3f", *fileRtt2
* 1e3
);
817 * A GHashFunc for g_hash_table_new()
822 static guint
ghfRttKeyHash(gconstpointer key
)
824 struct RttKey
* rttKey
;
827 rttKey
= (struct RttKey
*) key
;
839 * A GDestroyNotify function for g_hash_table_new_full()
842 * data: struct RttKey*
844 static void gdnDestroyRttKey(gpointer data
)
851 * A GDestroyNotify function for g_hash_table_new_full()
856 static void gdnDestroyDouble(gpointer data
)
863 * A GEqualFunc for g_hash_table_new()
869 * TRUE if both values are equal
871 static gboolean
gefRttKeyEqual(gconstpointer a
, gconstpointer b
)
873 const struct RttKey
* rkA
, * rkB
;
875 rkA
= (struct RttKey
*) a
;
876 rkB
= (struct RttKey
*) b
;
878 if (rkA
->saddr
== rkB
->saddr
&& rkA
->daddr
== rkB
->daddr
)
890 * Read a file contain minimum round trip time values and fill an array with
891 * them. The file is formatted as such:
892 * <host1 IP> <host2 IP> <RTT in milliseconds>
893 * ip's should be in dotted quad format
896 * rttInfo: double* rttInfo[RttKey], empty table, will be filled
897 * rttStream: stream from which to read
899 static void readRttInfo(GHashTable
* rttInfo
, FILE* rttStream
)
905 positionStream(rttStream
);
906 retval
= getline(&line
, &len
, rttStream
);
907 while(!feof(rttStream
))
909 struct RttKey
* rttKey
;
910 char saddrDQ
[20], daddrDQ
[20];
919 {saddrDQ
, offsetof(struct RttKey
, saddr
)},
920 {daddrDQ
, offsetof(struct RttKey
, daddr
)}
923 if (retval
== -1 && !feof(rttStream
))
925 g_error(strerror(errno
));
928 if (line
[retval
- 1] == '\n')
930 line
[retval
- 1]= '\0';
933 rtt
= malloc(sizeof(double));
934 retval
= sscanf(line
, " %19s %19s %lf %c", saddrDQ
, daddrDQ
, rtt
,
938 g_error(strerror(errno
));
940 else if (retval
!= 3)
942 g_error("Error parsing RTT file, line was '%s'", line
);
945 rttKey
= malloc(sizeof(struct RttKey
));
946 for (i
= 0; i
< sizeof(loopValues
) / sizeof(*loopValues
); i
++)
948 retval
= inet_aton(loopValues
[i
].dq
, &addr
);
951 g_error("Error converting address '%s'", loopValues
[i
].dq
);
953 *(uint32_t*) ((void*) rttKey
+ loopValues
[i
].offset
)=
958 g_debug("rttInfo, Inserting (%u, %u)->(%f)", rttKey
->saddr
,
959 rttKey
->daddr
, *rtt
);
960 g_hash_table_insert(rttInfo
, rttKey
, rtt
);
962 positionStream(rttStream
);
963 retval
= getline(&line
, &len
, rttStream
);
974 * Advance stream over empty space, empty lines and lines that begin with '#'
977 * stream: stream, at exit, will be over the first non-empty character
978 * of a line of be at EOF
980 static void positionStream(FILE* stream
)
989 firstChar
= fgetc(stream
);
990 if (firstChar
== (int) '#')
992 retval
= getline(&line
, &len
, stream
);
1001 g_error(strerror(errno
));
1005 else if (firstChar
== (int) '\n' || firstChar
== (int) ' ' ||
1006 firstChar
== (int) '\t')
1008 else if (firstChar
== EOF
)
1017 retval
= ungetc(firstChar
, stream
);
1020 g_error("Error: ungetc()");
1032 * A GFunc for g_queue_foreach()
1035 * data Event*, a UDP broadcast event
1036 * user_data double*, the running sum
1039 * Adds the time of the event to the sum
1041 static void gfSum(gpointer data
, gpointer userData
)
1043 Event
* event
= (Event
*) data
;
1045 *(double*) userData
+= event
->wallTime
.seconds
+ event
->wallTime
.nanosec
/
1051 * A GFunc for g_queue_foreach()
1054 * data Event*, a UDP broadcast event
1055 * user_data double*, the running sum
1058 * Adds the square of the time of the event to the sum
1060 static void gfSumSquares(gpointer data
, gpointer userData
)
1062 Event
* event
= (Event
*) data
;
1064 *(double*) userData
+= pow(event
->wallTime
.seconds
+ event
->wallTime
.nanosec
1070 * Update a struct Bins according to a new value
1073 * bins: the structure containing bins to build a histrogram
1074 * value: the new value
1076 static void hitBin(struct Bins
* const bins
, const double value
)
1078 unsigned int binN
= binNum(value
);
1080 if (binN
< bins
->min
)
1084 else if (binN
> bins
->max
)
1096 * Figure out the bin in a histogram to which a value belongs.
1098 * This uses exponentially sized bins that go from 0 to infinity.
1101 * value: in the range -INFINITY to INFINITY
1104 * The number of the bin in a struct Bins.bin
1106 static unsigned int binNum(const double value
)
1112 else if (value
< binEnd(1))
1116 else if (value
>= binStart(BIN_NB
- 1))
1122 return floor(log(value
) / log(binBase
)) + BIN_NB
+ 1;
1128 * Figure out the start of the interval of a bin in a histogram. See struct
1131 * This uses exponentially sized bins that go from 0 to infinity.
1134 * binNum: bin number
1137 * The start of the interval, this value is included in the interval (except
1138 * for -INFINITY, naturally)
1140 static double binStart(const unsigned int binNum
)
1142 g_assert_cmpuint(binNum
, <, BIN_NB
);
1148 else if (binNum
== 1)
1154 return pow(binBase
, (double) binNum
- BIN_NB
+ 1);
1160 * Figure out the end of the interval of a bin in a histogram. See struct
1163 * This uses exponentially sized bins that go from 0 to infinity.
1166 * binNum: bin number
1169 * The end of the interval, this value is not included in the interval
1171 static double binEnd(const unsigned int binNum
)
1173 g_assert_cmpuint(binNum
, <, BIN_NB
);
1179 else if (binNum
< BIN_NB
- 1)
1181 return pow(binBase
, (double) binNum
- BIN_NB
+ 2);