Perform accuracy analysis only on hull points
[lttv.git] / lttv / lttv / sync / event_analysis_eval.c
CommitLineData
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"
66eaf2eb 38#include "event_analysis_chull.h"
cdce23b3
BP
39
40#include "event_analysis_eval.h"
41
42
66eaf2eb 43struct WriteHistogramInfo
e072e1ab
BP
44{
45 GHashTable* rttInfo;
46 FILE* graphsStream;
47};
48
66eaf2eb
BP
49#ifdef HAVE_LIBGLPK
50struct LPAddRowInfo
51{
52 glp_prob* lp;
53 int boundType;
54 GArray* iArray, * jArray, * aArray;
55};
56#endif
e072e1ab 57
cdce23b3
BP
58// Functions common to all analysis modules
59static void initAnalysisEval(SyncState* const syncState);
60static void destroyAnalysisEval(SyncState* const syncState);
61
62static void analyzeMessageEval(SyncState* const syncState, Message* const
63 message);
64static void analyzeExchangeEval(SyncState* const syncState, Exchange* const
65 exchange);
66static void analyzeBroadcastEval(SyncState* const syncState, Broadcast* const
67 broadcast);
68static GArray* finalizeAnalysisEval(SyncState* const syncState);
69static void printAnalysisStatsEval(SyncState* const syncState);
c5571851
BP
70static void writeAnalysisTraceTimeBackPlotsEval(SyncState* const syncState,
71 const unsigned int i, const unsigned int j);
72static void writeAnalysisTraceTimeForePlotsEval(SyncState* const syncState,
73 const unsigned int i, const unsigned int j);
c6356aa7
BP
74static void writeAnalysisTraceTraceBackPlotsEval(SyncState* const syncState,
75 const unsigned int i, const unsigned int j);
76static void writeAnalysisTraceTraceForePlotsEval(SyncState* const syncState,
77 const unsigned int i, const unsigned int j);
cdce23b3
BP
78
79// Functions specific to this module
2bd4b3e4
BP
80static guint ghfRttKeyHash(gconstpointer key);
81static gboolean gefRttKeyEqual(gconstpointer a, gconstpointer b);
82static void gdnDestroyRttKey(gpointer data);
83static void gdnDestroyDouble(gpointer data);
84static void readRttInfo(GHashTable* rttInfo, FILE* rttFile);
85static void positionStream(FILE* stream);
cdce23b3 86
76be6fc2
BP
87static void gfSum(gpointer data, gpointer userData);
88static void gfSumSquares(gpointer data, gpointer userData);
66eaf2eb
BP
89static void ghfPrintExchangeRtt(gpointer key, gpointer value, gpointer
90 user_data);
76be6fc2 91
e072e1ab 92static void hitBin(struct Bins* const bins, const double value);
4ee223e5
BP
93static unsigned int binNum(const double value) __attribute__((pure));
94static double binStart(const unsigned int binNum) __attribute__((pure));
95static double binEnd(const unsigned int binNum) __attribute__((pure));
467066ee 96static uint32_t normalTotal(struct Bins* const bins) __attribute__((const));
4ee223e5 97
66eaf2eb 98static AnalysisHistogramEval* constructAnalysisHistogramEval(const char* const
e072e1ab 99 graphsDir, const struct RttKey* const rttKey);
66eaf2eb
BP
100static void destroyAnalysisHistogramEval(AnalysisHistogramEval* const
101 histogram);
102static void gdnDestroyAnalysisHistogramEval(gpointer data);
103static void ghfWriteHistogram(gpointer key, gpointer value, gpointer
104 user_data);
e072e1ab
BP
105static void dumpBinToFile(const struct Bins* const bins, FILE* const file);
106static void writeHistogram(FILE* graphsStream, const struct RttKey* rttKey,
66eaf2eb
BP
107 double* minRtt, AnalysisHistogramEval* const histogram);
108
c6356aa7
BP
109static void updateBounds(Bounds** const bounds, Event* const e1, Event* const
110 e2);
66eaf2eb 111
05a840df 112static void finalizeAnalysisEvalLP(SyncState* const syncState);
66eaf2eb
BP
113// The next group of functions is only needed when computing synchronization
114// accuracy.
115#ifdef HAVE_LIBGLPK
c6356aa7
BP
116static glp_prob* lpCreateProblem(GQueue* const lowerHull, GQueue* const
117 upperHull);
66eaf2eb
BP
118static void gfLPAddRow(gpointer data, gpointer user_data);
119static Factors* calculateFactors(glp_prob* const lp, const int direction);
c6356aa7
BP
120static void calculateCompleteFactors(glp_prob* const lp, FactorsCHull*
121 factors);
66eaf2eb 122static FactorsCHull** createAllFactors(const unsigned int traceNb);
9a04f8a3
BP
123static inline void finalizeAnalysisEvalLP(SyncState* const syncState);
124static void gfAddAbsiscaToArray(gpointer data, gpointer user_data);
125static gint gcfCompareDouble(gconstpointer a, gconstpointer b);
126#else
127static void finalizeAnalysisEvalLP(SyncState* const syncState);
66eaf2eb 128#endif
e072e1ab 129
4ee223e5 130
66eaf2eb 131// initialized in registerAnalysisEval()
4ee223e5 132double binBase;
cdce23b3
BP
133
134static AnalysisModule analysisModuleEval= {
135 .name= "eval",
136 .initAnalysis= &initAnalysisEval,
137 .destroyAnalysis= &destroyAnalysisEval,
138 .analyzeMessage= &analyzeMessageEval,
139 .analyzeExchange= &analyzeExchangeEval,
140 .analyzeBroadcast= &analyzeBroadcastEval,
141 .finalizeAnalysis= &finalizeAnalysisEval,
142 .printAnalysisStats= &printAnalysisStatsEval,
66eaf2eb 143 .graphFunctions= {
c5571851
BP
144 .writeTraceTimeBackPlots= &writeAnalysisTraceTimeBackPlotsEval,
145 .writeTraceTimeForePlots= &writeAnalysisTraceTimeForePlotsEval,
c6356aa7
BP
146 .writeTraceTraceBackPlots= &writeAnalysisTraceTraceBackPlotsEval,
147 .writeTraceTraceForePlots= &writeAnalysisTraceTraceForePlotsEval,
66eaf2eb 148 }
cdce23b3
BP
149};
150
2bd4b3e4
BP
151static ModuleOption optionEvalRttFile= {
152 .longName= "eval-rtt-file",
153 .hasArg= REQUIRED_ARG,
4ee223e5 154 .optionHelp= "specify the file containing RTT information",
2bd4b3e4
BP
155 .argHelp= "FILE",
156};
157
cdce23b3
BP
158
159/*
160 * Analysis module registering function
161 */
2f961b65 162void registerAnalysisEval()
cdce23b3 163{
66eaf2eb
BP
164 binBase= exp10(6. / (BIN_NB - 3));
165
cdce23b3 166 g_queue_push_tail(&analysisModules, &analysisModuleEval);
2bd4b3e4 167 g_queue_push_tail(&moduleOptions, &optionEvalRttFile);
cdce23b3
BP
168}
169
170
171/*
172 * Analysis init function
173 *
174 * This function is called at the beginning of a synchronization run for a set
175 * of traces.
176 *
177 * Args:
178 * syncState container for synchronization data.
179 */
180static void initAnalysisEval(SyncState* const syncState)
181{
182 AnalysisDataEval* analysisData;
66eaf2eb 183 unsigned int i, j;
cdce23b3
BP
184
185 analysisData= malloc(sizeof(AnalysisDataEval));
186 syncState->analysisData= analysisData;
187
2bd4b3e4
BP
188 analysisData->rttInfo= g_hash_table_new_full(&ghfRttKeyHash,
189 &gefRttKeyEqual, &gdnDestroyRttKey, &gdnDestroyDouble);
190 if (optionEvalRttFile.arg)
191 {
192 FILE* rttStream;
193 int retval;
194
195 rttStream= fopen(optionEvalRttFile.arg, "r");
196 if (rttStream == NULL)
197 {
198 g_error(strerror(errno));
199 }
200
201 readRttInfo(analysisData->rttInfo, rttStream);
202
203 retval= fclose(rttStream);
204 if (retval == EOF)
205 {
206 g_error(strerror(errno));
207 }
208 }
cdce23b3
BP
209
210 if (syncState->stats)
211 {
76be6fc2 212 analysisData->stats= calloc(1, sizeof(AnalysisStatsEval));
2849af52
BP
213 analysisData->stats->broadcastRangeMin= INFINITY;
214 analysisData->stats->broadcastRangeMax= -INFINITY;
cdce23b3 215
76be6fc2
BP
216 analysisData->stats->messageStats= malloc(syncState->traceNb *
217 sizeof(MessageStats*));
cdce23b3
BP
218 for (i= 0; i < syncState->traceNb; i++)
219 {
76be6fc2
BP
220 analysisData->stats->messageStats[i]= calloc(syncState->traceNb,
221 sizeof(MessageStats));
cdce23b3 222 }
d4721e1a
BP
223
224 analysisData->stats->exchangeRtt=
225 g_hash_table_new_full(&ghfRttKeyHash, &gefRttKeyEqual,
226 &gdnDestroyRttKey, &gdnDestroyDouble);
66eaf2eb
BP
227
228#ifdef HAVE_LIBGLPK
229 analysisData->stats->chFactorsArray= NULL;
230 analysisData->stats->lpFactorsArray= NULL;
231#endif
cdce23b3 232 }
4ee223e5 233
8d7d16dd 234 if (syncState->graphsStream)
4ee223e5 235 {
66eaf2eb
BP
236 AnalysisGraphsEval* graphs= malloc(sizeof(AnalysisGraphsEval));
237
238 analysisData->graphs= graphs;
239
240 graphs->histograms= g_hash_table_new_full(&ghfRttKeyHash,
241 &gefRttKeyEqual, &gdnDestroyRttKey,
242 &gdnDestroyAnalysisHistogramEval);
243
244 graphs->bounds= malloc(syncState->traceNb * sizeof(Bounds*));
245 for (i= 0; i < syncState->traceNb; i++)
246 {
247 graphs->bounds[i]= malloc(i * sizeof(Bounds));
248 for (j= 0; j < i; j++)
249 {
250 graphs->bounds[i][j].min= UINT64_MAX;
251 graphs->bounds[i][j].max= 0;
252 }
253 }
254
255#ifdef HAVE_LIBGLPK
256 graphs->lps= NULL;
257 graphs->lpFactorsArray= NULL;
258#endif
259 }
260
261 if (syncState->stats || syncState->graphsStream)
262 {
263 GList* result;
264
265 analysisData->chullSS= malloc(sizeof(SyncState));
266 memcpy(analysisData->chullSS, syncState, sizeof(SyncState));
267 analysisData->chullSS->stats= false;
268 analysisData->chullSS->analysisData= NULL;
269 result= g_queue_find_custom(&analysisModules, "chull",
270 &gcfCompareAnalysis);
271 analysisData->chullSS->analysisModule= (AnalysisModule*) result->data;
272 analysisData->chullSS->analysisModule->initAnalysis(analysisData->chullSS);
4ee223e5
BP
273 }
274}
275
276
277/*
e072e1ab
BP
278 * Create and open files used to store histogram points to generate graphs.
279 * Create data structures to store histogram points during analysis.
4ee223e5
BP
280 *
281 * Args:
e072e1ab
BP
282 * graphsDir: folder where to write files
283 * rttKey: host pair, make sure saddr < daddr
4ee223e5 284 */
66eaf2eb 285static AnalysisHistogramEval* constructAnalysisHistogramEval(const char* const
e072e1ab 286 graphsDir, const struct RttKey* const rttKey)
4ee223e5 287{
4ee223e5 288 int retval;
e072e1ab 289 unsigned int i;
4ee223e5 290 char* cwd;
e072e1ab 291 char name[60], saddr[16], daddr[16];
66eaf2eb 292 AnalysisHistogramEval* histogram= calloc(1, sizeof(*histogram));
e072e1ab
BP
293 const struct {
294 size_t pointsOffset;
295 const char* fileName;
296 const char* host1, *host2;
297 } loopValues[]= {
66eaf2eb
BP
298 {offsetof(AnalysisHistogramEval, ttSendPoints),
299 "analysis_eval_tt-%s_to_%s.data", saddr, daddr},
300 {offsetof(AnalysisHistogramEval, ttRecvPoints),
301 "analysis_eval_tt-%s_to_%s.data", daddr, saddr},
302 {offsetof(AnalysisHistogramEval, hrttPoints),
303 "analysis_eval_hrtt-%s_and_%s.data", saddr, daddr},
e072e1ab
BP
304 };
305
66eaf2eb
BP
306 histogram->ttSendBins.min= BIN_NB - 1;
307 histogram->ttRecvBins.min= BIN_NB - 1;
308 histogram->hrttBins.min= BIN_NB - 1;
e072e1ab
BP
309
310 convertIP(saddr, rttKey->saddr);
311 convertIP(daddr, rttKey->daddr);
312
1d597550 313 cwd= changeToGraphsDir(graphsDir);
e072e1ab
BP
314
315 for (i= 0; i < sizeof(loopValues) / sizeof(*loopValues); i++)
4ee223e5 316 {
e072e1ab
BP
317 retval= snprintf(name, sizeof(name), loopValues[i].fileName,
318 loopValues[i].host1, loopValues[i].host2);
319 if (retval > sizeof(name) - 1)
4ee223e5 320 {
e072e1ab 321 name[sizeof(name) - 1]= '\0';
4ee223e5 322 }
66eaf2eb 323 if ((*(FILE**)((void*) histogram + loopValues[i].pointsOffset)=
e072e1ab 324 fopen(name, "w")) == NULL)
4ee223e5 325 {
e072e1ab 326 g_error(strerror(errno));
4ee223e5
BP
327 }
328 }
329
330 retval= chdir(cwd);
331 if (retval == -1)
332 {
333 g_error(strerror(errno));
334 }
335 free(cwd);
e072e1ab 336
66eaf2eb 337 return histogram;
4ee223e5
BP
338}
339
340
341/*
e072e1ab 342 * Close files used to store histogram points to generate graphs.
4ee223e5
BP
343 *
344 * Args:
e072e1ab
BP
345 * graphsDir: folder where to write files
346 * rttKey: host pair, make sure saddr < daddr
4ee223e5 347 */
66eaf2eb
BP
348static void destroyAnalysisHistogramEval(AnalysisHistogramEval* const
349 histogram)
4ee223e5 350{
e072e1ab
BP
351 unsigned int i;
352 int retval;
353 const struct {
354 size_t pointsOffset;
355 } loopValues[]= {
66eaf2eb
BP
356 {offsetof(AnalysisHistogramEval, ttSendPoints)},
357 {offsetof(AnalysisHistogramEval, ttRecvPoints)},
358 {offsetof(AnalysisHistogramEval, hrttPoints)},
e072e1ab
BP
359 };
360
361 for (i= 0; i < sizeof(loopValues) / sizeof(*loopValues); i++)
4ee223e5 362 {
66eaf2eb 363 retval= fclose(*(FILE**)((void*) histogram + loopValues[i].pointsOffset));
e072e1ab 364 if (retval != 0)
4ee223e5 365 {
e072e1ab 366 g_error(strerror(errno));
4ee223e5
BP
367 }
368 }
66eaf2eb
BP
369
370 free(histogram);
4ee223e5
BP
371}
372
373
e072e1ab
BP
374/*
375 * A GDestroyNotify function for g_hash_table_new_full()
376 *
377 * Args:
66eaf2eb 378 * data: AnalysisHistogramEval*
e072e1ab 379 */
66eaf2eb 380static void gdnDestroyAnalysisHistogramEval(gpointer data)
e072e1ab 381{
66eaf2eb 382 destroyAnalysisHistogramEval(data);
e072e1ab
BP
383}
384
385
386/*
387 * A GHFunc for g_hash_table_foreach()
388 *
389 * Args:
390 * key: RttKey* where saddr < daddr
66eaf2eb
BP
391 * value: AnalysisHistogramEval*
392 * user_data struct WriteHistogramInfo*
e072e1ab 393 */
66eaf2eb 394static void ghfWriteHistogram(gpointer key, gpointer value, gpointer user_data)
e072e1ab
BP
395{
396 double* rtt1, * rtt2;
397 struct RttKey* rttKey= key;
398 struct RttKey oppositeRttKey= {.saddr= rttKey->daddr, .daddr=
399 rttKey->saddr};
66eaf2eb
BP
400 AnalysisHistogramEval* histogram= value;
401 struct WriteHistogramInfo* info= user_data;
e072e1ab
BP
402
403 rtt1= g_hash_table_lookup(info->rttInfo, rttKey);
404 rtt2= g_hash_table_lookup(info->rttInfo, &oppositeRttKey);
405
406 if (rtt1 == NULL)
407 {
408 rtt1= rtt2;
409 }
410 else if (rtt2 != NULL)
411 {
412 rtt1= MIN(rtt1, rtt2);
413 }
414
66eaf2eb
BP
415 dumpBinToFile(&histogram->ttSendBins, histogram->ttSendPoints);
416 dumpBinToFile(&histogram->ttRecvBins, histogram->ttRecvPoints);
417 dumpBinToFile(&histogram->hrttBins, histogram->hrttPoints);
418 writeHistogram(info->graphsStream, rttKey, rtt1, histogram);
e072e1ab
BP
419}
420
421
4ee223e5
BP
422/*
423 * Write the content of one bin in a histogram point file
424 *
425 * Args:
426 * bin: array of values that make up a histogram
e072e1ab 427 * file: FILE*, write to this file
4ee223e5 428 */
e072e1ab 429static void dumpBinToFile(const struct Bins* const bins, FILE* const file)
4ee223e5
BP
430{
431 unsigned int i;
432
e072e1ab
BP
433 // The first and last bins are skipped, see struct Bins
434 for (i= 1; i < BIN_NB - 1; i++)
4ee223e5 435 {
e072e1ab 436 if (bins->bin[i] > 0)
4ee223e5 437 {
e072e1ab
BP
438 fprintf(file, "%20.9f %20.9f %20.9f\n", (binStart(i) + binEnd(i))
439 / 2., (double) bins->bin[i] / ((binEnd(i) - binStart(i)) *
440 bins->total), binEnd(i) - binStart(i));
4ee223e5
BP
441 }
442 }
443}
444
445
446/*
e072e1ab 447 * Write the analysis-specific plot in the gnuplot script.
4ee223e5
BP
448 *
449 * Args:
e072e1ab
BP
450 * graphsStream: write to this file
451 * rttKey: must be sorted such that saddr < daddr
452 * minRtt: if available, else NULL
66eaf2eb 453 * histogram: struct that contains the bins for the pair of traces
467066ee 454 * identified by rttKey
4ee223e5 455 */
e072e1ab 456static void writeHistogram(FILE* graphsStream, const struct RttKey* rttKey,
66eaf2eb 457 double* minRtt, AnalysisHistogramEval* const histogram)
4ee223e5 458{
e072e1ab 459 char saddr[16], daddr[16];
4ee223e5 460
e072e1ab
BP
461 convertIP(saddr, rttKey->saddr);
462 convertIP(daddr, rttKey->daddr);
4ee223e5 463
e072e1ab 464 fprintf(graphsStream,
66eaf2eb 465 "\nreset\n"
e072e1ab
BP
466 "set output \"histogram-%s-%s.eps\"\n"
467 "set title \"\"\n"
468 "set xlabel \"Message Latency (s)\"\n"
469 "set ylabel \"Proportion of messages per second\"\n", saddr, daddr);
4ee223e5 470
e072e1ab 471 if (minRtt != NULL)
4ee223e5 472 {
e072e1ab
BP
473 fprintf(graphsStream,
474 "set arrow from %.9f, 0 rto 0, graph 1 "
467066ee
BP
475 "nohead linetype 3 linewidth 3 linecolor rgb \"black\"\n", *minRtt
476 / 2);
4ee223e5 477 }
4ee223e5 478
66eaf2eb
BP
479 if (normalTotal(&histogram->ttSendBins) ||
480 normalTotal(&histogram->ttRecvBins) ||
481 normalTotal(&histogram->hrttBins))
467066ee
BP
482 {
483 fprintf(graphsStream, "plot \\\n");
484
66eaf2eb 485 if (normalTotal(&histogram->hrttBins))
467066ee
BP
486 {
487 fprintf(graphsStream,
488 "\t\"analysis_eval_hrtt-%s_and_%s.data\" "
489 "title \"RTT/2\" with linespoints linetype 1 linewidth 2 "
490 "linecolor rgb \"black\" pointtype 6 pointsize 1,\\\n",
491 saddr, daddr);
492 }
493
66eaf2eb 494 if (normalTotal(&histogram->ttSendBins))
467066ee
BP
495 {
496 fprintf(graphsStream,
497 "\t\"analysis_eval_tt-%1$s_to_%2$s.data\" "
498 "title \"%1$s to %2$s\" with linespoints linetype 4 linewidth 2 "
499 "linecolor rgb \"gray60\" pointtype 6 pointsize 1,\\\n",
500 saddr, daddr);
501 }
502
66eaf2eb 503 if (normalTotal(&histogram->ttRecvBins))
467066ee
BP
504 {
505 fprintf(graphsStream,
506 "\t\"analysis_eval_tt-%1$s_to_%2$s.data\" "
507 "title \"%1$s to %2$s\" with linespoints linetype 4 linewidth 2 "
508 "linecolor rgb \"gray30\" pointtype 6 pointsize 1,\\\n",
509 daddr, saddr);
510 }
511
512 // Remove the ",\\\n" from the last graph plot line
513 if (ftruncate(fileno(graphsStream), ftell(graphsStream) - 3) == -1)
514 {
515 g_error(strerror(errno));
516 }
517 if (fseek(graphsStream, 0, SEEK_END) == -1)
518 {
519 g_error(strerror(errno));
520 }
521 fprintf(graphsStream, "\n");
522 }
cdce23b3
BP
523}
524
525
526/*
527 * Analysis destroy function
528 *
529 * Free the analysis specific data structures
530 *
531 * Args:
532 * syncState container for synchronization data.
533 */
534static void destroyAnalysisEval(SyncState* const syncState)
535{
05a840df 536 unsigned int i;
cdce23b3
BP
537 AnalysisDataEval* analysisData;
538
539 analysisData= (AnalysisDataEval*) syncState->analysisData;
540
66eaf2eb 541 if (analysisData == NULL)
cdce23b3
BP
542 {
543 return;
544 }
545
2bd4b3e4 546 g_hash_table_destroy(analysisData->rttInfo);
cdce23b3
BP
547
548 if (syncState->stats)
549 {
66eaf2eb
BP
550 AnalysisStatsEval* stats= analysisData->stats;
551
552 for (i= 0; i < syncState->traceNb; i++)
553 {
554 free(stats->messageStats[i]);
555 }
556 free(stats->messageStats);
557
558 g_hash_table_destroy(stats->exchangeRtt);
559
560#ifdef HAVE_LIBGLPK
561 freeAllFactors(syncState->traceNb, stats->chFactorsArray);
562 freeAllFactors(syncState->traceNb, stats->lpFactorsArray);
563#endif
564
565 free(stats);
566 }
567
568 if (syncState->graphsStream)
569 {
570 AnalysisGraphsEval* graphs= analysisData->graphs;
571
572 if (graphs->histograms)
573 {
574 g_hash_table_destroy(graphs->histograms);
575 }
576
cdce23b3
BP
577 for (i= 0; i < syncState->traceNb; i++)
578 {
66eaf2eb
BP
579 free(graphs->bounds[i]);
580 }
581 free(graphs->bounds);
582
583#ifdef HAVE_LIBGLPK
584 for (i= 0; i < syncState->traceNb; i++)
585 {
05a840df
BP
586 unsigned int j;
587
66eaf2eb
BP
588 for (j= 0; j < i; j++)
589 {
590 // There seems to be a memory leak in glpk, valgrind reports a
6ce8ceac 591 // loss (reachable) even if the problem is deleted
66eaf2eb
BP
592 glp_delete_prob(graphs->lps[i][j]);
593 }
594 free(graphs->lps[i]);
cdce23b3 595 }
66eaf2eb 596 free(graphs->lps);
d4721e1a 597
66eaf2eb
BP
598 if (!syncState->stats)
599 {
600 freeAllFactors(syncState->traceNb, graphs->lpFactorsArray);
601 }
602#endif
d4721e1a 603
66eaf2eb 604 free(graphs);
cdce23b3
BP
605 }
606
66eaf2eb 607 if (syncState->stats || syncState->graphsStream)
4ee223e5 608 {
66eaf2eb
BP
609 analysisData->chullSS->analysisModule->destroyAnalysis(analysisData->chullSS);
610 free(analysisData->chullSS);
4ee223e5
BP
611 }
612
cdce23b3
BP
613 free(syncState->analysisData);
614 syncState->analysisData= NULL;
615}
616
617
618/*
619 * Perform analysis on an event pair.
620 *
76be6fc2
BP
621 * Check if there is message inversion or messages that are too fast.
622 *
cdce23b3
BP
623 * Args:
624 * syncState container for synchronization data
625 * message structure containing the events
626 */
66eaf2eb
BP
627static void analyzeMessageEval(SyncState* const syncState, Message* const
628 message)
cdce23b3 629{
e072e1ab 630 AnalysisDataEval* analysisData= syncState->analysisData;
7e39acc6 631 MessageStats* messageStats;
d4721e1a 632 double* rtt;
76be6fc2
BP
633 double tt;
634 struct RttKey rttKey;
635
e072e1ab 636 g_assert(message->inE->type == TCP);
76be6fc2 637
66eaf2eb
BP
638 if (syncState->stats)
639 {
7e39acc6
BP
640 messageStats=
641 &analysisData->stats->messageStats[message->outE->traceNum][message->inE->traceNum];
66eaf2eb
BP
642 messageStats->total++;
643 }
76be6fc2
BP
644
645 tt= wallTimeSub(&message->inE->wallTime, &message->outE->wallTime);
646 if (tt <= 0)
647 {
66eaf2eb
BP
648 if (syncState->stats)
649 {
650 messageStats->inversionNb++;
651 }
76be6fc2 652 }
8d7d16dd 653 else if (syncState->graphsStream)
4ee223e5 654 {
e072e1ab
BP
655 struct RttKey rttKey= {
656 .saddr=MIN(message->inE->event.tcpEvent->segmentKey->connectionKey.saddr,
657 message->inE->event.tcpEvent->segmentKey->connectionKey.daddr),
658 .daddr=MAX(message->inE->event.tcpEvent->segmentKey->connectionKey.saddr,
659 message->inE->event.tcpEvent->segmentKey->connectionKey.daddr),
660 };
66eaf2eb
BP
661 AnalysisHistogramEval* histogram=
662 g_hash_table_lookup(analysisData->graphs->histograms, &rttKey);
e072e1ab 663
66eaf2eb 664 if (histogram == NULL)
e072e1ab
BP
665 {
666 struct RttKey* tableKey= malloc(sizeof(*tableKey));
667
66eaf2eb 668 histogram= constructAnalysisHistogramEval(syncState->graphsDir, &rttKey);
e072e1ab 669 memcpy(tableKey, &rttKey, sizeof(*tableKey));
66eaf2eb 670 g_hash_table_insert(analysisData->graphs->histograms, tableKey, histogram);
e072e1ab
BP
671 }
672
673 if (message->inE->event.udpEvent->datagramKey->saddr <
674 message->inE->event.udpEvent->datagramKey->daddr)
675 {
66eaf2eb 676 hitBin(&histogram->ttSendBins, tt);
e072e1ab
BP
677 }
678 else
679 {
66eaf2eb 680 hitBin(&histogram->ttRecvBins, tt);
e072e1ab 681 }
4ee223e5 682 }
76be6fc2 683
66eaf2eb 684 if (syncState->stats)
76be6fc2 685 {
66eaf2eb
BP
686 rttKey.saddr=
687 message->inE->event.tcpEvent->segmentKey->connectionKey.saddr;
688 rttKey.daddr=
689 message->inE->event.tcpEvent->segmentKey->connectionKey.daddr;
690 rtt= g_hash_table_lookup(analysisData->rttInfo, &rttKey);
691 g_debug("rttInfo, looking up (%u, %u)->(%f)", rttKey.saddr,
692 rttKey.daddr, rtt ? *rtt : NAN);
693
694 if (rtt)
76be6fc2 695 {
66eaf2eb
BP
696 g_debug("rttInfo, tt: %f rtt / 2: %f", tt, *rtt / 2.);
697 if (tt < *rtt / 2.)
698 {
699 messageStats->tooFastNb++;
700 }
701 }
702 else
703 {
704 messageStats->noRTTInfoNb++;
76be6fc2
BP
705 }
706 }
66eaf2eb
BP
707
708 if (syncState->graphsStream)
709 {
710 updateBounds(analysisData->graphs->bounds, message->inE,
711 message->outE);
712 }
713
714 if (syncState->stats || syncState->graphsStream)
76be6fc2 715 {
66eaf2eb
BP
716 analysisData->chullSS->analysisModule->analyzeMessage(analysisData->chullSS,
717 message);
76be6fc2 718 }
cdce23b3
BP
719}
720
721
722/*
723 * Perform analysis on multiple messages
724 *
76be6fc2
BP
725 * Measure the RTT
726 *
cdce23b3
BP
727 * Args:
728 * syncState container for synchronization data
729 * exchange structure containing the messages
730 */
66eaf2eb
BP
731static void analyzeExchangeEval(SyncState* const syncState, Exchange* const
732 exchange)
cdce23b3 733{
d4721e1a
BP
734 AnalysisDataEval* analysisData= syncState->analysisData;
735 Message* m1= g_queue_peek_tail(exchange->acks);
736 Message* m2= exchange->message;
737 struct RttKey* rttKey;
738 double* rtt, * exchangeRtt;
cdce23b3 739
e072e1ab
BP
740 g_assert(m1->inE->type == TCP);
741
d4721e1a
BP
742 // (T2 - T1) - (T3 - T4)
743 rtt= malloc(sizeof(double));
744 *rtt= wallTimeSub(&m1->inE->wallTime, &m1->outE->wallTime) -
745 wallTimeSub(&m2->outE->wallTime, &m2->inE->wallTime);
746
d4721e1a
BP
747 rttKey= malloc(sizeof(struct RttKey));
748 rttKey->saddr=
749 MIN(m1->inE->event.tcpEvent->segmentKey->connectionKey.saddr,
750 m1->inE->event.tcpEvent->segmentKey->connectionKey.daddr);
751 rttKey->daddr=
752 MAX(m1->inE->event.tcpEvent->segmentKey->connectionKey.saddr,
753 m1->inE->event.tcpEvent->segmentKey->connectionKey.daddr);
e072e1ab
BP
754
755 if (syncState->graphsStream)
756 {
66eaf2eb
BP
757 AnalysisHistogramEval* histogram=
758 g_hash_table_lookup(analysisData->graphs->histograms, rttKey);
e072e1ab 759
66eaf2eb 760 if (histogram == NULL)
e072e1ab
BP
761 {
762 struct RttKey* tableKey= malloc(sizeof(*tableKey));
763
66eaf2eb
BP
764 histogram= constructAnalysisHistogramEval(syncState->graphsDir,
765 rttKey);
e072e1ab 766 memcpy(tableKey, rttKey, sizeof(*tableKey));
66eaf2eb
BP
767 g_hash_table_insert(analysisData->graphs->histograms, tableKey,
768 histogram);
e072e1ab
BP
769 }
770
66eaf2eb 771 hitBin(&histogram->hrttBins, *rtt / 2);
e072e1ab
BP
772 }
773
66eaf2eb 774 if (syncState->stats)
d4721e1a 775 {
66eaf2eb
BP
776 exchangeRtt= g_hash_table_lookup(analysisData->stats->exchangeRtt,
777 rttKey);
778
779 if (exchangeRtt)
d4721e1a 780 {
66eaf2eb
BP
781 if (*rtt < *exchangeRtt)
782 {
783 g_hash_table_replace(analysisData->stats->exchangeRtt, rttKey, rtt);
784 }
785 else
786 {
787 free(rttKey);
788 free(rtt);
789 }
790 }
791 else
792 {
793 g_hash_table_insert(analysisData->stats->exchangeRtt, rttKey, rtt);
d4721e1a
BP
794 }
795 }
796 else
797 {
66eaf2eb
BP
798 free(rttKey);
799 free(rtt);
d4721e1a 800 }
cdce23b3
BP
801}
802
803
804/*
805 * Perform analysis on muliple events
806 *
76be6fc2
BP
807 * Sum the broadcast differential delays
808 *
cdce23b3
BP
809 * Args:
810 * syncState container for synchronization data
811 * broadcast structure containing the events
812 */
66eaf2eb
BP
813static void analyzeBroadcastEval(SyncState* const syncState, Broadcast* const
814 broadcast)
cdce23b3 815{
66eaf2eb 816 AnalysisDataEval* analysisData= syncState->analysisData;
76be6fc2 817
66eaf2eb 818 if (syncState->stats)
76be6fc2 819 {
66eaf2eb
BP
820 double sum= 0, squaresSum= 0;
821 double y;
cdce23b3 822
66eaf2eb
BP
823 g_queue_foreach(broadcast->events, &gfSum, &sum);
824 g_queue_foreach(broadcast->events, &gfSumSquares, &squaresSum);
76be6fc2 825
66eaf2eb
BP
826 analysisData->stats->broadcastNb++;
827 // Because of numerical errors, this can at times be < 0
828 y= squaresSum / g_queue_get_length(broadcast->events) - pow(sum /
829 g_queue_get_length(broadcast->events), 2.);
830 if (y > 0)
831 {
2849af52
BP
832 analysisData->stats->broadcastStdevSum+= sqrt(y);
833 }
834
835 if (syncState->traceNb == 2 && g_queue_get_length(broadcast->events)
836 == 2)
837 {
838 Event* e0, * e1;
839 double dd;
840
841 e0= g_queue_peek_head(broadcast->events);
842 e1= g_queue_peek_tail(broadcast->events);
843 if (e0->traceNum > e1->traceNum)
844 {
845 Event* tmp;
846
847 tmp= e0;
848 e0= e1;
849 e1= tmp;
850 }
851
852 dd= wallTimeSub(&e1->wallTime, &e0->wallTime);
853
854 analysisData->stats->broadcastPairNb++;
855 if (dd < analysisData->stats->broadcastRangeMin)
856 {
857 analysisData->stats->broadcastRangeMin= dd;
858 }
859 if (dd > analysisData->stats->broadcastRangeMax)
860 {
861 analysisData->stats->broadcastRangeMax= dd;
862 }
863
864 analysisData->stats->broadcastSum+= dd;
865 analysisData->stats->broadcastSumSquares+= pow(dd, 2);
66eaf2eb
BP
866 }
867 }
76be6fc2 868
66eaf2eb 869 if (syncState->graphsStream)
76be6fc2 870 {
66eaf2eb
BP
871 unsigned int i, j;
872 GArray* events;
873 unsigned int eventNb= broadcast->events->length;
874
875 events= g_array_sized_new(FALSE, FALSE, sizeof(Event*), eventNb);
876 g_queue_foreach(broadcast->events, &gfAddEventToArray, events);
877
878 for (i= 0; i < eventNb; i++)
879 {
880 for (j= 0; j < eventNb; j++)
881 {
882 Event* eventI= g_array_index(events, Event*, i), * eventJ=
883 g_array_index(events, Event*, j);
884
885 if (eventI->traceNum < eventJ->traceNum)
886 {
887 updateBounds(analysisData->graphs->bounds, eventI, eventJ);
888 }
889 }
890 }
891
892 g_array_free(events, TRUE);
76be6fc2 893 }
cdce23b3
BP
894}
895
896
897/*
66eaf2eb
BP
898 * Finalize the factor calculations. Since this module does not really
899 * calculate factors, identity factors are returned. Instead, histograms are
900 * written out and histogram structures are freed.
cdce23b3
BP
901 *
902 * Args:
903 * syncState container for synchronization data.
904 *
905 * Returns:
d4721e1a 906 * Factors[traceNb] identity factors for each trace
cdce23b3
BP
907 */
908static GArray* finalizeAnalysisEval(SyncState* const syncState)
909{
910 GArray* factors;
911 unsigned int i;
4ee223e5
BP
912 AnalysisDataEval* analysisData= syncState->analysisData;
913
66eaf2eb 914 if (syncState->graphsStream && analysisData->graphs->histograms)
4ee223e5 915 {
66eaf2eb
BP
916 g_hash_table_foreach(analysisData->graphs->histograms,
917 &ghfWriteHistogram, &(struct WriteHistogramInfo) {.rttInfo=
918 analysisData->rttInfo, .graphsStream= syncState->graphsStream});
919 g_hash_table_destroy(analysisData->graphs->histograms);
920 analysisData->graphs->histograms= NULL;
4ee223e5 921 }
cdce23b3 922
66eaf2eb
BP
923 finalizeAnalysisEvalLP(syncState);
924
cdce23b3
BP
925 factors= g_array_sized_new(FALSE, FALSE, sizeof(Factors),
926 syncState->traceNb);
927 g_array_set_size(factors, syncState->traceNb);
928 for (i= 0; i < syncState->traceNb; i++)
929 {
930 Factors* e;
931
932 e= &g_array_index(factors, Factors, i);
933 e->drift= 1.;
934 e->offset= 0.;
935 }
936
937 return factors;
938}
939
940
941/*
942 * Print statistics related to analysis. Must be called after
943 * finalizeAnalysis.
944 *
945 * Args:
946 * syncState container for synchronization data.
947 */
948static void printAnalysisStatsEval(SyncState* const syncState)
949{
950 AnalysisDataEval* analysisData;
f109919b
BP
951 unsigned int i, j, k;
952 unsigned int totInversion= 0, totTooFast= 0, totNoInfo= 0, totTotal= 0;
953 int charNb;
cdce23b3
BP
954
955 if (!syncState->stats)
956 {
957 return;
958 }
959
960 analysisData= (AnalysisDataEval*) syncState->analysisData;
961
962 printf("Synchronization evaluation analysis stats:\n");
ffa21cfd
BP
963 if (analysisData->stats->broadcastNb)
964 {
2849af52
BP
965 printf("\tBroadcast differential delay:\n");
966 printf("\t\tsum of standard deviations: %g\n",
967 analysisData->stats->broadcastStdevSum);
968 printf("\t\taverage standard deviation: %g\n",
969 analysisData->stats->broadcastStdevSum /
ffa21cfd 970 analysisData->stats->broadcastNb);
2849af52
BP
971
972 if (syncState->traceNb == 2)
973 {
974 printf("\t\tdifferential delay range: [ %g .. %g ]\n",
975 analysisData->stats->broadcastRangeMin,
976 analysisData->stats->broadcastRangeMax);
977 printf("\t\tdifferential delay average: %g\n",
978 analysisData->stats->broadcastSum /
979 analysisData->stats->broadcastPairNb);
980 printf("\t\tdifferential delay standard deviation: %g\n",
981 sqrt(analysisData->stats->broadcastSumSquares /
982 analysisData->stats->broadcastPairNb -
983 pow(analysisData->stats->broadcastSum /
984 analysisData->stats->broadcastPairNb, 2)));
985 }
ffa21cfd 986 }
cdce23b3
BP
987
988 printf("\tIndividual evaluation:\n"
f109919b 989 "\t\tTrace pair Inversions Too fast No RTT info Total\n");
cdce23b3
BP
990
991 for (i= 0; i < syncState->traceNb; i++)
992 {
993 for (j= i + 1; j < syncState->traceNb; j++)
994 {
76be6fc2 995 MessageStats* messageStats;
f109919b
BP
996 struct {
997 unsigned int t1, t2;
998 } loopValues[]= {
999 {i, j},
1000 {j, i}
1001 };
1002
1003 for (k= 0; k < sizeof(loopValues) / sizeof(*loopValues); k++)
1004 {
1005 messageStats=
1006 &analysisData->stats->messageStats[loopValues[k].t1][loopValues[k].t2];
1007
1008 printf("\t\t%3d - %-3d ", loopValues[k].t1, loopValues[k].t2);
2849af52
BP
1009 printf("%u (%.2f%%)%n", messageStats->inversionNb, (double)
1010 messageStats->inversionNb / messageStats->total * 100,
1011 &charNb);
f109919b 1012 printf("%*s", 17 - charNb > 0 ? 17 - charNb + 1: 1, " ");
2849af52
BP
1013 printf("%u (%.2f%%)%n", messageStats->tooFastNb, (double)
1014 messageStats->tooFastNb / messageStats->total * 100,
1015 &charNb);
f109919b
BP
1016 printf("%*s%-10u %u\n", 17 - charNb > 0 ? 17 - charNb + 1:
1017 1, " ", messageStats->noRTTInfoNb, messageStats->total);
1018
1019 totInversion+= messageStats->inversionNb;
1020 totTooFast+= messageStats->tooFastNb;
1021 totNoInfo+= messageStats->noRTTInfoNb;
1022 totTotal+= messageStats->total;
1023 }
cdce23b3
BP
1024 }
1025 }
d4721e1a 1026
f109919b 1027 printf("\t\t total ");
2849af52
BP
1028 printf("%u (%.2f%%)%n", totInversion, (double) totInversion / totTotal *
1029 100, &charNb);
f109919b 1030 printf("%*s", 17 - charNb > 0 ? 17 - charNb + 1: 1, " ");
2849af52
BP
1031 printf("%u (%.2f%%)%n", totTooFast, (double) totTooFast / totTotal * 100,
1032 &charNb);
f109919b
BP
1033 printf("%*s%-10u %u\n", 17 - charNb > 0 ? 17 - charNb + 1: 1, " ",
1034 totNoInfo, totTotal);
1035
d4721e1a
BP
1036 printf("\tRound-trip times:\n"
1037 "\t\tHost pair RTT from exchanges RTTs from file (ms)\n");
1038 g_hash_table_foreach(analysisData->stats->exchangeRtt,
1039 &ghfPrintExchangeRtt, analysisData->rttInfo);
66eaf2eb 1040
05a840df 1041#ifdef HAVE_LIBGLPK
66eaf2eb
BP
1042 printf("\tConvex hull factors comparisons:\n"
1043 "\t\tTrace pair Factors type Differences (lp - chull)\n"
1044 "\t\t a0 a1\n"
1045 "\t\t Min Max Min Max\n");
1046
1047 for (i= 0; i < syncState->traceNb; i++)
1048 {
1049 for (j= 0; j < i; j++)
1050 {
1051 FactorsCHull* chFactors= &analysisData->stats->chFactorsArray[i][j];
1052 FactorsCHull* lpFactors= &analysisData->stats->lpFactorsArray[i][j];
1053
1054 printf("\t\t%3d - %-3d ", i, j);
1055 if (lpFactors->type == chFactors->type)
1056 {
1057 if (lpFactors->type == MIDDLE)
1058 {
1059 printf("%-13s %-10.4g %-10.4g %-10.4g %.4g\n",
1060 approxNames[lpFactors->type],
1061 lpFactors->min->offset - chFactors->min->offset,
1062 lpFactors->max->offset - chFactors->max->offset,
1063 lpFactors->min->drift - chFactors->min->drift,
1064 lpFactors->max->drift - chFactors->max->drift);
1065 }
1066 else if (lpFactors->type == ABSENT)
1067 {
1068 printf("%s\n", approxNames[lpFactors->type]);
1069 }
1070 }
1071 else
1072 {
1073 printf("Different! %s and %s\n", approxNames[lpFactors->type],
1074 approxNames[chFactors->type]);
1075 }
1076 }
1077 }
05a840df 1078#endif
d4721e1a
BP
1079}
1080
1081
1082/*
1083 * A GHFunc for g_hash_table_foreach()
1084 *
1085 * Args:
1086 * key: RttKey* where saddr < daddr
1087 * value: double*, RTT estimated from exchanges
1088 * user_data GHashTable* rttInfo
1089 */
66eaf2eb
BP
1090static void ghfPrintExchangeRtt(gpointer key, gpointer value, gpointer
1091 user_data)
d4721e1a
BP
1092{
1093 char addr1[16], addr2[16];
1094 struct RttKey* rttKey1= key;
1095 struct RttKey rttKey2= {rttKey1->daddr, rttKey1->saddr};
1096 double* fileRtt1, *fileRtt2;
1097 GHashTable* rttInfo= user_data;
1098
1099 convertIP(addr1, rttKey1->saddr);
1100 convertIP(addr2, rttKey1->daddr);
1101
1102 fileRtt1= g_hash_table_lookup(rttInfo, rttKey1);
1103 fileRtt2= g_hash_table_lookup(rttInfo, &rttKey2);
1104
1105 printf("\t\t(%15s, %-15s) %-18.3f ", addr1, addr2, *(double*) value * 1e3);
1106
1107 if (fileRtt1 || fileRtt2)
1108 {
1109 if (fileRtt1)
1110 {
1111 printf("%.3f", *fileRtt1 * 1e3);
1112 }
1113 if (fileRtt1 && fileRtt2)
1114 {
1115 printf(", ");
1116 }
1117 if (fileRtt2)
1118 {
1119 printf("%.3f", *fileRtt2 * 1e3);
1120 }
1121 }
1122 else
1123 {
1124 printf("-");
1125 }
1126 printf("\n");
cdce23b3 1127}
2bd4b3e4
BP
1128
1129
1130/*
1131 * A GHashFunc for g_hash_table_new()
1132 *
1133 * Args:
1134 * key struct RttKey*
1135 */
1136static guint ghfRttKeyHash(gconstpointer key)
1137{
1138 struct RttKey* rttKey;
1139 uint32_t a, b, c;
1140
1141 rttKey= (struct RttKey*) key;
1142
1143 a= rttKey->saddr;
1144 b= rttKey->daddr;
1145 c= 0;
1146 final(a, b, c);
1147
1148 return c;
1149}
1150
1151
1152/*
1153 * A GDestroyNotify function for g_hash_table_new_full()
1154 *
1155 * Args:
1156 * data: struct RttKey*
1157 */
1158static void gdnDestroyRttKey(gpointer data)
1159{
1160 free(data);
1161}
1162
1163
1164/*
1165 * A GDestroyNotify function for g_hash_table_new_full()
1166 *
1167 * Args:
1168 * data: double*
1169 */
1170static void gdnDestroyDouble(gpointer data)
1171{
1172 free(data);
1173}
1174
1175
1176/*
1177 * A GEqualFunc for g_hash_table_new()
1178 *
1179 * Args:
1180 * a, b RttKey*
1181 *
1182 * Returns:
1183 * TRUE if both values are equal
1184 */
1185static gboolean gefRttKeyEqual(gconstpointer a, gconstpointer b)
1186{
1187 const struct RttKey* rkA, * rkB;
1188
1189 rkA= (struct RttKey*) a;
1190 rkB= (struct RttKey*) b;
1191
1192 if (rkA->saddr == rkB->saddr && rkA->daddr == rkB->daddr)
1193 {
1194 return TRUE;
1195 }
1196 else
1197 {
1198 return FALSE;
1199 }
1200}
1201
1202
1203/*
1204 * Read a file contain minimum round trip time values and fill an array with
1205 * them. The file is formatted as such:
1206 * <host1 IP> <host2 IP> <RTT in milliseconds>
1207 * ip's should be in dotted quad format
1208 *
1209 * Args:
1210 * rttInfo: double* rttInfo[RttKey], empty table, will be filled
1211 * rttStream: stream from which to read
1212 */
1213static void readRttInfo(GHashTable* rttInfo, FILE* rttStream)
1214{
1215 char* line= NULL;
1216 size_t len;
1217 int retval;
1218
1219 positionStream(rttStream);
1220 retval= getline(&line, &len, rttStream);
1221 while(!feof(rttStream))
1222 {
1223 struct RttKey* rttKey;
1224 char saddrDQ[20], daddrDQ[20];
1225 double* rtt;
1226 char tmp;
1227 struct in_addr addr;
1228 unsigned int i;
1229 struct {
1230 char* dq;
1231 size_t offset;
1232 } loopValues[] = {
1233 {saddrDQ, offsetof(struct RttKey, saddr)},
1234 {daddrDQ, offsetof(struct RttKey, daddr)}
1235 };
1236
1237 if (retval == -1 && !feof(rttStream))
1238 {
1239 g_error(strerror(errno));
1240 }
1241
1242 if (line[retval - 1] == '\n')
1243 {
1244 line[retval - 1]= '\0';
1245 }
1246
1247 rtt= malloc(sizeof(double));
1248 retval= sscanf(line, " %19s %19s %lf %c", saddrDQ, daddrDQ, rtt,
1249 &tmp);
1250 if (retval == EOF)
1251 {
1252 g_error(strerror(errno));
1253 }
1254 else if (retval != 3)
1255 {
1256 g_error("Error parsing RTT file, line was '%s'", line);
1257 }
1258
1259 rttKey= malloc(sizeof(struct RttKey));
1260 for (i= 0; i < sizeof(loopValues) / sizeof(*loopValues); i++)
1261 {
1262 retval= inet_aton(loopValues[i].dq, &addr);
1263 if (retval == 0)
1264 {
1265 g_error("Error converting address '%s'", loopValues[i].dq);
1266 }
1267 *(uint32_t*) ((void*) rttKey + loopValues[i].offset)=
1268 addr.s_addr;
1269 }
1270
76be6fc2 1271 *rtt/= 1e3;
d4721e1a
BP
1272 g_debug("rttInfo, Inserting (%u, %u)->(%f)", rttKey->saddr,
1273 rttKey->daddr, *rtt);
2bd4b3e4
BP
1274 g_hash_table_insert(rttInfo, rttKey, rtt);
1275
1276 positionStream(rttStream);
1277 retval= getline(&line, &len, rttStream);
1278 }
1279
1280 if (line)
1281 {
1282 free(line);
1283 }
1284}
1285
1286
1287/*
1288 * Advance stream over empty space, empty lines and lines that begin with '#'
1289 *
1290 * Args:
1291 * stream: stream, at exit, will be over the first non-empty character
1292 * of a line of be at EOF
1293 */
1294static void positionStream(FILE* stream)
1295{
1296 int firstChar;
1297 ssize_t retval;
1298 char* line= NULL;
1299 size_t len;
1300
1301 do
1302 {
1303 firstChar= fgetc(stream);
1304 if (firstChar == (int) '#')
1305 {
1306 retval= getline(&line, &len, stream);
1307 if (retval == -1)
1308 {
1309 if (feof(stream))
1310 {
1311 goto outEof;
1312 }
1313 else
1314 {
1315 g_error(strerror(errno));
1316 }
1317 }
1318 }
1319 else if (firstChar == (int) '\n' || firstChar == (int) ' ' ||
1320 firstChar == (int) '\t')
1321 {}
1322 else if (firstChar == EOF)
1323 {
1324 goto outEof;
1325 }
1326 else
1327 {
1328 break;
1329 }
1330 } while (true);
1331 retval= ungetc(firstChar, stream);
1332 if (retval == EOF)
1333 {
1334 g_error("Error: ungetc()");
1335 }
1336
1337outEof:
1338 if (line)
1339 {
1340 free(line);
1341 }
1342}
76be6fc2
BP
1343
1344
1345/*
1346 * A GFunc for g_queue_foreach()
1347 *
1348 * Args:
1349 * data Event*, a UDP broadcast event
1350 * user_data double*, the running sum
1351 *
1352 * Returns:
1353 * Adds the time of the event to the sum
1354 */
1355static void gfSum(gpointer data, gpointer userData)
1356{
1357 Event* event= (Event*) data;
1358
1359 *(double*) userData+= event->wallTime.seconds + event->wallTime.nanosec /
1360 1e9;
1361}
1362
1363
1364/*
1365 * A GFunc for g_queue_foreach()
1366 *
1367 * Args:
1368 * data Event*, a UDP broadcast event
1369 * user_data double*, the running sum
1370 *
1371 * Returns:
1372 * Adds the square of the time of the event to the sum
1373 */
1374static void gfSumSquares(gpointer data, gpointer userData)
1375{
1376 Event* event= (Event*) data;
1377
1378 *(double*) userData+= pow(event->wallTime.seconds + event->wallTime.nanosec
1379 / 1e9, 2.);
1380}
4ee223e5
BP
1381
1382
e072e1ab
BP
1383/*
1384 * Update a struct Bins according to a new value
1385 *
1386 * Args:
1387 * bins: the structure containing bins to build a histrogram
1388 * value: the new value
1389 */
1390static void hitBin(struct Bins* const bins, const double value)
1391{
1392 unsigned int binN= binNum(value);
1393
1394 if (binN < bins->min)
1395 {
1396 bins->min= binN;
1397 }
1398 else if (binN > bins->max)
1399 {
1400 bins->max= binN;
1401 }
1402
1403 bins->total++;
1404
1405 bins->bin[binN]++;
1406}
1407
1408
4ee223e5
BP
1409/*
1410 * Figure out the bin in a histogram to which a value belongs.
1411 *
1412 * This uses exponentially sized bins that go from 0 to infinity.
1413 *
1414 * Args:
e072e1ab
BP
1415 * value: in the range -INFINITY to INFINITY
1416 *
1417 * Returns:
1418 * The number of the bin in a struct Bins.bin
4ee223e5
BP
1419 */
1420static unsigned int binNum(const double value)
1421{
e072e1ab 1422 if (value <= 0)
4ee223e5
BP
1423 {
1424 return 0;
1425 }
e072e1ab
BP
1426 else if (value < binEnd(1))
1427 {
1428 return 1;
1429 }
1430 else if (value >= binStart(BIN_NB - 1))
1431 {
1432 return BIN_NB - 1;
1433 }
4ee223e5
BP
1434 else
1435 {
e072e1ab 1436 return floor(log(value) / log(binBase)) + BIN_NB + 1;
4ee223e5
BP
1437 }
1438}
1439
1440
1441/*
e072e1ab
BP
1442 * Figure out the start of the interval of a bin in a histogram. See struct
1443 * Bins.
4ee223e5
BP
1444 *
1445 * This uses exponentially sized bins that go from 0 to infinity.
1446 *
1447 * Args:
1448 * binNum: bin number
e072e1ab
BP
1449 *
1450 * Return:
1451 * The start of the interval, this value is included in the interval (except
1452 * for -INFINITY, naturally)
4ee223e5
BP
1453 */
1454static double binStart(const unsigned int binNum)
1455{
e072e1ab 1456 g_assert_cmpuint(binNum, <, BIN_NB);
4ee223e5
BP
1457
1458 if (binNum == 0)
1459 {
e072e1ab
BP
1460 return -INFINITY;
1461 }
1462 else if (binNum == 1)
1463 {
1464 return 0.;
4ee223e5
BP
1465 }
1466 else
1467 {
e072e1ab 1468 return pow(binBase, (double) binNum - BIN_NB + 1);
4ee223e5
BP
1469 }
1470}
1471
1472
1473/*
e072e1ab
BP
1474 * Figure out the end of the interval of a bin in a histogram. See struct
1475 * Bins.
4ee223e5
BP
1476 *
1477 * This uses exponentially sized bins that go from 0 to infinity.
1478 *
1479 * Args:
1480 * binNum: bin number
e072e1ab
BP
1481 *
1482 * Return:
1483 * The end of the interval, this value is not included in the interval
4ee223e5
BP
1484 */
1485static double binEnd(const unsigned int binNum)
1486{
e072e1ab 1487 g_assert_cmpuint(binNum, <, BIN_NB);
4ee223e5 1488
e072e1ab 1489 if (binNum == 0)
4ee223e5 1490 {
e072e1ab
BP
1491 return 0.;
1492 }
1493 else if (binNum < BIN_NB - 1)
1494 {
1495 return pow(binBase, (double) binNum - BIN_NB + 2);
4ee223e5
BP
1496 }
1497 else
1498 {
1499 return INFINITY;
1500 }
1501}
467066ee
BP
1502
1503
1504/*
1505 * Return the total number of elements in the "normal" bins (not underflow or
1506 * overflow)
1507 *
1508 * Args:
1509 * bins: the structure containing bins to build a histrogram
1510 */
1511static uint32_t normalTotal(struct Bins* const bins)
1512{
1513 return bins->total - bins->bin[0] - bins->bin[BIN_NB - 1];
1514}
66eaf2eb
BP
1515
1516
1517/* Update the bounds between two traces
1518 *
1519 * Args:
1520 * bounds: the array containing all the trace-pair bounds
1521 * e1, e2: the two related events
1522 */
c6356aa7
BP
1523static void updateBounds(Bounds** const bounds, Event* const e1, Event* const
1524 e2)
66eaf2eb
BP
1525{
1526 unsigned int traceI, traceJ;
1527 uint64_t messageTime;
1528 Bounds* tpBounds;
1529
1530 if (e1->traceNum < e2->traceNum)
1531 {
1532 traceI= e2->traceNum;
1533 traceJ= e1->traceNum;
1534 messageTime= e1->cpuTime;
1535 }
1536 else
1537 {
1538 traceI= e1->traceNum;
1539 traceJ= e2->traceNum;
1540 messageTime= e2->cpuTime;
1541 }
1542 tpBounds= &bounds[traceI][traceJ];
1543
1544 if (messageTime < tpBounds->min)
1545 {
1546 tpBounds->min= messageTime;
1547 }
1548 if (messageTime > tpBounds->max)
1549 {
1550 tpBounds->max= messageTime;
1551 }
1552}
1553
1554
1555#ifdef HAVE_LIBGLPK
1556/*
1557 * Create the linear programming problem containing the constraints defined by
1558 * two half-hulls. The objective function and optimization directions are not
1559 * written.
1560 *
1561 * Args:
1562 * syncState: container for synchronization data
1563 * i: first trace number
1564 * j: second trace number, garanteed to be larger than i
1565 * Returns:
1566 * A new glp_prob*, this problem must be freed by the caller with
1567 * glp_delete_prob()
1568 */
c6356aa7
BP
1569static glp_prob* lpCreateProblem(GQueue* const lowerHull, GQueue* const
1570 upperHull)
66eaf2eb
BP
1571{
1572 unsigned int it;
1573 const int zero= 0;
1574 const double zeroD= 0.;
1575 glp_prob* lp= glp_create_prob();
1576 unsigned int hullPointNb= g_queue_get_length(lowerHull) +
1577 g_queue_get_length(upperHull);
1578 GArray* iArray= g_array_sized_new(FALSE, FALSE, sizeof(int), hullPointNb +
1579 1);
1580 GArray* jArray= g_array_sized_new(FALSE, FALSE, sizeof(int), hullPointNb +
1581 1);
1582 GArray* aArray= g_array_sized_new(FALSE, FALSE, sizeof(double),
1583 hullPointNb + 1);
1584 struct {
1585 GQueue* hull;
1586 struct LPAddRowInfo rowInfo;
1587 } loopValues[2]= {
1588 {lowerHull, {lp, GLP_UP, iArray, jArray, aArray}},
1589 {upperHull, {lp, GLP_LO, iArray, jArray, aArray}},
1590 };
1591
1592 // Create the LP problem
1593 glp_term_out(GLP_OFF);
dce9bf0c
BP
1594 if (hullPointNb > 0)
1595 {
1596 glp_add_rows(lp, hullPointNb);
1597 }
66eaf2eb
BP
1598 glp_add_cols(lp, 2);
1599
1600 glp_set_col_name(lp, 1, "a0");
1601 glp_set_col_bnds(lp, 1, GLP_FR, 0., 0.);
1602 glp_set_col_name(lp, 2, "a1");
1603 glp_set_col_bnds(lp, 2, GLP_LO, 0., 0.);
1604
1605 // Add row constraints
1606 g_array_append_val(iArray, zero);
1607 g_array_append_val(jArray, zero);
1608 g_array_append_val(aArray, zeroD);
1609
1610 for (it= 0; it < sizeof(loopValues) / sizeof(*loopValues); it++)
1611 {
1612 g_queue_foreach(loopValues[it].hull, &gfLPAddRow,
1613 &loopValues[it].rowInfo);
1614 }
1615
1616 g_assert_cmpuint(iArray->len, ==, jArray->len);
1617 g_assert_cmpuint(jArray->len, ==, aArray->len);
1618 g_assert_cmpuint(aArray->len - 1, ==, hullPointNb * 2);
1619
1620 glp_load_matrix(lp, aArray->len - 1, &g_array_index(iArray, int, 0),
1621 &g_array_index(jArray, int, 0), &g_array_index(aArray, double, 0));
1622
1623 glp_scale_prob(lp, GLP_SF_AUTO);
1624
1625 g_array_free(iArray, TRUE);
1626 g_array_free(jArray, TRUE);
1627 g_array_free(aArray, TRUE);
1628
1629 return lp;
1630}
1631
1632
1633/*
1634 * A GFunc for g_queue_foreach(). Add constraints and bounds for one row.
1635 *
1636 * Args:
1637 * data Point*, synchronization point for which to add an LP row
1638 * (a constraint)
1639 * user_data LPAddRowInfo*
1640 */
1641static void gfLPAddRow(gpointer data, gpointer user_data)
1642{
1643 Point* p= data;
1644 struct LPAddRowInfo* rowInfo= user_data;
1645 int indexes[2];
1646 double constraints[2];
1647
1648 indexes[0]= g_array_index(rowInfo->iArray, int, rowInfo->iArray->len - 1) + 1;
1649 indexes[1]= indexes[0];
1650
1651 if (rowInfo->boundType == GLP_UP)
1652 {
1653 glp_set_row_bnds(rowInfo->lp, indexes[0], GLP_UP, 0., p->y);
1654 }
1655 else if (rowInfo->boundType == GLP_LO)
1656 {
1657 glp_set_row_bnds(rowInfo->lp, indexes[0], GLP_LO, p->y, 0.);
1658 }
1659 else
1660 {
1661 g_assert_not_reached();
1662 }
1663
1664 g_array_append_vals(rowInfo->iArray, indexes, 2);
1665 indexes[0]= 1;
1666 indexes[1]= 2;
1667 g_array_append_vals(rowInfo->jArray, indexes, 2);
1668 constraints[0]= 1.;
1669 constraints[1]= p->x;
1670 g_array_append_vals(rowInfo->aArray, constraints, 2);
1671}
1672
1673
1674/*
1675 * Calculate min or max correction factors (as possible) using an LP problem.
1676 *
1677 * Args:
1678 * lp: A linear programming problem with constraints and bounds
1679 * initialized.
1680 * direction: The type of factors desired. Use GLP_MAX for max
1681 * approximation factors (a1, the drift or slope is the
1682 * largest) and GLP_MIN in the other case.
1683 *
1684 * Returns:
1685 * If the calculation was successful, a new Factors struct. Otherwise, NULL.
1686 * The calculation will fail if the hull assumptions are not respected.
1687 */
1688static Factors* calculateFactors(glp_prob* const lp, const int direction)
1689{
1690 int retval, status;
1691 Factors* factors;
1692
1693 glp_set_obj_coef(lp, 1, 0.);
1694 glp_set_obj_coef(lp, 2, 1.);
1695
1696 glp_set_obj_dir(lp, direction);
1697 retval= glp_simplex(lp, NULL);
1698 status= glp_get_status(lp);
1699
1700 if (retval == 0 && status == GLP_OPT)
1701 {
1702 factors= malloc(sizeof(Factors));
1703 factors->offset= glp_get_col_prim(lp, 1);
1704 factors->drift= glp_get_col_prim(lp, 2);
1705 }
1706 else
1707 {
1708 factors= NULL;
1709 }
1710
1711 return factors;
1712}
1713
1714
1715/*
1716 * Calculate min, max and approx correction factors (as possible) using an LP
1717 * problem.
1718 *
1719 * Args:
1720 * lp: A linear programming problem with constraints and bounds
1721 * initialized.
1722 *
1723 * Returns:
1724 * Please note that the approximation type may be MIDDLE, INCOMPLETE or
1725 * ABSENT. Unlike in analysis_chull, ABSENT is also used when the hulls do
1726 * not respect assumptions.
1727 */
1728static void calculateCompleteFactors(glp_prob* const lp, FactorsCHull* factors)
1729{
1730 factors->min= calculateFactors(lp, GLP_MIN);
1731 factors->max= calculateFactors(lp, GLP_MAX);
1732
1733 if (factors->min && factors->max)
1734 {
1735 factors->type= MIDDLE;
1736 calculateFactorsMiddle(factors);
1737 }
1738 else if (factors->min || factors->max)
1739 {
1740 factors->type= INCOMPLETE;
1741 factors->approx= NULL;
1742 }
1743 else
1744 {
1745 factors->type= ABSENT;
1746 factors->approx= NULL;
1747 }
1748}
1749
1750
1751/*
1752 * Create and initialize an array like AnalysisStatsCHull.allFactors
1753 *
1754 * Args:
1755 * traceNb: number of traces
1756 *
1757 * Returns:
1758 * A new array, which can be freed with freeAllFactors()
1759 */
1760static FactorsCHull** createAllFactors(const unsigned int traceNb)
1761{
1762 FactorsCHull** factorsArray;
1763 unsigned int i;
1764
1765 factorsArray= malloc(traceNb * sizeof(FactorsCHull*));
1766 for (i= 0; i < traceNb; i++)
1767 {
1768 factorsArray[i]= calloc((i + 1), sizeof(FactorsCHull));
1769
1770 factorsArray[i][i].type= EXACT;
1771 factorsArray[i][i].approx= malloc(sizeof(Factors));
1772 factorsArray[i][i].approx->drift= 1.;
1773 factorsArray[i][i].approx->offset= 0.;
1774 }
1775
1776 return factorsArray;
1777}
9a04f8a3
BP
1778
1779
1780/*
1781 * A GFunc for g_queue_foreach()
1782 *
1783 * Args:
1784 * data Point*, a convex hull point
1785 * user_data GArray*, an array of convex hull point absisca values, as
1786 * double
1787 */
1788static void gfAddAbsiscaToArray(gpointer data, gpointer user_data)
1789{
1790 Point* p= data;
1791 GArray* a= user_data;
1792 double v= p->x;
1793
1794 g_array_append_val(a, v);
1795}
1796
1797
1798/*
1799 * A GCompareFunc for g_array_sort()
1800 *
1801 * Args:
1802 * a, b double*, absisca values
1803 *
1804 * Returns:
1805 * "returns less than zero for first arg is less than second arg, zero for
1806 * equal, greater zero if first arg is greater than second arg"
1807 * - the great glib documentation
1808 */
1809static gint gcfCompareDouble(gconstpointer a, gconstpointer b)
1810{
1811 if (*(double*) a < *(double*) b)
1812 {
1813 return -1;
1814 }
1815 else if (*(double*) a > *(double*) b)
1816 {
1817 return 1;
1818 }
1819 else
1820 {
1821 return 0;
1822 }
1823}
66eaf2eb
BP
1824#endif
1825
1826
1827/*
1828 * Compute synchronization factors using a linear programming approach.
1829 * Compute the factors using analysis_chull. Compare the two.
1830 *
05a840df
BP
1831 * When the solver library, glpk, is not available at build time, only compute
1832 * the factors using analysis_chull. This is to make sure that module runs its
1833 * finalize function so that its graph functions can be called later.
66eaf2eb
BP
1834 *
1835 * Args:
1836 * syncState: container for synchronization data
1837 */
66eaf2eb
BP
1838static void finalizeAnalysisEvalLP(SyncState* const syncState)
1839{
66eaf2eb 1840 AnalysisDataEval* analysisData= syncState->analysisData;
05a840df
BP
1841#ifdef HAVE_LIBGLPK
1842 unsigned int i, j;
66eaf2eb 1843 AnalysisDataCHull* chAnalysisData= analysisData->chullSS->analysisData;
6ce8ceac 1844 FactorsCHull** lpFactorsArray;
66eaf2eb
BP
1845
1846 if (!syncState->stats && !syncState->graphsStream)
1847 {
1848 return;
1849 }
1850
6ce8ceac
BP
1851 /* Because of matching_distributor, this analysis may be called twice.
1852 * Only run it once */
66eaf2eb
BP
1853 if ((syncState->graphsStream && analysisData->graphs->lps != NULL) ||
1854 (syncState->stats && analysisData->stats->chFactorsArray != NULL))
1855 {
1856 return;
1857 }
1858
6ce8ceac
BP
1859 lpFactorsArray= createAllFactors(syncState->traceNb);
1860
66eaf2eb
BP
1861 if (syncState->stats)
1862 {
1863 analysisData->stats->chFactorsArray=
1864 calculateAllFactors(analysisData->chullSS);
1865 analysisData->stats->lpFactorsArray= lpFactorsArray;
1866 }
1867
1868 if (syncState->graphsStream)
1869 {
1870 analysisData->graphs->lps= malloc(syncState->traceNb *
1871 sizeof(glp_prob**));
1872 for (i= 0; i < syncState->traceNb; i++)
1873 {
1874 analysisData->graphs->lps[i]= malloc(i * sizeof(glp_prob*));
1875 }
1876 analysisData->graphs->lpFactorsArray= lpFactorsArray;
1877 }
1878
1879 for (i= 0; i < syncState->traceNb; i++)
1880 {
1881 for (j= 0; j < i; j++)
1882 {
1883 glp_prob* lp;
1884
1885 // Create the LP problem
1886 lp= lpCreateProblem(chAnalysisData->hullArray[i][j],
1887 chAnalysisData->hullArray[j][i]);
1888
1889 // Use the LP problem to find the correction factors for this pair of
1890 // traces
1891 calculateCompleteFactors(lp, &lpFactorsArray[i][j]);
1892
1893 if (syncState->graphsStream)
1894 {
1895 analysisData->graphs->lps[i][j]= lp;
1896 }
1897 else
1898 {
1899 glp_delete_prob(lp);
66eaf2eb
BP
1900 }
1901 }
1902 }
05a840df 1903#endif
66eaf2eb
BP
1904
1905 g_array_free(analysisData->chullSS->analysisModule->finalizeAnalysis(analysisData->chullSS),
1906 TRUE);
1907}
66eaf2eb
BP
1908
1909
1910/*
1911 * Compute synchronization accuracy information using a linear programming
1912 * approach. Write the neccessary data files and plot lines in the gnuplot
1913 * script.
1914 *
c5571851
BP
1915 * When the solver library, glpk, is not available at build time nothing is
1916 * actually produced.
66eaf2eb
BP
1917 *
1918 * Args:
1919 * syncState: container for synchronization data
1920 * i: first trace number
1921 * j: second trace number, garanteed to be larger than i
1922 */
c5571851
BP
1923static void writeAnalysisTraceTimeBackPlotsEval(SyncState* const syncState,
1924 const unsigned int i, const unsigned int j)
66eaf2eb 1925{
c5571851 1926#ifdef HAVE_LIBGLPK
66eaf2eb
BP
1927 unsigned int it;
1928 AnalysisDataEval* analysisData= syncState->analysisData;
1929 AnalysisGraphsEval* graphs= analysisData->graphs;
1930 GQueue*** hullArray= ((AnalysisDataCHull*)
1931 analysisData->chullSS->analysisData)->hullArray;
1932 FactorsCHull* lpFactors= &graphs->lpFactorsArray[j][i];
1933 glp_prob* lp= graphs->lps[j][i];
1934
1935 if (lpFactors->type == MIDDLE)
1936 {
1937 int retval;
1938 char* cwd;
1939 char fileName[40];
1940 FILE* fp;
9a04f8a3 1941 GArray* xValues;
66eaf2eb
BP
1942
1943 // Open the data file
1944 snprintf(fileName, 40, "analysis_eval_accuracy-%03u_and_%03u.data", i, j);
1945 fileName[sizeof(fileName) - 1]= '\0';
1946
1d597550 1947 cwd= changeToGraphsDir(syncState->graphsDir);
66eaf2eb
BP
1948
1949 if ((fp= fopen(fileName, "w")) == NULL)
1950 {
1951 g_error(strerror(errno));
1952 }
1953 fprintf(fp, "#%-24s %-25s %-25s %-25s\n", "x", "middle", "min", "max");
1954
1955 retval= chdir(cwd);
1956 if (retval == -1)
1957 {
1958 g_error(strerror(errno));
1959 }
1960 free(cwd);
1961
1962 // Build the list of absisca values for the points in the accuracy graph
9a04f8a3
BP
1963 xValues= g_array_sized_new(FALSE, FALSE, sizeof(double),
1964 g_queue_get_length(hullArray[i][j]) +
1965 g_queue_get_length(hullArray[j][i]));
66eaf2eb 1966
9a04f8a3
BP
1967 g_queue_foreach(hullArray[i][j], &gfAddAbsiscaToArray, xValues);
1968 g_queue_foreach(hullArray[j][i], &gfAddAbsiscaToArray, xValues);
1969
1970 g_array_sort(xValues, &gcfCompareDouble);
66eaf2eb
BP
1971
1972 /* For each absisca value and each optimisation direction, solve the LP
1973 * and write a line in the data file */
9a04f8a3 1974 for (it= 0; it < xValues->len; it++)
66eaf2eb
BP
1975 {
1976 unsigned int it2;
1977 int directions[]= {GLP_MIN, GLP_MAX};
66eaf2eb 1978 glp_set_obj_coef(lp, 1, 1.);
9a04f8a3 1979 glp_set_obj_coef(lp, 2, g_array_index(xValues, double, it));
66eaf2eb 1980
9a04f8a3 1981 fprintf(fp, "%25.9f %25.9f", g_array_index(xValues, double, it),
2849af52 1982 lpFactors->approx->offset + lpFactors->approx->drift *
9a04f8a3 1983 g_array_index(xValues, double, it));
66eaf2eb
BP
1984 for (it2= 0; it2 < sizeof(directions) / sizeof(*directions); it2++)
1985 {
1986 int status;
1987
1988 glp_set_obj_dir(lp, directions[it2]);
1989 retval= glp_simplex(lp, NULL);
1990 status= glp_get_status(lp);
1991
1992 g_assert(retval == 0 && status == GLP_OPT);
1993 fprintf(fp, " %25.9f", glp_get_obj_val(lp));
1994 }
1995 fprintf(fp, "\n");
1996 }
1997
9a04f8a3 1998 g_array_free(xValues, TRUE);
66eaf2eb
BP
1999 fclose(fp);
2000
2001 fprintf(syncState->graphsStream,
2002 "\t\"analysis_eval_accuracy-%1$03u_and_%2$03u.data\" "
2003 "using 1:(($3 - $2) / clock_freq_%2$u):(($4 - $2) / clock_freq_%2$u) "
2004 "title \"Synchronization accuracy\" "
2005 "with filledcurves linewidth 2 linetype 1 "
2006 "linecolor rgb \"black\" fill solid 0.25 noborder, \\\n", i,
2007 j);
2008 }
66eaf2eb 2009#endif
c5571851 2010}
66eaf2eb
BP
2011
2012
2013/*
2014 * Write the analysis-specific graph lines in the gnuplot script.
2015 *
c5571851
BP
2016 * When the solver library, glpk, is not available at build time nothing is
2017 * actually produced.
2018 *
66eaf2eb
BP
2019 * Args:
2020 * syncState: container for synchronization data
2021 * i: first trace number
2022 * j: second trace number, garanteed to be larger than i
2023 */
c5571851
BP
2024static void writeAnalysisTraceTimeForePlotsEval(SyncState* const syncState,
2025 const unsigned int i, const unsigned int j)
66eaf2eb 2026{
c5571851
BP
2027#ifdef HAVE_LIBGLPK
2028 if (((AnalysisDataEval*)
2029 syncState->analysisData)->graphs->lpFactorsArray[j][i].type ==
2030 MIDDLE)
2031 {
2032 fprintf(syncState->graphsStream,
2033 "\t\"analysis_eval_accuracy-%1$03u_and_%2$03u.data\" "
2034 "using 1:(($3 - $2) / clock_freq_%2$u) notitle "
2035 "with lines linewidth 2 linetype 1 "
2036 "linecolor rgb \"gray60\", \\\n"
2037 "\t\"analysis_eval_accuracy-%1$03u_and_%2$03u.data\" "
2038 "using 1:(($4 - $2) / clock_freq_%2$u) notitle "
2039 "with lines linewidth 2 linetype 1 "
2040 "linecolor rgb \"gray60\", \\\n", i, j);
2041 }
2042#endif
66eaf2eb
BP
2043}
2044
2045
c6356aa7
BP
2046/*
2047 * Write the analysis-specific graph lines in the gnuplot script.
2048 *
2049 * Args:
2050 * syncState: container for synchronization data
2051 * i: first trace number
2052 * j: second trace number, garanteed to be larger than i
2053 */
2054static void writeAnalysisTraceTraceBackPlotsEval(SyncState* const syncState,
2055 const unsigned int i, const unsigned int j)
66eaf2eb 2056{
66eaf2eb
BP
2057#ifdef HAVE_LIBGLPK
2058 fprintf(syncState->graphsStream,
2059 "\t\"analysis_eval_accuracy-%1$03u_and_%2$03u.data\" "
2060 "using 1:3:4 "
2061 "title \"Synchronization accuracy\" "
2062 "with filledcurves linewidth 2 linetype 1 "
2063 "linecolor rgb \"black\" fill solid 0.25 noborder, \\\n", i, j);
2064#endif
c6356aa7
BP
2065}
2066
2067
2068/*
2069 * Write the analysis-specific graph lines in the gnuplot script.
2070 *
2071 * Args:
2072 * syncState: container for synchronization data
2073 * i: first trace number
2074 * j: second trace number, garanteed to be larger than i
2075 */
2076static void writeAnalysisTraceTraceForePlotsEval(SyncState* const syncState,
2077 const unsigned int i, const unsigned int j)
2078{
2079 AnalysisDataEval* analysisData= syncState->analysisData;
66eaf2eb 2080
c6356aa7 2081 analysisData->chullSS->analysisModule->graphFunctions.writeTraceTraceForePlots(analysisData->chullSS,
66eaf2eb
BP
2082 i, j);
2083}
This page took 0.15292 seconds and 4 git commands to generate.