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