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