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