Fix two memory leaks
[lttv.git] / lttv / lttv / sync / event_analysis_chull.c
CommitLineData
08365995 1/* This file is part of the Linux Trace Toolkit viewer
277e5b53 2 * Copyright (C) 2009, 2010 Benjamin Poirier <benjamin.poirier@polymtl.ca>
08365995 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.
08365995 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.
08365995 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/>.
08365995
BP
16 */
17#define _ISOC99_SOURCE
18
19#ifdef HAVE_CONFIG_H
20#include <config.h>
21#endif
22
23#include <errno.h>
053b4b77 24#include <inttypes.h>
08365995
BP
25#include <math.h>
26#include <float.h>
27#include <stdlib.h>
28#include <stdio.h>
2f076594 29#include <string.h>
08365995
BP
30#include <unistd.h>
31
2bd4b3e4 32#include "sync_chain.h"
08365995
BP
33
34#include "event_analysis_chull.h"
35
36
08365995
BP
37typedef enum
38{
39 LOWER,
40 UPPER
41} HullType;
42
08365995
BP
43typedef enum
44{
45 MINIMUM,
46 MAXIMUM
47} LineType;
48
ab6edc6a
BP
49#ifdef HAVE_LIBGLPK
50struct LPAddRowInfo
51{
52 glp_prob* lp;
53 int boundType;
54 GArray* iArray, * jArray, * aArray;
55};
56#endif
57
08365995
BP
58
59// Functions common to all analysis modules
60static void initAnalysisCHull(SyncState* const syncState);
61static void destroyAnalysisCHull(SyncState* const syncState);
62
10341d26
BP
63static void analyzeMessageCHull(SyncState* const syncState, Message* const
64 message);
0a87ec9a 65static AllFactors* finalizeAnalysisCHull(SyncState* const syncState);
08365995 66static void printAnalysisStatsCHull(SyncState* const syncState);
ab6edc6a
BP
67static void writeAnalysisTraceTraceForePlotsCHull(SyncState* const syncState,
68 const unsigned int i, const unsigned int j);
08365995
BP
69
70// Functions specific to this module
08365995
BP
71static void openGraphFiles(SyncState* const syncState);
72static void closeGraphFiles(SyncState* const syncState);
73static void writeGraphFiles(SyncState* const syncState);
74static void gfDumpHullToFile(gpointer data, gpointer userData);
75
ab6edc6a
BP
76AllFactors* calculateAllFactors(struct _SyncState* const syncState);
77void calculateFactorsMiddle(PairFactors* const factors);
78static Factors* calculateFactorsExact(GQueue* const cu, GQueue* const cl, const
79 LineType lineType) __attribute__((pure));
80static void calculateFactorsFallback(GQueue* const cr, GQueue* const cs,
81 PairFactors* const result);
08365995
BP
82static void grahamScan(GQueue* const hull, Point* const newPoint, const
83 HullType type);
84static int jointCmp(const Point* const p1, const Point* const p2, const Point*
85 const p3) __attribute__((pure));
86static double crossProductK(const Point const* p1, const Point const* p2,
87 const Point const* p3, const Point const* p4) __attribute__((pure));
08365995
BP
88static double slope(const Point* const p1, const Point* const p2)
89 __attribute__((pure));
90static double intercept(const Point* const p1, const Point* const p2)
91 __attribute__((pure));
08365995
BP
92static double verticalDistance(Point* p1, Point* p2, Point* const point)
93 __attribute__((pure));
08365995
BP
94
95static void gfPointDestroy(gpointer data, gpointer userData);
96
ab6edc6a
BP
97// The next group of functions is only needed when computing synchronization
98// accuracy.
99#ifdef HAVE_LIBGLPK
100static AllFactors* finalizeAnalysisCHullLP(SyncState* const syncState);
101static void writeAnalysisTraceTimeBackPlotsCHull(SyncState* const syncState,
102 const unsigned int i, const unsigned int j);
103static void writeAnalysisTraceTimeForePlotsCHull(SyncState* const syncState,
104 const unsigned int i, const unsigned int j);
105static void writeAnalysisTraceTraceBackPlotsCHull(SyncState* const syncState,
106 const unsigned int i, const unsigned int j);
107
108static glp_prob* lpCreateProblem(GQueue* const lowerHull, GQueue* const
109 upperHull);
110static void gfLPAddRow(gpointer data, gpointer user_data);
111static Factors* calculateFactorsLP(glp_prob* const lp, const int direction);
112static void calculateCompleteFactorsLP(glp_prob* const lp, PairFactors*
113 factors);
114void timeCorrectionLP(glp_prob* const lp, const PairFactors* const lpFactors,
115 const uint64_t time, CorrectedTime* const correctedTime);
116
117static void gfAddAbsiscaToArray(gpointer data, gpointer user_data);
118static gint gcfCompareUint64(gconstpointer a, gconstpointer b);
119#else
120static inline AllFactors* finalizeAnalysisCHullLP(SyncState* const syncState)
121{
122 return NULL;
123}
124#endif
125
126
08365995
BP
127
128static AnalysisModule analysisModuleCHull= {
129 .name= "chull",
130 .initAnalysis= &initAnalysisCHull,
131 .destroyAnalysis= &destroyAnalysisCHull,
10341d26 132 .analyzeMessage= &analyzeMessageCHull,
08365995
BP
133 .finalizeAnalysis= &finalizeAnalysisCHull,
134 .printAnalysisStats= &printAnalysisStatsCHull,
467066ee 135 .graphFunctions= {
ab6edc6a
BP
136#ifdef HAVE_LIBGLPK
137 .writeTraceTimeBackPlots= &writeAnalysisTraceTimeBackPlotsCHull,
138 .writeTraceTimeForePlots= &writeAnalysisTraceTimeForePlotsCHull,
139 .writeTraceTraceBackPlots= &writeAnalysisTraceTraceBackPlotsCHull,
140#endif
141 .writeTraceTraceForePlots= &writeAnalysisTraceTraceForePlotsCHull,
467066ee 142 }
08365995
BP
143};
144
c6356aa7 145
08365995
BP
146/*
147 * Analysis module registering function
148 */
2f961b65 149void registerAnalysisCHull()
08365995
BP
150{
151 g_queue_push_tail(&analysisModules, &analysisModuleCHull);
152}
153
154
155/*
156 * Analysis init function
157 *
158 * This function is called at the beginning of a synchronization run for a set
159 * of traces.
160 *
161 * Allocate some of the analysis specific data structures
162 *
163 * Args:
164 * syncState container for synchronization data.
165 * This function allocates or initializes these analysisData
166 * members:
167 * hullArray
168 * dropped
169 */
170static void initAnalysisCHull(SyncState* const syncState)
171{
172 unsigned int i, j;
173 AnalysisDataCHull* analysisData;
174
175 analysisData= malloc(sizeof(AnalysisDataCHull));
176 syncState->analysisData= analysisData;
177
178 analysisData->hullArray= malloc(syncState->traceNb * sizeof(GQueue**));
179 for (i= 0; i < syncState->traceNb; i++)
180 {
181 analysisData->hullArray[i]= malloc(syncState->traceNb * sizeof(GQueue*));
182
183 for (j= 0; j < syncState->traceNb; j++)
184 {
185 analysisData->hullArray[i][j]= g_queue_new();
186 }
187 }
ab6edc6a
BP
188#ifdef HAVE_LIBGLPK
189 analysisData->lps= NULL;
190#endif
08365995
BP
191
192 if (syncState->stats)
193 {
ab6edc6a 194 analysisData->stats= calloc(1, sizeof(AnalysisStatsCHull));
08365995
BP
195 }
196
8d7d16dd 197 if (syncState->graphsStream)
08365995 198 {
ab6edc6a 199 analysisData->graphsData= calloc(1, sizeof(AnalysisGraphsDataCHull));
08365995 200 openGraphFiles(syncState);
08365995
BP
201 }
202}
203
204
205/*
206 * Create and open files used to store convex hull points to genereate
207 * graphs. Allocate and populate array to store file pointers.
208 *
209 * Args:
210 * syncState: container for synchronization data
211 */
212static void openGraphFiles(SyncState* const syncState)
213{
214 unsigned int i, j;
215 int retval;
216 char* cwd;
217 char name[31];
218 AnalysisDataCHull* analysisData;
219
220 analysisData= (AnalysisDataCHull*) syncState->analysisData;
221
1d597550 222 cwd= changeToGraphsDir(syncState->graphsDir);
08365995
BP
223
224 analysisData->graphsData->hullPoints= malloc(syncState->traceNb *
225 sizeof(FILE**));
226 for (i= 0; i < syncState->traceNb; i++)
227 {
228 analysisData->graphsData->hullPoints[i]= malloc(syncState->traceNb *
229 sizeof(FILE*));
230 for (j= 0; j < syncState->traceNb; j++)
231 {
232 if (i != j)
233 {
234 retval= snprintf(name, sizeof(name),
235 "analysis_chull-%03u_to_%03u.data", j, i);
236 if (retval > sizeof(name) - 1)
237 {
238 name[sizeof(name) - 1]= '\0';
239 }
240 if ((analysisData->graphsData->hullPoints[i][j]= fopen(name, "w")) ==
241 NULL)
242 {
243 g_error(strerror(errno));
244 }
245 }
246 }
247 }
248
249 retval= chdir(cwd);
250 if (retval == -1)
251 {
252 g_error(strerror(errno));
253 }
254 free(cwd);
255}
256
257
258/*
259 * Write hull points to files to generate graphs.
260 *
261 * Args:
262 * syncState: container for synchronization data
263 */
264static void writeGraphFiles(SyncState* const syncState)
265{
266 unsigned int i, j;
267 AnalysisDataCHull* analysisData;
268
269 analysisData= (AnalysisDataCHull*) syncState->analysisData;
270
271 for (i= 0; i < syncState->traceNb; i++)
272 {
273 for (j= 0; j < syncState->traceNb; j++)
274 {
275 if (i != j)
276 {
277 g_queue_foreach(analysisData->hullArray[i][j],
278 &gfDumpHullToFile,
279 analysisData->graphsData->hullPoints[i][j]);
280 }
281 }
282 }
283}
284
285
286/*
287 * A GFunc for g_queue_foreach. Write a hull point to a file used to generate
288 * graphs
289 *
290 * Args:
291 * data: Point*, point to write to the file
292 * userData: FILE*, file pointer where to write the point
293 */
294static void gfDumpHullToFile(gpointer data, gpointer userData)
295{
296 Point* point;
297
298 point= (Point*) data;
053b4b77 299 fprintf((FILE*) userData, "%20" PRIu64 " %20" PRIu64 "\n", point->x, point->y);
08365995
BP
300}
301
302
303/*
304 * Close files used to store convex hull points to generate graphs.
305 * Deallocate array to store file pointers.
306 *
307 * Args:
308 * syncState: container for synchronization data
309 */
310static void closeGraphFiles(SyncState* const syncState)
311{
312 unsigned int i, j;
313 AnalysisDataCHull* analysisData;
314 int retval;
315
316 analysisData= (AnalysisDataCHull*) syncState->analysisData;
317
318 if (analysisData->graphsData->hullPoints == NULL)
319 {
320 return;
321 }
322
323 for (i= 0; i < syncState->traceNb; i++)
324 {
325 for (j= 0; j < syncState->traceNb; j++)
326 {
327 if (i != j)
328 {
329 retval= fclose(analysisData->graphsData->hullPoints[i][j]);
330 if (retval != 0)
331 {
332 g_error(strerror(errno));
333 }
334 }
335 }
336 free(analysisData->graphsData->hullPoints[i]);
337 }
338 free(analysisData->graphsData->hullPoints);
339 analysisData->graphsData->hullPoints= NULL;
340}
341
342
343/*
344 * Analysis destroy function
345 *
346 * Free the analysis specific data structures
347 *
348 * Args:
349 * syncState container for synchronization data.
350 * This function deallocates these analysisData members:
351 * hullArray
352 * stDev
353 */
354static void destroyAnalysisCHull(SyncState* const syncState)
355{
356 unsigned int i, j;
357 AnalysisDataCHull* analysisData;
358
359 analysisData= (AnalysisDataCHull*) syncState->analysisData;
360
361 if (analysisData == NULL)
362 {
363 return;
364 }
365
366 for (i= 0; i < syncState->traceNb; i++)
367 {
368 for (j= 0; j < syncState->traceNb; j++)
369 {
b2da0724
BP
370 g_queue_foreach(analysisData->hullArray[i][j], gfPointDestroy,
371 NULL);
6ce8ceac 372 g_queue_free(analysisData->hullArray[i][j]);
08365995
BP
373 }
374 free(analysisData->hullArray[i]);
375 }
376 free(analysisData->hullArray);
377
ab6edc6a
BP
378#ifdef HAVE_LIBGLPK
379 if (analysisData->lps != NULL)
380 {
381 for (i= 0; i < syncState->traceNb; i++)
382 {
383 unsigned int j;
384
385 for (j= 0; j < i; j++)
386 {
ab6edc6a
BP
387 glp_delete_prob(analysisData->lps[i][j]);
388 }
389 free(analysisData->lps[i]);
390 }
391 free(analysisData->lps);
336e21a5
BP
392
393 /* Be careful, this invalidates all problem objects which still exist.
394 * Don't keep copies of lps past this point. */
395 glp_free_env();
ab6edc6a
BP
396 }
397#endif
398
08365995
BP
399 if (syncState->stats)
400 {
b2da0724 401 freeAllFactors(analysisData->stats->allFactors, syncState->traceNb);
ab6edc6a
BP
402 freeAllFactors(analysisData->stats->geoFactors, syncState->traceNb);
403
404#ifdef HAVE_LIBGLPK
405 freeAllFactors(analysisData->stats->lpFactors, syncState->traceNb);
406#endif
08365995
BP
407
408 free(analysisData->stats);
409 }
410
8d7d16dd 411 if (syncState->graphsStream)
08365995 412 {
ab6edc6a
BP
413 AnalysisGraphsDataCHull* graphs= analysisData->graphsData;
414
415 if (graphs->hullPoints != NULL)
08365995
BP
416 {
417 closeGraphFiles(syncState);
418 }
419
ab6edc6a
BP
420 freeAllFactors(graphs->allFactors, syncState->traceNb);
421
422#ifdef HAVE_LIBGLPK
423 freeAllFactors(graphs->lpFactors, syncState->traceNb);
424#endif
08365995
BP
425
426 free(analysisData->graphsData);
427 }
428
429 free(syncState->analysisData);
430 syncState->analysisData= NULL;
431}
432
433
434/*
435 * Perform analysis on an event pair.
436 *
437 * Args:
438 * syncState container for synchronization data
10341d26 439 * message structure containing the events
08365995 440 */
10341d26 441static void analyzeMessageCHull(SyncState* const syncState, Message* const message)
08365995
BP
442{
443 AnalysisDataCHull* analysisData;
444 Point* newPoint;
445 HullType hullType;
446 GQueue* hull;
447
448 analysisData= (AnalysisDataCHull*) syncState->analysisData;
449
450 newPoint= malloc(sizeof(Point));
10341d26 451 if (message->inE->traceNum < message->outE->traceNum)
08365995
BP
452 {
453 // CA is inE->traceNum
76be6fc2
BP
454 newPoint->x= message->inE->cpuTime;
455 newPoint->y= message->outE->cpuTime;
08365995 456 hullType= UPPER;
053b4b77
BP
457 g_debug("Reception point hullArray[%lu][%lu] "
458 "x= inE->time= %" PRIu64 " y= outE->time= %" PRIu64,
10341d26 459 message->inE->traceNum, message->outE->traceNum, newPoint->x,
08365995
BP
460 newPoint->y);
461 }
462 else
463 {
464 // CA is outE->traceNum
76be6fc2
BP
465 newPoint->x= message->outE->cpuTime;
466 newPoint->y= message->inE->cpuTime;
08365995 467 hullType= LOWER;
053b4b77
BP
468 g_debug("Send point hullArray[%lu][%lu] "
469 "x= inE->time= %" PRIu64 " y= outE->time= %" PRIu64,
10341d26 470 message->inE->traceNum, message->outE->traceNum, newPoint->x,
08365995
BP
471 newPoint->y);
472 }
473
474 hull=
10341d26 475 analysisData->hullArray[message->inE->traceNum][message->outE->traceNum];
08365995
BP
476
477 if (hull->length >= 1 && newPoint->x < ((Point*)
478 g_queue_peek_tail(hull))->x)
479 {
480 if (syncState->stats)
481 {
482 analysisData->stats->dropped++;
483 }
484
485 free(newPoint);
486 }
487 else
488 {
489 grahamScan(hull, newPoint, hullType);
490 }
491}
492
493
494/*
495 * Construct one half of a convex hull from abscissa-sorted points
496 *
497 * Args:
498 * hull: the points already in the hull
499 * newPoint: a new point to consider
500 * type: which half of the hull to construct
501 */
502static void grahamScan(GQueue* const hull, Point* const newPoint, const
503 HullType type)
504{
505 int inversionFactor;
506
507 g_debug("grahamScan(hull (length: %u), newPoint, %s)", hull->length, type
508 == LOWER ? "LOWER" : "UPPER");
509
510 if (type == LOWER)
511 {
512 inversionFactor= 1;
513 }
514 else
515 {
516 inversionFactor= -1;
517 }
518
519 if (hull->length >= 2)
520 {
521 g_debug("jointCmp(hull[%u], hull[%u], newPoint) * inversionFactor = %d * %d = %d",
522 hull->length - 2,
523 hull->length - 1,
524 jointCmp(g_queue_peek_nth(hull, hull->length - 2),
525 g_queue_peek_tail(hull), newPoint),
526 inversionFactor,
527 jointCmp(g_queue_peek_nth(hull, hull->length - 2),
528 g_queue_peek_tail(hull), newPoint) * inversionFactor);
529 }
530 while (hull->length >= 2 && jointCmp(g_queue_peek_nth(hull, hull->length -
531 2), g_queue_peek_tail(hull), newPoint) * inversionFactor <= 0)
532 {
533 g_debug("Removing hull[%u]", hull->length);
534 free((Point*) g_queue_pop_tail(hull));
535
536 if (hull->length >= 2)
537 {
538 g_debug("jointCmp(hull[%u], hull[%u], newPoint) * inversionFactor = %d * %d = %d",
539 hull->length - 2,
540 hull->length - 1,
541 jointCmp(g_queue_peek_nth(hull, hull->length - 2),
542 g_queue_peek_tail(hull), newPoint),
543 inversionFactor,
544 jointCmp(g_queue_peek_nth(hull, hull->length - 2),
545 g_queue_peek_tail(hull), newPoint) * inversionFactor);
546 }
547 }
548 g_queue_push_tail(hull, newPoint);
549}
550
551
552/*
553 * Finalize the factor calculations
554 *
555 * Args:
556 * syncState container for synchronization data.
557 *
558 * Returns:
0a87ec9a
BP
559 * AllFactors* synchronization factors for each trace pair, the caller is
560 * responsible for freeing the structure
08365995 561 */
0a87ec9a 562static AllFactors* finalizeAnalysisCHull(SyncState* const syncState)
08365995
BP
563{
564 AnalysisDataCHull* analysisData;
ab6edc6a 565 AllFactors* geoFactors, * lpFactors;
08365995
BP
566
567 analysisData= (AnalysisDataCHull*) syncState->analysisData;
568
8d7d16dd 569 if (syncState->graphsStream && analysisData->graphsData->hullPoints != NULL)
08365995
BP
570 {
571 writeGraphFiles(syncState);
572 closeGraphFiles(syncState);
573 }
574
ab6edc6a
BP
575 geoFactors= calculateAllFactors(syncState);
576 lpFactors= finalizeAnalysisCHullLP(syncState);
08365995 577
0a87ec9a 578 if (syncState->stats)
08365995 579 {
ab6edc6a
BP
580 geoFactors->refCount++;
581 analysisData->stats->geoFactors= geoFactors;
582
583 if (lpFactors != NULL)
584 {
585 lpFactors->refCount++;
586 analysisData->stats->allFactors= lpFactors;
587 }
588 else
589 {
590 geoFactors->refCount++;
591 analysisData->stats->allFactors= geoFactors;
592 }
08365995 593 }
0a87ec9a
BP
594
595 if (syncState->graphsStream)
08365995 596 {
ab6edc6a
BP
597 if (lpFactors != NULL)
598 {
599 lpFactors->refCount++;
600 analysisData->graphsData->allFactors= lpFactors;
601 }
602 else
603 {
604 geoFactors->refCount++;
605 analysisData->graphsData->allFactors= geoFactors;
606 }
08365995
BP
607 }
608
ab6edc6a
BP
609 if (lpFactors != NULL)
610 {
611 freeAllFactors(geoFactors, syncState->traceNb);
612 return lpFactors;
613 }
614 else
615 {
616 freeAllFactors(lpFactors, syncState->traceNb);
617 return geoFactors;
618 }
08365995
BP
619}
620
621
622/*
623 * Print statistics related to analysis. Must be called after
624 * finalizeAnalysis.
625 *
626 * Args:
627 * syncState container for synchronization data.
628 */
629static void printAnalysisStatsCHull(SyncState* const syncState)
630{
631 AnalysisDataCHull* analysisData;
632 unsigned int i, j;
633
634 if (!syncState->stats)
635 {
636 return;
637 }
638
639 analysisData= (AnalysisDataCHull*) syncState->analysisData;
640
641 printf("Convex hull analysis stats:\n");
642 printf("\tout of order packets dropped from analysis: %u\n",
643 analysisData->stats->dropped);
644
645 printf("\tNumber of points in convex hulls:\n");
646
647 for (i= 0; i < syncState->traceNb; i++)
648 {
649 for (j= i + 1; j < syncState->traceNb; j++)
650 {
651 printf("\t\t%3d - %-3d: lower half-hull %-5u upper half-hull %-5u\n",
652 i, j, analysisData->hullArray[j][i]->length,
653 analysisData->hullArray[i][j]->length);
654 }
655 }
656
657 printf("\tIndividual synchronization factors:\n");
658
659 for (i= 0; i < syncState->traceNb; i++)
660 {
661 for (j= i + 1; j < syncState->traceNb; j++)
662 {
0a87ec9a 663 PairFactors* factorsCHull;
08365995 664
0a87ec9a 665 factorsCHull= &analysisData->stats->allFactors->pairFactors[j][i];
ce3dcf0e
BP
666 printf("\t\t%3d - %-3d: %s", i, j,
667 approxNames[factorsCHull->type]);
08365995
BP
668
669 if (factorsCHull->type == EXACT)
670 {
ce3dcf0e 671 printf(" a0= % 7g a1= 1 %c %7g\n",
08365995
BP
672 factorsCHull->approx->offset,
673 factorsCHull->approx->drift < 0. ? '-' : '+',
674 fabs(factorsCHull->approx->drift));
675 }
0a87ec9a 676 else if (factorsCHull->type == ACCURATE)
08365995 677 {
0a87ec9a 678 printf("\n\t\t a0: % 7g to % 7g (delta= %7g)\n",
08365995
BP
679 factorsCHull->max->offset, factorsCHull->min->offset,
680 factorsCHull->min->offset - factorsCHull->max->offset);
681 printf("\t\t a1: 1 %+7g to %+7g (delta= %7g)\n",
682 factorsCHull->min->drift - 1., factorsCHull->max->drift -
683 1., factorsCHull->max->drift - factorsCHull->min->drift);
684 }
0a87ec9a 685 else if (factorsCHull->type == APPROXIMATE)
08365995 686 {
ce3dcf0e 687 printf(" a0= % 7g a1= 1 %c %7g error= %7g\n",
08365995
BP
688 factorsCHull->approx->offset, factorsCHull->approx->drift
689 - 1. < 0. ? '-' : '+', fabs(factorsCHull->approx->drift -
690 1.), factorsCHull->accuracy);
691 }
692 else if (factorsCHull->type == INCOMPLETE)
693 {
ce3dcf0e 694 printf("\n");
08365995
BP
695
696 if (factorsCHull->min->drift != -INFINITY)
697 {
698 printf("\t\t min: a0: % 7g a1: 1 %c %7g\n",
699 factorsCHull->min->offset, factorsCHull->min->drift -
700 1. < 0 ? '-' : '+', fabs(factorsCHull->min->drift -
701 1.));
702 }
703 if (factorsCHull->max->drift != INFINITY)
704 {
705 printf("\t\t max: a0: % 7g a1: 1 %c %7g\n",
706 factorsCHull->max->offset, factorsCHull->max->drift -
707 1. < 0 ? '-' : '+', fabs(factorsCHull->max->drift -
708 1.));
709 }
710 }
ab6edc6a 711 else if (factorsCHull->type == FAIL)
08365995 712 {
ce3dcf0e 713 printf("\n");
08365995
BP
714
715 if (factorsCHull->min != NULL && factorsCHull->min->drift != -INFINITY)
716 {
717 printf("\t\t min: a0: % 7g a1: 1 %c %7g\n",
718 factorsCHull->min->offset, factorsCHull->min->drift -
719 1. < 0 ? '-' : '+', fabs(factorsCHull->min->drift -
720 1.));
721 }
722 if (factorsCHull->max != NULL && factorsCHull->max->drift != INFINITY)
723 {
724 printf("\t\t max: a0: % 7g a1: 1 %c %7g\n",
725 factorsCHull->max->offset, factorsCHull->max->drift -
726 1. < 0 ? '-' : '+', fabs(factorsCHull->max->drift -
727 1.));
728 }
729 }
730 else if (factorsCHull->type == ABSENT)
731 {
ce3dcf0e 732 printf("\n");
08365995
BP
733 }
734 else
735 {
736 g_assert_not_reached();
737 }
738 }
739 }
ab6edc6a
BP
740
741#ifdef HAVE_LIBGLPK
742 printf("\tFactor comparison:\n"
743 "\t\tTrace pair Factors type Differences (lp - chull)\n"
744 "\t\t a0 a1\n"
745 "\t\t Min Max Min Max\n");
746
747 for (i= 0; i < syncState->traceNb; i++)
748 {
749 for (j= 0; j < i; j++)
750 {
751 PairFactors* geoFactors=
752 &analysisData->stats->geoFactors->pairFactors[i][j];
753 PairFactors* lpFactors=
754 &analysisData->stats->lpFactors->pairFactors[i][j];
755
756 printf("\t\t%3d - %-3d ", i, j);
757 if (lpFactors->type == geoFactors->type)
758 {
759 if (lpFactors->type == ACCURATE)
760 {
761 printf("%-13s %-10.4g %-10.4g %-10.4g %.4g\n",
762 approxNames[lpFactors->type],
763 lpFactors->min->offset - geoFactors->min->offset,
764 lpFactors->max->offset - geoFactors->max->offset,
765 lpFactors->min->drift - geoFactors->min->drift,
766 lpFactors->max->drift - geoFactors->max->drift);
767 }
768 else if (lpFactors->type == ABSENT)
769 {
770 printf("%s\n", approxNames[lpFactors->type]);
771 }
772 }
773 else
774 {
775 printf("Different! %s and %s\n", approxNames[lpFactors->type],
776 approxNames[geoFactors->type]);
777 }
778 }
779 }
780#endif
08365995
BP
781}
782
783
784/*
785 * A GFunc for g_queue_foreach()
786 *
787 * Args:
788 * data Point*, point to destroy
789 * user_data NULL
790 */
791static void gfPointDestroy(gpointer data, gpointer userData)
792{
793 Point* point;
794
795 point= (Point*) data;
796 free(point);
797}
798
799
800/*
801 * Find out if a sequence of three points constitutes a "left turn" or a
802 * "right turn".
803 *
804 * Args:
805 * p1, p2, p3: The three points.
806 *
807 * Returns:
808 * < 0 right turn
809 * 0 colinear (unlikely result since this uses floating point
810 * arithmetic)
811 * > 0 left turn
812 */
813static int jointCmp(const Point const* p1, const Point const* p2, const
814 Point const* p3)
815{
816 double result;
817 const double fuzzFactor= 0.;
818
819 result= crossProductK(p1, p2, p1, p3);
053b4b77
BP
820 g_debug("crossProductK(p1= (%" PRIu64 ", %" PRIu64 "), "
821 "p2= (%" PRIu64 ", %" PRIu64 "), p1= (%" PRIu64 ", %" PRIu64 "), "
822 "p3= (%" PRIu64 ", %" PRIu64 "))= %g",
08365995
BP
823 p1->x, p1->y, p2->x, p2->y, p1->x, p1->y, p3->x, p3->y, result);
824 if (result < fuzzFactor)
825 {
826 return -1;
827 }
828 else if (result > fuzzFactor)
829 {
830 return 1;
831 }
832 else
833 {
834 return 0;
835 }
836}
837
838
839/*
840 * Calculate the k component of the cross product of two vectors.
841 *
842 * Args:
843 * p1, p2: start and end points of the first vector
844 * p3, p4: start and end points of the second vector
845 *
846 * Returns:
847 * the k component of the cross product when considering the two vectors to
848 * be in the i-j plane. The direction (sign) of the result can be useful to
849 * determine the relative orientation of the two vectors.
850 */
851static double crossProductK(const Point const* p1, const Point const* p2,
852 const Point const* p3, const Point const* p4)
853{
854 return ((double) p2->x - p1->x) * ((double) p4->y - p3->y) - ((double)
855 p2->y - p1->y) * ((double) p4->x - p3->x);
856}
857
858
08365995
BP
859/*
860 * Analyze the convex hulls to determine the synchronization factors between
861 * each pair of trace.
862 *
863 * Args:
864 * syncState container for synchronization data.
865 *
866 * Returns:
ab6edc6a 867 * AllFactors*, see the documentation for the member geoFactors of
0a87ec9a 868 * AnalysisStatsCHull.
08365995 869 */
0a87ec9a 870AllFactors* calculateAllFactors(SyncState* const syncState)
08365995
BP
871{
872 unsigned int traceNumA, traceNumB;
ab6edc6a 873 AllFactors* geoFactors;
08365995
BP
874 AnalysisDataCHull* analysisData;
875
876 analysisData= (AnalysisDataCHull*) syncState->analysisData;
877
ab6edc6a
BP
878 // Allocate geoFactors and calculate min and max
879 geoFactors= createAllFactors(syncState->traceNb);
08365995
BP
880 for (traceNumA= 0; traceNumA < syncState->traceNb; traceNumA++)
881 {
08365995
BP
882 for (traceNumB= 0; traceNumB < traceNumA; traceNumB++)
883 {
884 unsigned int i;
885 GQueue* cs, * cr;
886 const struct
887 {
888 LineType lineType;
889 size_t factorsOffset;
890 } loopValues[]= {
0a87ec9a
BP
891 {MINIMUM, offsetof(PairFactors, min)},
892 {MAXIMUM, offsetof(PairFactors, max)}
08365995
BP
893 };
894
895 cr= analysisData->hullArray[traceNumB][traceNumA];
896 cs= analysisData->hullArray[traceNumA][traceNumB];
897
898 for (i= 0; i < sizeof(loopValues) / sizeof(*loopValues); i++)
899 {
ab6edc6a 900 g_debug("geoFactors[%u][%u].%s = calculateFactorsExact(cr= "
0a87ec9a 901 "hullArray[%u][%u], cs= hullArray[%u][%u], %s)",
08365995 902 traceNumA, traceNumB, loopValues[i].factorsOffset ==
0a87ec9a 903 offsetof(PairFactors, min) ? "min" : "max", traceNumB,
08365995
BP
904 traceNumA, traceNumA, traceNumB, loopValues[i].lineType ==
905 MINIMUM ? "MINIMUM" : "MAXIMUM");
0a87ec9a 906 *((Factors**) ((void*)
ab6edc6a 907 &geoFactors->pairFactors[traceNumA][traceNumB] +
08365995
BP
908 loopValues[i].factorsOffset))=
909 calculateFactorsExact(cr, cs, loopValues[i].lineType);
910 }
911 }
912 }
913
914 // Calculate approx when possible
915 for (traceNumA= 0; traceNumA < syncState->traceNb; traceNumA++)
916 {
917 for (traceNumB= 0; traceNumB < traceNumA; traceNumB++)
918 {
0a87ec9a 919 PairFactors* factorsCHull;
08365995 920
ab6edc6a 921 factorsCHull= &geoFactors->pairFactors[traceNumA][traceNumB];
08365995
BP
922 if (factorsCHull->min == NULL && factorsCHull->max == NULL)
923 {
0a87ec9a 924 factorsCHull->type= APPROXIMATE;
08365995
BP
925 calculateFactorsFallback(analysisData->hullArray[traceNumB][traceNumA],
926 analysisData->hullArray[traceNumA][traceNumB],
ab6edc6a 927 &geoFactors->pairFactors[traceNumA][traceNumB]);
08365995
BP
928 }
929 else if (factorsCHull->min != NULL && factorsCHull->max != NULL)
930 {
931 if (factorsCHull->min->drift != -INFINITY &&
932 factorsCHull->max->drift != INFINITY)
933 {
0a87ec9a 934 factorsCHull->type= ACCURATE;
08365995
BP
935 calculateFactorsMiddle(factorsCHull);
936 }
937 else if (factorsCHull->min->drift != -INFINITY ||
938 factorsCHull->max->drift != INFINITY)
939 {
940 factorsCHull->type= INCOMPLETE;
941 }
942 else
943 {
944 factorsCHull->type= ABSENT;
945 }
946 }
947 else
948 {
949 //g_assert_not_reached();
ab6edc6a 950 factorsCHull->type= FAIL;
08365995
BP
951 }
952 }
953 }
954
ab6edc6a 955 return geoFactors;
08365995
BP
956}
957
958
959/* Calculate approximative factors based on minimum and maximum limits. The
960 * best approximation to make is the interior bissector of the angle formed by
961 * the minimum and maximum lines.
962 *
963 * The formulae used come from [Haddad, Yoram: Performance dans les systèmes
964 * répartis: des outils pour les mesures, Université de Paris-Sud, Centre
965 * d'Orsay, September 1988] Section 6.1 p.44
966 *
967 * The reasoning for choosing this estimator comes from [Duda, A., Harrus, G.,
968 * Haddad, Y., and Bernard, G.: Estimating global time in distributed systems,
969 * Proc. 7th Int. Conf. on Distributed Computing Systems, Berlin, volume 18,
970 * 1987] p.303
971 *
972 * Args:
973 * factors: contains the min and max limits, used to store the result
974 */
0a87ec9a 975void calculateFactorsMiddle(PairFactors* const factors)
08365995
BP
976{
977 double amin, amax, bmin, bmax, bhat;
978
979 amin= factors->max->offset;
980 amax= factors->min->offset;
981 bmin= factors->min->drift;
982 bmax= factors->max->drift;
983
48b641c1 984 g_assert_cmpfloat(bmax, >=, bmin);
08365995
BP
985
986 factors->approx= malloc(sizeof(Factors));
987 bhat= (bmax * bmin - 1. + sqrt(1. + pow(bmax, 2.) * pow(bmin, 2.) +
988 pow(bmax, 2.) + pow(bmin, 2.))) / (bmax + bmin);
989 factors->approx->offset= amax - (amax - amin) / 2. * (pow(bhat, 2.) + 1.)
990 / (1. + bhat * bmax);
991 factors->approx->drift= bhat;
992 factors->accuracy= bmax - bmin;
993}
994
995
996/*
997 * Analyze the convex hulls to determine the minimum or maximum
998 * synchronization factors between one pair of trace.
999 *
1000 * This implements and improves upon the algorithm in [Haddad, Yoram:
1001 * Performance dans les systèmes répartis: des outils pour les mesures,
1002 * Université de Paris-Sud, Centre d'Orsay, September 1988] Section 6.2 p.47
1003 *
1004 * Some degenerate cases are possible:
1005 * 1) the result is unbounded. In that case, when searching for the maximum
1006 * factors, result->drift= INFINITY; result->offset= -INFINITY. When
1007 * searching for the minimum factors, it is the opposite. It is not
1008 * possible to improve the situation with this data.
1009 * 2) no line can be above the upper hull and below the lower hull. This is
1010 * because the hulls intersect each other or are reversed. This means that
1011 * an assertion was false. Most probably, the clocks are not linear. It is
1012 * possible to repeat the search with another algorithm that will find a
1013 * "best effort" approximation. See calculateFactorsApprox().
1014 *
1015 * Args:
1016 * cu: the upper half-convex hull, the line must pass above this
1017 * and touch it in one point
1018 * cl: the lower half-convex hull, the line must pass below this
1019 * and touch it in one point
1020 * lineType: search for minimum or maximum factors
1021 *
1022 * Returns:
1023 * If a result is found, a struct Factors is allocated, filed with the
1024 * result and returned
1025 * NULL otherwise, degenerate case 2 is in effect
1026 */
1027static Factors* calculateFactorsExact(GQueue* const cu, GQueue* const cl, const
1028 LineType lineType)
1029{
1030 GQueue* c1, * c2;
1031 unsigned int i1, i2;
1032 Point* p1, * p2;
1033 double inversionFactor;
1034 Factors* result;
1035
1036 g_debug("calculateFactorsExact(cu= %p, cl= %p, %s)", cu, cl, lineType ==
1037 MINIMUM ? "MINIMUM" : "MAXIMUM");
1038
1039 if (lineType == MINIMUM)
1040 {
1041 c1= cl;
1042 c2= cu;
1043 inversionFactor= -1.;
1044 }
1045 else
1046 {
1047 c1= cu;
1048 c2= cl;
1049 inversionFactor= 1.;
1050 }
1051
1052 i1= 0;
1053 i2= c2->length - 1;
1054
1055 // Check for degenerate case 1
1056 if (c1->length == 0 || c2->length == 0 || ((Point*) g_queue_peek_nth(c1,
1057 i1))->x >= ((Point*) g_queue_peek_nth(c2, i2))->x)
1058 {
1059 result= malloc(sizeof(Factors));
1060 if (lineType == MINIMUM)
1061 {
1062 result->drift= -INFINITY;
1063 result->offset= INFINITY;
1064 }
1065 else
1066 {
1067 result->drift= INFINITY;
1068 result->offset= -INFINITY;
1069 }
1070
1071 return result;
1072 }
1073
1074 do
1075 {
1076 while
1077 (
1078 (int) i2 - 1 > 0
1079 && crossProductK(
1080 g_queue_peek_nth(c1, i1),
1081 g_queue_peek_nth(c2, i2),
1082 g_queue_peek_nth(c1, i1),
1083 g_queue_peek_nth(c2, i2 - 1)) * inversionFactor < 0.
1084 )
1085 {
1086 if (((Point*) g_queue_peek_nth(c1, i1))->x
1087 < ((Point*) g_queue_peek_nth(c2, i2 - 1))->x)
1088 {
1089 i2--;
1090 }
1091 else
1092 {
1093 // Degenerate case 2
1094 return NULL;
1095 }
1096 }
1097 while
1098 (
1099 i1 + 1 < c1->length - 1
1100 && crossProductK(
1101 g_queue_peek_nth(c1, i1),
1102 g_queue_peek_nth(c2, i2),
1103 g_queue_peek_nth(c1, i1 + 1),
1104 g_queue_peek_nth(c2, i2)) * inversionFactor < 0.
1105 )
1106 {
1107 if (((Point*) g_queue_peek_nth(c1, i1 + 1))->x
1108 < ((Point*) g_queue_peek_nth(c2, i2))->x)
1109 {
1110 i1++;
1111 }
1112 else
1113 {
1114 // Degenerate case 2
1115 return NULL;
1116 }
1117 }
1118 } while
1119 (
1120 (int) i2 - 1 > 0
1121 && crossProductK(
1122 g_queue_peek_nth(c1, i1),
1123 g_queue_peek_nth(c2, i2),
1124 g_queue_peek_nth(c1, i1),
1125 g_queue_peek_nth(c2, i2 - 1)) * inversionFactor < 0.
1126 );
1127
1128 p1= g_queue_peek_nth(c1, i1);
1129 p2= g_queue_peek_nth(c2, i2);
1130
053b4b77
BP
1131 g_debug("Resulting points are: c1[i1]: x= %" PRIu64 " y= %" PRIu64
1132 " c2[i2]: x= %" PRIu64 " y= %" PRIu64 "", p1->x, p1->y, p2->x, p2->y);
08365995
BP
1133
1134 result= malloc(sizeof(Factors));
1135 result->drift= slope(p1, p2);
1136 result->offset= intercept(p1, p2);
1137
053b4b77
BP
1138 g_debug("Resulting factors are: drift= %g offset= %g", result->drift,
1139 result->offset);
08365995
BP
1140
1141 return result;
1142}
1143
1144
1145/*
1146 * Analyze the convex hulls to determine approximate synchronization factors
1147 * between one pair of trace when there is no line that can fit in the
1148 * corridor separating them.
1149 *
1150 * This implements the algorithm in [Ashton, P.: Algorithms for Off-line Clock
1151 * Synchronisation, University of Canterbury, December 1995, 26] Section 4.2.2
1152 * p.7
1153 *
1154 * For each point p1 in cr
1155 * For each point p2 in cs
1156 * errorMin= 0
1157 * Calculate the line paramaters
1158 * For each point p3 in each convex hull
1159 * If p3 is on the wrong side of the line
1160 * error+= distance
1161 * If error < errorMin
1162 * Update results
1163 *
1164 * Args:
1165 * cr: the upper half-convex hull
1166 * cs: the lower half-convex hull
1167 * result: a pointer to the pre-allocated struct where the results
1168 * will be stored
1169 */
1170static void calculateFactorsFallback(GQueue* const cr, GQueue* const cs,
0a87ec9a 1171 PairFactors* const result)
08365995
BP
1172{
1173 unsigned int i, j, k;
1174 double errorMin;
1175 Factors* approx;
1176
1177 errorMin= INFINITY;
1178 approx= malloc(sizeof(Factors));
1179
1180 for (i= 0; i < cs->length; i++)
1181 {
1182 for (j= 0; j < cr->length; j++)
1183 {
1184 double error;
1185 Point p1, p2;
1186
1187 error= 0.;
1188
1189 if (((Point*) g_queue_peek_nth(cs, i))->x < ((Point*)g_queue_peek_nth(cr, j))->x)
1190 {
1191 p1= *(Point*)g_queue_peek_nth(cs, i);
1192 p2= *(Point*)g_queue_peek_nth(cr, j);
1193 }
1194 else
1195 {
1196 p1= *(Point*)g_queue_peek_nth(cr, j);
1197 p2= *(Point*)g_queue_peek_nth(cs, i);
1198 }
1199
1200 // The lower hull should be above the point
1201 for (k= 0; k < cs->length; k++)
1202 {
1203 if (jointCmp(&p1, &p2, g_queue_peek_nth(cs, k)) < 0.)
1204 {
1205 error+= verticalDistance(&p1, &p2, g_queue_peek_nth(cs, k));
1206 }
1207 }
1208
1209 // The upper hull should be below the point
1210 for (k= 0; k < cr->length; k++)
1211 {
1212 if (jointCmp(&p1, &p2, g_queue_peek_nth(cr, k)) > 0.)
1213 {
1214 error+= verticalDistance(&p1, &p2, g_queue_peek_nth(cr, k));
1215 }
1216 }
1217
1218 if (error < errorMin)
1219 {
1220 g_debug("Fallback: i= %u j= %u is a better match (error= %g)", i, j, error);
1221 approx->drift= slope(&p1, &p2);
1222 approx->offset= intercept(&p1, &p2);
1223 errorMin= error;
1224 }
1225 }
1226 }
1227
1228 result->approx= approx;
1229 result->accuracy= errorMin;
1230}
1231
1232
1233/*
1234 * Calculate the vertical distance between a line and a point
1235 *
1236 * Args:
1237 * p1, p2: Two points defining the line
1238 * point: a point
1239 *
1240 * Return:
1241 * the vertical distance
1242 */
1243static double verticalDistance(Point* p1, Point* p2, Point* const point)
1244{
1245 return fabs(slope(p1, p2) * point->x + intercept(p1, p2) - point->y);
1246}
1247
1248
1249/*
1250 * Calculate the slope between two points
1251 *
1252 * Args:
1253 * p1, p2 the two points
1254 *
1255 * Returns:
1256 * the slope
1257 */
1258static double slope(const Point* const p1, const Point* const p2)
1259{
1260 return ((double) p2->y - p1->y) / (p2->x - p1->x);
1261}
1262
1263
1264/* Calculate the y-intercept of a line that passes by two points
1265 *
1266 * Args:
1267 * p1, p2 the two points
1268 *
1269 * Returns:
1270 * the y-intercept
1271 */
1272static double intercept(const Point* const p1, const Point* const p2)
1273{
1274 return ((double) p2->y * p1->x - (double) p1->y * p2->x) / ((double) p1->x - p2->x);
1275}
1276
1277
08365995
BP
1278/*
1279 * Write the analysis-specific graph lines in the gnuplot script.
1280 *
1281 * Args:
08365995
BP
1282 * syncState: container for synchronization data
1283 * i: first trace number
1284 * j: second trace number, garanteed to be larger than i
1285 */
ab6edc6a 1286void writeAnalysisTraceTraceForePlotsCHull(SyncState* const syncState, const unsigned
8d7d16dd 1287 int i, const unsigned int j)
08365995
BP
1288{
1289 AnalysisDataCHull* analysisData;
0a87ec9a 1290 PairFactors* factorsCHull;
08365995
BP
1291
1292 analysisData= (AnalysisDataCHull*) syncState->analysisData;
1293
8d7d16dd 1294 fprintf(syncState->graphsStream,
08365995
BP
1295 "\t\"analysis_chull-%1$03d_to_%2$03d.data\" "
1296 "title \"Lower half-hull\" with linespoints "
1297 "linecolor rgb \"#015a01\" linetype 4 pointtype 8 pointsize 0.8, \\\n"
1298 "\t\"analysis_chull-%2$03d_to_%1$03d.data\" "
1299 "title \"Upper half-hull\" with linespoints "
1300 "linecolor rgb \"#003366\" linetype 4 pointtype 10 pointsize 0.8, \\\n",
1301 i, j);
1302
0a87ec9a 1303 factorsCHull= &analysisData->graphsData->allFactors->pairFactors[j][i];
08365995
BP
1304 if (factorsCHull->type == EXACT)
1305 {
8d7d16dd 1306 fprintf(syncState->graphsStream,
08365995
BP
1307 "\t%7g + %7g * x "
1308 "title \"Exact conversion\" with lines "
1309 "linecolor rgb \"black\" linetype 1, \\\n",
1310 factorsCHull->approx->offset, factorsCHull->approx->drift);
1311 }
0a87ec9a 1312 else if (factorsCHull->type == ACCURATE)
08365995 1313 {
8d7d16dd 1314 fprintf(syncState->graphsStream,
08365995
BP
1315 "\t%.2f + %.10f * x "
1316 "title \"Min conversion\" with lines "
1317 "linecolor rgb \"black\" linetype 5, \\\n",
1318 factorsCHull->min->offset, factorsCHull->min->drift);
8d7d16dd 1319 fprintf(syncState->graphsStream,
08365995
BP
1320 "\t%.2f + %.10f * x "
1321 "title \"Max conversion\" with lines "
1322 "linecolor rgb \"black\" linetype 8, \\\n",
1323 factorsCHull->max->offset, factorsCHull->max->drift);
8d7d16dd 1324 fprintf(syncState->graphsStream,
08365995
BP
1325 "\t%.2f + %.10f * x "
1326 "title \"Middle conversion\" with lines "
66eaf2eb 1327 "linecolor rgb \"black\" linetype 1, \\\n",
08365995
BP
1328 factorsCHull->approx->offset, factorsCHull->approx->drift);
1329 }
0a87ec9a 1330 else if (factorsCHull->type == APPROXIMATE)
08365995 1331 {
8d7d16dd 1332 fprintf(syncState->graphsStream,
08365995
BP
1333 "\t%.2f + %.10f * x "
1334 "title \"Fallback conversion\" with lines "
1335 "linecolor rgb \"gray60\" linetype 1, \\\n",
1336 factorsCHull->approx->offset, factorsCHull->approx->drift);
1337 }
1338 else if (factorsCHull->type == INCOMPLETE)
1339 {
1340 if (factorsCHull->min->drift != -INFINITY)
1341 {
8d7d16dd 1342 fprintf(syncState->graphsStream,
08365995
BP
1343 "\t%.2f + %.10f * x "
1344 "title \"Min conversion\" with lines "
1345 "linecolor rgb \"black\" linetype 5, \\\n",
1346 factorsCHull->min->offset, factorsCHull->min->drift);
1347 }
1348
1349 if (factorsCHull->max->drift != INFINITY)
1350 {
8d7d16dd 1351 fprintf(syncState->graphsStream,
08365995
BP
1352 "\t%.2f + %.10f * x "
1353 "title \"Max conversion\" with lines "
1354 "linecolor rgb \"black\" linetype 8, \\\n",
1355 factorsCHull->max->offset, factorsCHull->max->drift);
1356 }
1357 }
ab6edc6a 1358 else if (factorsCHull->type == FAIL)
08365995
BP
1359 {
1360 if (factorsCHull->min != NULL && factorsCHull->min->drift != -INFINITY)
1361 {
8d7d16dd 1362 fprintf(syncState->graphsStream,
08365995
BP
1363 "\t%.2f + %.10f * x "
1364 "title \"Min conversion\" with lines "
1365 "linecolor rgb \"black\" linetype 5, \\\n",
1366 factorsCHull->min->offset, factorsCHull->min->drift);
1367 }
1368
1369 if (factorsCHull->max != NULL && factorsCHull->max->drift != INFINITY)
1370 {
8d7d16dd 1371 fprintf(syncState->graphsStream,
08365995
BP
1372 "\t%.2f + %.10f * x "
1373 "title \"Max conversion\" with lines "
1374 "linecolor rgb \"black\" linetype 8, \\\n",
1375 factorsCHull->max->offset, factorsCHull->max->drift);
1376 }
1377 }
1378 else if (factorsCHull->type == ABSENT)
1379 {
1380 }
1381 else
1382 {
1383 g_assert_not_reached();
1384 }
1385}
ab6edc6a
BP
1386
1387
1388#ifdef HAVE_LIBGLPK
1389/*
1390 * Create the linear programming problem containing the constraints defined by
1391 * two half-hulls. The objective function and optimization directions are not
1392 * written.
1393 *
1394 * Args:
1395 * syncState: container for synchronization data
1396 * i: first trace number
1397 * j: second trace number, garanteed to be larger than i
1398 * Returns:
1399 * A new glp_prob*, this problem must be freed by the caller with
1400 * glp_delete_prob()
1401 */
1402static glp_prob* lpCreateProblem(GQueue* const lowerHull, GQueue* const
1403 upperHull)
1404{
1405 unsigned int it;
1406 const int zero= 0;
1407 const double zeroD= 0.;
1408 glp_prob* lp= glp_create_prob();
1409 unsigned int hullPointNb= g_queue_get_length(lowerHull) +
1410 g_queue_get_length(upperHull);
1411 GArray* iArray= g_array_sized_new(FALSE, FALSE, sizeof(int), hullPointNb +
1412 1);
1413 GArray* jArray= g_array_sized_new(FALSE, FALSE, sizeof(int), hullPointNb +
1414 1);
1415 GArray* aArray= g_array_sized_new(FALSE, FALSE, sizeof(double),
1416 hullPointNb + 1);
1417 struct {
1418 GQueue* hull;
1419 struct LPAddRowInfo rowInfo;
1420 } loopValues[2]= {
1421 {lowerHull, {lp, GLP_UP, iArray, jArray, aArray}},
1422 {upperHull, {lp, GLP_LO, iArray, jArray, aArray}},
1423 };
1424
1425 // Create the LP problem
1426 glp_term_out(GLP_OFF);
1427 if (hullPointNb > 0)
1428 {
1429 glp_add_rows(lp, hullPointNb);
1430 }
1431 glp_add_cols(lp, 2);
1432
1433 glp_set_col_name(lp, 1, "a0");
1434 glp_set_col_bnds(lp, 1, GLP_FR, 0., 0.);
1435 glp_set_col_name(lp, 2, "a1");
1436 glp_set_col_bnds(lp, 2, GLP_LO, 0., 0.);
1437
1438 // Add row constraints
1439 g_array_append_val(iArray, zero);
1440 g_array_append_val(jArray, zero);
1441 g_array_append_val(aArray, zeroD);
1442
1443 for (it= 0; it < sizeof(loopValues) / sizeof(*loopValues); it++)
1444 {
1445 g_queue_foreach(loopValues[it].hull, &gfLPAddRow,
1446 &loopValues[it].rowInfo);
1447 }
1448
1449 g_assert_cmpuint(iArray->len, ==, jArray->len);
1450 g_assert_cmpuint(jArray->len, ==, aArray->len);
1451 g_assert_cmpuint(aArray->len - 1, ==, hullPointNb * 2);
1452
1453 glp_load_matrix(lp, aArray->len - 1, &g_array_index(iArray, int, 0),
1454 &g_array_index(jArray, int, 0), &g_array_index(aArray, double, 0));
1455
1456 glp_scale_prob(lp, GLP_SF_AUTO);
1457
1458 g_array_free(iArray, TRUE);
1459 g_array_free(jArray, TRUE);
1460 g_array_free(aArray, TRUE);
1461
1462 return lp;
1463}
1464
1465
1466/*
1467 * A GFunc for g_queue_foreach(). Add constraints and bounds for one row.
1468 *
1469 * Args:
1470 * data Point*, synchronization point for which to add an LP row
1471 * (a constraint)
1472 * user_data LPAddRowInfo*
1473 */
1474static void gfLPAddRow(gpointer data, gpointer user_data)
1475{
1476 Point* p= data;
1477 struct LPAddRowInfo* rowInfo= user_data;
1478 int indexes[2];
1479 double constraints[2];
1480
1481 indexes[0]= g_array_index(rowInfo->iArray, int, rowInfo->iArray->len - 1) + 1;
1482 indexes[1]= indexes[0];
1483
1484 if (rowInfo->boundType == GLP_UP)
1485 {
1486 glp_set_row_bnds(rowInfo->lp, indexes[0], GLP_UP, 0., p->y);
1487 }
1488 else if (rowInfo->boundType == GLP_LO)
1489 {
1490 glp_set_row_bnds(rowInfo->lp, indexes[0], GLP_LO, p->y, 0.);
1491 }
1492 else
1493 {
1494 g_assert_not_reached();
1495 }
1496
1497 g_array_append_vals(rowInfo->iArray, indexes, 2);
1498 indexes[0]= 1;
1499 indexes[1]= 2;
1500 g_array_append_vals(rowInfo->jArray, indexes, 2);
1501 constraints[0]= 1.;
1502 constraints[1]= p->x;
1503 g_array_append_vals(rowInfo->aArray, constraints, 2);
1504}
1505
1506
1507/*
1508 * Calculate min or max correction factors (as possible) using an LP problem.
1509 *
1510 * Args:
1511 * lp: A linear programming problem with constraints and bounds
1512 * initialized.
1513 * direction: The type of factors desired. Use GLP_MAX for max
1514 * approximation factors (a1, the drift or slope is the
1515 * largest) and GLP_MIN in the other case.
1516 *
1517 * Returns:
1518 * If the calculation was successful, a new Factors struct. Otherwise, NULL.
1519 * The calculation will fail if the hull assumptions are not respected.
1520 */
1521static Factors* calculateFactorsLP(glp_prob* const lp, const int direction)
1522{
1523 int retval, status;
1524 Factors* factors;
1525
1526 glp_set_obj_coef(lp, 1, 0.);
1527 glp_set_obj_coef(lp, 2, 1.);
1528
1529 glp_set_obj_dir(lp, direction);
1530 retval= glp_simplex(lp, NULL);
1531 status= glp_get_status(lp);
1532
1533 if (retval == 0 && status == GLP_OPT)
1534 {
1535 factors= malloc(sizeof(Factors));
1536 factors->offset= glp_get_col_prim(lp, 1);
1537 factors->drift= glp_get_col_prim(lp, 2);
1538 }
1539 else
1540 {
1541 factors= NULL;
1542 }
1543
1544 return factors;
1545}
1546
1547
1548/*
1549 * Calculate min, max and approx correction factors (as possible) using an LP
1550 * problem.
1551 *
1552 * Args:
1553 * lp A linear programming problem with constraints and bounds
1554 * initialized.
1555 * factors Resulting factors, must be preallocated
1556 */
1557static void calculateCompleteFactorsLP(glp_prob* const lp, PairFactors* factors)
1558{
1559 factors->min= calculateFactorsLP(lp, GLP_MIN);
1560 factors->max= calculateFactorsLP(lp, GLP_MAX);
1561
1562 if (factors->min && factors->max)
1563 {
1564 factors->type= ACCURATE;
1565 calculateFactorsMiddle(factors);
1566 }
1567 else if (factors->min || factors->max)
1568 {
1569 factors->type= INCOMPLETE;
1570 }
1571 else
1572 {
1573 factors->type= ABSENT;
1574 }
1575}
1576
1577
1578/*
1579 * A GFunc for g_queue_foreach()
1580 *
1581 * Args:
1582 * data Point*, a convex hull point
1583 * user_data GArray*, an array of convex hull point absisca values, as
1584 * uint64_t
1585 */
1586static void gfAddAbsiscaToArray(gpointer data, gpointer user_data)
1587{
1588 Point* p= data;
1589 GArray* a= user_data;
1590 uint64_t v= p->x;
1591
1592 g_array_append_val(a, v);
1593}
1594
1595
1596/*
1597 * A GCompareFunc for g_array_sort()
1598 *
1599 * Args:
1600 * a, b uint64_t*, absisca values
1601 *
1602 * Returns:
1603 * "returns less than zero for first arg is less than second arg, zero for
1604 * equal, greater zero if first arg is greater than second arg"
1605 * - the great glib documentation
1606 */
1607static gint gcfCompareUint64(gconstpointer a, gconstpointer b)
1608{
1609 if (*(uint64_t*) a < *(uint64_t*) b)
1610 {
1611 return -1;
1612 }
1613 else if (*(uint64_t*) a > *(uint64_t*) b)
1614 {
1615 return 1;
1616 }
1617 else
1618 {
1619 return 0;
1620 }
1621}
1622
1623
1624/*
1625 * Compute synchronization factors using a linear programming approach.
1626 *
1627 * Args:
1628 * syncState: container for synchronization data
1629 */
1630static AllFactors* finalizeAnalysisCHullLP(SyncState* const syncState)
1631{
1632 AnalysisDataCHull* analysisData= syncState->analysisData;
1633 unsigned int i, j;
1634 AllFactors* lpFactorsArray;
1635
1636 lpFactorsArray= createAllFactors(syncState->traceNb);
1637
1638 analysisData->lps= malloc(syncState->traceNb * sizeof(glp_prob**));
1639 for (i= 0; i < syncState->traceNb; i++)
1640 {
1641 analysisData->lps[i]= malloc(i * sizeof(glp_prob*));
1642 }
1643
1644 for (i= 0; i < syncState->traceNb; i++)
1645 {
1646 for (j= 0; j < i; j++)
1647 {
1648 glp_prob* lp;
1649 unsigned int it;
1650 GQueue*** hullArray= analysisData->hullArray;
1651 PairFactors* lpFactors= &lpFactorsArray->pairFactors[i][j];
1652
1653 // Create the LP problem
1654 lp= lpCreateProblem(hullArray[i][j], hullArray[j][i]);
1655 analysisData->lps[i][j]= lp;
1656
1657 // Use the LP problem to find the correction factors for this pair of
1658 // traces
1659 calculateCompleteFactorsLP(lp, lpFactors);
1660
1661 // If possible, compute synchronization accuracy information for
1662 // graphs
1663 if (syncState->graphsStream && lpFactors->type == ACCURATE)
1664 {
1665 int retval;
1666 char* cwd;
1667 char fileName[43];
1668 FILE* fp;
1669 GArray* xValues;
1670
1671 // Open the data file
1672 snprintf(fileName, sizeof(fileName),
1673 "analysis_chull_accuracy-%03u_and_%03u.data", j, i);
1674 fileName[sizeof(fileName) - 1]= '\0';
1675
1676 cwd= changeToGraphsDir(syncState->graphsDir);
1677
1678 if ((fp= fopen(fileName, "w")) == NULL)
1679 {
1680 g_error(strerror(errno));
1681 }
1682 fprintf(fp, "#%-24s %-25s %-25s %-25s\n", "x", "middle", "min", "max");
1683
1684 retval= chdir(cwd);
1685 if (retval == -1)
1686 {
1687 g_error(strerror(errno));
1688 }
1689 free(cwd);
1690
1691 // Build the list of absisca values for the points in the accuracy graph
1692 xValues= g_array_sized_new(FALSE, FALSE, sizeof(uint64_t),
1693 g_queue_get_length(hullArray[i][j]) +
1694 g_queue_get_length(hullArray[j][i]));
1695
1696 g_queue_foreach(hullArray[i][j], &gfAddAbsiscaToArray, xValues);
1697 g_queue_foreach(hullArray[j][i], &gfAddAbsiscaToArray, xValues);
1698
1699 g_array_sort(xValues, &gcfCompareUint64);
1700
1701 /* For each absisca value and each optimisation direction, solve the LP
1702 * and write a line in the data file */
1703 for (it= 0; it < xValues->len; it++)
1704 {
1705 uint64_t time;
1706 CorrectedTime correctedTime;
1707
1708 time= g_array_index(xValues, uint64_t, it);
1709 timeCorrectionLP(lp, lpFactors, time, &correctedTime);
1710 fprintf(fp, "%24" PRIu64 " %24" PRIu64 " %24" PRIu64
1711 "%24" PRIu64 "\n", time, correctedTime.time,
1712 correctedTime.min, correctedTime.max);
1713 }
1714
1715 g_array_free(xValues, TRUE);
1716 fclose(fp);
1717 }
1718 }
1719 }
1720
1721 if (syncState->stats)
1722 {
1723 lpFactorsArray->refCount++;
1724 analysisData->stats->lpFactors= lpFactorsArray;
1725 }
1726
1727 if (syncState->graphsStream)
1728 {
1729 lpFactorsArray->refCount++;
1730 analysisData->graphsData->lpFactors= lpFactorsArray;
1731 }
1732
1733 return lpFactorsArray;
1734}
1735
1736
1737/*
1738 * Perform correction on one time value and calculate accuracy bounds.
1739 *
1740 * Args:
1741 * lp: Linear Programming problem containing the coefficients for
1742 * the trace pair between which to perform time correction.
1743 * lpFactors: Correction factors for this trace pair, the factors must be
1744 * of type ACCURATE.
1745 * time: Time value to correct.
1746 * correctedTime: Result of the time correction, preallocated.
1747 */
1748void timeCorrectionLP(glp_prob* const lp, const PairFactors* const lpFactors,
1749 const uint64_t time, CorrectedTime* const correctedTime)
1750{
1751 unsigned int it;
1752 const struct
1753 {
1754 int direction;
1755 size_t offset;
1756 } loopValues[]= {
1757 {GLP_MIN, offsetof(CorrectedTime, min)},
1758 {GLP_MAX, offsetof(CorrectedTime, max)}
1759 };
1760
1761 glp_set_obj_coef(lp, 1, 1.);
1762 glp_set_obj_coef(lp, 2, time);
1763
1764 g_assert(lpFactors->type == ACCURATE);
1765
1766 correctedTime->time= lpFactors->approx->offset + lpFactors->approx->drift
1767 * time;
1768
1769 for (it= 0; it < ARRAY_SIZE(loopValues); it++)
1770 {
1771 int status;
1772 int retval;
1773
1774 glp_set_obj_dir(lp, loopValues[it].direction);
1775 retval= glp_simplex(lp, NULL);
1776 status= glp_get_status(lp);
1777
1778 g_assert(retval == 0 && status == GLP_OPT);
1779 *(uint64_t*) ((void*) correctedTime + loopValues[it].offset)=
1780 round(glp_get_obj_val(lp));
1781 }
1782}
1783
1784
1785/*
1786 * Write the analysis-specific graph lines in the gnuplot script.
1787 *
1788 * Args:
1789 * syncState: container for synchronization data
1790 * i: first trace number
1791 * j: second trace number, garanteed to be larger than i
1792 */
1793static void writeAnalysisTraceTimeBackPlotsCHull(SyncState* const syncState,
1794 const unsigned int i, const unsigned int j)
1795{
1796 if (((AnalysisDataCHull*)
1797 syncState->analysisData)->graphsData->lpFactors->pairFactors[j][i].type
1798 == ACCURATE)
1799 {
1800 fprintf(syncState->graphsStream,
1801 "\t\"analysis_chull_accuracy-%1$03u_and_%2$03u.data\" "
1802 "using 1:(($3 - $2) / clock_freq_%2$u):(($4 - $2) / clock_freq_%2$u) "
1803 "title \"Synchronization accuracy\" "
1804 "with filledcurves linewidth 2 linetype 1 "
1805 "linecolor rgb \"black\" fill solid 0.25 noborder, \\\n", i,
1806 j);
1807 }
1808}
1809
1810
1811/*
1812 * Write the analysis-specific graph lines in the gnuplot script.
1813 *
1814 * Args:
1815 * syncState: container for synchronization data
1816 * i: first trace number
1817 * j: second trace number, garanteed to be larger than i
1818 */
1819static void writeAnalysisTraceTimeForePlotsCHull(SyncState* const syncState,
1820 const unsigned int i, const unsigned int j)
1821{
1822 if (((AnalysisDataCHull*)
1823 syncState->analysisData)->graphsData->lpFactors->pairFactors[j][i].type
1824 == ACCURATE)
1825 {
1826 fprintf(syncState->graphsStream,
1827 "\t\"analysis_chull_accuracy-%1$03u_and_%2$03u.data\" "
1828 "using 1:(($3 - $2) / clock_freq_%2$u) notitle "
1829 "with lines linewidth 2 linetype 1 "
1830 "linecolor rgb \"gray60\", \\\n"
1831 "\t\"analysis_chull_accuracy-%1$03u_and_%2$03u.data\" "
1832 "using 1:(($4 - $2) / clock_freq_%2$u) notitle "
1833 "with lines linewidth 2 linetype 1 "
1834 "linecolor rgb \"gray60\", \\\n", i, j);
1835 }
1836}
1837
1838
1839/*
1840 * Write the analysis-specific graph lines in the gnuplot script.
1841 *
1842 * Args:
1843 * syncState: container for synchronization data
1844 * i: first trace number
1845 * j: second trace number, garanteed to be larger than i
1846 */
1847static void writeAnalysisTraceTraceBackPlotsCHull(SyncState* const syncState,
1848 const unsigned int i, const unsigned int j)
1849{
1850 if (((AnalysisDataCHull*)
1851 syncState->analysisData)->graphsData->lpFactors->pairFactors[j][i].type
1852 == ACCURATE)
1853 {
1854 fprintf(syncState->graphsStream,
1855 "\t\"analysis_chull_accuracy-%1$03u_and_%2$03u.data\" "
1856 "using 1:3:4 "
1857 "title \"Synchronization accuracy\" "
1858 "with filledcurves linewidth 2 linetype 1 "
1859 "linecolor rgb \"black\" fill solid 0.25 noborder, \\\n", i, j);
1860 }
1861}
1862#endif
This page took 0.100162 seconds and 4 git commands to generate.