Change synchronization code license to LGPLv2.1
[lttv.git] / lttv / lttv / sync / event_analysis_eval.c
CommitLineData
cdce23b3 1/* This file is part of the Linux Trace Toolkit viewer
277e5b53 2 * Copyright (C) 2009, 2010 Benjamin Poirier <benjamin.poirier@polymtl.ca>
cdce23b3 3 *
277e5b53
BP
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation, either version 2.1 of the License, or (at
7 * your option) any later version.
cdce23b3 8 *
277e5b53
BP
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
12 * License for more details.
cdce23b3 13 *
277e5b53
BP
14 * You should have received a copy of the GNU Lesser General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
cdce23b3
BP
16 */
17
2bd4b3e4 18#define _GNU_SOURCE
d4721e1a 19#define _ISOC99_SOURCE
2bd4b3e4 20
cdce23b3
BP
21#ifdef HAVE_CONFIG_H
22#include <config.h>
23#endif
24
2bd4b3e4
BP
25#include <arpa/inet.h>
26#include <errno.h>
76be6fc2 27#include <math.h>
2bd4b3e4
BP
28#include <netinet/in.h>
29#include <stddef.h>
cdce23b3 30#include <stdlib.h>
2bd4b3e4
BP
31#include <stdio.h>
32#include <string.h>
33#include <sys/socket.h>
4ee223e5 34#include <unistd.h>
cdce23b3 35
2bd4b3e4
BP
36#include "lookup3.h"
37#include "sync_chain.h"
66eaf2eb 38#include "event_analysis_chull.h"
cdce23b3
BP
39
40#include "event_analysis_eval.h"
41
42
66eaf2eb 43struct WriteHistogramInfo
e072e1ab
BP
44{
45 GHashTable* rttInfo;
46 FILE* graphsStream;
47};
48
66eaf2eb
BP
49#ifdef HAVE_LIBGLPK
50struct LPAddRowInfo
51{
52 glp_prob* lp;
53 int boundType;
54 GArray* iArray, * jArray, * aArray;
55};
56#endif
e072e1ab 57
cdce23b3
BP
58// Functions common to all analysis modules
59static void initAnalysisEval(SyncState* const syncState);
60static void destroyAnalysisEval(SyncState* const syncState);
61
62static void analyzeMessageEval(SyncState* const syncState, Message* const
63 message);
64static void analyzeExchangeEval(SyncState* const syncState, Exchange* const
65 exchange);
66static void analyzeBroadcastEval(SyncState* const syncState, Broadcast* const
67 broadcast);
68static GArray* finalizeAnalysisEval(SyncState* const syncState);
69static void printAnalysisStatsEval(SyncState* const syncState);
c5571851
BP
70static void writeAnalysisTraceTimeBackPlotsEval(SyncState* const syncState,
71 const unsigned int i, const unsigned int j);
72static void writeAnalysisTraceTimeForePlotsEval(SyncState* const syncState,
73 const unsigned int i, const unsigned int j);
c6356aa7
BP
74static void writeAnalysisTraceTraceBackPlotsEval(SyncState* const syncState,
75 const unsigned int i, const unsigned int j);
76static void writeAnalysisTraceTraceForePlotsEval(SyncState* const syncState,
77 const unsigned int i, const unsigned int j);
cdce23b3
BP
78
79// Functions specific to this module
2bd4b3e4
BP
80static guint ghfRttKeyHash(gconstpointer key);
81static gboolean gefRttKeyEqual(gconstpointer a, gconstpointer b);
82static void gdnDestroyRttKey(gpointer data);
83static void gdnDestroyDouble(gpointer data);
84static void readRttInfo(GHashTable* rttInfo, FILE* rttFile);
85static void positionStream(FILE* stream);
cdce23b3 86
76be6fc2
BP
87static void gfSum(gpointer data, gpointer userData);
88static void gfSumSquares(gpointer data, gpointer userData);
66eaf2eb
BP
89static void ghfPrintExchangeRtt(gpointer key, gpointer value, gpointer
90 user_data);
76be6fc2 91
e072e1ab 92static void hitBin(struct Bins* const bins, const double value);
4ee223e5
BP
93static unsigned int binNum(const double value) __attribute__((pure));
94static double binStart(const unsigned int binNum) __attribute__((pure));
95static double binEnd(const unsigned int binNum) __attribute__((pure));
467066ee 96static uint32_t normalTotal(struct Bins* const bins) __attribute__((const));
4ee223e5 97
66eaf2eb 98static AnalysisHistogramEval* constructAnalysisHistogramEval(const char* const
e072e1ab 99 graphsDir, const struct RttKey* const rttKey);
66eaf2eb
BP
100static void destroyAnalysisHistogramEval(AnalysisHistogramEval* const
101 histogram);
102static void gdnDestroyAnalysisHistogramEval(gpointer data);
103static void ghfWriteHistogram(gpointer key, gpointer value, gpointer
104 user_data);
e072e1ab
BP
105static void dumpBinToFile(const struct Bins* const bins, FILE* const file);
106static void writeHistogram(FILE* graphsStream, const struct RttKey* rttKey,
66eaf2eb
BP
107 double* minRtt, AnalysisHistogramEval* const histogram);
108
c6356aa7
BP
109static void updateBounds(Bounds** const bounds, Event* const e1, Event* const
110 e2);
66eaf2eb 111
05a840df 112static void finalizeAnalysisEvalLP(SyncState* const syncState);
66eaf2eb
BP
113// The next group of functions is only needed when computing synchronization
114// accuracy.
115#ifdef HAVE_LIBGLPK
c6356aa7
BP
116static glp_prob* lpCreateProblem(GQueue* const lowerHull, GQueue* const
117 upperHull);
66eaf2eb
BP
118static void gfLPAddRow(gpointer data, gpointer user_data);
119static Factors* calculateFactors(glp_prob* const lp, const int direction);
c6356aa7
BP
120static void calculateCompleteFactors(glp_prob* const lp, FactorsCHull*
121 factors);
66eaf2eb 122static FactorsCHull** createAllFactors(const unsigned int traceNb);
66eaf2eb 123#endif
e072e1ab 124
4ee223e5 125
66eaf2eb 126// initialized in registerAnalysisEval()
4ee223e5 127double binBase;
cdce23b3
BP
128
129static AnalysisModule analysisModuleEval= {
130 .name= "eval",
131 .initAnalysis= &initAnalysisEval,
132 .destroyAnalysis= &destroyAnalysisEval,
133 .analyzeMessage= &analyzeMessageEval,
134 .analyzeExchange= &analyzeExchangeEval,
135 .analyzeBroadcast= &analyzeBroadcastEval,
136 .finalizeAnalysis= &finalizeAnalysisEval,
137 .printAnalysisStats= &printAnalysisStatsEval,
66eaf2eb 138 .graphFunctions= {
c5571851
BP
139 .writeTraceTimeBackPlots= &writeAnalysisTraceTimeBackPlotsEval,
140 .writeTraceTimeForePlots= &writeAnalysisTraceTimeForePlotsEval,
c6356aa7
BP
141 .writeTraceTraceBackPlots= &writeAnalysisTraceTraceBackPlotsEval,
142 .writeTraceTraceForePlots= &writeAnalysisTraceTraceForePlotsEval,
66eaf2eb 143 }
cdce23b3
BP
144};
145
2bd4b3e4
BP
146static ModuleOption optionEvalRttFile= {
147 .longName= "eval-rtt-file",
148 .hasArg= REQUIRED_ARG,
4ee223e5 149 .optionHelp= "specify the file containing RTT information",
2bd4b3e4
BP
150 .argHelp= "FILE",
151};
152
cdce23b3
BP
153
154/*
155 * Analysis module registering function
156 */
2f961b65 157void registerAnalysisEval()
cdce23b3 158{
66eaf2eb
BP
159 binBase= exp10(6. / (BIN_NB - 3));
160
cdce23b3 161 g_queue_push_tail(&analysisModules, &analysisModuleEval);
2bd4b3e4 162 g_queue_push_tail(&moduleOptions, &optionEvalRttFile);
cdce23b3
BP
163}
164
165
166/*
167 * Analysis init function
168 *
169 * This function is called at the beginning of a synchronization run for a set
170 * of traces.
171 *
172 * Args:
173 * syncState container for synchronization data.
174 */
175static void initAnalysisEval(SyncState* const syncState)
176{
177 AnalysisDataEval* analysisData;
66eaf2eb 178 unsigned int i, j;
cdce23b3
BP
179
180 analysisData= malloc(sizeof(AnalysisDataEval));
181 syncState->analysisData= analysisData;
182
2bd4b3e4
BP
183 analysisData->rttInfo= g_hash_table_new_full(&ghfRttKeyHash,
184 &gefRttKeyEqual, &gdnDestroyRttKey, &gdnDestroyDouble);
185 if (optionEvalRttFile.arg)
186 {
187 FILE* rttStream;
188 int retval;
189
190 rttStream= fopen(optionEvalRttFile.arg, "r");
191 if (rttStream == NULL)
192 {
193 g_error(strerror(errno));
194 }
195
196 readRttInfo(analysisData->rttInfo, rttStream);
197
198 retval= fclose(rttStream);
199 if (retval == EOF)
200 {
201 g_error(strerror(errno));
202 }
203 }
cdce23b3
BP
204
205 if (syncState->stats)
206 {
76be6fc2 207 analysisData->stats= calloc(1, sizeof(AnalysisStatsEval));
cdce23b3
BP
208 analysisData->stats->broadcastDiffSum= 0.;
209
76be6fc2
BP
210 analysisData->stats->messageStats= malloc(syncState->traceNb *
211 sizeof(MessageStats*));
cdce23b3
BP
212 for (i= 0; i < syncState->traceNb; i++)
213 {
76be6fc2
BP
214 analysisData->stats->messageStats[i]= calloc(syncState->traceNb,
215 sizeof(MessageStats));
cdce23b3 216 }
d4721e1a
BP
217
218 analysisData->stats->exchangeRtt=
219 g_hash_table_new_full(&ghfRttKeyHash, &gefRttKeyEqual,
220 &gdnDestroyRttKey, &gdnDestroyDouble);
66eaf2eb
BP
221
222#ifdef HAVE_LIBGLPK
223 analysisData->stats->chFactorsArray= NULL;
224 analysisData->stats->lpFactorsArray= NULL;
225#endif
cdce23b3 226 }
4ee223e5 227
8d7d16dd 228 if (syncState->graphsStream)
4ee223e5 229 {
66eaf2eb
BP
230 AnalysisGraphsEval* graphs= malloc(sizeof(AnalysisGraphsEval));
231
232 analysisData->graphs= graphs;
233
234 graphs->histograms= g_hash_table_new_full(&ghfRttKeyHash,
235 &gefRttKeyEqual, &gdnDestroyRttKey,
236 &gdnDestroyAnalysisHistogramEval);
237
238 graphs->bounds= malloc(syncState->traceNb * sizeof(Bounds*));
239 for (i= 0; i < syncState->traceNb; i++)
240 {
241 graphs->bounds[i]= malloc(i * sizeof(Bounds));
242 for (j= 0; j < i; j++)
243 {
244 graphs->bounds[i][j].min= UINT64_MAX;
245 graphs->bounds[i][j].max= 0;
246 }
247 }
248
249#ifdef HAVE_LIBGLPK
250 graphs->lps= NULL;
251 graphs->lpFactorsArray= NULL;
252#endif
253 }
254
255 if (syncState->stats || syncState->graphsStream)
256 {
257 GList* result;
258
259 analysisData->chullSS= malloc(sizeof(SyncState));
260 memcpy(analysisData->chullSS, syncState, sizeof(SyncState));
261 analysisData->chullSS->stats= false;
262 analysisData->chullSS->analysisData= NULL;
263 result= g_queue_find_custom(&analysisModules, "chull",
264 &gcfCompareAnalysis);
265 analysisData->chullSS->analysisModule= (AnalysisModule*) result->data;
266 analysisData->chullSS->analysisModule->initAnalysis(analysisData->chullSS);
4ee223e5
BP
267 }
268}
269
270
271/*
e072e1ab
BP
272 * Create and open files used to store histogram points to generate graphs.
273 * Create data structures to store histogram points during analysis.
4ee223e5
BP
274 *
275 * Args:
e072e1ab
BP
276 * graphsDir: folder where to write files
277 * rttKey: host pair, make sure saddr < daddr
4ee223e5 278 */
66eaf2eb 279static AnalysisHistogramEval* constructAnalysisHistogramEval(const char* const
e072e1ab 280 graphsDir, const struct RttKey* const rttKey)
4ee223e5 281{
4ee223e5 282 int retval;
e072e1ab 283 unsigned int i;
4ee223e5 284 char* cwd;
e072e1ab 285 char name[60], saddr[16], daddr[16];
66eaf2eb 286 AnalysisHistogramEval* histogram= calloc(1, sizeof(*histogram));
e072e1ab
BP
287 const struct {
288 size_t pointsOffset;
289 const char* fileName;
290 const char* host1, *host2;
291 } loopValues[]= {
66eaf2eb
BP
292 {offsetof(AnalysisHistogramEval, ttSendPoints),
293 "analysis_eval_tt-%s_to_%s.data", saddr, daddr},
294 {offsetof(AnalysisHistogramEval, ttRecvPoints),
295 "analysis_eval_tt-%s_to_%s.data", daddr, saddr},
296 {offsetof(AnalysisHistogramEval, hrttPoints),
297 "analysis_eval_hrtt-%s_and_%s.data", saddr, daddr},
e072e1ab
BP
298 };
299
66eaf2eb
BP
300 histogram->ttSendBins.min= BIN_NB - 1;
301 histogram->ttRecvBins.min= BIN_NB - 1;
302 histogram->hrttBins.min= BIN_NB - 1;
e072e1ab
BP
303
304 convertIP(saddr, rttKey->saddr);
305 convertIP(daddr, rttKey->daddr);
306
1d597550 307 cwd= changeToGraphsDir(graphsDir);
e072e1ab
BP
308
309 for (i= 0; i < sizeof(loopValues) / sizeof(*loopValues); i++)
4ee223e5 310 {
e072e1ab
BP
311 retval= snprintf(name, sizeof(name), loopValues[i].fileName,
312 loopValues[i].host1, loopValues[i].host2);
313 if (retval > sizeof(name) - 1)
4ee223e5 314 {
e072e1ab 315 name[sizeof(name) - 1]= '\0';
4ee223e5 316 }
66eaf2eb 317 if ((*(FILE**)((void*) histogram + loopValues[i].pointsOffset)=
e072e1ab 318 fopen(name, "w")) == NULL)
4ee223e5 319 {
e072e1ab 320 g_error(strerror(errno));
4ee223e5
BP
321 }
322 }
323
324 retval= chdir(cwd);
325 if (retval == -1)
326 {
327 g_error(strerror(errno));
328 }
329 free(cwd);
e072e1ab 330
66eaf2eb 331 return histogram;
4ee223e5
BP
332}
333
334
335/*
e072e1ab 336 * Close files used to store histogram points to generate graphs.
4ee223e5
BP
337 *
338 * Args:
e072e1ab
BP
339 * graphsDir: folder where to write files
340 * rttKey: host pair, make sure saddr < daddr
4ee223e5 341 */
66eaf2eb
BP
342static void destroyAnalysisHistogramEval(AnalysisHistogramEval* const
343 histogram)
4ee223e5 344{
e072e1ab
BP
345 unsigned int i;
346 int retval;
347 const struct {
348 size_t pointsOffset;
349 } loopValues[]= {
66eaf2eb
BP
350 {offsetof(AnalysisHistogramEval, ttSendPoints)},
351 {offsetof(AnalysisHistogramEval, ttRecvPoints)},
352 {offsetof(AnalysisHistogramEval, hrttPoints)},
e072e1ab
BP
353 };
354
355 for (i= 0; i < sizeof(loopValues) / sizeof(*loopValues); i++)
4ee223e5 356 {
66eaf2eb 357 retval= fclose(*(FILE**)((void*) histogram + loopValues[i].pointsOffset));
e072e1ab 358 if (retval != 0)
4ee223e5 359 {
e072e1ab 360 g_error(strerror(errno));
4ee223e5
BP
361 }
362 }
66eaf2eb
BP
363
364 free(histogram);
4ee223e5
BP
365}
366
367
e072e1ab
BP
368/*
369 * A GDestroyNotify function for g_hash_table_new_full()
370 *
371 * Args:
66eaf2eb 372 * data: AnalysisHistogramEval*
e072e1ab 373 */
66eaf2eb 374static void gdnDestroyAnalysisHistogramEval(gpointer data)
e072e1ab 375{
66eaf2eb 376 destroyAnalysisHistogramEval(data);
e072e1ab
BP
377}
378
379
380/*
381 * A GHFunc for g_hash_table_foreach()
382 *
383 * Args:
384 * key: RttKey* where saddr < daddr
66eaf2eb
BP
385 * value: AnalysisHistogramEval*
386 * user_data struct WriteHistogramInfo*
e072e1ab 387 */
66eaf2eb 388static void ghfWriteHistogram(gpointer key, gpointer value, gpointer user_data)
e072e1ab
BP
389{
390 double* rtt1, * rtt2;
391 struct RttKey* rttKey= key;
392 struct RttKey oppositeRttKey= {.saddr= rttKey->daddr, .daddr=
393 rttKey->saddr};
66eaf2eb
BP
394 AnalysisHistogramEval* histogram= value;
395 struct WriteHistogramInfo* info= user_data;
e072e1ab
BP
396
397 rtt1= g_hash_table_lookup(info->rttInfo, rttKey);
398 rtt2= g_hash_table_lookup(info->rttInfo, &oppositeRttKey);
399
400 if (rtt1 == NULL)
401 {
402 rtt1= rtt2;
403 }
404 else if (rtt2 != NULL)
405 {
406 rtt1= MIN(rtt1, rtt2);
407 }
408
66eaf2eb
BP
409 dumpBinToFile(&histogram->ttSendBins, histogram->ttSendPoints);
410 dumpBinToFile(&histogram->ttRecvBins, histogram->ttRecvPoints);
411 dumpBinToFile(&histogram->hrttBins, histogram->hrttPoints);
412 writeHistogram(info->graphsStream, rttKey, rtt1, histogram);
e072e1ab
BP
413}
414
415
4ee223e5
BP
416/*
417 * Write the content of one bin in a histogram point file
418 *
419 * Args:
420 * bin: array of values that make up a histogram
e072e1ab 421 * file: FILE*, write to this file
4ee223e5 422 */
e072e1ab 423static void dumpBinToFile(const struct Bins* const bins, FILE* const file)
4ee223e5
BP
424{
425 unsigned int i;
426
e072e1ab
BP
427 // The first and last bins are skipped, see struct Bins
428 for (i= 1; i < BIN_NB - 1; i++)
4ee223e5 429 {
e072e1ab 430 if (bins->bin[i] > 0)
4ee223e5 431 {
e072e1ab
BP
432 fprintf(file, "%20.9f %20.9f %20.9f\n", (binStart(i) + binEnd(i))
433 / 2., (double) bins->bin[i] / ((binEnd(i) - binStart(i)) *
434 bins->total), binEnd(i) - binStart(i));
4ee223e5
BP
435 }
436 }
437}
438
439
440/*
e072e1ab 441 * Write the analysis-specific plot in the gnuplot script.
4ee223e5
BP
442 *
443 * Args:
e072e1ab
BP
444 * graphsStream: write to this file
445 * rttKey: must be sorted such that saddr < daddr
446 * minRtt: if available, else NULL
66eaf2eb 447 * histogram: struct that contains the bins for the pair of traces
467066ee 448 * identified by rttKey
4ee223e5 449 */
e072e1ab 450static void writeHistogram(FILE* graphsStream, const struct RttKey* rttKey,
66eaf2eb 451 double* minRtt, AnalysisHistogramEval* const histogram)
4ee223e5 452{
e072e1ab 453 char saddr[16], daddr[16];
4ee223e5 454
e072e1ab
BP
455 convertIP(saddr, rttKey->saddr);
456 convertIP(daddr, rttKey->daddr);
4ee223e5 457
e072e1ab 458 fprintf(graphsStream,
66eaf2eb 459 "\nreset\n"
e072e1ab
BP
460 "set output \"histogram-%s-%s.eps\"\n"
461 "set title \"\"\n"
462 "set xlabel \"Message Latency (s)\"\n"
463 "set ylabel \"Proportion of messages per second\"\n", saddr, daddr);
4ee223e5 464
e072e1ab 465 if (minRtt != NULL)
4ee223e5 466 {
e072e1ab
BP
467 fprintf(graphsStream,
468 "set arrow from %.9f, 0 rto 0, graph 1 "
467066ee
BP
469 "nohead linetype 3 linewidth 3 linecolor rgb \"black\"\n", *minRtt
470 / 2);
4ee223e5 471 }
4ee223e5 472
66eaf2eb
BP
473 if (normalTotal(&histogram->ttSendBins) ||
474 normalTotal(&histogram->ttRecvBins) ||
475 normalTotal(&histogram->hrttBins))
467066ee
BP
476 {
477 fprintf(graphsStream, "plot \\\n");
478
66eaf2eb 479 if (normalTotal(&histogram->hrttBins))
467066ee
BP
480 {
481 fprintf(graphsStream,
482 "\t\"analysis_eval_hrtt-%s_and_%s.data\" "
483 "title \"RTT/2\" with linespoints linetype 1 linewidth 2 "
484 "linecolor rgb \"black\" pointtype 6 pointsize 1,\\\n",
485 saddr, daddr);
486 }
487
66eaf2eb 488 if (normalTotal(&histogram->ttSendBins))
467066ee
BP
489 {
490 fprintf(graphsStream,
491 "\t\"analysis_eval_tt-%1$s_to_%2$s.data\" "
492 "title \"%1$s to %2$s\" with linespoints linetype 4 linewidth 2 "
493 "linecolor rgb \"gray60\" pointtype 6 pointsize 1,\\\n",
494 saddr, daddr);
495 }
496
66eaf2eb 497 if (normalTotal(&histogram->ttRecvBins))
467066ee
BP
498 {
499 fprintf(graphsStream,
500 "\t\"analysis_eval_tt-%1$s_to_%2$s.data\" "
501 "title \"%1$s to %2$s\" with linespoints linetype 4 linewidth 2 "
502 "linecolor rgb \"gray30\" pointtype 6 pointsize 1,\\\n",
503 daddr, saddr);
504 }
505
506 // Remove the ",\\\n" from the last graph plot line
507 if (ftruncate(fileno(graphsStream), ftell(graphsStream) - 3) == -1)
508 {
509 g_error(strerror(errno));
510 }
511 if (fseek(graphsStream, 0, SEEK_END) == -1)
512 {
513 g_error(strerror(errno));
514 }
515 fprintf(graphsStream, "\n");
516 }
cdce23b3
BP
517}
518
519
520/*
521 * Analysis destroy function
522 *
523 * Free the analysis specific data structures
524 *
525 * Args:
526 * syncState container for synchronization data.
527 */
528static void destroyAnalysisEval(SyncState* const syncState)
529{
05a840df 530 unsigned int i;
cdce23b3
BP
531 AnalysisDataEval* analysisData;
532
533 analysisData= (AnalysisDataEval*) syncState->analysisData;
534
66eaf2eb 535 if (analysisData == NULL)
cdce23b3
BP
536 {
537 return;
538 }
539
2bd4b3e4 540 g_hash_table_destroy(analysisData->rttInfo);
cdce23b3
BP
541
542 if (syncState->stats)
543 {
66eaf2eb
BP
544 AnalysisStatsEval* stats= analysisData->stats;
545
546 for (i= 0; i < syncState->traceNb; i++)
547 {
548 free(stats->messageStats[i]);
549 }
550 free(stats->messageStats);
551
552 g_hash_table_destroy(stats->exchangeRtt);
553
554#ifdef HAVE_LIBGLPK
555 freeAllFactors(syncState->traceNb, stats->chFactorsArray);
556 freeAllFactors(syncState->traceNb, stats->lpFactorsArray);
557#endif
558
559 free(stats);
560 }
561
562 if (syncState->graphsStream)
563 {
564 AnalysisGraphsEval* graphs= analysisData->graphs;
565
566 if (graphs->histograms)
567 {
568 g_hash_table_destroy(graphs->histograms);
569 }
570
cdce23b3
BP
571 for (i= 0; i < syncState->traceNb; i++)
572 {
66eaf2eb
BP
573 free(graphs->bounds[i]);
574 }
575 free(graphs->bounds);
576
577#ifdef HAVE_LIBGLPK
578 for (i= 0; i < syncState->traceNb; i++)
579 {
05a840df
BP
580 unsigned int j;
581
66eaf2eb
BP
582 for (j= 0; j < i; j++)
583 {
584 // There seems to be a memory leak in glpk, valgrind reports a
6ce8ceac 585 // loss (reachable) even if the problem is deleted
66eaf2eb
BP
586 glp_delete_prob(graphs->lps[i][j]);
587 }
588 free(graphs->lps[i]);
cdce23b3 589 }
66eaf2eb 590 free(graphs->lps);
d4721e1a 591
66eaf2eb
BP
592 if (!syncState->stats)
593 {
594 freeAllFactors(syncState->traceNb, graphs->lpFactorsArray);
595 }
596#endif
d4721e1a 597
66eaf2eb 598 free(graphs);
cdce23b3
BP
599 }
600
66eaf2eb 601 if (syncState->stats || syncState->graphsStream)
4ee223e5 602 {
66eaf2eb
BP
603 analysisData->chullSS->analysisModule->destroyAnalysis(analysisData->chullSS);
604 free(analysisData->chullSS);
4ee223e5
BP
605 }
606
cdce23b3
BP
607 free(syncState->analysisData);
608 syncState->analysisData= NULL;
609}
610
611
612/*
613 * Perform analysis on an event pair.
614 *
76be6fc2
BP
615 * Check if there is message inversion or messages that are too fast.
616 *
cdce23b3
BP
617 * Args:
618 * syncState container for synchronization data
619 * message structure containing the events
620 */
66eaf2eb
BP
621static void analyzeMessageEval(SyncState* const syncState, Message* const
622 message)
cdce23b3 623{
e072e1ab 624 AnalysisDataEval* analysisData= syncState->analysisData;
7e39acc6 625 MessageStats* messageStats;
d4721e1a 626 double* rtt;
76be6fc2
BP
627 double tt;
628 struct RttKey rttKey;
629
e072e1ab 630 g_assert(message->inE->type == TCP);
76be6fc2 631
66eaf2eb
BP
632 if (syncState->stats)
633 {
7e39acc6
BP
634 messageStats=
635 &analysisData->stats->messageStats[message->outE->traceNum][message->inE->traceNum];
66eaf2eb
BP
636 messageStats->total++;
637 }
76be6fc2
BP
638
639 tt= wallTimeSub(&message->inE->wallTime, &message->outE->wallTime);
640 if (tt <= 0)
641 {
66eaf2eb
BP
642 if (syncState->stats)
643 {
644 messageStats->inversionNb++;
645 }
76be6fc2 646 }
8d7d16dd 647 else if (syncState->graphsStream)
4ee223e5 648 {
e072e1ab
BP
649 struct RttKey rttKey= {
650 .saddr=MIN(message->inE->event.tcpEvent->segmentKey->connectionKey.saddr,
651 message->inE->event.tcpEvent->segmentKey->connectionKey.daddr),
652 .daddr=MAX(message->inE->event.tcpEvent->segmentKey->connectionKey.saddr,
653 message->inE->event.tcpEvent->segmentKey->connectionKey.daddr),
654 };
66eaf2eb
BP
655 AnalysisHistogramEval* histogram=
656 g_hash_table_lookup(analysisData->graphs->histograms, &rttKey);
e072e1ab 657
66eaf2eb 658 if (histogram == NULL)
e072e1ab
BP
659 {
660 struct RttKey* tableKey= malloc(sizeof(*tableKey));
661
66eaf2eb 662 histogram= constructAnalysisHistogramEval(syncState->graphsDir, &rttKey);
e072e1ab 663 memcpy(tableKey, &rttKey, sizeof(*tableKey));
66eaf2eb 664 g_hash_table_insert(analysisData->graphs->histograms, tableKey, histogram);
e072e1ab
BP
665 }
666
667 if (message->inE->event.udpEvent->datagramKey->saddr <
668 message->inE->event.udpEvent->datagramKey->daddr)
669 {
66eaf2eb 670 hitBin(&histogram->ttSendBins, tt);
e072e1ab
BP
671 }
672 else
673 {
66eaf2eb 674 hitBin(&histogram->ttRecvBins, tt);
e072e1ab 675 }
4ee223e5 676 }
76be6fc2 677
66eaf2eb 678 if (syncState->stats)
76be6fc2 679 {
66eaf2eb
BP
680 rttKey.saddr=
681 message->inE->event.tcpEvent->segmentKey->connectionKey.saddr;
682 rttKey.daddr=
683 message->inE->event.tcpEvent->segmentKey->connectionKey.daddr;
684 rtt= g_hash_table_lookup(analysisData->rttInfo, &rttKey);
685 g_debug("rttInfo, looking up (%u, %u)->(%f)", rttKey.saddr,
686 rttKey.daddr, rtt ? *rtt : NAN);
687
688 if (rtt)
76be6fc2 689 {
66eaf2eb
BP
690 g_debug("rttInfo, tt: %f rtt / 2: %f", tt, *rtt / 2.);
691 if (tt < *rtt / 2.)
692 {
693 messageStats->tooFastNb++;
694 }
695 }
696 else
697 {
698 messageStats->noRTTInfoNb++;
76be6fc2
BP
699 }
700 }
66eaf2eb
BP
701
702 if (syncState->graphsStream)
703 {
704 updateBounds(analysisData->graphs->bounds, message->inE,
705 message->outE);
706 }
707
708 if (syncState->stats || syncState->graphsStream)
76be6fc2 709 {
66eaf2eb
BP
710 analysisData->chullSS->analysisModule->analyzeMessage(analysisData->chullSS,
711 message);
76be6fc2 712 }
cdce23b3
BP
713}
714
715
716/*
717 * Perform analysis on multiple messages
718 *
76be6fc2
BP
719 * Measure the RTT
720 *
cdce23b3
BP
721 * Args:
722 * syncState container for synchronization data
723 * exchange structure containing the messages
724 */
66eaf2eb
BP
725static void analyzeExchangeEval(SyncState* const syncState, Exchange* const
726 exchange)
cdce23b3 727{
d4721e1a
BP
728 AnalysisDataEval* analysisData= syncState->analysisData;
729 Message* m1= g_queue_peek_tail(exchange->acks);
730 Message* m2= exchange->message;
731 struct RttKey* rttKey;
732 double* rtt, * exchangeRtt;
cdce23b3 733
e072e1ab
BP
734 g_assert(m1->inE->type == TCP);
735
d4721e1a
BP
736 // (T2 - T1) - (T3 - T4)
737 rtt= malloc(sizeof(double));
738 *rtt= wallTimeSub(&m1->inE->wallTime, &m1->outE->wallTime) -
739 wallTimeSub(&m2->outE->wallTime, &m2->inE->wallTime);
740
d4721e1a
BP
741 rttKey= malloc(sizeof(struct RttKey));
742 rttKey->saddr=
743 MIN(m1->inE->event.tcpEvent->segmentKey->connectionKey.saddr,
744 m1->inE->event.tcpEvent->segmentKey->connectionKey.daddr);
745 rttKey->daddr=
746 MAX(m1->inE->event.tcpEvent->segmentKey->connectionKey.saddr,
747 m1->inE->event.tcpEvent->segmentKey->connectionKey.daddr);
e072e1ab
BP
748
749 if (syncState->graphsStream)
750 {
66eaf2eb
BP
751 AnalysisHistogramEval* histogram=
752 g_hash_table_lookup(analysisData->graphs->histograms, rttKey);
e072e1ab 753
66eaf2eb 754 if (histogram == NULL)
e072e1ab
BP
755 {
756 struct RttKey* tableKey= malloc(sizeof(*tableKey));
757
66eaf2eb
BP
758 histogram= constructAnalysisHistogramEval(syncState->graphsDir,
759 rttKey);
e072e1ab 760 memcpy(tableKey, rttKey, sizeof(*tableKey));
66eaf2eb
BP
761 g_hash_table_insert(analysisData->graphs->histograms, tableKey,
762 histogram);
e072e1ab
BP
763 }
764
66eaf2eb 765 hitBin(&histogram->hrttBins, *rtt / 2);
e072e1ab
BP
766 }
767
66eaf2eb 768 if (syncState->stats)
d4721e1a 769 {
66eaf2eb
BP
770 exchangeRtt= g_hash_table_lookup(analysisData->stats->exchangeRtt,
771 rttKey);
772
773 if (exchangeRtt)
d4721e1a 774 {
66eaf2eb
BP
775 if (*rtt < *exchangeRtt)
776 {
777 g_hash_table_replace(analysisData->stats->exchangeRtt, rttKey, rtt);
778 }
779 else
780 {
781 free(rttKey);
782 free(rtt);
783 }
784 }
785 else
786 {
787 g_hash_table_insert(analysisData->stats->exchangeRtt, rttKey, rtt);
d4721e1a
BP
788 }
789 }
790 else
791 {
66eaf2eb
BP
792 free(rttKey);
793 free(rtt);
d4721e1a 794 }
cdce23b3
BP
795}
796
797
798/*
799 * Perform analysis on muliple events
800 *
76be6fc2
BP
801 * Sum the broadcast differential delays
802 *
cdce23b3
BP
803 * Args:
804 * syncState container for synchronization data
805 * broadcast structure containing the events
806 */
66eaf2eb
BP
807static void analyzeBroadcastEval(SyncState* const syncState, Broadcast* const
808 broadcast)
cdce23b3 809{
66eaf2eb 810 AnalysisDataEval* analysisData= syncState->analysisData;
76be6fc2 811
66eaf2eb 812 if (syncState->stats)
76be6fc2 813 {
66eaf2eb
BP
814 double sum= 0, squaresSum= 0;
815 double y;
cdce23b3 816
66eaf2eb
BP
817 g_queue_foreach(broadcast->events, &gfSum, &sum);
818 g_queue_foreach(broadcast->events, &gfSumSquares, &squaresSum);
76be6fc2 819
66eaf2eb
BP
820 analysisData->stats->broadcastNb++;
821 // Because of numerical errors, this can at times be < 0
822 y= squaresSum / g_queue_get_length(broadcast->events) - pow(sum /
823 g_queue_get_length(broadcast->events), 2.);
824 if (y > 0)
825 {
826 analysisData->stats->broadcastDiffSum+= sqrt(y);
827 }
828 }
76be6fc2 829
66eaf2eb 830 if (syncState->graphsStream)
76be6fc2 831 {
66eaf2eb
BP
832 unsigned int i, j;
833 GArray* events;
834 unsigned int eventNb= broadcast->events->length;
835
836 events= g_array_sized_new(FALSE, FALSE, sizeof(Event*), eventNb);
837 g_queue_foreach(broadcast->events, &gfAddEventToArray, events);
838
839 for (i= 0; i < eventNb; i++)
840 {
841 for (j= 0; j < eventNb; j++)
842 {
843 Event* eventI= g_array_index(events, Event*, i), * eventJ=
844 g_array_index(events, Event*, j);
845
846 if (eventI->traceNum < eventJ->traceNum)
847 {
848 updateBounds(analysisData->graphs->bounds, eventI, eventJ);
849 }
850 }
851 }
852
853 g_array_free(events, TRUE);
76be6fc2 854 }
cdce23b3
BP
855}
856
857
858/*
66eaf2eb
BP
859 * Finalize the factor calculations. Since this module does not really
860 * calculate factors, identity factors are returned. Instead, histograms are
861 * written out and histogram structures are freed.
cdce23b3
BP
862 *
863 * Args:
864 * syncState container for synchronization data.
865 *
866 * Returns:
d4721e1a 867 * Factors[traceNb] identity factors for each trace
cdce23b3
BP
868 */
869static GArray* finalizeAnalysisEval(SyncState* const syncState)
870{
871 GArray* factors;
872 unsigned int i;
4ee223e5
BP
873 AnalysisDataEval* analysisData= syncState->analysisData;
874
66eaf2eb 875 if (syncState->graphsStream && analysisData->graphs->histograms)
4ee223e5 876 {
66eaf2eb
BP
877 g_hash_table_foreach(analysisData->graphs->histograms,
878 &ghfWriteHistogram, &(struct WriteHistogramInfo) {.rttInfo=
879 analysisData->rttInfo, .graphsStream= syncState->graphsStream});
880 g_hash_table_destroy(analysisData->graphs->histograms);
881 analysisData->graphs->histograms= NULL;
4ee223e5 882 }
cdce23b3 883
66eaf2eb
BP
884 finalizeAnalysisEvalLP(syncState);
885
cdce23b3
BP
886 factors= g_array_sized_new(FALSE, FALSE, sizeof(Factors),
887 syncState->traceNb);
888 g_array_set_size(factors, syncState->traceNb);
889 for (i= 0; i < syncState->traceNb; i++)
890 {
891 Factors* e;
892
893 e= &g_array_index(factors, Factors, i);
894 e->drift= 1.;
895 e->offset= 0.;
896 }
897
898 return factors;
899}
900
901
902/*
903 * Print statistics related to analysis. Must be called after
904 * finalizeAnalysis.
905 *
906 * Args:
907 * syncState container for synchronization data.
908 */
909static void printAnalysisStatsEval(SyncState* const syncState)
910{
911 AnalysisDataEval* analysisData;
f109919b
BP
912 unsigned int i, j, k;
913 unsigned int totInversion= 0, totTooFast= 0, totNoInfo= 0, totTotal= 0;
914 int charNb;
cdce23b3
BP
915
916 if (!syncState->stats)
917 {
918 return;
919 }
920
921 analysisData= (AnalysisDataEval*) syncState->analysisData;
922
923 printf("Synchronization evaluation analysis stats:\n");
ffa21cfd
BP
924 if (analysisData->stats->broadcastNb)
925 {
926 printf("\tsum of broadcast differential delays: %g\n",
927 analysisData->stats->broadcastDiffSum);
467066ee 928 printf("\taverage broadcast differential delay: %g\n",
ffa21cfd
BP
929 analysisData->stats->broadcastDiffSum /
930 analysisData->stats->broadcastNb);
931 }
cdce23b3
BP
932
933 printf("\tIndividual evaluation:\n"
f109919b 934 "\t\tTrace pair Inversions Too fast No RTT info Total\n");
cdce23b3
BP
935
936 for (i= 0; i < syncState->traceNb; i++)
937 {
938 for (j= i + 1; j < syncState->traceNb; j++)
939 {
76be6fc2 940 MessageStats* messageStats;
f109919b
BP
941 struct {
942 unsigned int t1, t2;
943 } loopValues[]= {
944 {i, j},
945 {j, i}
946 };
947
948 for (k= 0; k < sizeof(loopValues) / sizeof(*loopValues); k++)
949 {
950 messageStats=
951 &analysisData->stats->messageStats[loopValues[k].t1][loopValues[k].t2];
952
953 printf("\t\t%3d - %-3d ", loopValues[k].t1, loopValues[k].t2);
954 printf("%u (%u%%)%n", messageStats->inversionNb, (unsigned
955 int) ceil((double) messageStats->inversionNb /
956 messageStats->total * 100), &charNb);
957 printf("%*s", 17 - charNb > 0 ? 17 - charNb + 1: 1, " ");
958 printf("%u (%u%%)%n", messageStats->tooFastNb, (unsigned int)
959 ceil((double) messageStats->tooFastNb /
960 messageStats->total * 100), &charNb);
961 printf("%*s%-10u %u\n", 17 - charNb > 0 ? 17 - charNb + 1:
962 1, " ", messageStats->noRTTInfoNb, messageStats->total);
963
964 totInversion+= messageStats->inversionNb;
965 totTooFast+= messageStats->tooFastNb;
966 totNoInfo+= messageStats->noRTTInfoNb;
967 totTotal+= messageStats->total;
968 }
cdce23b3
BP
969 }
970 }
d4721e1a 971
f109919b
BP
972 printf("\t\t total ");
973 printf("%u (%u%%)%n", totInversion, (unsigned int) ceil((double)
974 totInversion / totTotal * 100), &charNb);
975 printf("%*s", 17 - charNb > 0 ? 17 - charNb + 1: 1, " ");
976 printf("%u (%u%%)%n", totTooFast, (unsigned int) ceil((double) totTooFast
977 / totTotal * 100), &charNb);
978 printf("%*s%-10u %u\n", 17 - charNb > 0 ? 17 - charNb + 1: 1, " ",
979 totNoInfo, totTotal);
980
d4721e1a
BP
981 printf("\tRound-trip times:\n"
982 "\t\tHost pair RTT from exchanges RTTs from file (ms)\n");
983 g_hash_table_foreach(analysisData->stats->exchangeRtt,
984 &ghfPrintExchangeRtt, analysisData->rttInfo);
66eaf2eb 985
05a840df 986#ifdef HAVE_LIBGLPK
66eaf2eb
BP
987 printf("\tConvex hull factors comparisons:\n"
988 "\t\tTrace pair Factors type Differences (lp - chull)\n"
989 "\t\t a0 a1\n"
990 "\t\t Min Max Min Max\n");
991
992 for (i= 0; i < syncState->traceNb; i++)
993 {
994 for (j= 0; j < i; j++)
995 {
996 FactorsCHull* chFactors= &analysisData->stats->chFactorsArray[i][j];
997 FactorsCHull* lpFactors= &analysisData->stats->lpFactorsArray[i][j];
998
999 printf("\t\t%3d - %-3d ", i, j);
1000 if (lpFactors->type == chFactors->type)
1001 {
1002 if (lpFactors->type == MIDDLE)
1003 {
1004 printf("%-13s %-10.4g %-10.4g %-10.4g %.4g\n",
1005 approxNames[lpFactors->type],
1006 lpFactors->min->offset - chFactors->min->offset,
1007 lpFactors->max->offset - chFactors->max->offset,
1008 lpFactors->min->drift - chFactors->min->drift,
1009 lpFactors->max->drift - chFactors->max->drift);
1010 }
1011 else if (lpFactors->type == ABSENT)
1012 {
1013 printf("%s\n", approxNames[lpFactors->type]);
1014 }
1015 }
1016 else
1017 {
1018 printf("Different! %s and %s\n", approxNames[lpFactors->type],
1019 approxNames[chFactors->type]);
1020 }
1021 }
1022 }
05a840df 1023#endif
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);
dce9bf0c
BP
1539 if (hullPointNb > 0)
1540 {
1541 glp_add_rows(lp, hullPointNb);
1542 }
66eaf2eb
BP
1543 glp_add_cols(lp, 2);
1544
1545 glp_set_col_name(lp, 1, "a0");
1546 glp_set_col_bnds(lp, 1, GLP_FR, 0., 0.);
1547 glp_set_col_name(lp, 2, "a1");
1548 glp_set_col_bnds(lp, 2, GLP_LO, 0., 0.);
1549
1550 // Add row constraints
1551 g_array_append_val(iArray, zero);
1552 g_array_append_val(jArray, zero);
1553 g_array_append_val(aArray, zeroD);
1554
1555 for (it= 0; it < sizeof(loopValues) / sizeof(*loopValues); it++)
1556 {
1557 g_queue_foreach(loopValues[it].hull, &gfLPAddRow,
1558 &loopValues[it].rowInfo);
1559 }
1560
1561 g_assert_cmpuint(iArray->len, ==, jArray->len);
1562 g_assert_cmpuint(jArray->len, ==, aArray->len);
1563 g_assert_cmpuint(aArray->len - 1, ==, hullPointNb * 2);
1564
1565 glp_load_matrix(lp, aArray->len - 1, &g_array_index(iArray, int, 0),
1566 &g_array_index(jArray, int, 0), &g_array_index(aArray, double, 0));
1567
1568 glp_scale_prob(lp, GLP_SF_AUTO);
1569
1570 g_array_free(iArray, TRUE);
1571 g_array_free(jArray, TRUE);
1572 g_array_free(aArray, TRUE);
1573
1574 return lp;
1575}
1576
1577
1578/*
1579 * A GFunc for g_queue_foreach(). Add constraints and bounds for one row.
1580 *
1581 * Args:
1582 * data Point*, synchronization point for which to add an LP row
1583 * (a constraint)
1584 * user_data LPAddRowInfo*
1585 */
1586static void gfLPAddRow(gpointer data, gpointer user_data)
1587{
1588 Point* p= data;
1589 struct LPAddRowInfo* rowInfo= user_data;
1590 int indexes[2];
1591 double constraints[2];
1592
1593 indexes[0]= g_array_index(rowInfo->iArray, int, rowInfo->iArray->len - 1) + 1;
1594 indexes[1]= indexes[0];
1595
1596 if (rowInfo->boundType == GLP_UP)
1597 {
1598 glp_set_row_bnds(rowInfo->lp, indexes[0], GLP_UP, 0., p->y);
1599 }
1600 else if (rowInfo->boundType == GLP_LO)
1601 {
1602 glp_set_row_bnds(rowInfo->lp, indexes[0], GLP_LO, p->y, 0.);
1603 }
1604 else
1605 {
1606 g_assert_not_reached();
1607 }
1608
1609 g_array_append_vals(rowInfo->iArray, indexes, 2);
1610 indexes[0]= 1;
1611 indexes[1]= 2;
1612 g_array_append_vals(rowInfo->jArray, indexes, 2);
1613 constraints[0]= 1.;
1614 constraints[1]= p->x;
1615 g_array_append_vals(rowInfo->aArray, constraints, 2);
1616}
1617
1618
1619/*
1620 * Calculate min or max correction factors (as possible) using an LP problem.
1621 *
1622 * Args:
1623 * lp: A linear programming problem with constraints and bounds
1624 * initialized.
1625 * direction: The type of factors desired. Use GLP_MAX for max
1626 * approximation factors (a1, the drift or slope is the
1627 * largest) and GLP_MIN in the other case.
1628 *
1629 * Returns:
1630 * If the calculation was successful, a new Factors struct. Otherwise, NULL.
1631 * The calculation will fail if the hull assumptions are not respected.
1632 */
1633static Factors* calculateFactors(glp_prob* const lp, const int direction)
1634{
1635 int retval, status;
1636 Factors* factors;
1637
1638 glp_set_obj_coef(lp, 1, 0.);
1639 glp_set_obj_coef(lp, 2, 1.);
1640
1641 glp_set_obj_dir(lp, direction);
1642 retval= glp_simplex(lp, NULL);
1643 status= glp_get_status(lp);
1644
1645 if (retval == 0 && status == GLP_OPT)
1646 {
1647 factors= malloc(sizeof(Factors));
1648 factors->offset= glp_get_col_prim(lp, 1);
1649 factors->drift= glp_get_col_prim(lp, 2);
1650 }
1651 else
1652 {
1653 factors= NULL;
1654 }
1655
1656 return factors;
1657}
1658
1659
1660/*
1661 * Calculate min, max and approx correction factors (as possible) using an LP
1662 * problem.
1663 *
1664 * Args:
1665 * lp: A linear programming problem with constraints and bounds
1666 * initialized.
1667 *
1668 * Returns:
1669 * Please note that the approximation type may be MIDDLE, INCOMPLETE or
1670 * ABSENT. Unlike in analysis_chull, ABSENT is also used when the hulls do
1671 * not respect assumptions.
1672 */
1673static void calculateCompleteFactors(glp_prob* const lp, FactorsCHull* factors)
1674{
1675 factors->min= calculateFactors(lp, GLP_MIN);
1676 factors->max= calculateFactors(lp, GLP_MAX);
1677
1678 if (factors->min && factors->max)
1679 {
1680 factors->type= MIDDLE;
1681 calculateFactorsMiddle(factors);
1682 }
1683 else if (factors->min || factors->max)
1684 {
1685 factors->type= INCOMPLETE;
1686 factors->approx= NULL;
1687 }
1688 else
1689 {
1690 factors->type= ABSENT;
1691 factors->approx= NULL;
1692 }
1693}
1694
1695
1696/*
1697 * Create and initialize an array like AnalysisStatsCHull.allFactors
1698 *
1699 * Args:
1700 * traceNb: number of traces
1701 *
1702 * Returns:
1703 * A new array, which can be freed with freeAllFactors()
1704 */
1705static FactorsCHull** createAllFactors(const unsigned int traceNb)
1706{
1707 FactorsCHull** factorsArray;
1708 unsigned int i;
1709
1710 factorsArray= malloc(traceNb * sizeof(FactorsCHull*));
1711 for (i= 0; i < traceNb; i++)
1712 {
1713 factorsArray[i]= calloc((i + 1), sizeof(FactorsCHull));
1714
1715 factorsArray[i][i].type= EXACT;
1716 factorsArray[i][i].approx= malloc(sizeof(Factors));
1717 factorsArray[i][i].approx->drift= 1.;
1718 factorsArray[i][i].approx->offset= 0.;
1719 }
1720
1721 return factorsArray;
1722}
1723#endif
1724
1725
1726/*
1727 * Compute synchronization factors using a linear programming approach.
1728 * Compute the factors using analysis_chull. Compare the two.
1729 *
05a840df
BP
1730 * When the solver library, glpk, is not available at build time, only compute
1731 * the factors using analysis_chull. This is to make sure that module runs its
1732 * finalize function so that its graph functions can be called later.
66eaf2eb
BP
1733 *
1734 * Args:
1735 * syncState: container for synchronization data
1736 */
66eaf2eb
BP
1737static void finalizeAnalysisEvalLP(SyncState* const syncState)
1738{
66eaf2eb 1739 AnalysisDataEval* analysisData= syncState->analysisData;
05a840df
BP
1740#ifdef HAVE_LIBGLPK
1741 unsigned int i, j;
66eaf2eb 1742 AnalysisDataCHull* chAnalysisData= analysisData->chullSS->analysisData;
6ce8ceac 1743 FactorsCHull** lpFactorsArray;
66eaf2eb
BP
1744
1745 if (!syncState->stats && !syncState->graphsStream)
1746 {
1747 return;
1748 }
1749
6ce8ceac
BP
1750 /* Because of matching_distributor, this analysis may be called twice.
1751 * Only run it once */
66eaf2eb
BP
1752 if ((syncState->graphsStream && analysisData->graphs->lps != NULL) ||
1753 (syncState->stats && analysisData->stats->chFactorsArray != NULL))
1754 {
1755 return;
1756 }
1757
6ce8ceac
BP
1758 lpFactorsArray= createAllFactors(syncState->traceNb);
1759
66eaf2eb
BP
1760 if (syncState->stats)
1761 {
1762 analysisData->stats->chFactorsArray=
1763 calculateAllFactors(analysisData->chullSS);
1764 analysisData->stats->lpFactorsArray= lpFactorsArray;
1765 }
1766
1767 if (syncState->graphsStream)
1768 {
1769 analysisData->graphs->lps= malloc(syncState->traceNb *
1770 sizeof(glp_prob**));
1771 for (i= 0; i < syncState->traceNb; i++)
1772 {
1773 analysisData->graphs->lps[i]= malloc(i * sizeof(glp_prob*));
1774 }
1775 analysisData->graphs->lpFactorsArray= lpFactorsArray;
1776 }
1777
1778 for (i= 0; i < syncState->traceNb; i++)
1779 {
1780 for (j= 0; j < i; j++)
1781 {
1782 glp_prob* lp;
1783
1784 // Create the LP problem
1785 lp= lpCreateProblem(chAnalysisData->hullArray[i][j],
1786 chAnalysisData->hullArray[j][i]);
1787
1788 // Use the LP problem to find the correction factors for this pair of
1789 // traces
1790 calculateCompleteFactors(lp, &lpFactorsArray[i][j]);
1791
1792 if (syncState->graphsStream)
1793 {
1794 analysisData->graphs->lps[i][j]= lp;
1795 }
1796 else
1797 {
1798 glp_delete_prob(lp);
66eaf2eb
BP
1799 }
1800 }
1801 }
05a840df 1802#endif
66eaf2eb
BP
1803
1804 g_array_free(analysisData->chullSS->analysisModule->finalizeAnalysis(analysisData->chullSS),
1805 TRUE);
1806}
66eaf2eb
BP
1807
1808
1809/*
1810 * Compute synchronization accuracy information using a linear programming
1811 * approach. Write the neccessary data files and plot lines in the gnuplot
1812 * script.
1813 *
c5571851
BP
1814 * When the solver library, glpk, is not available at build time nothing is
1815 * actually produced.
66eaf2eb
BP
1816 *
1817 * Args:
1818 * syncState: container for synchronization data
1819 * i: first trace number
1820 * j: second trace number, garanteed to be larger than i
1821 */
c5571851
BP
1822static void writeAnalysisTraceTimeBackPlotsEval(SyncState* const syncState,
1823 const unsigned int i, const unsigned int j)
66eaf2eb 1824{
c5571851 1825#ifdef HAVE_LIBGLPK
66eaf2eb
BP
1826 unsigned int it;
1827 AnalysisDataEval* analysisData= syncState->analysisData;
1828 AnalysisGraphsEval* graphs= analysisData->graphs;
1829 GQueue*** hullArray= ((AnalysisDataCHull*)
1830 analysisData->chullSS->analysisData)->hullArray;
1831 FactorsCHull* lpFactors= &graphs->lpFactorsArray[j][i];
1832 glp_prob* lp= graphs->lps[j][i];
1833
1834 if (lpFactors->type == MIDDLE)
1835 {
1836 int retval;
1837 char* cwd;
1838 char fileName[40];
1839 FILE* fp;
1840 double* xValues;
1841 unsigned int xBegin, xEnd;
1842 double interval;
1843 const unsigned int graphPointNb= 1000;
1844
1845 // Open the data file
1846 snprintf(fileName, 40, "analysis_eval_accuracy-%03u_and_%03u.data", i, j);
1847 fileName[sizeof(fileName) - 1]= '\0';
1848
1d597550 1849 cwd= changeToGraphsDir(syncState->graphsDir);
66eaf2eb
BP
1850
1851 if ((fp= fopen(fileName, "w")) == NULL)
1852 {
1853 g_error(strerror(errno));
1854 }
1855 fprintf(fp, "#%-24s %-25s %-25s %-25s\n", "x", "middle", "min", "max");
1856
1857 retval= chdir(cwd);
1858 if (retval == -1)
1859 {
1860 g_error(strerror(errno));
1861 }
1862 free(cwd);
1863
1864 // Build the list of absisca values for the points in the accuracy graph
1865 g_assert_cmpuint(graphPointNb, >=, 4);
1866 xValues= malloc(graphPointNb * sizeof(double));
1867 xValues[0]= graphs->bounds[j][i].min;
1868 xValues[graphPointNb - 1]= graphs->bounds[j][i].max;
1869 xValues[1]= MIN(((Point*) g_queue_peek_head(hullArray[i][j]))->x,
1870 ((Point*) g_queue_peek_head(hullArray[j][i]))->x);
1871 xValues[graphPointNb - 2]= MAX(((Point*)
1872 g_queue_peek_tail(hullArray[i][j]))->x, ((Point*)
1873 g_queue_peek_tail(hullArray[j][i]))->x);
1874
1875 if (xValues[0] == xValues[1])
1876 {
1877 xBegin= 0;
1878 }
1879 else
1880 {
1881 xBegin= 1;
1882 }
1883 if (xValues[graphPointNb - 2] == xValues[graphPointNb - 1])
1884 {
1885 xEnd= graphPointNb - 1;
1886 }
1887 else
1888 {
1889 xEnd= graphPointNb - 2;
1890 }
1891 interval= (xValues[xEnd] - xValues[xBegin]) / (graphPointNb - 1);
1892
1893 for (it= xBegin; it <= xEnd; it++)
1894 {
1895 xValues[it]= xValues[xBegin] + interval * (it - xBegin);
1896 }
1897
1898 /* For each absisca value and each optimisation direction, solve the LP
1899 * and write a line in the data file */
1900 for (it= 0; it < graphPointNb; it++)
1901 {
1902 unsigned int it2;
1903 int directions[]= {GLP_MIN, GLP_MAX};
1904
1905 glp_set_obj_coef(lp, 1, 1.);
1906 glp_set_obj_coef(lp, 2, xValues[it]);
1907
1908 fprintf(fp, "%25.9f %25.9f", xValues[it], lpFactors->approx->offset
1909 + lpFactors->approx->drift * xValues[it]);
1910 for (it2= 0; it2 < sizeof(directions) / sizeof(*directions); it2++)
1911 {
1912 int status;
1913
1914 glp_set_obj_dir(lp, directions[it2]);
1915 retval= glp_simplex(lp, NULL);
1916 status= glp_get_status(lp);
1917
1918 g_assert(retval == 0 && status == GLP_OPT);
1919 fprintf(fp, " %25.9f", glp_get_obj_val(lp));
1920 }
1921 fprintf(fp, "\n");
1922 }
1923
1924 free(xValues);
1925 fclose(fp);
1926
1927 fprintf(syncState->graphsStream,
1928 "\t\"analysis_eval_accuracy-%1$03u_and_%2$03u.data\" "
1929 "using 1:(($3 - $2) / clock_freq_%2$u):(($4 - $2) / clock_freq_%2$u) "
1930 "title \"Synchronization accuracy\" "
1931 "with filledcurves linewidth 2 linetype 1 "
1932 "linecolor rgb \"black\" fill solid 0.25 noborder, \\\n", i,
1933 j);
1934 }
66eaf2eb 1935#endif
c5571851 1936}
66eaf2eb
BP
1937
1938
1939/*
1940 * Write the analysis-specific graph lines in the gnuplot script.
1941 *
c5571851
BP
1942 * When the solver library, glpk, is not available at build time nothing is
1943 * actually produced.
1944 *
66eaf2eb
BP
1945 * Args:
1946 * syncState: container for synchronization data
1947 * i: first trace number
1948 * j: second trace number, garanteed to be larger than i
1949 */
c5571851
BP
1950static void writeAnalysisTraceTimeForePlotsEval(SyncState* const syncState,
1951 const unsigned int i, const unsigned int j)
66eaf2eb 1952{
c5571851
BP
1953#ifdef HAVE_LIBGLPK
1954 if (((AnalysisDataEval*)
1955 syncState->analysisData)->graphs->lpFactorsArray[j][i].type ==
1956 MIDDLE)
1957 {
1958 fprintf(syncState->graphsStream,
1959 "\t\"analysis_eval_accuracy-%1$03u_and_%2$03u.data\" "
1960 "using 1:(($3 - $2) / clock_freq_%2$u) notitle "
1961 "with lines linewidth 2 linetype 1 "
1962 "linecolor rgb \"gray60\", \\\n"
1963 "\t\"analysis_eval_accuracy-%1$03u_and_%2$03u.data\" "
1964 "using 1:(($4 - $2) / clock_freq_%2$u) notitle "
1965 "with lines linewidth 2 linetype 1 "
1966 "linecolor rgb \"gray60\", \\\n", i, j);
1967 }
1968#endif
66eaf2eb
BP
1969}
1970
1971
c6356aa7
BP
1972/*
1973 * Write the analysis-specific graph lines in the gnuplot script.
1974 *
1975 * Args:
1976 * syncState: container for synchronization data
1977 * i: first trace number
1978 * j: second trace number, garanteed to be larger than i
1979 */
1980static void writeAnalysisTraceTraceBackPlotsEval(SyncState* const syncState,
1981 const unsigned int i, const unsigned int j)
66eaf2eb 1982{
66eaf2eb
BP
1983#ifdef HAVE_LIBGLPK
1984 fprintf(syncState->graphsStream,
1985 "\t\"analysis_eval_accuracy-%1$03u_and_%2$03u.data\" "
1986 "using 1:3:4 "
1987 "title \"Synchronization accuracy\" "
1988 "with filledcurves linewidth 2 linetype 1 "
1989 "linecolor rgb \"black\" fill solid 0.25 noborder, \\\n", i, j);
1990#endif
c6356aa7
BP
1991}
1992
1993
1994/*
1995 * Write the analysis-specific graph lines in the gnuplot script.
1996 *
1997 * Args:
1998 * syncState: container for synchronization data
1999 * i: first trace number
2000 * j: second trace number, garanteed to be larger than i
2001 */
2002static void writeAnalysisTraceTraceForePlotsEval(SyncState* const syncState,
2003 const unsigned int i, const unsigned int j)
2004{
2005 AnalysisDataEval* analysisData= syncState->analysisData;
66eaf2eb 2006
c6356aa7 2007 analysisData->chullSS->analysisModule->graphFunctions.writeTraceTraceForePlots(analysisData->chullSS,
66eaf2eb
BP
2008 i, j);
2009}
This page took 0.114306 seconds and 4 git commands to generate.