Change synchronization code license to LGPLv2.1
[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
43
44typedef enum
45{
46 MINIMUM,
47 MAXIMUM
48} LineType;
49
50
51// Functions common to all analysis modules
52static void initAnalysisCHull(SyncState* const syncState);
53static void destroyAnalysisCHull(SyncState* const syncState);
54
10341d26
BP
55static void analyzeMessageCHull(SyncState* const syncState, Message* const
56 message);
08365995
BP
57static GArray* finalizeAnalysisCHull(SyncState* const syncState);
58static void printAnalysisStatsCHull(SyncState* const syncState);
8d7d16dd
BP
59static void writeAnalysisGraphsPlotsCHull(SyncState* const syncState, const
60 unsigned int i, const unsigned int j);
08365995
BP
61
62// Functions specific to this module
08365995
BP
63static void openGraphFiles(SyncState* const syncState);
64static void closeGraphFiles(SyncState* const syncState);
65static void writeGraphFiles(SyncState* const syncState);
66static void gfDumpHullToFile(gpointer data, gpointer userData);
67
68static void grahamScan(GQueue* const hull, Point* const newPoint, const
69 HullType type);
70static int jointCmp(const Point* const p1, const Point* const p2, const Point*
71 const p3) __attribute__((pure));
72static double crossProductK(const Point const* p1, const Point const* p2,
73 const Point const* p3, const Point const* p4) __attribute__((pure));
08365995
BP
74static Factors* calculateFactorsExact(GQueue* const cu, GQueue* const cl, const
75 LineType lineType) __attribute__((pure));
08365995
BP
76static void calculateFactorsFallback(GQueue* const cr, GQueue* const cs,
77 FactorsCHull* const result);
78static double slope(const Point* const p1, const Point* const p2)
79 __attribute__((pure));
80static double intercept(const Point* const p1, const Point* const p2)
81 __attribute__((pure));
82static GArray* reduceFactors(SyncState* const syncState, FactorsCHull**
83 allFactors);
08365995
BP
84static double verticalDistance(Point* p1, Point* p2, Point* const point)
85 __attribute__((pure));
86static void floydWarshall(SyncState* const syncState, FactorsCHull** const
87 allFactors, double*** const distances, unsigned int*** const
88 predecessors);
89static void getFactors(FactorsCHull** const allFactors, unsigned int** const
90 predecessors, unsigned int* const references, const unsigned int traceNum,
91 Factors* const factors);
92
93static void gfPointDestroy(gpointer data, gpointer userData);
94
95
96static AnalysisModule analysisModuleCHull= {
97 .name= "chull",
98 .initAnalysis= &initAnalysisCHull,
99 .destroyAnalysis= &destroyAnalysisCHull,
10341d26 100 .analyzeMessage= &analyzeMessageCHull,
08365995
BP
101 .finalizeAnalysis= &finalizeAnalysisCHull,
102 .printAnalysisStats= &printAnalysisStatsCHull,
467066ee 103 .graphFunctions= {
c6356aa7 104 .writeTraceTraceForePlots= &writeAnalysisGraphsPlotsCHull,
467066ee 105 }
08365995
BP
106};
107
66eaf2eb
BP
108const char* const approxNames[]= {
109 [EXACT]= "Exact",
110 [MIDDLE]= "Middle",
111 [FALLBACK]= "Fallback",
112 [INCOMPLETE]= "Incomplete",
113 [ABSENT]= "Absent",
114 [SCREWED]= "Screwed",
115};
08365995 116
c6356aa7 117
08365995
BP
118/*
119 * Analysis module registering function
120 */
2f961b65 121void registerAnalysisCHull()
08365995
BP
122{
123 g_queue_push_tail(&analysisModules, &analysisModuleCHull);
124}
125
126
127/*
128 * Analysis init function
129 *
130 * This function is called at the beginning of a synchronization run for a set
131 * of traces.
132 *
133 * Allocate some of the analysis specific data structures
134 *
135 * Args:
136 * syncState container for synchronization data.
137 * This function allocates or initializes these analysisData
138 * members:
139 * hullArray
140 * dropped
141 */
142static void initAnalysisCHull(SyncState* const syncState)
143{
144 unsigned int i, j;
145 AnalysisDataCHull* analysisData;
146
147 analysisData= malloc(sizeof(AnalysisDataCHull));
148 syncState->analysisData= analysisData;
149
150 analysisData->hullArray= malloc(syncState->traceNb * sizeof(GQueue**));
151 for (i= 0; i < syncState->traceNb; i++)
152 {
153 analysisData->hullArray[i]= malloc(syncState->traceNb * sizeof(GQueue*));
154
155 for (j= 0; j < syncState->traceNb; j++)
156 {
157 analysisData->hullArray[i][j]= g_queue_new();
158 }
159 }
160
161 if (syncState->stats)
162 {
163 analysisData->stats= malloc(sizeof(AnalysisStatsCHull));
164 analysisData->stats->dropped= 0;
165 analysisData->stats->allFactors= NULL;
166 }
167
8d7d16dd 168 if (syncState->graphsStream)
08365995
BP
169 {
170 analysisData->graphsData= malloc(sizeof(AnalysisGraphsDataCHull));
171 openGraphFiles(syncState);
172 analysisData->graphsData->allFactors= NULL;
173 }
174}
175
176
177/*
178 * Create and open files used to store convex hull points to genereate
179 * graphs. Allocate and populate array to store file pointers.
180 *
181 * Args:
182 * syncState: container for synchronization data
183 */
184static void openGraphFiles(SyncState* const syncState)
185{
186 unsigned int i, j;
187 int retval;
188 char* cwd;
189 char name[31];
190 AnalysisDataCHull* analysisData;
191
192 analysisData= (AnalysisDataCHull*) syncState->analysisData;
193
1d597550 194 cwd= changeToGraphsDir(syncState->graphsDir);
08365995
BP
195
196 analysisData->graphsData->hullPoints= malloc(syncState->traceNb *
197 sizeof(FILE**));
198 for (i= 0; i < syncState->traceNb; i++)
199 {
200 analysisData->graphsData->hullPoints[i]= malloc(syncState->traceNb *
201 sizeof(FILE*));
202 for (j= 0; j < syncState->traceNb; j++)
203 {
204 if (i != j)
205 {
206 retval= snprintf(name, sizeof(name),
207 "analysis_chull-%03u_to_%03u.data", j, i);
208 if (retval > sizeof(name) - 1)
209 {
210 name[sizeof(name) - 1]= '\0';
211 }
212 if ((analysisData->graphsData->hullPoints[i][j]= fopen(name, "w")) ==
213 NULL)
214 {
215 g_error(strerror(errno));
216 }
217 }
218 }
219 }
220
221 retval= chdir(cwd);
222 if (retval == -1)
223 {
224 g_error(strerror(errno));
225 }
226 free(cwd);
227}
228
229
230/*
231 * Write hull points to files to generate graphs.
232 *
233 * Args:
234 * syncState: container for synchronization data
235 */
236static void writeGraphFiles(SyncState* const syncState)
237{
238 unsigned int i, j;
239 AnalysisDataCHull* analysisData;
240
241 analysisData= (AnalysisDataCHull*) syncState->analysisData;
242
243 for (i= 0; i < syncState->traceNb; i++)
244 {
245 for (j= 0; j < syncState->traceNb; j++)
246 {
247 if (i != j)
248 {
249 g_queue_foreach(analysisData->hullArray[i][j],
250 &gfDumpHullToFile,
251 analysisData->graphsData->hullPoints[i][j]);
252 }
253 }
254 }
255}
256
257
258/*
259 * A GFunc for g_queue_foreach. Write a hull point to a file used to generate
260 * graphs
261 *
262 * Args:
263 * data: Point*, point to write to the file
264 * userData: FILE*, file pointer where to write the point
265 */
266static void gfDumpHullToFile(gpointer data, gpointer userData)
267{
268 Point* point;
269
270 point= (Point*) data;
053b4b77 271 fprintf((FILE*) userData, "%20" PRIu64 " %20" PRIu64 "\n", point->x, point->y);
08365995
BP
272}
273
274
275/*
276 * Close files used to store convex hull points to generate graphs.
277 * Deallocate array to store file pointers.
278 *
279 * Args:
280 * syncState: container for synchronization data
281 */
282static void closeGraphFiles(SyncState* const syncState)
283{
284 unsigned int i, j;
285 AnalysisDataCHull* analysisData;
286 int retval;
287
288 analysisData= (AnalysisDataCHull*) syncState->analysisData;
289
290 if (analysisData->graphsData->hullPoints == NULL)
291 {
292 return;
293 }
294
295 for (i= 0; i < syncState->traceNb; i++)
296 {
297 for (j= 0; j < syncState->traceNb; j++)
298 {
299 if (i != j)
300 {
301 retval= fclose(analysisData->graphsData->hullPoints[i][j]);
302 if (retval != 0)
303 {
304 g_error(strerror(errno));
305 }
306 }
307 }
308 free(analysisData->graphsData->hullPoints[i]);
309 }
310 free(analysisData->graphsData->hullPoints);
311 analysisData->graphsData->hullPoints= NULL;
312}
313
314
315/*
316 * Analysis destroy function
317 *
318 * Free the analysis specific data structures
319 *
320 * Args:
321 * syncState container for synchronization data.
322 * This function deallocates these analysisData members:
323 * hullArray
324 * stDev
325 */
326static void destroyAnalysisCHull(SyncState* const syncState)
327{
328 unsigned int i, j;
329 AnalysisDataCHull* analysisData;
330
331 analysisData= (AnalysisDataCHull*) syncState->analysisData;
332
333 if (analysisData == NULL)
334 {
335 return;
336 }
337
338 for (i= 0; i < syncState->traceNb; i++)
339 {
340 for (j= 0; j < syncState->traceNb; j++)
341 {
342 g_queue_foreach(analysisData->hullArray[i][j], gfPointDestroy, NULL);
6ce8ceac 343 g_queue_free(analysisData->hullArray[i][j]);
08365995
BP
344 }
345 free(analysisData->hullArray[i]);
346 }
347 free(analysisData->hullArray);
348
349 if (syncState->stats)
350 {
351 if (analysisData->stats->allFactors != NULL)
352 {
66eaf2eb 353 freeAllFactors(syncState->traceNb, analysisData->stats->allFactors);
08365995
BP
354 }
355
356 free(analysisData->stats);
357 }
358
8d7d16dd 359 if (syncState->graphsStream)
08365995
BP
360 {
361 if (analysisData->graphsData->hullPoints != NULL)
362 {
363 closeGraphFiles(syncState);
364 }
365
366 if (!syncState->stats && analysisData->graphsData->allFactors != NULL)
367 {
66eaf2eb 368 freeAllFactors(syncState->traceNb, analysisData->graphsData->allFactors);
08365995
BP
369 }
370
371 free(analysisData->graphsData);
372 }
373
374 free(syncState->analysisData);
375 syncState->analysisData= NULL;
376}
377
378
379/*
380 * Perform analysis on an event pair.
381 *
382 * Args:
383 * syncState container for synchronization data
10341d26 384 * message structure containing the events
08365995 385 */
10341d26 386static void analyzeMessageCHull(SyncState* const syncState, Message* const message)
08365995
BP
387{
388 AnalysisDataCHull* analysisData;
389 Point* newPoint;
390 HullType hullType;
391 GQueue* hull;
392
393 analysisData= (AnalysisDataCHull*) syncState->analysisData;
394
395 newPoint= malloc(sizeof(Point));
10341d26 396 if (message->inE->traceNum < message->outE->traceNum)
08365995
BP
397 {
398 // CA is inE->traceNum
76be6fc2
BP
399 newPoint->x= message->inE->cpuTime;
400 newPoint->y= message->outE->cpuTime;
08365995 401 hullType= UPPER;
053b4b77
BP
402 g_debug("Reception point hullArray[%lu][%lu] "
403 "x= inE->time= %" PRIu64 " y= outE->time= %" PRIu64,
10341d26 404 message->inE->traceNum, message->outE->traceNum, newPoint->x,
08365995
BP
405 newPoint->y);
406 }
407 else
408 {
409 // CA is outE->traceNum
76be6fc2
BP
410 newPoint->x= message->outE->cpuTime;
411 newPoint->y= message->inE->cpuTime;
08365995 412 hullType= LOWER;
053b4b77
BP
413 g_debug("Send point hullArray[%lu][%lu] "
414 "x= inE->time= %" PRIu64 " y= outE->time= %" PRIu64,
10341d26 415 message->inE->traceNum, message->outE->traceNum, newPoint->x,
08365995
BP
416 newPoint->y);
417 }
418
419 hull=
10341d26 420 analysisData->hullArray[message->inE->traceNum][message->outE->traceNum];
08365995
BP
421
422 if (hull->length >= 1 && newPoint->x < ((Point*)
423 g_queue_peek_tail(hull))->x)
424 {
425 if (syncState->stats)
426 {
427 analysisData->stats->dropped++;
428 }
429
430 free(newPoint);
431 }
432 else
433 {
434 grahamScan(hull, newPoint, hullType);
435 }
436}
437
438
439/*
440 * Construct one half of a convex hull from abscissa-sorted points
441 *
442 * Args:
443 * hull: the points already in the hull
444 * newPoint: a new point to consider
445 * type: which half of the hull to construct
446 */
447static void grahamScan(GQueue* const hull, Point* const newPoint, const
448 HullType type)
449{
450 int inversionFactor;
451
452 g_debug("grahamScan(hull (length: %u), newPoint, %s)", hull->length, type
453 == LOWER ? "LOWER" : "UPPER");
454
455 if (type == LOWER)
456 {
457 inversionFactor= 1;
458 }
459 else
460 {
461 inversionFactor= -1;
462 }
463
464 if (hull->length >= 2)
465 {
466 g_debug("jointCmp(hull[%u], hull[%u], newPoint) * inversionFactor = %d * %d = %d",
467 hull->length - 2,
468 hull->length - 1,
469 jointCmp(g_queue_peek_nth(hull, hull->length - 2),
470 g_queue_peek_tail(hull), newPoint),
471 inversionFactor,
472 jointCmp(g_queue_peek_nth(hull, hull->length - 2),
473 g_queue_peek_tail(hull), newPoint) * inversionFactor);
474 }
475 while (hull->length >= 2 && jointCmp(g_queue_peek_nth(hull, hull->length -
476 2), g_queue_peek_tail(hull), newPoint) * inversionFactor <= 0)
477 {
478 g_debug("Removing hull[%u]", hull->length);
479 free((Point*) g_queue_pop_tail(hull));
480
481 if (hull->length >= 2)
482 {
483 g_debug("jointCmp(hull[%u], hull[%u], newPoint) * inversionFactor = %d * %d = %d",
484 hull->length - 2,
485 hull->length - 1,
486 jointCmp(g_queue_peek_nth(hull, hull->length - 2),
487 g_queue_peek_tail(hull), newPoint),
488 inversionFactor,
489 jointCmp(g_queue_peek_nth(hull, hull->length - 2),
490 g_queue_peek_tail(hull), newPoint) * inversionFactor);
491 }
492 }
493 g_queue_push_tail(hull, newPoint);
494}
495
496
497/*
498 * Finalize the factor calculations
499 *
500 * Args:
501 * syncState container for synchronization data.
502 *
503 * Returns:
504 * Factors[traceNb] synchronization factors for each trace
505 */
506static GArray* finalizeAnalysisCHull(SyncState* const syncState)
507{
508 AnalysisDataCHull* analysisData;
509 GArray* factors;
510 FactorsCHull** allFactors;
511
512 analysisData= (AnalysisDataCHull*) syncState->analysisData;
513
8d7d16dd 514 if (syncState->graphsStream && analysisData->graphsData->hullPoints != NULL)
08365995
BP
515 {
516 writeGraphFiles(syncState);
517 closeGraphFiles(syncState);
518 }
519
520 allFactors= calculateAllFactors(syncState);
521
522 factors= reduceFactors(syncState, allFactors);
523
8d7d16dd 524 if (syncState->stats || syncState->graphsStream)
08365995
BP
525 {
526 if (syncState->stats)
527 {
528 analysisData->stats->allFactors= allFactors;
529 }
530
8d7d16dd 531 if (syncState->graphsStream)
08365995
BP
532 {
533 analysisData->graphsData->allFactors= allFactors;
534 }
535 }
536 else
537 {
66eaf2eb 538 freeAllFactors(syncState->traceNb, allFactors);
08365995
BP
539 }
540
541 return factors;
542}
543
544
545/*
546 * Print statistics related to analysis. Must be called after
547 * finalizeAnalysis.
548 *
549 * Args:
550 * syncState container for synchronization data.
551 */
552static void printAnalysisStatsCHull(SyncState* const syncState)
553{
554 AnalysisDataCHull* analysisData;
555 unsigned int i, j;
556
557 if (!syncState->stats)
558 {
559 return;
560 }
561
562 analysisData= (AnalysisDataCHull*) syncState->analysisData;
563
564 printf("Convex hull analysis stats:\n");
565 printf("\tout of order packets dropped from analysis: %u\n",
566 analysisData->stats->dropped);
567
568 printf("\tNumber of points in convex hulls:\n");
569
570 for (i= 0; i < syncState->traceNb; i++)
571 {
572 for (j= i + 1; j < syncState->traceNb; j++)
573 {
574 printf("\t\t%3d - %-3d: lower half-hull %-5u upper half-hull %-5u\n",
575 i, j, analysisData->hullArray[j][i]->length,
576 analysisData->hullArray[i][j]->length);
577 }
578 }
579
580 printf("\tIndividual synchronization factors:\n");
581
582 for (i= 0; i < syncState->traceNb; i++)
583 {
584 for (j= i + 1; j < syncState->traceNb; j++)
585 {
586 FactorsCHull* factorsCHull;
587
588 factorsCHull= &analysisData->stats->allFactors[j][i];
ce3dcf0e
BP
589 printf("\t\t%3d - %-3d: %s", i, j,
590 approxNames[factorsCHull->type]);
08365995
BP
591
592 if (factorsCHull->type == EXACT)
593 {
ce3dcf0e 594 printf(" a0= % 7g a1= 1 %c %7g\n",
08365995
BP
595 factorsCHull->approx->offset,
596 factorsCHull->approx->drift < 0. ? '-' : '+',
597 fabs(factorsCHull->approx->drift));
598 }
599 else if (factorsCHull->type == MIDDLE)
600 {
ce3dcf0e 601 printf(" a0= % 7g a1= 1 %c %7g accuracy %7g\n",
08365995
BP
602 factorsCHull->approx->offset, factorsCHull->approx->drift
603 - 1. < 0. ? '-' : '+', fabs(factorsCHull->approx->drift -
604 1.), factorsCHull->accuracy);
605 printf("\t\t a0: % 7g to % 7g (delta= %7g)\n",
606 factorsCHull->max->offset, factorsCHull->min->offset,
607 factorsCHull->min->offset - factorsCHull->max->offset);
608 printf("\t\t a1: 1 %+7g to %+7g (delta= %7g)\n",
609 factorsCHull->min->drift - 1., factorsCHull->max->drift -
610 1., factorsCHull->max->drift - factorsCHull->min->drift);
611 }
612 else if (factorsCHull->type == FALLBACK)
613 {
ce3dcf0e 614 printf(" a0= % 7g a1= 1 %c %7g error= %7g\n",
08365995
BP
615 factorsCHull->approx->offset, factorsCHull->approx->drift
616 - 1. < 0. ? '-' : '+', fabs(factorsCHull->approx->drift -
617 1.), factorsCHull->accuracy);
618 }
619 else if (factorsCHull->type == INCOMPLETE)
620 {
ce3dcf0e 621 printf("\n");
08365995
BP
622
623 if (factorsCHull->min->drift != -INFINITY)
624 {
625 printf("\t\t min: a0: % 7g a1: 1 %c %7g\n",
626 factorsCHull->min->offset, factorsCHull->min->drift -
627 1. < 0 ? '-' : '+', fabs(factorsCHull->min->drift -
628 1.));
629 }
630 if (factorsCHull->max->drift != INFINITY)
631 {
632 printf("\t\t max: a0: % 7g a1: 1 %c %7g\n",
633 factorsCHull->max->offset, factorsCHull->max->drift -
634 1. < 0 ? '-' : '+', fabs(factorsCHull->max->drift -
635 1.));
636 }
637 }
638 else if (factorsCHull->type == SCREWED)
639 {
ce3dcf0e 640 printf("\n");
08365995
BP
641
642 if (factorsCHull->min != NULL && factorsCHull->min->drift != -INFINITY)
643 {
644 printf("\t\t min: a0: % 7g a1: 1 %c %7g\n",
645 factorsCHull->min->offset, factorsCHull->min->drift -
646 1. < 0 ? '-' : '+', fabs(factorsCHull->min->drift -
647 1.));
648 }
649 if (factorsCHull->max != NULL && factorsCHull->max->drift != INFINITY)
650 {
651 printf("\t\t max: a0: % 7g a1: 1 %c %7g\n",
652 factorsCHull->max->offset, factorsCHull->max->drift -
653 1. < 0 ? '-' : '+', fabs(factorsCHull->max->drift -
654 1.));
655 }
656 }
657 else if (factorsCHull->type == ABSENT)
658 {
ce3dcf0e 659 printf("\n");
08365995
BP
660 }
661 else
662 {
663 g_assert_not_reached();
664 }
665 }
666 }
667}
668
669
670/*
671 * A GFunc for g_queue_foreach()
672 *
673 * Args:
674 * data Point*, point to destroy
675 * user_data NULL
676 */
677static void gfPointDestroy(gpointer data, gpointer userData)
678{
679 Point* point;
680
681 point= (Point*) data;
682 free(point);
683}
684
685
686/*
687 * Find out if a sequence of three points constitutes a "left turn" or a
688 * "right turn".
689 *
690 * Args:
691 * p1, p2, p3: The three points.
692 *
693 * Returns:
694 * < 0 right turn
695 * 0 colinear (unlikely result since this uses floating point
696 * arithmetic)
697 * > 0 left turn
698 */
699static int jointCmp(const Point const* p1, const Point const* p2, const
700 Point const* p3)
701{
702 double result;
703 const double fuzzFactor= 0.;
704
705 result= crossProductK(p1, p2, p1, p3);
053b4b77
BP
706 g_debug("crossProductK(p1= (%" PRIu64 ", %" PRIu64 "), "
707 "p2= (%" PRIu64 ", %" PRIu64 "), p1= (%" PRIu64 ", %" PRIu64 "), "
708 "p3= (%" PRIu64 ", %" PRIu64 "))= %g",
08365995
BP
709 p1->x, p1->y, p2->x, p2->y, p1->x, p1->y, p3->x, p3->y, result);
710 if (result < fuzzFactor)
711 {
712 return -1;
713 }
714 else if (result > fuzzFactor)
715 {
716 return 1;
717 }
718 else
719 {
720 return 0;
721 }
722}
723
724
725/*
726 * Calculate the k component of the cross product of two vectors.
727 *
728 * Args:
729 * p1, p2: start and end points of the first vector
730 * p3, p4: start and end points of the second vector
731 *
732 * Returns:
733 * the k component of the cross product when considering the two vectors to
734 * be in the i-j plane. The direction (sign) of the result can be useful to
735 * determine the relative orientation of the two vectors.
736 */
737static double crossProductK(const Point const* p1, const Point const* p2,
738 const Point const* p3, const Point const* p4)
739{
740 return ((double) p2->x - p1->x) * ((double) p4->y - p3->y) - ((double)
741 p2->y - p1->y) * ((double) p4->x - p3->x);
742}
743
744
745/*
746 * Free a container of FactorsCHull
747 *
748 * Args:
66eaf2eb
BP
749 * traceNb: number of traces
750 * allFactors: container of FactorsCHull
08365995 751 */
66eaf2eb
BP
752void freeAllFactors(const unsigned int traceNb, FactorsCHull** const
753 allFactors)
08365995
BP
754{
755 unsigned int i, j;
756
66eaf2eb 757 for (i= 0; i < traceNb; i++)
08365995
BP
758 {
759 for (j= 0; j <= i; j++)
760 {
66eaf2eb 761 destroyFactorsCHull(&allFactors[i][j]);
08365995
BP
762 }
763 free(allFactors[i]);
764 }
765 free(allFactors);
766}
767
768
66eaf2eb
BP
769/*
770 * Free a FactorsCHull
771 *
772 * Args:
773 * factorsCHull: container of Factors
774 */
775void destroyFactorsCHull(FactorsCHull* factorsCHull)
776{
777 if (factorsCHull->type == MIDDLE || factorsCHull->type ==
778 INCOMPLETE || factorsCHull->type == ABSENT)
779 {
780 free(factorsCHull->min);
781 free(factorsCHull->max);
782 }
783 else if (factorsCHull->type == SCREWED)
784 {
785 if (factorsCHull->min != NULL)
786 {
787 free(factorsCHull->min);
788 }
789 if (factorsCHull->max != NULL)
790 {
791 free(factorsCHull->max);
792 }
793 }
794
795 if (factorsCHull->type == EXACT || factorsCHull->type == MIDDLE ||
796 factorsCHull->type == FALLBACK)
797 {
798 free(factorsCHull->approx);
799 }
800}
801
802
08365995
BP
803/*
804 * Analyze the convex hulls to determine the synchronization factors between
805 * each pair of trace.
806 *
807 * Args:
808 * syncState container for synchronization data.
809 *
810 * Returns:
811 * FactorsCHull*[TraceNum][TraceNum] array. See the documentation for the
812 * member allFactors of AnalysisStatsCHull.
813 */
66eaf2eb 814FactorsCHull** calculateAllFactors(SyncState* const syncState)
08365995
BP
815{
816 unsigned int traceNumA, traceNumB;
817 FactorsCHull** allFactors;
818 AnalysisDataCHull* analysisData;
819
820 analysisData= (AnalysisDataCHull*) syncState->analysisData;
821
822 // Allocate allFactors and calculate min and max
823 allFactors= malloc(syncState->traceNb * sizeof(FactorsCHull*));
824 for (traceNumA= 0; traceNumA < syncState->traceNb; traceNumA++)
825 {
826 allFactors[traceNumA]= malloc((traceNumA + 1) * sizeof(FactorsCHull));
827
828 allFactors[traceNumA][traceNumA].type= EXACT;
829 allFactors[traceNumA][traceNumA].approx= malloc(sizeof(Factors));
830 allFactors[traceNumA][traceNumA].approx->drift= 1.;
831 allFactors[traceNumA][traceNumA].approx->offset= 0.;
832
833 for (traceNumB= 0; traceNumB < traceNumA; traceNumB++)
834 {
835 unsigned int i;
836 GQueue* cs, * cr;
837 const struct
838 {
839 LineType lineType;
840 size_t factorsOffset;
841 } loopValues[]= {
842 {MINIMUM, offsetof(FactorsCHull, min)},
843 {MAXIMUM, offsetof(FactorsCHull, max)}
844 };
845
846 cr= analysisData->hullArray[traceNumB][traceNumA];
847 cs= analysisData->hullArray[traceNumA][traceNumB];
848
849 for (i= 0; i < sizeof(loopValues) / sizeof(*loopValues); i++)
850 {
851 g_debug("allFactors[%u][%u].%s = calculateFactorsExact(cr= hullArray[%u][%u], cs= hullArray[%u][%u], %s)",
852 traceNumA, traceNumB, loopValues[i].factorsOffset ==
853 offsetof(FactorsCHull, min) ? "min" : "max", traceNumB,
854 traceNumA, traceNumA, traceNumB, loopValues[i].lineType ==
855 MINIMUM ? "MINIMUM" : "MAXIMUM");
856 *((Factors**) ((void*) &allFactors[traceNumA][traceNumB] +
857 loopValues[i].factorsOffset))=
858 calculateFactorsExact(cr, cs, loopValues[i].lineType);
859 }
860 }
861 }
862
863 // Calculate approx when possible
864 for (traceNumA= 0; traceNumA < syncState->traceNb; traceNumA++)
865 {
866 for (traceNumB= 0; traceNumB < traceNumA; traceNumB++)
867 {
868 FactorsCHull* factorsCHull;
869
870 factorsCHull= &allFactors[traceNumA][traceNumB];
871 if (factorsCHull->min == NULL && factorsCHull->max == NULL)
872 {
873 factorsCHull->type= FALLBACK;
874 calculateFactorsFallback(analysisData->hullArray[traceNumB][traceNumA],
875 analysisData->hullArray[traceNumA][traceNumB],
876 &allFactors[traceNumA][traceNumB]);
877 }
878 else if (factorsCHull->min != NULL && factorsCHull->max != NULL)
879 {
880 if (factorsCHull->min->drift != -INFINITY &&
881 factorsCHull->max->drift != INFINITY)
882 {
883 factorsCHull->type= MIDDLE;
884 calculateFactorsMiddle(factorsCHull);
885 }
886 else if (factorsCHull->min->drift != -INFINITY ||
887 factorsCHull->max->drift != INFINITY)
888 {
889 factorsCHull->type= INCOMPLETE;
890 }
891 else
892 {
893 factorsCHull->type= ABSENT;
894 }
895 }
896 else
897 {
898 //g_assert_not_reached();
899 factorsCHull->type= SCREWED;
900 }
901 }
902 }
903
904 return allFactors;
905}
906
907
908/* Calculate approximative factors based on minimum and maximum limits. The
909 * best approximation to make is the interior bissector of the angle formed by
910 * the minimum and maximum lines.
911 *
912 * The formulae used come from [Haddad, Yoram: Performance dans les systèmes
913 * répartis: des outils pour les mesures, Université de Paris-Sud, Centre
914 * d'Orsay, September 1988] Section 6.1 p.44
915 *
916 * The reasoning for choosing this estimator comes from [Duda, A., Harrus, G.,
917 * Haddad, Y., and Bernard, G.: Estimating global time in distributed systems,
918 * Proc. 7th Int. Conf. on Distributed Computing Systems, Berlin, volume 18,
919 * 1987] p.303
920 *
921 * Args:
922 * factors: contains the min and max limits, used to store the result
923 */
66eaf2eb 924void calculateFactorsMiddle(FactorsCHull* const factors)
08365995
BP
925{
926 double amin, amax, bmin, bmax, bhat;
927
928 amin= factors->max->offset;
929 amax= factors->min->offset;
930 bmin= factors->min->drift;
931 bmax= factors->max->drift;
932
48b641c1 933 g_assert_cmpfloat(bmax, >=, bmin);
08365995
BP
934
935 factors->approx= malloc(sizeof(Factors));
936 bhat= (bmax * bmin - 1. + sqrt(1. + pow(bmax, 2.) * pow(bmin, 2.) +
937 pow(bmax, 2.) + pow(bmin, 2.))) / (bmax + bmin);
938 factors->approx->offset= amax - (amax - amin) / 2. * (pow(bhat, 2.) + 1.)
939 / (1. + bhat * bmax);
940 factors->approx->drift= bhat;
941 factors->accuracy= bmax - bmin;
942}
943
944
945/*
946 * Analyze the convex hulls to determine the minimum or maximum
947 * synchronization factors between one pair of trace.
948 *
949 * This implements and improves upon the algorithm in [Haddad, Yoram:
950 * Performance dans les systèmes répartis: des outils pour les mesures,
951 * Université de Paris-Sud, Centre d'Orsay, September 1988] Section 6.2 p.47
952 *
953 * Some degenerate cases are possible:
954 * 1) the result is unbounded. In that case, when searching for the maximum
955 * factors, result->drift= INFINITY; result->offset= -INFINITY. When
956 * searching for the minimum factors, it is the opposite. It is not
957 * possible to improve the situation with this data.
958 * 2) no line can be above the upper hull and below the lower hull. This is
959 * because the hulls intersect each other or are reversed. This means that
960 * an assertion was false. Most probably, the clocks are not linear. It is
961 * possible to repeat the search with another algorithm that will find a
962 * "best effort" approximation. See calculateFactorsApprox().
963 *
964 * Args:
965 * cu: the upper half-convex hull, the line must pass above this
966 * and touch it in one point
967 * cl: the lower half-convex hull, the line must pass below this
968 * and touch it in one point
969 * lineType: search for minimum or maximum factors
970 *
971 * Returns:
972 * If a result is found, a struct Factors is allocated, filed with the
973 * result and returned
974 * NULL otherwise, degenerate case 2 is in effect
975 */
976static Factors* calculateFactorsExact(GQueue* const cu, GQueue* const cl, const
977 LineType lineType)
978{
979 GQueue* c1, * c2;
980 unsigned int i1, i2;
981 Point* p1, * p2;
982 double inversionFactor;
983 Factors* result;
984
985 g_debug("calculateFactorsExact(cu= %p, cl= %p, %s)", cu, cl, lineType ==
986 MINIMUM ? "MINIMUM" : "MAXIMUM");
987
988 if (lineType == MINIMUM)
989 {
990 c1= cl;
991 c2= cu;
992 inversionFactor= -1.;
993 }
994 else
995 {
996 c1= cu;
997 c2= cl;
998 inversionFactor= 1.;
999 }
1000
1001 i1= 0;
1002 i2= c2->length - 1;
1003
1004 // Check for degenerate case 1
1005 if (c1->length == 0 || c2->length == 0 || ((Point*) g_queue_peek_nth(c1,
1006 i1))->x >= ((Point*) g_queue_peek_nth(c2, i2))->x)
1007 {
1008 result= malloc(sizeof(Factors));
1009 if (lineType == MINIMUM)
1010 {
1011 result->drift= -INFINITY;
1012 result->offset= INFINITY;
1013 }
1014 else
1015 {
1016 result->drift= INFINITY;
1017 result->offset= -INFINITY;
1018 }
1019
1020 return result;
1021 }
1022
1023 do
1024 {
1025 while
1026 (
1027 (int) i2 - 1 > 0
1028 && crossProductK(
1029 g_queue_peek_nth(c1, i1),
1030 g_queue_peek_nth(c2, i2),
1031 g_queue_peek_nth(c1, i1),
1032 g_queue_peek_nth(c2, i2 - 1)) * inversionFactor < 0.
1033 )
1034 {
1035 if (((Point*) g_queue_peek_nth(c1, i1))->x
1036 < ((Point*) g_queue_peek_nth(c2, i2 - 1))->x)
1037 {
1038 i2--;
1039 }
1040 else
1041 {
1042 // Degenerate case 2
1043 return NULL;
1044 }
1045 }
1046 while
1047 (
1048 i1 + 1 < c1->length - 1
1049 && crossProductK(
1050 g_queue_peek_nth(c1, i1),
1051 g_queue_peek_nth(c2, i2),
1052 g_queue_peek_nth(c1, i1 + 1),
1053 g_queue_peek_nth(c2, i2)) * inversionFactor < 0.
1054 )
1055 {
1056 if (((Point*) g_queue_peek_nth(c1, i1 + 1))->x
1057 < ((Point*) g_queue_peek_nth(c2, i2))->x)
1058 {
1059 i1++;
1060 }
1061 else
1062 {
1063 // Degenerate case 2
1064 return NULL;
1065 }
1066 }
1067 } while
1068 (
1069 (int) i2 - 1 > 0
1070 && crossProductK(
1071 g_queue_peek_nth(c1, i1),
1072 g_queue_peek_nth(c2, i2),
1073 g_queue_peek_nth(c1, i1),
1074 g_queue_peek_nth(c2, i2 - 1)) * inversionFactor < 0.
1075 );
1076
1077 p1= g_queue_peek_nth(c1, i1);
1078 p2= g_queue_peek_nth(c2, i2);
1079
053b4b77
BP
1080 g_debug("Resulting points are: c1[i1]: x= %" PRIu64 " y= %" PRIu64
1081 " c2[i2]: x= %" PRIu64 " y= %" PRIu64 "", p1->x, p1->y, p2->x, p2->y);
08365995
BP
1082
1083 result= malloc(sizeof(Factors));
1084 result->drift= slope(p1, p2);
1085 result->offset= intercept(p1, p2);
1086
053b4b77
BP
1087 g_debug("Resulting factors are: drift= %g offset= %g", result->drift,
1088 result->offset);
08365995
BP
1089
1090 return result;
1091}
1092
1093
1094/*
1095 * Analyze the convex hulls to determine approximate synchronization factors
1096 * between one pair of trace when there is no line that can fit in the
1097 * corridor separating them.
1098 *
1099 * This implements the algorithm in [Ashton, P.: Algorithms for Off-line Clock
1100 * Synchronisation, University of Canterbury, December 1995, 26] Section 4.2.2
1101 * p.7
1102 *
1103 * For each point p1 in cr
1104 * For each point p2 in cs
1105 * errorMin= 0
1106 * Calculate the line paramaters
1107 * For each point p3 in each convex hull
1108 * If p3 is on the wrong side of the line
1109 * error+= distance
1110 * If error < errorMin
1111 * Update results
1112 *
1113 * Args:
1114 * cr: the upper half-convex hull
1115 * cs: the lower half-convex hull
1116 * result: a pointer to the pre-allocated struct where the results
1117 * will be stored
1118 */
1119static void calculateFactorsFallback(GQueue* const cr, GQueue* const cs,
1120 FactorsCHull* const result)
1121{
1122 unsigned int i, j, k;
1123 double errorMin;
1124 Factors* approx;
1125
1126 errorMin= INFINITY;
1127 approx= malloc(sizeof(Factors));
1128
1129 for (i= 0; i < cs->length; i++)
1130 {
1131 for (j= 0; j < cr->length; j++)
1132 {
1133 double error;
1134 Point p1, p2;
1135
1136 error= 0.;
1137
1138 if (((Point*) g_queue_peek_nth(cs, i))->x < ((Point*)g_queue_peek_nth(cr, j))->x)
1139 {
1140 p1= *(Point*)g_queue_peek_nth(cs, i);
1141 p2= *(Point*)g_queue_peek_nth(cr, j);
1142 }
1143 else
1144 {
1145 p1= *(Point*)g_queue_peek_nth(cr, j);
1146 p2= *(Point*)g_queue_peek_nth(cs, i);
1147 }
1148
1149 // The lower hull should be above the point
1150 for (k= 0; k < cs->length; k++)
1151 {
1152 if (jointCmp(&p1, &p2, g_queue_peek_nth(cs, k)) < 0.)
1153 {
1154 error+= verticalDistance(&p1, &p2, g_queue_peek_nth(cs, k));
1155 }
1156 }
1157
1158 // The upper hull should be below the point
1159 for (k= 0; k < cr->length; k++)
1160 {
1161 if (jointCmp(&p1, &p2, g_queue_peek_nth(cr, k)) > 0.)
1162 {
1163 error+= verticalDistance(&p1, &p2, g_queue_peek_nth(cr, k));
1164 }
1165 }
1166
1167 if (error < errorMin)
1168 {
1169 g_debug("Fallback: i= %u j= %u is a better match (error= %g)", i, j, error);
1170 approx->drift= slope(&p1, &p2);
1171 approx->offset= intercept(&p1, &p2);
1172 errorMin= error;
1173 }
1174 }
1175 }
1176
1177 result->approx= approx;
1178 result->accuracy= errorMin;
1179}
1180
1181
1182/*
1183 * Calculate the vertical distance between a line and a point
1184 *
1185 * Args:
1186 * p1, p2: Two points defining the line
1187 * point: a point
1188 *
1189 * Return:
1190 * the vertical distance
1191 */
1192static double verticalDistance(Point* p1, Point* p2, Point* const point)
1193{
1194 return fabs(slope(p1, p2) * point->x + intercept(p1, p2) - point->y);
1195}
1196
1197
1198/*
1199 * Calculate the slope between two points
1200 *
1201 * Args:
1202 * p1, p2 the two points
1203 *
1204 * Returns:
1205 * the slope
1206 */
1207static double slope(const Point* const p1, const Point* const p2)
1208{
1209 return ((double) p2->y - p1->y) / (p2->x - p1->x);
1210}
1211
1212
1213/* Calculate the y-intercept of a line that passes by two points
1214 *
1215 * Args:
1216 * p1, p2 the two points
1217 *
1218 * Returns:
1219 * the y-intercept
1220 */
1221static double intercept(const Point* const p1, const Point* const p2)
1222{
1223 return ((double) p2->y * p1->x - (double) p1->y * p2->x) / ((double) p1->x - p2->x);
1224}
1225
1226
1227/*
1228 * Calculate a resulting offset and drift for each trace.
1229 *
1230 * Traces are assembled in groups. A group is an "island" of nodes/traces that
1231 * exchanged messages. A reference is determined for each group by using a
1232 * shortest path search based on the accuracy of the approximation. This also
1233 * forms a tree of the best way to relate each node's clock to the reference's
1234 * based on the accuracy. Sometimes it may be necessary or advantageous to
1235 * propagate the factors through intermediary clocks. Resulting factors for
1236 * each trace are determined based on this tree.
1237 *
1238 * This part was not the focus of my research. The algorithm used here is
1239 * inexact in some ways:
1240 * 1) The reference used may not actually be the best one to use. This is
1241 * because the accuracy is not corrected based on the drift during the
1242 * shortest path search.
1243 * 2) The min and max factors are not propagated and are no longer valid.
1244 * 3) Approximations of different types (MIDDLE and FALLBACK) are compared
1245 * together. The "accuracy" parameters of these have different meanings and
1246 * are not readily comparable.
1247 *
1248 * Nevertheless, the result is satisfactory. You just can't tell "how much" it
1249 * is.
1250 *
1251 * Two alternative (and subtly different) ways of propagating factors to
1252 * preserve min and max bondaries have been proposed, see:
1253 * [Duda, A., Harrus, G., Haddad, Y., and Bernard, G.: Estimating global time
1254 * in distributed systems, Proc. 7th Int. Conf. on Distributed Computing
1255 * Systems, Berlin, volume 18, 1987] p.304
1256 *
1257 * [Jezequel, J.M., and Jard, C.: Building a global clock for observing
1258 * computations in distributed memory parallel computers, Concurrency:
1259 * Practice and Experience 8(1), volume 8, John Wiley & Sons, Ltd Chichester,
1260 * 1996, 32] Section 5; which is mostly the same as
1261 * [Jezequel, J.M.: Building a global time on parallel machines, Proceedings
1262 * of the 3rd International Workshop on Distributed Algorithms, LNCS, volume
1263 * 392, 136–147, 1989] Section 5
1264 *
1265 * Args:
1266 * syncState: container for synchronization data.
1267 * allFactors: offset and drift between each pair of traces
1268 *
1269 * Returns:
1270 * Factors[traceNb] synchronization factors for each trace
1271 */
1272static GArray* reduceFactors(SyncState* const syncState, FactorsCHull** const
1273 allFactors)
1274{
1275 GArray* factors;
1276 double** distances;
1277 unsigned int** predecessors;
1278 double* distanceSums;
1279 unsigned int* references;
1280 unsigned int i, j;
1281
1282 // Solve the all-pairs shortest path problem using the Floyd-Warshall
1283 // algorithm
1284 floydWarshall(syncState, allFactors, &distances, &predecessors);
1285
1286 /* Find the reference for each node
1287 *
1288 * First calculate, for each node, the sum of the distances to each other
1289 * node it can reach.
1290 *
1291 * Then, go through each "island" of traces to find the trace that has the
1292 * lowest distance sum. Assign this trace as the reference to each trace
1293 * of the island.
1294 */
1295 distanceSums= malloc(syncState->traceNb * sizeof(double));
1296 for (i= 0; i < syncState->traceNb; i++)
1297 {
1298 distanceSums[i]= 0.;
1299 for (j= 0; j < syncState->traceNb; j++)
1300 {
1301 distanceSums[i]+= distances[i][j];
1302 }
1303 }
1304
1305 references= malloc(syncState->traceNb * sizeof(unsigned int));
1306 for (i= 0; i < syncState->traceNb; i++)
1307 {
1308 references[i]= UINT_MAX;
1309 }
1310 for (i= 0; i < syncState->traceNb; i++)
1311 {
1312 if (references[i] == UINT_MAX)
1313 {
1314 unsigned int reference;
1315 double distanceSumMin;
1316
1317 // A node is its own reference by default
1318 reference= i;
1319 distanceSumMin= INFINITY;
1320 for (j= 0; j < syncState->traceNb; j++)
1321 {
1322 if (distances[i][j] != INFINITY && distanceSums[j] <
1323 distanceSumMin)
1324 {
1325 reference= j;
1326 distanceSumMin= distanceSums[j];
1327 }
1328 }
1329 for (j= 0; j < syncState->traceNb; j++)
1330 {
1331 if (distances[i][j] != INFINITY)
1332 {
1333 references[j]= reference;
1334 }
1335 }
1336 }
1337 }
1338
1339 for (i= 0; i < syncState->traceNb; i++)
1340 {
1341 free(distances[i]);
1342 }
1343 free(distances);
1344 free(distanceSums);
1345
1346 /* For each trace, calculate the factors based on their corresponding
1347 * tree. The tree is rooted at the reference and the shortest path to each
1348 * other nodes are the branches.
1349 */
1350 factors= g_array_sized_new(FALSE, FALSE, sizeof(Factors),
1351 syncState->traceNb);
1352 g_array_set_size(factors, syncState->traceNb);
1353 for (i= 0; i < syncState->traceNb; i++)
1354 {
1355 getFactors(allFactors, predecessors, references, i, &g_array_index(factors,
1356 Factors, i));
1357 }
1358
1359 for (i= 0; i < syncState->traceNb; i++)
1360 {
1361 free(predecessors[i]);
1362 }
1363 free(predecessors);
1364 free(references);
1365
1366 return factors;
1367}
1368
1369
1370/*
1371 * Perform an all-source shortest path search using the Floyd-Warshall
1372 * algorithm.
1373 *
1374 * The algorithm is implemented accoding to the description here:
1375 * http://web.mit.edu/urban_or_book/www/book/chapter6/6.2.2.html
1376 *
1377 * Args:
1378 * syncState: container for synchronization data.
1379 * allFactors: offset and drift between each pair of traces
1380 * distances: resulting matrix of the length of the shortest path between
1381 * two nodes. If there is no path between two nodes, the
1382 * length is INFINITY
1383 * predecessors: resulting matrix of each node's predecessor on the shortest
1384 * path between two nodes
1385 */
1386static void floydWarshall(SyncState* const syncState, FactorsCHull** const
1387 allFactors, double*** const distances, unsigned int*** const
1388 predecessors)
1389{
1390 unsigned int i, j, k;
1391
1392 // Setup initial conditions
1393 *distances= malloc(syncState->traceNb * sizeof(double*));
1394 *predecessors= malloc(syncState->traceNb * sizeof(unsigned int*));
1395 for (i= 0; i < syncState->traceNb; i++)
1396 {
1397 (*distances)[i]= malloc(syncState->traceNb * sizeof(double));
1398 for (j= 0; j < syncState->traceNb; j++)
1399 {
1400 if (i == j)
1401 {
1402 g_assert(allFactors[i][j].type == EXACT);
1403
1404 (*distances)[i][j]= 0.;
1405 }
1406 else
1407 {
1408 unsigned int row, col;
1409
1410 if (i > j)
1411 {
1412 row= i;
1413 col= j;
1414 }
1415 else if (i < j)
1416 {
1417 row= j;
1418 col= i;
1419 }
1420
1421 if (allFactors[row][col].type == MIDDLE ||
1422 allFactors[row][col].type == FALLBACK)
1423 {
1424 (*distances)[i][j]= allFactors[row][col].accuracy;
1425 }
1426 else if (allFactors[row][col].type == INCOMPLETE ||
1427 allFactors[row][col].type == SCREWED ||
1428 allFactors[row][col].type == ABSENT)
1429 {
1430 (*distances)[i][j]= INFINITY;
1431 }
1432 else
1433 {
1434 g_assert_not_reached();
1435 }
1436 }
1437 }
1438
1439 (*predecessors)[i]= malloc(syncState->traceNb * sizeof(unsigned int));
1440 for (j= 0; j < syncState->traceNb; j++)
1441 {
1442 if (i != j)
1443 {
1444 (*predecessors)[i][j]= i;
1445 }
1446 else
1447 {
1448 (*predecessors)[i][j]= UINT_MAX;
1449 }
1450 }
1451 }
1452
1453 // Run the iterations
1454 for (k= 0; k < syncState->traceNb; k++)
1455 {
1456 for (i= 0; i < syncState->traceNb; i++)
1457 {
1458 for (j= 0; j < syncState->traceNb; j++)
1459 {
1460 double distanceMin;
1461
1462 distanceMin= MIN((*distances)[i][j], (*distances)[i][k] +
1463 (*distances)[k][j]);
1464
1465 if (distanceMin != (*distances)[i][j])
1466 {
1467 (*predecessors)[i][j]= (*predecessors)[k][j];
1468 }
1469
1470 (*distances)[i][j]= distanceMin;
1471 }
1472 }
1473 }
1474}
1475
1476
1477/*
1478 * Cummulate the time correction factors to convert a node's time to its
1479 * reference's time.
1480 * This function recursively calls itself until it reaches the reference node.
1481 *
1482 * Args:
1483 * allFactors: offset and drift between each pair of traces
1484 * predecessors: matrix of each node's predecessor on the shortest
1485 * path between two nodes
1486 * references: reference node for each node
1487 * traceNum: node for which to find the factors
1488 * factors: resulting factors
1489 */
1490static void getFactors(FactorsCHull** const allFactors, unsigned int** const
1491 predecessors, unsigned int* const references, const unsigned int traceNum,
1492 Factors* const factors)
1493{
1494 unsigned int reference;
1495
1496 reference= references[traceNum];
1497
1498 if (reference == traceNum)
1499 {
1500 factors->offset= 0.;
1501 factors->drift= 1.;
1502 }
1503 else
1504 {
1505 Factors previousVertexFactors;
1506
1507 getFactors(allFactors, predecessors, references,
1508 predecessors[reference][traceNum], &previousVertexFactors);
1509
1510 // convertir de traceNum à reference
1511
1512 // allFactors convertit de col à row
1513
1514 if (reference > traceNum)
1515 {
1516 factors->offset= previousVertexFactors.drift *
1517 allFactors[reference][traceNum].approx->offset +
1518 previousVertexFactors.offset;
1519 factors->drift= previousVertexFactors.drift *
1520 allFactors[reference][traceNum].approx->drift;
1521 }
1522 else
1523 {
1524 factors->offset= previousVertexFactors.drift * (-1. *
1525 allFactors[traceNum][reference].approx->offset /
1526 allFactors[traceNum][reference].approx->drift) +
1527 previousVertexFactors.offset;
1528 factors->drift= previousVertexFactors.drift * (1. /
1529 allFactors[traceNum][reference].approx->drift);
1530 }
1531 }
1532}
1533
1534
1535/*
1536 * Write the analysis-specific graph lines in the gnuplot script.
1537 *
1538 * Args:
08365995
BP
1539 * syncState: container for synchronization data
1540 * i: first trace number
1541 * j: second trace number, garanteed to be larger than i
1542 */
8d7d16dd
BP
1543void writeAnalysisGraphsPlotsCHull(SyncState* const syncState, const unsigned
1544 int i, const unsigned int j)
08365995
BP
1545{
1546 AnalysisDataCHull* analysisData;
1547 FactorsCHull* factorsCHull;
1548
1549 analysisData= (AnalysisDataCHull*) syncState->analysisData;
1550
8d7d16dd 1551 fprintf(syncState->graphsStream,
08365995
BP
1552 "\t\"analysis_chull-%1$03d_to_%2$03d.data\" "
1553 "title \"Lower half-hull\" with linespoints "
1554 "linecolor rgb \"#015a01\" linetype 4 pointtype 8 pointsize 0.8, \\\n"
1555 "\t\"analysis_chull-%2$03d_to_%1$03d.data\" "
1556 "title \"Upper half-hull\" with linespoints "
1557 "linecolor rgb \"#003366\" linetype 4 pointtype 10 pointsize 0.8, \\\n",
1558 i, j);
1559
1560 factorsCHull= &analysisData->graphsData->allFactors[j][i];
1561 if (factorsCHull->type == EXACT)
1562 {
8d7d16dd 1563 fprintf(syncState->graphsStream,
08365995
BP
1564 "\t%7g + %7g * x "
1565 "title \"Exact conversion\" with lines "
1566 "linecolor rgb \"black\" linetype 1, \\\n",
1567 factorsCHull->approx->offset, factorsCHull->approx->drift);
1568 }
1569 else if (factorsCHull->type == MIDDLE)
1570 {
8d7d16dd 1571 fprintf(syncState->graphsStream,
08365995
BP
1572 "\t%.2f + %.10f * x "
1573 "title \"Min conversion\" with lines "
1574 "linecolor rgb \"black\" linetype 5, \\\n",
1575 factorsCHull->min->offset, factorsCHull->min->drift);
8d7d16dd 1576 fprintf(syncState->graphsStream,
08365995
BP
1577 "\t%.2f + %.10f * x "
1578 "title \"Max conversion\" with lines "
1579 "linecolor rgb \"black\" linetype 8, \\\n",
1580 factorsCHull->max->offset, factorsCHull->max->drift);
8d7d16dd 1581 fprintf(syncState->graphsStream,
08365995
BP
1582 "\t%.2f + %.10f * x "
1583 "title \"Middle conversion\" with lines "
66eaf2eb 1584 "linecolor rgb \"black\" linetype 1, \\\n",
08365995
BP
1585 factorsCHull->approx->offset, factorsCHull->approx->drift);
1586 }
1587 else if (factorsCHull->type == FALLBACK)
1588 {
8d7d16dd 1589 fprintf(syncState->graphsStream,
08365995
BP
1590 "\t%.2f + %.10f * x "
1591 "title \"Fallback conversion\" with lines "
1592 "linecolor rgb \"gray60\" linetype 1, \\\n",
1593 factorsCHull->approx->offset, factorsCHull->approx->drift);
1594 }
1595 else if (factorsCHull->type == INCOMPLETE)
1596 {
1597 if (factorsCHull->min->drift != -INFINITY)
1598 {
8d7d16dd 1599 fprintf(syncState->graphsStream,
08365995
BP
1600 "\t%.2f + %.10f * x "
1601 "title \"Min conversion\" with lines "
1602 "linecolor rgb \"black\" linetype 5, \\\n",
1603 factorsCHull->min->offset, factorsCHull->min->drift);
1604 }
1605
1606 if (factorsCHull->max->drift != INFINITY)
1607 {
8d7d16dd 1608 fprintf(syncState->graphsStream,
08365995
BP
1609 "\t%.2f + %.10f * x "
1610 "title \"Max conversion\" with lines "
1611 "linecolor rgb \"black\" linetype 8, \\\n",
1612 factorsCHull->max->offset, factorsCHull->max->drift);
1613 }
1614 }
1615 else if (factorsCHull->type == SCREWED)
1616 {
1617 if (factorsCHull->min != NULL && factorsCHull->min->drift != -INFINITY)
1618 {
8d7d16dd 1619 fprintf(syncState->graphsStream,
08365995
BP
1620 "\t%.2f + %.10f * x "
1621 "title \"Min conversion\" with lines "
1622 "linecolor rgb \"black\" linetype 5, \\\n",
1623 factorsCHull->min->offset, factorsCHull->min->drift);
1624 }
1625
1626 if (factorsCHull->max != NULL && factorsCHull->max->drift != INFINITY)
1627 {
8d7d16dd 1628 fprintf(syncState->graphsStream,
08365995
BP
1629 "\t%.2f + %.10f * x "
1630 "title \"Max conversion\" with lines "
1631 "linecolor rgb \"black\" linetype 8, \\\n",
1632 factorsCHull->max->offset, factorsCHull->max->drift);
1633 }
1634 }
1635 else if (factorsCHull->type == ABSENT)
1636 {
1637 }
1638 else
1639 {
1640 g_assert_not_reached();
1641 }
1642}
This page took 0.088405 seconds and 4 git commands to generate.