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