Make option type OPTIONAL_ARG available
[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
BP
113
114// The next group of functions is only needed when computing synchronization
115// accuracy.
116#ifdef HAVE_LIBGLPK
c6356aa7
BP
117static glp_prob* lpCreateProblem(GQueue* const lowerHull, GQueue* const
118 upperHull);
66eaf2eb
BP
119static void gfLPAddRow(gpointer data, gpointer user_data);
120static Factors* calculateFactors(glp_prob* const lp, const int direction);
c6356aa7
BP
121static void calculateCompleteFactors(glp_prob* const lp, FactorsCHull*
122 factors);
66eaf2eb
BP
123static FactorsCHull** createAllFactors(const unsigned int traceNb);
124static inline void finalizeAnalysisEvalLP(SyncState* const syncState);
125#else
126static void finalizeAnalysisEvalLP(SyncState* const syncState);
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 */
161static void registerAnalysisEval()
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));
cdce23b3
BP
212 analysisData->stats->broadcastDiffSum= 0.;
213
76be6fc2
BP
214 analysisData->stats->messageStats= malloc(syncState->traceNb *
215 sizeof(MessageStats*));
cdce23b3
BP
216 for (i= 0; i < syncState->traceNb; i++)
217 {
76be6fc2
BP
218 analysisData->stats->messageStats[i]= calloc(syncState->traceNb,
219 sizeof(MessageStats));
cdce23b3 220 }
d4721e1a
BP
221
222 analysisData->stats->exchangeRtt=
223 g_hash_table_new_full(&ghfRttKeyHash, &gefRttKeyEqual,
224 &gdnDestroyRttKey, &gdnDestroyDouble);
66eaf2eb
BP
225
226#ifdef HAVE_LIBGLPK
227 analysisData->stats->chFactorsArray= NULL;
228 analysisData->stats->lpFactorsArray= NULL;
229#endif
cdce23b3 230 }
4ee223e5 231
8d7d16dd 232 if (syncState->graphsStream)
4ee223e5 233 {
66eaf2eb
BP
234 AnalysisGraphsEval* graphs= malloc(sizeof(AnalysisGraphsEval));
235
236 analysisData->graphs= graphs;
237
238 graphs->histograms= g_hash_table_new_full(&ghfRttKeyHash,
239 &gefRttKeyEqual, &gdnDestroyRttKey,
240 &gdnDestroyAnalysisHistogramEval);
241
242 graphs->bounds= malloc(syncState->traceNb * sizeof(Bounds*));
243 for (i= 0; i < syncState->traceNb; i++)
244 {
245 graphs->bounds[i]= malloc(i * sizeof(Bounds));
246 for (j= 0; j < i; j++)
247 {
248 graphs->bounds[i][j].min= UINT64_MAX;
249 graphs->bounds[i][j].max= 0;
250 }
251 }
252
253#ifdef HAVE_LIBGLPK
254 graphs->lps= NULL;
255 graphs->lpFactorsArray= NULL;
256#endif
257 }
258
259 if (syncState->stats || syncState->graphsStream)
260 {
261 GList* result;
262
263 analysisData->chullSS= malloc(sizeof(SyncState));
264 memcpy(analysisData->chullSS, syncState, sizeof(SyncState));
265 analysisData->chullSS->stats= false;
266 analysisData->chullSS->analysisData= NULL;
267 result= g_queue_find_custom(&analysisModules, "chull",
268 &gcfCompareAnalysis);
269 analysisData->chullSS->analysisModule= (AnalysisModule*) result->data;
270 analysisData->chullSS->analysisModule->initAnalysis(analysisData->chullSS);
4ee223e5
BP
271 }
272}
273
274
275/*
e072e1ab
BP
276 * Create and open files used to store histogram points to generate graphs.
277 * Create data structures to store histogram points during analysis.
4ee223e5
BP
278 *
279 * Args:
e072e1ab
BP
280 * graphsDir: folder where to write files
281 * rttKey: host pair, make sure saddr < daddr
4ee223e5 282 */
66eaf2eb 283static AnalysisHistogramEval* constructAnalysisHistogramEval(const char* const
e072e1ab 284 graphsDir, const struct RttKey* const rttKey)
4ee223e5 285{
4ee223e5 286 int retval;
e072e1ab 287 unsigned int i;
4ee223e5 288 char* cwd;
e072e1ab 289 char name[60], saddr[16], daddr[16];
66eaf2eb 290 AnalysisHistogramEval* histogram= calloc(1, sizeof(*histogram));
e072e1ab
BP
291 const struct {
292 size_t pointsOffset;
293 const char* fileName;
294 const char* host1, *host2;
295 } loopValues[]= {
66eaf2eb
BP
296 {offsetof(AnalysisHistogramEval, ttSendPoints),
297 "analysis_eval_tt-%s_to_%s.data", saddr, daddr},
298 {offsetof(AnalysisHistogramEval, ttRecvPoints),
299 "analysis_eval_tt-%s_to_%s.data", daddr, saddr},
300 {offsetof(AnalysisHistogramEval, hrttPoints),
301 "analysis_eval_hrtt-%s_and_%s.data", saddr, daddr},
e072e1ab
BP
302 };
303
66eaf2eb
BP
304 histogram->ttSendBins.min= BIN_NB - 1;
305 histogram->ttRecvBins.min= BIN_NB - 1;
306 histogram->hrttBins.min= BIN_NB - 1;
e072e1ab
BP
307
308 convertIP(saddr, rttKey->saddr);
309 convertIP(daddr, rttKey->daddr);
310
1d597550 311 cwd= changeToGraphsDir(graphsDir);
e072e1ab
BP
312
313 for (i= 0; i < sizeof(loopValues) / sizeof(*loopValues); i++)
4ee223e5 314 {
e072e1ab
BP
315 retval= snprintf(name, sizeof(name), loopValues[i].fileName,
316 loopValues[i].host1, loopValues[i].host2);
317 if (retval > sizeof(name) - 1)
4ee223e5 318 {
e072e1ab 319 name[sizeof(name) - 1]= '\0';
4ee223e5 320 }
66eaf2eb 321 if ((*(FILE**)((void*) histogram + loopValues[i].pointsOffset)=
e072e1ab 322 fopen(name, "w")) == NULL)
4ee223e5 323 {
e072e1ab 324 g_error(strerror(errno));
4ee223e5
BP
325 }
326 }
327
328 retval= chdir(cwd);
329 if (retval == -1)
330 {
331 g_error(strerror(errno));
332 }
333 free(cwd);
e072e1ab 334
66eaf2eb 335 return histogram;
4ee223e5
BP
336}
337
338
339/*
e072e1ab 340 * Close files used to store histogram points to generate graphs.
4ee223e5
BP
341 *
342 * Args:
e072e1ab
BP
343 * graphsDir: folder where to write files
344 * rttKey: host pair, make sure saddr < daddr
4ee223e5 345 */
66eaf2eb
BP
346static void destroyAnalysisHistogramEval(AnalysisHistogramEval* const
347 histogram)
4ee223e5 348{
e072e1ab
BP
349 unsigned int i;
350 int retval;
351 const struct {
352 size_t pointsOffset;
353 } loopValues[]= {
66eaf2eb
BP
354 {offsetof(AnalysisHistogramEval, ttSendPoints)},
355 {offsetof(AnalysisHistogramEval, ttRecvPoints)},
356 {offsetof(AnalysisHistogramEval, hrttPoints)},
e072e1ab
BP
357 };
358
359 for (i= 0; i < sizeof(loopValues) / sizeof(*loopValues); i++)
4ee223e5 360 {
66eaf2eb 361 retval= fclose(*(FILE**)((void*) histogram + loopValues[i].pointsOffset));
e072e1ab 362 if (retval != 0)
4ee223e5 363 {
e072e1ab 364 g_error(strerror(errno));
4ee223e5
BP
365 }
366 }
66eaf2eb
BP
367
368 free(histogram);
4ee223e5
BP
369}
370
371
e072e1ab
BP
372/*
373 * A GDestroyNotify function for g_hash_table_new_full()
374 *
375 * Args:
66eaf2eb 376 * data: AnalysisHistogramEval*
e072e1ab 377 */
66eaf2eb 378static void gdnDestroyAnalysisHistogramEval(gpointer data)
e072e1ab 379{
66eaf2eb 380 destroyAnalysisHistogramEval(data);
e072e1ab
BP
381}
382
383
384/*
385 * A GHFunc for g_hash_table_foreach()
386 *
387 * Args:
388 * key: RttKey* where saddr < daddr
66eaf2eb
BP
389 * value: AnalysisHistogramEval*
390 * user_data struct WriteHistogramInfo*
e072e1ab 391 */
66eaf2eb 392static void ghfWriteHistogram(gpointer key, gpointer value, gpointer user_data)
e072e1ab
BP
393{
394 double* rtt1, * rtt2;
395 struct RttKey* rttKey= key;
396 struct RttKey oppositeRttKey= {.saddr= rttKey->daddr, .daddr=
397 rttKey->saddr};
66eaf2eb
BP
398 AnalysisHistogramEval* histogram= value;
399 struct WriteHistogramInfo* info= user_data;
e072e1ab
BP
400
401 rtt1= g_hash_table_lookup(info->rttInfo, rttKey);
402 rtt2= g_hash_table_lookup(info->rttInfo, &oppositeRttKey);
403
404 if (rtt1 == NULL)
405 {
406 rtt1= rtt2;
407 }
408 else if (rtt2 != NULL)
409 {
410 rtt1= MIN(rtt1, rtt2);
411 }
412
66eaf2eb
BP
413 dumpBinToFile(&histogram->ttSendBins, histogram->ttSendPoints);
414 dumpBinToFile(&histogram->ttRecvBins, histogram->ttRecvPoints);
415 dumpBinToFile(&histogram->hrttBins, histogram->hrttPoints);
416 writeHistogram(info->graphsStream, rttKey, rtt1, histogram);
e072e1ab
BP
417}
418
419
4ee223e5
BP
420/*
421 * Write the content of one bin in a histogram point file
422 *
423 * Args:
424 * bin: array of values that make up a histogram
e072e1ab 425 * file: FILE*, write to this file
4ee223e5 426 */
e072e1ab 427static void dumpBinToFile(const struct Bins* const bins, FILE* const file)
4ee223e5
BP
428{
429 unsigned int i;
430
e072e1ab
BP
431 // The first and last bins are skipped, see struct Bins
432 for (i= 1; i < BIN_NB - 1; i++)
4ee223e5 433 {
e072e1ab 434 if (bins->bin[i] > 0)
4ee223e5 435 {
e072e1ab
BP
436 fprintf(file, "%20.9f %20.9f %20.9f\n", (binStart(i) + binEnd(i))
437 / 2., (double) bins->bin[i] / ((binEnd(i) - binStart(i)) *
438 bins->total), binEnd(i) - binStart(i));
4ee223e5
BP
439 }
440 }
441}
442
443
444/*
e072e1ab 445 * Write the analysis-specific plot in the gnuplot script.
4ee223e5
BP
446 *
447 * Args:
e072e1ab
BP
448 * graphsStream: write to this file
449 * rttKey: must be sorted such that saddr < daddr
450 * minRtt: if available, else NULL
66eaf2eb 451 * histogram: struct that contains the bins for the pair of traces
467066ee 452 * identified by rttKey
4ee223e5 453 */
e072e1ab 454static void writeHistogram(FILE* graphsStream, const struct RttKey* rttKey,
66eaf2eb 455 double* minRtt, AnalysisHistogramEval* const histogram)
4ee223e5 456{
e072e1ab 457 char saddr[16], daddr[16];
4ee223e5 458
e072e1ab
BP
459 convertIP(saddr, rttKey->saddr);
460 convertIP(daddr, rttKey->daddr);
4ee223e5 461
e072e1ab 462 fprintf(graphsStream,
66eaf2eb 463 "\nreset\n"
e072e1ab
BP
464 "set output \"histogram-%s-%s.eps\"\n"
465 "set title \"\"\n"
466 "set xlabel \"Message Latency (s)\"\n"
467 "set ylabel \"Proportion of messages per second\"\n", saddr, daddr);
4ee223e5 468
e072e1ab 469 if (minRtt != NULL)
4ee223e5 470 {
e072e1ab
BP
471 fprintf(graphsStream,
472 "set arrow from %.9f, 0 rto 0, graph 1 "
467066ee
BP
473 "nohead linetype 3 linewidth 3 linecolor rgb \"black\"\n", *minRtt
474 / 2);
4ee223e5 475 }
4ee223e5 476
66eaf2eb
BP
477 if (normalTotal(&histogram->ttSendBins) ||
478 normalTotal(&histogram->ttRecvBins) ||
479 normalTotal(&histogram->hrttBins))
467066ee
BP
480 {
481 fprintf(graphsStream, "plot \\\n");
482
66eaf2eb 483 if (normalTotal(&histogram->hrttBins))
467066ee
BP
484 {
485 fprintf(graphsStream,
486 "\t\"analysis_eval_hrtt-%s_and_%s.data\" "
487 "title \"RTT/2\" with linespoints linetype 1 linewidth 2 "
488 "linecolor rgb \"black\" pointtype 6 pointsize 1,\\\n",
489 saddr, daddr);
490 }
491
66eaf2eb 492 if (normalTotal(&histogram->ttSendBins))
467066ee
BP
493 {
494 fprintf(graphsStream,
495 "\t\"analysis_eval_tt-%1$s_to_%2$s.data\" "
496 "title \"%1$s to %2$s\" with linespoints linetype 4 linewidth 2 "
497 "linecolor rgb \"gray60\" pointtype 6 pointsize 1,\\\n",
498 saddr, daddr);
499 }
500
66eaf2eb 501 if (normalTotal(&histogram->ttRecvBins))
467066ee
BP
502 {
503 fprintf(graphsStream,
504 "\t\"analysis_eval_tt-%1$s_to_%2$s.data\" "
505 "title \"%1$s to %2$s\" with linespoints linetype 4 linewidth 2 "
506 "linecolor rgb \"gray30\" pointtype 6 pointsize 1,\\\n",
507 daddr, saddr);
508 }
509
510 // Remove the ",\\\n" from the last graph plot line
511 if (ftruncate(fileno(graphsStream), ftell(graphsStream) - 3) == -1)
512 {
513 g_error(strerror(errno));
514 }
515 if (fseek(graphsStream, 0, SEEK_END) == -1)
516 {
517 g_error(strerror(errno));
518 }
519 fprintf(graphsStream, "\n");
520 }
cdce23b3
BP
521}
522
523
524/*
525 * Analysis destroy function
526 *
527 * Free the analysis specific data structures
528 *
529 * Args:
530 * syncState container for synchronization data.
531 */
532static void destroyAnalysisEval(SyncState* const syncState)
533{
66eaf2eb 534 unsigned int i, j;
cdce23b3
BP
535 AnalysisDataEval* analysisData;
536
537 analysisData= (AnalysisDataEval*) syncState->analysisData;
538
66eaf2eb 539 if (analysisData == NULL)
cdce23b3
BP
540 {
541 return;
542 }
543
2bd4b3e4 544 g_hash_table_destroy(analysisData->rttInfo);
cdce23b3
BP
545
546 if (syncState->stats)
547 {
66eaf2eb
BP
548 AnalysisStatsEval* stats= analysisData->stats;
549
550 for (i= 0; i < syncState->traceNb; i++)
551 {
552 free(stats->messageStats[i]);
553 }
554 free(stats->messageStats);
555
556 g_hash_table_destroy(stats->exchangeRtt);
557
558#ifdef HAVE_LIBGLPK
559 freeAllFactors(syncState->traceNb, stats->chFactorsArray);
560 freeAllFactors(syncState->traceNb, stats->lpFactorsArray);
561#endif
562
563 free(stats);
564 }
565
566 if (syncState->graphsStream)
567 {
568 AnalysisGraphsEval* graphs= analysisData->graphs;
569
570 if (graphs->histograms)
571 {
572 g_hash_table_destroy(graphs->histograms);
573 }
574
cdce23b3
BP
575 for (i= 0; i < syncState->traceNb; i++)
576 {
66eaf2eb
BP
577 free(graphs->bounds[i]);
578 }
579 free(graphs->bounds);
580
581#ifdef HAVE_LIBGLPK
582 for (i= 0; i < syncState->traceNb; i++)
583 {
584 for (j= 0; j < i; j++)
585 {
586 // There seems to be a memory leak in glpk, valgrind reports a
587 // loss even if the problem is deleted
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
BP
987
988 printf("\tConvex hull factors comparisons:\n"
989 "\t\tTrace pair Factors type Differences (lp - chull)\n"
990 "\t\t a0 a1\n"
991 "\t\t Min Max Min Max\n");
992
993 for (i= 0; i < syncState->traceNb; i++)
994 {
995 for (j= 0; j < i; j++)
996 {
997 FactorsCHull* chFactors= &analysisData->stats->chFactorsArray[i][j];
998 FactorsCHull* lpFactors= &analysisData->stats->lpFactorsArray[i][j];
999
1000 printf("\t\t%3d - %-3d ", i, j);
1001 if (lpFactors->type == chFactors->type)
1002 {
1003 if (lpFactors->type == MIDDLE)
1004 {
1005 printf("%-13s %-10.4g %-10.4g %-10.4g %.4g\n",
1006 approxNames[lpFactors->type],
1007 lpFactors->min->offset - chFactors->min->offset,
1008 lpFactors->max->offset - chFactors->max->offset,
1009 lpFactors->min->drift - chFactors->min->drift,
1010 lpFactors->max->drift - chFactors->max->drift);
1011 }
1012 else if (lpFactors->type == ABSENT)
1013 {
1014 printf("%s\n", approxNames[lpFactors->type]);
1015 }
1016 }
1017 else
1018 {
1019 printf("Different! %s and %s\n", approxNames[lpFactors->type],
1020 approxNames[chFactors->type]);
1021 }
1022 }
1023 }
d4721e1a
BP
1024}
1025
1026
1027/*
1028 * A GHFunc for g_hash_table_foreach()
1029 *
1030 * Args:
1031 * key: RttKey* where saddr < daddr
1032 * value: double*, RTT estimated from exchanges
1033 * user_data GHashTable* rttInfo
1034 */
66eaf2eb
BP
1035static void ghfPrintExchangeRtt(gpointer key, gpointer value, gpointer
1036 user_data)
d4721e1a
BP
1037{
1038 char addr1[16], addr2[16];
1039 struct RttKey* rttKey1= key;
1040 struct RttKey rttKey2= {rttKey1->daddr, rttKey1->saddr};
1041 double* fileRtt1, *fileRtt2;
1042 GHashTable* rttInfo= user_data;
1043
1044 convertIP(addr1, rttKey1->saddr);
1045 convertIP(addr2, rttKey1->daddr);
1046
1047 fileRtt1= g_hash_table_lookup(rttInfo, rttKey1);
1048 fileRtt2= g_hash_table_lookup(rttInfo, &rttKey2);
1049
1050 printf("\t\t(%15s, %-15s) %-18.3f ", addr1, addr2, *(double*) value * 1e3);
1051
1052 if (fileRtt1 || fileRtt2)
1053 {
1054 if (fileRtt1)
1055 {
1056 printf("%.3f", *fileRtt1 * 1e3);
1057 }
1058 if (fileRtt1 && fileRtt2)
1059 {
1060 printf(", ");
1061 }
1062 if (fileRtt2)
1063 {
1064 printf("%.3f", *fileRtt2 * 1e3);
1065 }
1066 }
1067 else
1068 {
1069 printf("-");
1070 }
1071 printf("\n");
cdce23b3 1072}
2bd4b3e4
BP
1073
1074
1075/*
1076 * A GHashFunc for g_hash_table_new()
1077 *
1078 * Args:
1079 * key struct RttKey*
1080 */
1081static guint ghfRttKeyHash(gconstpointer key)
1082{
1083 struct RttKey* rttKey;
1084 uint32_t a, b, c;
1085
1086 rttKey= (struct RttKey*) key;
1087
1088 a= rttKey->saddr;
1089 b= rttKey->daddr;
1090 c= 0;
1091 final(a, b, c);
1092
1093 return c;
1094}
1095
1096
1097/*
1098 * A GDestroyNotify function for g_hash_table_new_full()
1099 *
1100 * Args:
1101 * data: struct RttKey*
1102 */
1103static void gdnDestroyRttKey(gpointer data)
1104{
1105 free(data);
1106}
1107
1108
1109/*
1110 * A GDestroyNotify function for g_hash_table_new_full()
1111 *
1112 * Args:
1113 * data: double*
1114 */
1115static void gdnDestroyDouble(gpointer data)
1116{
1117 free(data);
1118}
1119
1120
1121/*
1122 * A GEqualFunc for g_hash_table_new()
1123 *
1124 * Args:
1125 * a, b RttKey*
1126 *
1127 * Returns:
1128 * TRUE if both values are equal
1129 */
1130static gboolean gefRttKeyEqual(gconstpointer a, gconstpointer b)
1131{
1132 const struct RttKey* rkA, * rkB;
1133
1134 rkA= (struct RttKey*) a;
1135 rkB= (struct RttKey*) b;
1136
1137 if (rkA->saddr == rkB->saddr && rkA->daddr == rkB->daddr)
1138 {
1139 return TRUE;
1140 }
1141 else
1142 {
1143 return FALSE;
1144 }
1145}
1146
1147
1148/*
1149 * Read a file contain minimum round trip time values and fill an array with
1150 * them. The file is formatted as such:
1151 * <host1 IP> <host2 IP> <RTT in milliseconds>
1152 * ip's should be in dotted quad format
1153 *
1154 * Args:
1155 * rttInfo: double* rttInfo[RttKey], empty table, will be filled
1156 * rttStream: stream from which to read
1157 */
1158static void readRttInfo(GHashTable* rttInfo, FILE* rttStream)
1159{
1160 char* line= NULL;
1161 size_t len;
1162 int retval;
1163
1164 positionStream(rttStream);
1165 retval= getline(&line, &len, rttStream);
1166 while(!feof(rttStream))
1167 {
1168 struct RttKey* rttKey;
1169 char saddrDQ[20], daddrDQ[20];
1170 double* rtt;
1171 char tmp;
1172 struct in_addr addr;
1173 unsigned int i;
1174 struct {
1175 char* dq;
1176 size_t offset;
1177 } loopValues[] = {
1178 {saddrDQ, offsetof(struct RttKey, saddr)},
1179 {daddrDQ, offsetof(struct RttKey, daddr)}
1180 };
1181
1182 if (retval == -1 && !feof(rttStream))
1183 {
1184 g_error(strerror(errno));
1185 }
1186
1187 if (line[retval - 1] == '\n')
1188 {
1189 line[retval - 1]= '\0';
1190 }
1191
1192 rtt= malloc(sizeof(double));
1193 retval= sscanf(line, " %19s %19s %lf %c", saddrDQ, daddrDQ, rtt,
1194 &tmp);
1195 if (retval == EOF)
1196 {
1197 g_error(strerror(errno));
1198 }
1199 else if (retval != 3)
1200 {
1201 g_error("Error parsing RTT file, line was '%s'", line);
1202 }
1203
1204 rttKey= malloc(sizeof(struct RttKey));
1205 for (i= 0; i < sizeof(loopValues) / sizeof(*loopValues); i++)
1206 {
1207 retval= inet_aton(loopValues[i].dq, &addr);
1208 if (retval == 0)
1209 {
1210 g_error("Error converting address '%s'", loopValues[i].dq);
1211 }
1212 *(uint32_t*) ((void*) rttKey + loopValues[i].offset)=
1213 addr.s_addr;
1214 }
1215
76be6fc2 1216 *rtt/= 1e3;
d4721e1a
BP
1217 g_debug("rttInfo, Inserting (%u, %u)->(%f)", rttKey->saddr,
1218 rttKey->daddr, *rtt);
2bd4b3e4
BP
1219 g_hash_table_insert(rttInfo, rttKey, rtt);
1220
1221 positionStream(rttStream);
1222 retval= getline(&line, &len, rttStream);
1223 }
1224
1225 if (line)
1226 {
1227 free(line);
1228 }
1229}
1230
1231
1232/*
1233 * Advance stream over empty space, empty lines and lines that begin with '#'
1234 *
1235 * Args:
1236 * stream: stream, at exit, will be over the first non-empty character
1237 * of a line of be at EOF
1238 */
1239static void positionStream(FILE* stream)
1240{
1241 int firstChar;
1242 ssize_t retval;
1243 char* line= NULL;
1244 size_t len;
1245
1246 do
1247 {
1248 firstChar= fgetc(stream);
1249 if (firstChar == (int) '#')
1250 {
1251 retval= getline(&line, &len, stream);
1252 if (retval == -1)
1253 {
1254 if (feof(stream))
1255 {
1256 goto outEof;
1257 }
1258 else
1259 {
1260 g_error(strerror(errno));
1261 }
1262 }
1263 }
1264 else if (firstChar == (int) '\n' || firstChar == (int) ' ' ||
1265 firstChar == (int) '\t')
1266 {}
1267 else if (firstChar == EOF)
1268 {
1269 goto outEof;
1270 }
1271 else
1272 {
1273 break;
1274 }
1275 } while (true);
1276 retval= ungetc(firstChar, stream);
1277 if (retval == EOF)
1278 {
1279 g_error("Error: ungetc()");
1280 }
1281
1282outEof:
1283 if (line)
1284 {
1285 free(line);
1286 }
1287}
76be6fc2
BP
1288
1289
1290/*
1291 * A GFunc for g_queue_foreach()
1292 *
1293 * Args:
1294 * data Event*, a UDP broadcast event
1295 * user_data double*, the running sum
1296 *
1297 * Returns:
1298 * Adds the time of the event to the sum
1299 */
1300static void gfSum(gpointer data, gpointer userData)
1301{
1302 Event* event= (Event*) data;
1303
1304 *(double*) userData+= event->wallTime.seconds + event->wallTime.nanosec /
1305 1e9;
1306}
1307
1308
1309/*
1310 * A GFunc for g_queue_foreach()
1311 *
1312 * Args:
1313 * data Event*, a UDP broadcast event
1314 * user_data double*, the running sum
1315 *
1316 * Returns:
1317 * Adds the square of the time of the event to the sum
1318 */
1319static void gfSumSquares(gpointer data, gpointer userData)
1320{
1321 Event* event= (Event*) data;
1322
1323 *(double*) userData+= pow(event->wallTime.seconds + event->wallTime.nanosec
1324 / 1e9, 2.);
1325}
4ee223e5
BP
1326
1327
e072e1ab
BP
1328/*
1329 * Update a struct Bins according to a new value
1330 *
1331 * Args:
1332 * bins: the structure containing bins to build a histrogram
1333 * value: the new value
1334 */
1335static void hitBin(struct Bins* const bins, const double value)
1336{
1337 unsigned int binN= binNum(value);
1338
1339 if (binN < bins->min)
1340 {
1341 bins->min= binN;
1342 }
1343 else if (binN > bins->max)
1344 {
1345 bins->max= binN;
1346 }
1347
1348 bins->total++;
1349
1350 bins->bin[binN]++;
1351}
1352
1353
4ee223e5
BP
1354/*
1355 * Figure out the bin in a histogram to which a value belongs.
1356 *
1357 * This uses exponentially sized bins that go from 0 to infinity.
1358 *
1359 * Args:
e072e1ab
BP
1360 * value: in the range -INFINITY to INFINITY
1361 *
1362 * Returns:
1363 * The number of the bin in a struct Bins.bin
4ee223e5
BP
1364 */
1365static unsigned int binNum(const double value)
1366{
e072e1ab 1367 if (value <= 0)
4ee223e5
BP
1368 {
1369 return 0;
1370 }
e072e1ab
BP
1371 else if (value < binEnd(1))
1372 {
1373 return 1;
1374 }
1375 else if (value >= binStart(BIN_NB - 1))
1376 {
1377 return BIN_NB - 1;
1378 }
4ee223e5
BP
1379 else
1380 {
e072e1ab 1381 return floor(log(value) / log(binBase)) + BIN_NB + 1;
4ee223e5
BP
1382 }
1383}
1384
1385
1386/*
e072e1ab
BP
1387 * Figure out the start of the interval of a bin in a histogram. See struct
1388 * Bins.
4ee223e5
BP
1389 *
1390 * This uses exponentially sized bins that go from 0 to infinity.
1391 *
1392 * Args:
1393 * binNum: bin number
e072e1ab
BP
1394 *
1395 * Return:
1396 * The start of the interval, this value is included in the interval (except
1397 * for -INFINITY, naturally)
4ee223e5
BP
1398 */
1399static double binStart(const unsigned int binNum)
1400{
e072e1ab 1401 g_assert_cmpuint(binNum, <, BIN_NB);
4ee223e5
BP
1402
1403 if (binNum == 0)
1404 {
e072e1ab
BP
1405 return -INFINITY;
1406 }
1407 else if (binNum == 1)
1408 {
1409 return 0.;
4ee223e5
BP
1410 }
1411 else
1412 {
e072e1ab 1413 return pow(binBase, (double) binNum - BIN_NB + 1);
4ee223e5
BP
1414 }
1415}
1416
1417
1418/*
e072e1ab
BP
1419 * Figure out the end of the interval of a bin in a histogram. See struct
1420 * Bins.
4ee223e5
BP
1421 *
1422 * This uses exponentially sized bins that go from 0 to infinity.
1423 *
1424 * Args:
1425 * binNum: bin number
e072e1ab
BP
1426 *
1427 * Return:
1428 * The end of the interval, this value is not included in the interval
4ee223e5
BP
1429 */
1430static double binEnd(const unsigned int binNum)
1431{
e072e1ab 1432 g_assert_cmpuint(binNum, <, BIN_NB);
4ee223e5 1433
e072e1ab 1434 if (binNum == 0)
4ee223e5 1435 {
e072e1ab
BP
1436 return 0.;
1437 }
1438 else if (binNum < BIN_NB - 1)
1439 {
1440 return pow(binBase, (double) binNum - BIN_NB + 2);
4ee223e5
BP
1441 }
1442 else
1443 {
1444 return INFINITY;
1445 }
1446}
467066ee
BP
1447
1448
1449/*
1450 * Return the total number of elements in the "normal" bins (not underflow or
1451 * overflow)
1452 *
1453 * Args:
1454 * bins: the structure containing bins to build a histrogram
1455 */
1456static uint32_t normalTotal(struct Bins* const bins)
1457{
1458 return bins->total - bins->bin[0] - bins->bin[BIN_NB - 1];
1459}
66eaf2eb
BP
1460
1461
1462/* Update the bounds between two traces
1463 *
1464 * Args:
1465 * bounds: the array containing all the trace-pair bounds
1466 * e1, e2: the two related events
1467 */
c6356aa7
BP
1468static void updateBounds(Bounds** const bounds, Event* const e1, Event* const
1469 e2)
66eaf2eb
BP
1470{
1471 unsigned int traceI, traceJ;
1472 uint64_t messageTime;
1473 Bounds* tpBounds;
1474
1475 if (e1->traceNum < e2->traceNum)
1476 {
1477 traceI= e2->traceNum;
1478 traceJ= e1->traceNum;
1479 messageTime= e1->cpuTime;
1480 }
1481 else
1482 {
1483 traceI= e1->traceNum;
1484 traceJ= e2->traceNum;
1485 messageTime= e2->cpuTime;
1486 }
1487 tpBounds= &bounds[traceI][traceJ];
1488
1489 if (messageTime < tpBounds->min)
1490 {
1491 tpBounds->min= messageTime;
1492 }
1493 if (messageTime > tpBounds->max)
1494 {
1495 tpBounds->max= messageTime;
1496 }
1497}
1498
1499
1500#ifdef HAVE_LIBGLPK
1501/*
1502 * Create the linear programming problem containing the constraints defined by
1503 * two half-hulls. The objective function and optimization directions are not
1504 * written.
1505 *
1506 * Args:
1507 * syncState: container for synchronization data
1508 * i: first trace number
1509 * j: second trace number, garanteed to be larger than i
1510 * Returns:
1511 * A new glp_prob*, this problem must be freed by the caller with
1512 * glp_delete_prob()
1513 */
c6356aa7
BP
1514static glp_prob* lpCreateProblem(GQueue* const lowerHull, GQueue* const
1515 upperHull)
66eaf2eb
BP
1516{
1517 unsigned int it;
1518 const int zero= 0;
1519 const double zeroD= 0.;
1520 glp_prob* lp= glp_create_prob();
1521 unsigned int hullPointNb= g_queue_get_length(lowerHull) +
1522 g_queue_get_length(upperHull);
1523 GArray* iArray= g_array_sized_new(FALSE, FALSE, sizeof(int), hullPointNb +
1524 1);
1525 GArray* jArray= g_array_sized_new(FALSE, FALSE, sizeof(int), hullPointNb +
1526 1);
1527 GArray* aArray= g_array_sized_new(FALSE, FALSE, sizeof(double),
1528 hullPointNb + 1);
1529 struct {
1530 GQueue* hull;
1531 struct LPAddRowInfo rowInfo;
1532 } loopValues[2]= {
1533 {lowerHull, {lp, GLP_UP, iArray, jArray, aArray}},
1534 {upperHull, {lp, GLP_LO, iArray, jArray, aArray}},
1535 };
1536
1537 // Create the LP problem
1538 glp_term_out(GLP_OFF);
1539 glp_add_rows(lp, hullPointNb);
1540 glp_add_cols(lp, 2);
1541
1542 glp_set_col_name(lp, 1, "a0");
1543 glp_set_col_bnds(lp, 1, GLP_FR, 0., 0.);
1544 glp_set_col_name(lp, 2, "a1");
1545 glp_set_col_bnds(lp, 2, GLP_LO, 0., 0.);
1546
1547 // Add row constraints
1548 g_array_append_val(iArray, zero);
1549 g_array_append_val(jArray, zero);
1550 g_array_append_val(aArray, zeroD);
1551
1552 for (it= 0; it < sizeof(loopValues) / sizeof(*loopValues); it++)
1553 {
1554 g_queue_foreach(loopValues[it].hull, &gfLPAddRow,
1555 &loopValues[it].rowInfo);
1556 }
1557
1558 g_assert_cmpuint(iArray->len, ==, jArray->len);
1559 g_assert_cmpuint(jArray->len, ==, aArray->len);
1560 g_assert_cmpuint(aArray->len - 1, ==, hullPointNb * 2);
1561
1562 glp_load_matrix(lp, aArray->len - 1, &g_array_index(iArray, int, 0),
1563 &g_array_index(jArray, int, 0), &g_array_index(aArray, double, 0));
1564
1565 glp_scale_prob(lp, GLP_SF_AUTO);
1566
1567 g_array_free(iArray, TRUE);
1568 g_array_free(jArray, TRUE);
1569 g_array_free(aArray, TRUE);
1570
1571 return lp;
1572}
1573
1574
1575/*
1576 * A GFunc for g_queue_foreach(). Add constraints and bounds for one row.
1577 *
1578 * Args:
1579 * data Point*, synchronization point for which to add an LP row
1580 * (a constraint)
1581 * user_data LPAddRowInfo*
1582 */
1583static void gfLPAddRow(gpointer data, gpointer user_data)
1584{
1585 Point* p= data;
1586 struct LPAddRowInfo* rowInfo= user_data;
1587 int indexes[2];
1588 double constraints[2];
1589
1590 indexes[0]= g_array_index(rowInfo->iArray, int, rowInfo->iArray->len - 1) + 1;
1591 indexes[1]= indexes[0];
1592
1593 if (rowInfo->boundType == GLP_UP)
1594 {
1595 glp_set_row_bnds(rowInfo->lp, indexes[0], GLP_UP, 0., p->y);
1596 }
1597 else if (rowInfo->boundType == GLP_LO)
1598 {
1599 glp_set_row_bnds(rowInfo->lp, indexes[0], GLP_LO, p->y, 0.);
1600 }
1601 else
1602 {
1603 g_assert_not_reached();
1604 }
1605
1606 g_array_append_vals(rowInfo->iArray, indexes, 2);
1607 indexes[0]= 1;
1608 indexes[1]= 2;
1609 g_array_append_vals(rowInfo->jArray, indexes, 2);
1610 constraints[0]= 1.;
1611 constraints[1]= p->x;
1612 g_array_append_vals(rowInfo->aArray, constraints, 2);
1613}
1614
1615
1616/*
1617 * Calculate min or max correction factors (as possible) using an LP problem.
1618 *
1619 * Args:
1620 * lp: A linear programming problem with constraints and bounds
1621 * initialized.
1622 * direction: The type of factors desired. Use GLP_MAX for max
1623 * approximation factors (a1, the drift or slope is the
1624 * largest) and GLP_MIN in the other case.
1625 *
1626 * Returns:
1627 * If the calculation was successful, a new Factors struct. Otherwise, NULL.
1628 * The calculation will fail if the hull assumptions are not respected.
1629 */
1630static Factors* calculateFactors(glp_prob* const lp, const int direction)
1631{
1632 int retval, status;
1633 Factors* factors;
1634
1635 glp_set_obj_coef(lp, 1, 0.);
1636 glp_set_obj_coef(lp, 2, 1.);
1637
1638 glp_set_obj_dir(lp, direction);
1639 retval= glp_simplex(lp, NULL);
1640 status= glp_get_status(lp);
1641
1642 if (retval == 0 && status == GLP_OPT)
1643 {
1644 factors= malloc(sizeof(Factors));
1645 factors->offset= glp_get_col_prim(lp, 1);
1646 factors->drift= glp_get_col_prim(lp, 2);
1647 }
1648 else
1649 {
1650 factors= NULL;
1651 }
1652
1653 return factors;
1654}
1655
1656
1657/*
1658 * Calculate min, max and approx correction factors (as possible) using an LP
1659 * problem.
1660 *
1661 * Args:
1662 * lp: A linear programming problem with constraints and bounds
1663 * initialized.
1664 *
1665 * Returns:
1666 * Please note that the approximation type may be MIDDLE, INCOMPLETE or
1667 * ABSENT. Unlike in analysis_chull, ABSENT is also used when the hulls do
1668 * not respect assumptions.
1669 */
1670static void calculateCompleteFactors(glp_prob* const lp, FactorsCHull* factors)
1671{
1672 factors->min= calculateFactors(lp, GLP_MIN);
1673 factors->max= calculateFactors(lp, GLP_MAX);
1674
1675 if (factors->min && factors->max)
1676 {
1677 factors->type= MIDDLE;
1678 calculateFactorsMiddle(factors);
1679 }
1680 else if (factors->min || factors->max)
1681 {
1682 factors->type= INCOMPLETE;
1683 factors->approx= NULL;
1684 }
1685 else
1686 {
1687 factors->type= ABSENT;
1688 factors->approx= NULL;
1689 }
1690}
1691
1692
1693/*
1694 * Create and initialize an array like AnalysisStatsCHull.allFactors
1695 *
1696 * Args:
1697 * traceNb: number of traces
1698 *
1699 * Returns:
1700 * A new array, which can be freed with freeAllFactors()
1701 */
1702static FactorsCHull** createAllFactors(const unsigned int traceNb)
1703{
1704 FactorsCHull** factorsArray;
1705 unsigned int i;
1706
1707 factorsArray= malloc(traceNb * sizeof(FactorsCHull*));
1708 for (i= 0; i < traceNb; i++)
1709 {
1710 factorsArray[i]= calloc((i + 1), sizeof(FactorsCHull));
1711
1712 factorsArray[i][i].type= EXACT;
1713 factorsArray[i][i].approx= malloc(sizeof(Factors));
1714 factorsArray[i][i].approx->drift= 1.;
1715 factorsArray[i][i].approx->offset= 0.;
1716 }
1717
1718 return factorsArray;
1719}
1720#endif
1721
1722
1723/*
1724 * Compute synchronization factors using a linear programming approach.
1725 * Compute the factors using analysis_chull. Compare the two.
1726 *
1727 * There are two definitions of this function. The empty one is used when the
1728 * solver library, glpk, is not available at build time. In that case, nothing
1729 * is actually produced.
1730 *
1731 * Args:
1732 * syncState: container for synchronization data
1733 */
1734#ifndef HAVE_LIBGLPK
1735static inline void finalizeAnalysisEvalLP(SyncState* const syncState)
1736{
1737}
1738#else
1739static void finalizeAnalysisEvalLP(SyncState* const syncState)
1740{
1741 unsigned int i, j;
1742 AnalysisDataEval* analysisData= syncState->analysisData;
1743 AnalysisDataCHull* chAnalysisData= analysisData->chullSS->analysisData;
1744 FactorsCHull** lpFactorsArray= createAllFactors(syncState->traceNb);
1745 FactorsCHull* lpFactors;
1746
1747 if (!syncState->stats && !syncState->graphsStream)
1748 {
1749 return;
1750 }
1751
1752 if ((syncState->graphsStream && analysisData->graphs->lps != NULL) ||
1753 (syncState->stats && analysisData->stats->chFactorsArray != NULL))
1754 {
1755 return;
1756 }
1757
1758 if (syncState->stats)
1759 {
1760 analysisData->stats->chFactorsArray=
1761 calculateAllFactors(analysisData->chullSS);
1762 analysisData->stats->lpFactorsArray= lpFactorsArray;
1763 }
1764
1765 if (syncState->graphsStream)
1766 {
1767 analysisData->graphs->lps= malloc(syncState->traceNb *
1768 sizeof(glp_prob**));
1769 for (i= 0; i < syncState->traceNb; i++)
1770 {
1771 analysisData->graphs->lps[i]= malloc(i * sizeof(glp_prob*));
1772 }
1773 analysisData->graphs->lpFactorsArray= lpFactorsArray;
1774 }
1775
1776 for (i= 0; i < syncState->traceNb; i++)
1777 {
1778 for (j= 0; j < i; j++)
1779 {
1780 glp_prob* lp;
1781
1782 // Create the LP problem
1783 lp= lpCreateProblem(chAnalysisData->hullArray[i][j],
1784 chAnalysisData->hullArray[j][i]);
1785
1786 // Use the LP problem to find the correction factors for this pair of
1787 // traces
1788 calculateCompleteFactors(lp, &lpFactorsArray[i][j]);
1789
1790 if (syncState->graphsStream)
1791 {
1792 analysisData->graphs->lps[i][j]= lp;
1793 }
1794 else
1795 {
1796 glp_delete_prob(lp);
1797 destroyFactorsCHull(lpFactors);
1798 }
1799 }
1800 }
1801
1802 g_array_free(analysisData->chullSS->analysisModule->finalizeAnalysis(analysisData->chullSS),
1803 TRUE);
1804}
1805#endif
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.109287 seconds and 4 git commands to generate.