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
;
695 if (!syncState
->stats
)
700 analysisData
= (AnalysisDataEval
*) syncState
->analysisData
;
702 printf("Synchronization evaluation analysis stats:\n");
703 printf("\tsum of broadcast differential delays: %g\n",
704 analysisData
->stats
->broadcastDiffSum
);
705 printf("\taverage broadcast differential delays: %g\n",
706 analysisData
->stats
->broadcastDiffSum
/
707 analysisData
->stats
->broadcastNb
);
709 printf("\tIndividual evaluation:\n"
710 "\t\tTrace pair Inversions Too fast (No RTT info) Total\n");
712 for (i
= 0; i
< syncState
->traceNb
; i
++)
714 for (j
= i
+ 1; j
< syncState
->traceNb
; j
++)
716 MessageStats
* messageStats
;
717 const char* format
= "\t\t%3d - %-3d %-10u %-10u %-10u %u\n";
719 messageStats
= &analysisData
->stats
->messageStats
[i
][j
];
721 printf(format
, i
, j
, messageStats
->inversionNb
, messageStats
->tooFastNb
,
722 messageStats
->noRTTInfoNb
, messageStats
->total
);
724 messageStats
= &analysisData
->stats
->messageStats
[j
][i
];
726 printf(format
, j
, i
, messageStats
->inversionNb
, messageStats
->tooFastNb
,
727 messageStats
->noRTTInfoNb
, messageStats
->total
);
731 printf("\tRound-trip times:\n"
732 "\t\tHost pair RTT from exchanges RTTs from file (ms)\n");
733 g_hash_table_foreach(analysisData
->stats
->exchangeRtt
,
734 &ghfPrintExchangeRtt
, analysisData
->rttInfo
);
739 * A GHFunc for g_hash_table_foreach()
742 * key: RttKey* where saddr < daddr
743 * value: double*, RTT estimated from exchanges
744 * user_data GHashTable* rttInfo
746 static void ghfPrintExchangeRtt(gpointer key
, gpointer value
, gpointer user_data
)
748 char addr1
[16], addr2
[16];
749 struct RttKey
* rttKey1
= key
;
750 struct RttKey rttKey2
= {rttKey1
->daddr
, rttKey1
->saddr
};
751 double* fileRtt1
, *fileRtt2
;
752 GHashTable
* rttInfo
= user_data
;
754 convertIP(addr1
, rttKey1
->saddr
);
755 convertIP(addr2
, rttKey1
->daddr
);
757 fileRtt1
= g_hash_table_lookup(rttInfo
, rttKey1
);
758 fileRtt2
= g_hash_table_lookup(rttInfo
, &rttKey2
);
760 printf("\t\t(%15s, %-15s) %-18.3f ", addr1
, addr2
, *(double*) value
* 1e3
);
762 if (fileRtt1
|| fileRtt2
)
766 printf("%.3f", *fileRtt1
* 1e3
);
768 if (fileRtt1
&& fileRtt2
)
774 printf("%.3f", *fileRtt2
* 1e3
);
786 * A GHashFunc for g_hash_table_new()
791 static guint
ghfRttKeyHash(gconstpointer key
)
793 struct RttKey
* rttKey
;
796 rttKey
= (struct RttKey
*) key
;
808 * A GDestroyNotify function for g_hash_table_new_full()
811 * data: struct RttKey*
813 static void gdnDestroyRttKey(gpointer data
)
820 * A GDestroyNotify function for g_hash_table_new_full()
825 static void gdnDestroyDouble(gpointer data
)
832 * A GEqualFunc for g_hash_table_new()
838 * TRUE if both values are equal
840 static gboolean
gefRttKeyEqual(gconstpointer a
, gconstpointer b
)
842 const struct RttKey
* rkA
, * rkB
;
844 rkA
= (struct RttKey
*) a
;
845 rkB
= (struct RttKey
*) b
;
847 if (rkA
->saddr
== rkB
->saddr
&& rkA
->daddr
== rkB
->daddr
)
859 * Read a file contain minimum round trip time values and fill an array with
860 * them. The file is formatted as such:
861 * <host1 IP> <host2 IP> <RTT in milliseconds>
862 * ip's should be in dotted quad format
865 * rttInfo: double* rttInfo[RttKey], empty table, will be filled
866 * rttStream: stream from which to read
868 static void readRttInfo(GHashTable
* rttInfo
, FILE* rttStream
)
874 positionStream(rttStream
);
875 retval
= getline(&line
, &len
, rttStream
);
876 while(!feof(rttStream
))
878 struct RttKey
* rttKey
;
879 char saddrDQ
[20], daddrDQ
[20];
888 {saddrDQ
, offsetof(struct RttKey
, saddr
)},
889 {daddrDQ
, offsetof(struct RttKey
, daddr
)}
892 if (retval
== -1 && !feof(rttStream
))
894 g_error(strerror(errno
));
897 if (line
[retval
- 1] == '\n')
899 line
[retval
- 1]= '\0';
902 rtt
= malloc(sizeof(double));
903 retval
= sscanf(line
, " %19s %19s %lf %c", saddrDQ
, daddrDQ
, rtt
,
907 g_error(strerror(errno
));
909 else if (retval
!= 3)
911 g_error("Error parsing RTT file, line was '%s'", line
);
914 rttKey
= malloc(sizeof(struct RttKey
));
915 for (i
= 0; i
< sizeof(loopValues
) / sizeof(*loopValues
); i
++)
917 retval
= inet_aton(loopValues
[i
].dq
, &addr
);
920 g_error("Error converting address '%s'", loopValues
[i
].dq
);
922 *(uint32_t*) ((void*) rttKey
+ loopValues
[i
].offset
)=
927 g_debug("rttInfo, Inserting (%u, %u)->(%f)", rttKey
->saddr
,
928 rttKey
->daddr
, *rtt
);
929 g_hash_table_insert(rttInfo
, rttKey
, rtt
);
931 positionStream(rttStream
);
932 retval
= getline(&line
, &len
, rttStream
);
943 * Advance stream over empty space, empty lines and lines that begin with '#'
946 * stream: stream, at exit, will be over the first non-empty character
947 * of a line of be at EOF
949 static void positionStream(FILE* stream
)
958 firstChar
= fgetc(stream
);
959 if (firstChar
== (int) '#')
961 retval
= getline(&line
, &len
, stream
);
970 g_error(strerror(errno
));
974 else if (firstChar
== (int) '\n' || firstChar
== (int) ' ' ||
975 firstChar
== (int) '\t')
977 else if (firstChar
== EOF
)
986 retval
= ungetc(firstChar
, stream
);
989 g_error("Error: ungetc()");
1001 * A GFunc for g_queue_foreach()
1004 * data Event*, a UDP broadcast event
1005 * user_data double*, the running sum
1008 * Adds the time of the event to the sum
1010 static void gfSum(gpointer data
, gpointer userData
)
1012 Event
* event
= (Event
*) data
;
1014 *(double*) userData
+= event
->wallTime
.seconds
+ event
->wallTime
.nanosec
/
1020 * A GFunc for g_queue_foreach()
1023 * data Event*, a UDP broadcast event
1024 * user_data double*, the running sum
1027 * Adds the square of the time of the event to the sum
1029 static void gfSumSquares(gpointer data
, gpointer userData
)
1031 Event
* event
= (Event
*) data
;
1033 *(double*) userData
+= pow(event
->wallTime
.seconds
+ event
->wallTime
.nanosec
1039 * Update a struct Bins according to a new value
1042 * bins: the structure containing bins to build a histrogram
1043 * value: the new value
1045 static void hitBin(struct Bins
* const bins
, const double value
)
1047 unsigned int binN
= binNum(value
);
1049 if (binN
< bins
->min
)
1053 else if (binN
> bins
->max
)
1065 * Figure out the bin in a histogram to which a value belongs.
1067 * This uses exponentially sized bins that go from 0 to infinity.
1070 * value: in the range -INFINITY to INFINITY
1073 * The number of the bin in a struct Bins.bin
1075 static unsigned int binNum(const double value
)
1081 else if (value
< binEnd(1))
1085 else if (value
>= binStart(BIN_NB
- 1))
1091 return floor(log(value
) / log(binBase
)) + BIN_NB
+ 1;
1097 * Figure out the start of the interval of a bin in a histogram. See struct
1100 * This uses exponentially sized bins that go from 0 to infinity.
1103 * binNum: bin number
1106 * The start of the interval, this value is included in the interval (except
1107 * for -INFINITY, naturally)
1109 static double binStart(const unsigned int binNum
)
1111 g_assert_cmpuint(binNum
, <, BIN_NB
);
1117 else if (binNum
== 1)
1123 return pow(binBase
, (double) binNum
- BIN_NB
+ 1);
1129 * Figure out the end of the interval of a bin in a histogram. See struct
1132 * This uses exponentially sized bins that go from 0 to infinity.
1135 * binNum: bin number
1138 * The end of the interval, this value is not included in the interval
1140 static double binEnd(const unsigned int binNum
)
1142 g_assert_cmpuint(binNum
, <, BIN_NB
);
1148 else if (binNum
< BIN_NB
- 1)
1150 return pow(binBase
, (double) binNum
- BIN_NB
+ 2);