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
));
80 static uint32_t normalTotal(struct Bins
* const bins
) __attribute__((const));
82 static AnalysisGraphEval
* constructAnalysisGraphEval(const char* const
83 graphsDir
, const struct RttKey
* const rttKey
);
84 static void destroyAnalysisGraphEval(AnalysisGraphEval
* const graph
);
85 static void gdnDestroyAnalysisGraphEval(gpointer data
);
86 static void ghfWriteGraph(gpointer key
, gpointer value
, gpointer user_data
);
87 static void dumpBinToFile(const struct Bins
* const bins
, FILE* const file
);
88 static void writeHistogram(FILE* graphsStream
, const struct RttKey
* rttKey
,
89 double* minRtt
, AnalysisGraphEval
* const graph
);
94 static AnalysisModule analysisModuleEval
= {
96 .initAnalysis
= &initAnalysisEval
,
97 .destroyAnalysis
= &destroyAnalysisEval
,
98 .analyzeMessage
= &analyzeMessageEval
,
99 .analyzeExchange
= &analyzeExchangeEval
,
100 .analyzeBroadcast
= &analyzeBroadcastEval
,
101 .finalizeAnalysis
= &finalizeAnalysisEval
,
102 .printAnalysisStats
= &printAnalysisStatsEval
,
105 static ModuleOption optionEvalRttFile
= {
106 .longName
= "eval-rtt-file",
107 .hasArg
= REQUIRED_ARG
,
109 .optionHelp
= "specify the file containing RTT information",
115 * Analysis module registering function
117 static void registerAnalysisEval()
119 g_queue_push_tail(&analysisModules
, &analysisModuleEval
);
120 g_queue_push_tail(&moduleOptions
, &optionEvalRttFile
);
125 * Analysis init function
127 * This function is called at the beginning of a synchronization run for a set
131 * syncState container for synchronization data.
133 static void initAnalysisEval(SyncState
* const syncState
)
135 AnalysisDataEval
* analysisData
;
138 analysisData
= malloc(sizeof(AnalysisDataEval
));
139 syncState
->analysisData
= analysisData
;
141 analysisData
->rttInfo
= g_hash_table_new_full(&ghfRttKeyHash
,
142 &gefRttKeyEqual
, &gdnDestroyRttKey
, &gdnDestroyDouble
);
143 if (optionEvalRttFile
.arg
)
148 rttStream
= fopen(optionEvalRttFile
.arg
, "r");
149 if (rttStream
== NULL
)
151 g_error(strerror(errno
));
154 readRttInfo(analysisData
->rttInfo
, rttStream
);
156 retval
= fclose(rttStream
);
159 g_error(strerror(errno
));
163 if (syncState
->stats
)
165 analysisData
->stats
= calloc(1, sizeof(AnalysisStatsEval
));
166 analysisData
->stats
->broadcastDiffSum
= 0.;
168 analysisData
->stats
->messageStats
= malloc(syncState
->traceNb
*
169 sizeof(MessageStats
*));
170 for (i
= 0; i
< syncState
->traceNb
; i
++)
172 analysisData
->stats
->messageStats
[i
]= calloc(syncState
->traceNb
,
173 sizeof(MessageStats
));
176 analysisData
->stats
->exchangeRtt
=
177 g_hash_table_new_full(&ghfRttKeyHash
, &gefRttKeyEqual
,
178 &gdnDestroyRttKey
, &gdnDestroyDouble
);
181 if (syncState
->graphsStream
)
183 binBase
= exp10(6. / (BIN_NB
- 3));
184 analysisData
->graphs
= g_hash_table_new_full(&ghfRttKeyHash
,
185 &gefRttKeyEqual
, &gdnDestroyRttKey
, &gdnDestroyAnalysisGraphEval
);
191 * Create and open files used to store histogram points to generate graphs.
192 * Create data structures to store histogram points during analysis.
195 * graphsDir: folder where to write files
196 * rttKey: host pair, make sure saddr < daddr
198 static AnalysisGraphEval
* constructAnalysisGraphEval(const char* const
199 graphsDir
, const struct RttKey
* const rttKey
)
204 char name
[60], saddr
[16], daddr
[16];
205 AnalysisGraphEval
* graph
= calloc(1, sizeof(*graph
));
208 const char* fileName
;
209 const char* host1
, *host2
;
211 {offsetof(AnalysisGraphEval
, ttSendPoints
), "analysis_eval_tt-%s_to_%s.data",
213 {offsetof(AnalysisGraphEval
, ttRecvPoints
), "analysis_eval_tt-%s_to_%s.data",
215 {offsetof(AnalysisGraphEval
, hrttPoints
), "analysis_eval_hrtt-%s_and_%s.data",
219 graph
->ttSendBins
.max
= BIN_NB
- 1;
220 graph
->ttRecvBins
.max
= BIN_NB
- 1;
221 graph
->hrttBins
.max
= BIN_NB
- 1;
223 convertIP(saddr
, rttKey
->saddr
);
224 convertIP(daddr
, rttKey
->daddr
);
226 cwd
= changeToGraphDir(graphsDir
);
228 for (i
= 0; i
< sizeof(loopValues
) / sizeof(*loopValues
); i
++)
230 retval
= snprintf(name
, sizeof(name
), loopValues
[i
].fileName
,
231 loopValues
[i
].host1
, loopValues
[i
].host2
);
232 if (retval
> sizeof(name
) - 1)
234 name
[sizeof(name
) - 1]= '\0';
236 if ((*(FILE**)((void*) graph
+ loopValues
[i
].pointsOffset
)=
237 fopen(name
, "w")) == NULL
)
239 g_error(strerror(errno
));
246 g_error(strerror(errno
));
255 * Close files used to store histogram points to generate graphs.
258 * graphsDir: folder where to write files
259 * rttKey: host pair, make sure saddr < daddr
261 static void destroyAnalysisGraphEval(AnalysisGraphEval
* const graph
)
268 {offsetof(AnalysisGraphEval
, ttSendPoints
)},
269 {offsetof(AnalysisGraphEval
, ttRecvPoints
)},
270 {offsetof(AnalysisGraphEval
, hrttPoints
)},
273 for (i
= 0; i
< sizeof(loopValues
) / sizeof(*loopValues
); i
++)
275 retval
= fclose(*(FILE**)((void*) graph
+ loopValues
[i
].pointsOffset
));
278 g_error(strerror(errno
));
285 * A GDestroyNotify function for g_hash_table_new_full()
288 * data: AnalysisGraphEval*
290 static void gdnDestroyAnalysisGraphEval(gpointer data
)
292 destroyAnalysisGraphEval(data
);
297 * A GHFunc for g_hash_table_foreach()
300 * key: RttKey* where saddr < daddr
301 * value: AnalysisGraphEval*
302 * user_data struct WriteGraphInfo*
304 static void ghfWriteGraph(gpointer key
, gpointer value
, gpointer user_data
)
306 double* rtt1
, * rtt2
;
307 struct RttKey
* rttKey
= key
;
308 struct RttKey oppositeRttKey
= {.saddr
= rttKey
->daddr
, .daddr
=
310 AnalysisGraphEval
* graph
= value
;
311 struct WriteGraphInfo
* info
= user_data
;
313 rtt1
= g_hash_table_lookup(info
->rttInfo
, rttKey
);
314 rtt2
= g_hash_table_lookup(info
->rttInfo
, &oppositeRttKey
);
320 else if (rtt2
!= NULL
)
322 rtt1
= MIN(rtt1
, rtt2
);
325 dumpBinToFile(&graph
->ttSendBins
, graph
->ttSendPoints
);
326 dumpBinToFile(&graph
->ttRecvBins
, graph
->ttRecvPoints
);
327 dumpBinToFile(&graph
->hrttBins
, graph
->hrttPoints
);
328 writeHistogram(info
->graphsStream
, rttKey
, rtt1
, graph
);
333 * Write the content of one bin in a histogram point file
336 * bin: array of values that make up a histogram
337 * file: FILE*, write to this file
339 static void dumpBinToFile(const struct Bins
* const bins
, FILE* const file
)
343 // The first and last bins are skipped, see struct Bins
344 for (i
= 1; i
< BIN_NB
- 1; i
++)
346 if (bins
->bin
[i
] > 0)
348 fprintf(file
, "%20.9f %20.9f %20.9f\n", (binStart(i
) + binEnd(i
))
349 / 2., (double) bins
->bin
[i
] / ((binEnd(i
) - binStart(i
)) *
350 bins
->total
), binEnd(i
) - binStart(i
));
357 * Write the analysis-specific plot in the gnuplot script.
360 * graphsStream: write to this file
361 * rttKey: must be sorted such that saddr < daddr
362 * minRtt: if available, else NULL
363 * graph: struct that contains the bins for the pair of traces
364 * identified by rttKey
366 static void writeHistogram(FILE* graphsStream
, const struct RttKey
* rttKey
,
367 double* minRtt
, AnalysisGraphEval
* const graph
)
369 char saddr
[16], daddr
[16];
371 convertIP(saddr
, rttKey
->saddr
);
372 convertIP(daddr
, rttKey
->daddr
);
374 fprintf(graphsStream
,
376 "set output \"histogram-%s-%s.eps\"\n"
378 "set xlabel \"Message Latency (s)\"\n"
379 "set ylabel \"Proportion of messages per second\"\n", saddr
, daddr
);
383 fprintf(graphsStream
,
384 "set arrow from %.9f, 0 rto 0, graph 1 "
385 "nohead linetype 3 linewidth 3 linecolor rgb \"black\"\n", *minRtt
389 if (normalTotal(&graph
->ttSendBins
) || normalTotal(&graph
->ttRecvBins
) ||
390 normalTotal(&graph
->hrttBins
))
392 fprintf(graphsStream
, "plot \\\n");
394 if (normalTotal(&graph
->hrttBins
))
396 fprintf(graphsStream
,
397 "\t\"analysis_eval_hrtt-%s_and_%s.data\" "
398 "title \"RTT/2\" with linespoints linetype 1 linewidth 2 "
399 "linecolor rgb \"black\" pointtype 6 pointsize 1,\\\n",
403 if (normalTotal(&graph
->ttSendBins
))
405 fprintf(graphsStream
,
406 "\t\"analysis_eval_tt-%1$s_to_%2$s.data\" "
407 "title \"%1$s to %2$s\" with linespoints linetype 4 linewidth 2 "
408 "linecolor rgb \"gray60\" pointtype 6 pointsize 1,\\\n",
412 if (normalTotal(&graph
->ttRecvBins
))
414 fprintf(graphsStream
,
415 "\t\"analysis_eval_tt-%1$s_to_%2$s.data\" "
416 "title \"%1$s to %2$s\" with linespoints linetype 4 linewidth 2 "
417 "linecolor rgb \"gray30\" pointtype 6 pointsize 1,\\\n",
421 // Remove the ",\\\n" from the last graph plot line
422 if (ftruncate(fileno(graphsStream
), ftell(graphsStream
) - 3) == -1)
424 g_error(strerror(errno
));
426 if (fseek(graphsStream
, 0, SEEK_END
) == -1)
428 g_error(strerror(errno
));
430 fprintf(graphsStream
, "\n");
436 * Analysis destroy function
438 * Free the analysis specific data structures
441 * syncState container for synchronization data.
443 static void destroyAnalysisEval(SyncState
* const syncState
)
446 AnalysisDataEval
* analysisData
;
448 analysisData
= (AnalysisDataEval
*) syncState
->analysisData
;
450 if (analysisData
== NULL
|| analysisData
->rttInfo
== NULL
)
455 g_hash_table_destroy(analysisData
->rttInfo
);
456 analysisData
->rttInfo
= NULL
;
458 if (syncState
->stats
)
460 for (i
= 0; i
< syncState
->traceNb
; i
++)
462 free(analysisData
->stats
->messageStats
[i
]);
464 free(analysisData
->stats
->messageStats
);
466 g_hash_table_destroy(analysisData
->stats
->exchangeRtt
);
468 free(analysisData
->stats
);
471 if (syncState
->graphsStream
&& analysisData
->graphs
)
473 g_hash_table_destroy(analysisData
->graphs
);
476 free(syncState
->analysisData
);
477 syncState
->analysisData
= NULL
;
482 * Perform analysis on an event pair.
484 * Check if there is message inversion or messages that are too fast.
487 * syncState container for synchronization data
488 * message structure containing the events
490 static void analyzeMessageEval(SyncState
* const syncState
, Message
* const message
)
492 AnalysisDataEval
* analysisData
= syncState
->analysisData
;
493 MessageStats
* messageStats
=
494 &analysisData
->stats
->messageStats
[message
->outE
->traceNum
][message
->inE
->traceNum
];;
497 struct RttKey rttKey
;
499 if (!syncState
->stats
)
504 g_assert(message
->inE
->type
== TCP
);
506 messageStats
->total
++;
508 tt
= wallTimeSub(&message
->inE
->wallTime
, &message
->outE
->wallTime
);
511 messageStats
->inversionNb
++;
513 else if (syncState
->graphsStream
)
515 struct RttKey rttKey
= {
516 .saddr
=MIN(message
->inE
->event
.tcpEvent
->segmentKey
->connectionKey
.saddr
,
517 message
->inE
->event
.tcpEvent
->segmentKey
->connectionKey
.daddr
),
518 .daddr
=MAX(message
->inE
->event
.tcpEvent
->segmentKey
->connectionKey
.saddr
,
519 message
->inE
->event
.tcpEvent
->segmentKey
->connectionKey
.daddr
),
521 AnalysisGraphEval
* graph
= g_hash_table_lookup(analysisData
->graphs
,
526 struct RttKey
* tableKey
= malloc(sizeof(*tableKey
));
528 graph
= constructAnalysisGraphEval(syncState
->graphsDir
, &rttKey
);
529 memcpy(tableKey
, &rttKey
, sizeof(*tableKey
));
530 g_hash_table_insert(analysisData
->graphs
, tableKey
, graph
);
533 if (message
->inE
->event
.udpEvent
->datagramKey
->saddr
<
534 message
->inE
->event
.udpEvent
->datagramKey
->daddr
)
536 hitBin(&graph
->ttSendBins
, tt
);
540 hitBin(&graph
->ttRecvBins
, tt
);
545 message
->inE
->event
.tcpEvent
->segmentKey
->connectionKey
.saddr
;
547 message
->inE
->event
.tcpEvent
->segmentKey
->connectionKey
.daddr
;
548 rtt
= g_hash_table_lookup(analysisData
->rttInfo
, &rttKey
);
549 g_debug("rttInfo, looking up (%u, %u)->(%f)", rttKey
.saddr
,
550 rttKey
.daddr
, rtt
? *rtt
: NAN
);
554 g_debug("rttInfo, tt: %f rtt / 2: %f", tt
, *rtt
/ 2.);
557 messageStats
->tooFastNb
++;
562 messageStats
->noRTTInfoNb
++;
568 * Perform analysis on multiple messages
573 * syncState container for synchronization data
574 * exchange structure containing the messages
576 static void analyzeExchangeEval(SyncState
* const syncState
, Exchange
* const exchange
)
578 AnalysisDataEval
* analysisData
= syncState
->analysisData
;
579 Message
* m1
= g_queue_peek_tail(exchange
->acks
);
580 Message
* m2
= exchange
->message
;
581 struct RttKey
* rttKey
;
582 double* rtt
, * exchangeRtt
;
584 if (!syncState
->stats
)
589 g_assert(m1
->inE
->type
== TCP
);
591 // (T2 - T1) - (T3 - T4)
592 rtt
= malloc(sizeof(double));
593 *rtt
= wallTimeSub(&m1
->inE
->wallTime
, &m1
->outE
->wallTime
) -
594 wallTimeSub(&m2
->outE
->wallTime
, &m2
->inE
->wallTime
);
596 rttKey
= malloc(sizeof(struct RttKey
));
598 MIN(m1
->inE
->event
.tcpEvent
->segmentKey
->connectionKey
.saddr
,
599 m1
->inE
->event
.tcpEvent
->segmentKey
->connectionKey
.daddr
);
601 MAX(m1
->inE
->event
.tcpEvent
->segmentKey
->connectionKey
.saddr
,
602 m1
->inE
->event
.tcpEvent
->segmentKey
->connectionKey
.daddr
);
604 if (syncState
->graphsStream
)
606 AnalysisGraphEval
* graph
= g_hash_table_lookup(analysisData
->graphs
,
611 struct RttKey
* tableKey
= malloc(sizeof(*tableKey
));
613 graph
= constructAnalysisGraphEval(syncState
->graphsDir
, rttKey
);
614 memcpy(tableKey
, rttKey
, sizeof(*tableKey
));
615 g_hash_table_insert(analysisData
->graphs
, tableKey
, graph
);
618 hitBin(&graph
->hrttBins
, *rtt
/ 2);
621 exchangeRtt
= g_hash_table_lookup(analysisData
->stats
->exchangeRtt
,
626 if (*rtt
< *exchangeRtt
)
628 g_hash_table_replace(analysisData
->stats
->exchangeRtt
, rttKey
, rtt
);
633 g_hash_table_insert(analysisData
->stats
->exchangeRtt
, rttKey
, rtt
);
639 * Perform analysis on muliple events
641 * Sum the broadcast differential delays
644 * syncState container for synchronization data
645 * broadcast structure containing the events
647 static void analyzeBroadcastEval(SyncState
* const syncState
, Broadcast
* const broadcast
)
649 AnalysisDataEval
* analysisData
;
650 double sum
= 0, squaresSum
= 0;
653 if (!syncState
->stats
)
658 analysisData
= (AnalysisDataEval
*) syncState
->analysisData
;
660 g_queue_foreach(broadcast
->events
, &gfSum
, &sum
);
661 g_queue_foreach(broadcast
->events
, &gfSumSquares
, &squaresSum
);
663 analysisData
->stats
->broadcastNb
++;
664 // Because of numerical errors, this can at times be < 0
665 y
= squaresSum
/ g_queue_get_length(broadcast
->events
) - pow(sum
/
666 g_queue_get_length(broadcast
->events
), 2.);
669 analysisData
->stats
->broadcastDiffSum
+= sqrt(y
);
675 * Finalize the factor calculations
677 * Since this module does not really calculate factors, identity factors are
681 * syncState container for synchronization data.
684 * Factors[traceNb] identity factors for each trace
686 static GArray
* finalizeAnalysisEval(SyncState
* const syncState
)
690 AnalysisDataEval
* analysisData
= syncState
->analysisData
;
692 if (syncState
->graphsStream
&& analysisData
->graphs
)
694 g_hash_table_foreach(analysisData
->graphs
, &ghfWriteGraph
, &(struct
695 WriteGraphInfo
) {.rttInfo
= analysisData
->rttInfo
,
696 .graphsStream
= syncState
->graphsStream
});
697 g_hash_table_destroy(analysisData
->graphs
);
698 analysisData
->graphs
= NULL
;
701 factors
= g_array_sized_new(FALSE
, FALSE
, sizeof(Factors
),
703 g_array_set_size(factors
, syncState
->traceNb
);
704 for (i
= 0; i
< syncState
->traceNb
; i
++)
708 e
= &g_array_index(factors
, Factors
, i
);
718 * Print statistics related to analysis. Must be called after
722 * syncState container for synchronization data.
724 static void printAnalysisStatsEval(SyncState
* const syncState
)
726 AnalysisDataEval
* analysisData
;
727 unsigned int i
, j
, k
;
728 unsigned int totInversion
= 0, totTooFast
= 0, totNoInfo
= 0, totTotal
= 0;
731 if (!syncState
->stats
)
736 analysisData
= (AnalysisDataEval
*) syncState
->analysisData
;
738 printf("Synchronization evaluation analysis stats:\n");
739 if (analysisData
->stats
->broadcastNb
)
741 printf("\tsum of broadcast differential delays: %g\n",
742 analysisData
->stats
->broadcastDiffSum
);
743 printf("\taverage broadcast differential delay: %g\n",
744 analysisData
->stats
->broadcastDiffSum
/
745 analysisData
->stats
->broadcastNb
);
748 printf("\tIndividual evaluation:\n"
749 "\t\tTrace pair Inversions Too fast No RTT info Total\n");
751 for (i
= 0; i
< syncState
->traceNb
; i
++)
753 for (j
= i
+ 1; j
< syncState
->traceNb
; j
++)
755 MessageStats
* messageStats
;
763 for (k
= 0; k
< sizeof(loopValues
) / sizeof(*loopValues
); k
++)
766 &analysisData
->stats
->messageStats
[loopValues
[k
].t1
][loopValues
[k
].t2
];
768 printf("\t\t%3d - %-3d ", loopValues
[k
].t1
, loopValues
[k
].t2
);
769 printf("%u (%u%%)%n", messageStats
->inversionNb
, (unsigned
770 int) ceil((double) messageStats
->inversionNb
/
771 messageStats
->total
* 100), &charNb
);
772 printf("%*s", 17 - charNb
> 0 ? 17 - charNb
+ 1: 1, " ");
773 printf("%u (%u%%)%n", messageStats
->tooFastNb
, (unsigned int)
774 ceil((double) messageStats
->tooFastNb
/
775 messageStats
->total
* 100), &charNb
);
776 printf("%*s%-10u %u\n", 17 - charNb
> 0 ? 17 - charNb
+ 1:
777 1, " ", messageStats
->noRTTInfoNb
, messageStats
->total
);
779 totInversion
+= messageStats
->inversionNb
;
780 totTooFast
+= messageStats
->tooFastNb
;
781 totNoInfo
+= messageStats
->noRTTInfoNb
;
782 totTotal
+= messageStats
->total
;
787 printf("\t\t total ");
788 printf("%u (%u%%)%n", totInversion
, (unsigned int) ceil((double)
789 totInversion
/ totTotal
* 100), &charNb
);
790 printf("%*s", 17 - charNb
> 0 ? 17 - charNb
+ 1: 1, " ");
791 printf("%u (%u%%)%n", totTooFast
, (unsigned int) ceil((double) totTooFast
792 / totTotal
* 100), &charNb
);
793 printf("%*s%-10u %u\n", 17 - charNb
> 0 ? 17 - charNb
+ 1: 1, " ",
794 totNoInfo
, totTotal
);
796 printf("\tRound-trip times:\n"
797 "\t\tHost pair RTT from exchanges RTTs from file (ms)\n");
798 g_hash_table_foreach(analysisData
->stats
->exchangeRtt
,
799 &ghfPrintExchangeRtt
, analysisData
->rttInfo
);
804 * A GHFunc for g_hash_table_foreach()
807 * key: RttKey* where saddr < daddr
808 * value: double*, RTT estimated from exchanges
809 * user_data GHashTable* rttInfo
811 static void ghfPrintExchangeRtt(gpointer key
, gpointer value
, gpointer user_data
)
813 char addr1
[16], addr2
[16];
814 struct RttKey
* rttKey1
= key
;
815 struct RttKey rttKey2
= {rttKey1
->daddr
, rttKey1
->saddr
};
816 double* fileRtt1
, *fileRtt2
;
817 GHashTable
* rttInfo
= user_data
;
819 convertIP(addr1
, rttKey1
->saddr
);
820 convertIP(addr2
, rttKey1
->daddr
);
822 fileRtt1
= g_hash_table_lookup(rttInfo
, rttKey1
);
823 fileRtt2
= g_hash_table_lookup(rttInfo
, &rttKey2
);
825 printf("\t\t(%15s, %-15s) %-18.3f ", addr1
, addr2
, *(double*) value
* 1e3
);
827 if (fileRtt1
|| fileRtt2
)
831 printf("%.3f", *fileRtt1
* 1e3
);
833 if (fileRtt1
&& fileRtt2
)
839 printf("%.3f", *fileRtt2
* 1e3
);
851 * A GHashFunc for g_hash_table_new()
856 static guint
ghfRttKeyHash(gconstpointer key
)
858 struct RttKey
* rttKey
;
861 rttKey
= (struct RttKey
*) key
;
873 * A GDestroyNotify function for g_hash_table_new_full()
876 * data: struct RttKey*
878 static void gdnDestroyRttKey(gpointer data
)
885 * A GDestroyNotify function for g_hash_table_new_full()
890 static void gdnDestroyDouble(gpointer data
)
897 * A GEqualFunc for g_hash_table_new()
903 * TRUE if both values are equal
905 static gboolean
gefRttKeyEqual(gconstpointer a
, gconstpointer b
)
907 const struct RttKey
* rkA
, * rkB
;
909 rkA
= (struct RttKey
*) a
;
910 rkB
= (struct RttKey
*) b
;
912 if (rkA
->saddr
== rkB
->saddr
&& rkA
->daddr
== rkB
->daddr
)
924 * Read a file contain minimum round trip time values and fill an array with
925 * them. The file is formatted as such:
926 * <host1 IP> <host2 IP> <RTT in milliseconds>
927 * ip's should be in dotted quad format
930 * rttInfo: double* rttInfo[RttKey], empty table, will be filled
931 * rttStream: stream from which to read
933 static void readRttInfo(GHashTable
* rttInfo
, FILE* rttStream
)
939 positionStream(rttStream
);
940 retval
= getline(&line
, &len
, rttStream
);
941 while(!feof(rttStream
))
943 struct RttKey
* rttKey
;
944 char saddrDQ
[20], daddrDQ
[20];
953 {saddrDQ
, offsetof(struct RttKey
, saddr
)},
954 {daddrDQ
, offsetof(struct RttKey
, daddr
)}
957 if (retval
== -1 && !feof(rttStream
))
959 g_error(strerror(errno
));
962 if (line
[retval
- 1] == '\n')
964 line
[retval
- 1]= '\0';
967 rtt
= malloc(sizeof(double));
968 retval
= sscanf(line
, " %19s %19s %lf %c", saddrDQ
, daddrDQ
, rtt
,
972 g_error(strerror(errno
));
974 else if (retval
!= 3)
976 g_error("Error parsing RTT file, line was '%s'", line
);
979 rttKey
= malloc(sizeof(struct RttKey
));
980 for (i
= 0; i
< sizeof(loopValues
) / sizeof(*loopValues
); i
++)
982 retval
= inet_aton(loopValues
[i
].dq
, &addr
);
985 g_error("Error converting address '%s'", loopValues
[i
].dq
);
987 *(uint32_t*) ((void*) rttKey
+ loopValues
[i
].offset
)=
992 g_debug("rttInfo, Inserting (%u, %u)->(%f)", rttKey
->saddr
,
993 rttKey
->daddr
, *rtt
);
994 g_hash_table_insert(rttInfo
, rttKey
, rtt
);
996 positionStream(rttStream
);
997 retval
= getline(&line
, &len
, rttStream
);
1008 * Advance stream over empty space, empty lines and lines that begin with '#'
1011 * stream: stream, at exit, will be over the first non-empty character
1012 * of a line of be at EOF
1014 static void positionStream(FILE* stream
)
1023 firstChar
= fgetc(stream
);
1024 if (firstChar
== (int) '#')
1026 retval
= getline(&line
, &len
, stream
);
1035 g_error(strerror(errno
));
1039 else if (firstChar
== (int) '\n' || firstChar
== (int) ' ' ||
1040 firstChar
== (int) '\t')
1042 else if (firstChar
== EOF
)
1051 retval
= ungetc(firstChar
, stream
);
1054 g_error("Error: ungetc()");
1066 * A GFunc for g_queue_foreach()
1069 * data Event*, a UDP broadcast event
1070 * user_data double*, the running sum
1073 * Adds the time of the event to the sum
1075 static void gfSum(gpointer data
, gpointer userData
)
1077 Event
* event
= (Event
*) data
;
1079 *(double*) userData
+= event
->wallTime
.seconds
+ event
->wallTime
.nanosec
/
1085 * A GFunc for g_queue_foreach()
1088 * data Event*, a UDP broadcast event
1089 * user_data double*, the running sum
1092 * Adds the square of the time of the event to the sum
1094 static void gfSumSquares(gpointer data
, gpointer userData
)
1096 Event
* event
= (Event
*) data
;
1098 *(double*) userData
+= pow(event
->wallTime
.seconds
+ event
->wallTime
.nanosec
1104 * Update a struct Bins according to a new value
1107 * bins: the structure containing bins to build a histrogram
1108 * value: the new value
1110 static void hitBin(struct Bins
* const bins
, const double value
)
1112 unsigned int binN
= binNum(value
);
1114 if (binN
< bins
->min
)
1118 else if (binN
> bins
->max
)
1130 * Figure out the bin in a histogram to which a value belongs.
1132 * This uses exponentially sized bins that go from 0 to infinity.
1135 * value: in the range -INFINITY to INFINITY
1138 * The number of the bin in a struct Bins.bin
1140 static unsigned int binNum(const double value
)
1146 else if (value
< binEnd(1))
1150 else if (value
>= binStart(BIN_NB
- 1))
1156 return floor(log(value
) / log(binBase
)) + BIN_NB
+ 1;
1162 * Figure out the start of the interval of a bin in a histogram. See struct
1165 * This uses exponentially sized bins that go from 0 to infinity.
1168 * binNum: bin number
1171 * The start of the interval, this value is included in the interval (except
1172 * for -INFINITY, naturally)
1174 static double binStart(const unsigned int binNum
)
1176 g_assert_cmpuint(binNum
, <, BIN_NB
);
1182 else if (binNum
== 1)
1188 return pow(binBase
, (double) binNum
- BIN_NB
+ 1);
1194 * Figure out the end of the interval of a bin in a histogram. See struct
1197 * This uses exponentially sized bins that go from 0 to infinity.
1200 * binNum: bin number
1203 * The end of the interval, this value is not included in the interval
1205 static double binEnd(const unsigned int binNum
)
1207 g_assert_cmpuint(binNum
, <, BIN_NB
);
1213 else if (binNum
< BIN_NB
- 1)
1215 return pow(binBase
, (double) binNum
- BIN_NB
+ 2);
1225 * Return the total number of elements in the "normal" bins (not underflow or
1229 * bins: the structure containing bins to build a histrogram
1231 static uint32_t normalTotal(struct Bins
* const bins
)
1233 return bins
->total
- bins
->bin
[0] - bins
->bin
[BIN_NB
- 1];