Print approximation type from a constant instead of hardcoded
[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>
25#include <math.h>
26#include <float.h>
27#include <stdlib.h>
28#include <stdio.h>
29#include <unistd.h>
30
2bd4b3e4 31#include "sync_chain.h"
08365995
BP
32
33#include "event_analysis_chull.h"
34
35
36#ifndef g_info
37#define g_info(format...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, format)
38#endif
39
40
41typedef enum
42{
43 LOWER,
44 UPPER
45} HullType;
46
47
48typedef enum
49{
50 MINIMUM,
51 MAXIMUM
52} LineType;
53
54
55// Functions common to all analysis modules
56static void initAnalysisCHull(SyncState* const syncState);
57static void destroyAnalysisCHull(SyncState* const syncState);
58
10341d26
BP
59static void analyzeMessageCHull(SyncState* const syncState, Message* const
60 message);
08365995
BP
61static GArray* finalizeAnalysisCHull(SyncState* const syncState);
62static void printAnalysisStatsCHull(SyncState* const syncState);
8d7d16dd
BP
63static void writeAnalysisGraphsPlotsCHull(SyncState* const syncState, const
64 unsigned int i, const unsigned int j);
08365995
BP
65
66// Functions specific to this module
67static void registerAnalysisCHull() __attribute__((constructor (101)));
68
69static void openGraphFiles(SyncState* const syncState);
70static void closeGraphFiles(SyncState* const syncState);
71static void writeGraphFiles(SyncState* const syncState);
72static void gfDumpHullToFile(gpointer data, gpointer userData);
73
74static void grahamScan(GQueue* const hull, Point* const newPoint, const
75 HullType type);
76static int jointCmp(const Point* const p1, const Point* const p2, const Point*
77 const p3) __attribute__((pure));
78static double crossProductK(const Point const* p1, const Point const* p2,
79 const Point const* p3, const Point const* p4) __attribute__((pure));
08365995
BP
80static Factors* calculateFactorsExact(GQueue* const cu, GQueue* const cl, const
81 LineType lineType) __attribute__((pure));
08365995
BP
82static void calculateFactorsFallback(GQueue* const cr, GQueue* const cs,
83 FactorsCHull* const result);
84static double slope(const Point* const p1, const Point* const p2)
85 __attribute__((pure));
86static double intercept(const Point* const p1, const Point* const p2)
87 __attribute__((pure));
88static GArray* reduceFactors(SyncState* const syncState, FactorsCHull**
89 allFactors);
08365995
BP
90static double verticalDistance(Point* p1, Point* p2, Point* const point)
91 __attribute__((pure));
92static void floydWarshall(SyncState* const syncState, FactorsCHull** const
93 allFactors, double*** const distances, unsigned int*** const
94 predecessors);
95static void getFactors(FactorsCHull** const allFactors, unsigned int** const
96 predecessors, unsigned int* const references, const unsigned int traceNum,
97 Factors* const factors);
98
99static void gfPointDestroy(gpointer data, gpointer userData);
100
101
102static AnalysisModule analysisModuleCHull= {
103 .name= "chull",
104 .initAnalysis= &initAnalysisCHull,
105 .destroyAnalysis= &destroyAnalysisCHull,
10341d26 106 .analyzeMessage= &analyzeMessageCHull,
08365995
BP
107 .finalizeAnalysis= &finalizeAnalysisCHull,
108 .printAnalysisStats= &printAnalysisStatsCHull,
467066ee 109 .graphFunctions= {
c6356aa7 110 .writeTraceTraceForePlots= &writeAnalysisGraphsPlotsCHull,
467066ee 111 }
08365995
BP
112};
113
66eaf2eb
BP
114const char* const approxNames[]= {
115 [EXACT]= "Exact",
116 [MIDDLE]= "Middle",
117 [FALLBACK]= "Fallback",
118 [INCOMPLETE]= "Incomplete",
119 [ABSENT]= "Absent",
120 [SCREWED]= "Screwed",
121};
08365995 122
c6356aa7 123
08365995
BP
124/*
125 * Analysis module registering function
126 */
127static void registerAnalysisCHull()
128{
129 g_queue_push_tail(&analysisModules, &analysisModuleCHull);
130}
131
132
133/*
134 * Analysis init function
135 *
136 * This function is called at the beginning of a synchronization run for a set
137 * of traces.
138 *
139 * Allocate some of the analysis specific data structures
140 *
141 * Args:
142 * syncState container for synchronization data.
143 * This function allocates or initializes these analysisData
144 * members:
145 * hullArray
146 * dropped
147 */
148static void initAnalysisCHull(SyncState* const syncState)
149{
150 unsigned int i, j;
151 AnalysisDataCHull* analysisData;
152
153 analysisData= malloc(sizeof(AnalysisDataCHull));
154 syncState->analysisData= analysisData;
155
156 analysisData->hullArray= malloc(syncState->traceNb * sizeof(GQueue**));
157 for (i= 0; i < syncState->traceNb; i++)
158 {
159 analysisData->hullArray[i]= malloc(syncState->traceNb * sizeof(GQueue*));
160
161 for (j= 0; j < syncState->traceNb; j++)
162 {
163 analysisData->hullArray[i][j]= g_queue_new();
164 }
165 }
166
167 if (syncState->stats)
168 {
169 analysisData->stats= malloc(sizeof(AnalysisStatsCHull));
170 analysisData->stats->dropped= 0;
171 analysisData->stats->allFactors= NULL;
172 }
173
8d7d16dd 174 if (syncState->graphsStream)
08365995
BP
175 {
176 analysisData->graphsData= malloc(sizeof(AnalysisGraphsDataCHull));
177 openGraphFiles(syncState);
178 analysisData->graphsData->allFactors= NULL;
179 }
180}
181
182
183/*
184 * Create and open files used to store convex hull points to genereate
185 * graphs. Allocate and populate array to store file pointers.
186 *
187 * Args:
188 * syncState: container for synchronization data
189 */
190static void openGraphFiles(SyncState* const syncState)
191{
192 unsigned int i, j;
193 int retval;
194 char* cwd;
195 char name[31];
196 AnalysisDataCHull* analysisData;
197
198 analysisData= (AnalysisDataCHull*) syncState->analysisData;
199
8d7d16dd 200 cwd= changeToGraphDir(syncState->graphsDir);
08365995
BP
201
202 analysisData->graphsData->hullPoints= malloc(syncState->traceNb *
203 sizeof(FILE**));
204 for (i= 0; i < syncState->traceNb; i++)
205 {
206 analysisData->graphsData->hullPoints[i]= malloc(syncState->traceNb *
207 sizeof(FILE*));
208 for (j= 0; j < syncState->traceNb; j++)
209 {
210 if (i != j)
211 {
212 retval= snprintf(name, sizeof(name),
213 "analysis_chull-%03u_to_%03u.data", j, i);
214 if (retval > sizeof(name) - 1)
215 {
216 name[sizeof(name) - 1]= '\0';
217 }
218 if ((analysisData->graphsData->hullPoints[i][j]= fopen(name, "w")) ==
219 NULL)
220 {
221 g_error(strerror(errno));
222 }
223 }
224 }
225 }
226
227 retval= chdir(cwd);
228 if (retval == -1)
229 {
230 g_error(strerror(errno));
231 }
232 free(cwd);
233}
234
235
236/*
237 * Write hull points to files to generate graphs.
238 *
239 * Args:
240 * syncState: container for synchronization data
241 */
242static void writeGraphFiles(SyncState* const syncState)
243{
244 unsigned int i, j;
245 AnalysisDataCHull* analysisData;
246
247 analysisData= (AnalysisDataCHull*) syncState->analysisData;
248
249 for (i= 0; i < syncState->traceNb; i++)
250 {
251 for (j= 0; j < syncState->traceNb; j++)
252 {
253 if (i != j)
254 {
255 g_queue_foreach(analysisData->hullArray[i][j],
256 &gfDumpHullToFile,
257 analysisData->graphsData->hullPoints[i][j]);
258 }
259 }
260 }
261}
262
263
264/*
265 * A GFunc for g_queue_foreach. Write a hull point to a file used to generate
266 * graphs
267 *
268 * Args:
269 * data: Point*, point to write to the file
270 * userData: FILE*, file pointer where to write the point
271 */
272static void gfDumpHullToFile(gpointer data, gpointer userData)
273{
274 Point* point;
275
276 point= (Point*) data;
277 fprintf((FILE*) userData, "%20llu %20llu\n", point->x, point->y);
278}
279
280
281/*
282 * Close files used to store convex hull points to generate graphs.
283 * Deallocate array to store file pointers.
284 *
285 * Args:
286 * syncState: container for synchronization data
287 */
288static void closeGraphFiles(SyncState* const syncState)
289{
290 unsigned int i, j;
291 AnalysisDataCHull* analysisData;
292 int retval;
293
294 analysisData= (AnalysisDataCHull*) syncState->analysisData;
295
296 if (analysisData->graphsData->hullPoints == NULL)
297 {
298 return;
299 }
300
301 for (i= 0; i < syncState->traceNb; i++)
302 {
303 for (j= 0; j < syncState->traceNb; j++)
304 {
305 if (i != j)
306 {
307 retval= fclose(analysisData->graphsData->hullPoints[i][j]);
308 if (retval != 0)
309 {
310 g_error(strerror(errno));
311 }
312 }
313 }
314 free(analysisData->graphsData->hullPoints[i]);
315 }
316 free(analysisData->graphsData->hullPoints);
317 analysisData->graphsData->hullPoints= NULL;
318}
319
320
321/*
322 * Analysis destroy function
323 *
324 * Free the analysis specific data structures
325 *
326 * Args:
327 * syncState container for synchronization data.
328 * This function deallocates these analysisData members:
329 * hullArray
330 * stDev
331 */
332static void destroyAnalysisCHull(SyncState* const syncState)
333{
334 unsigned int i, j;
335 AnalysisDataCHull* analysisData;
336
337 analysisData= (AnalysisDataCHull*) syncState->analysisData;
338
339 if (analysisData == NULL)
340 {
341 return;
342 }
343
344 for (i= 0; i < syncState->traceNb; i++)
345 {
346 for (j= 0; j < syncState->traceNb; j++)
347 {
348 g_queue_foreach(analysisData->hullArray[i][j], gfPointDestroy, NULL);
349 }
350 free(analysisData->hullArray[i]);
351 }
352 free(analysisData->hullArray);
353
354 if (syncState->stats)
355 {
356 if (analysisData->stats->allFactors != NULL)
357 {
66eaf2eb 358 freeAllFactors(syncState->traceNb, analysisData->stats->allFactors);
08365995
BP
359 }
360
361 free(analysisData->stats);
362 }
363
8d7d16dd 364 if (syncState->graphsStream)
08365995
BP
365 {
366 if (analysisData->graphsData->hullPoints != NULL)
367 {
368 closeGraphFiles(syncState);
369 }
370
371 if (!syncState->stats && analysisData->graphsData->allFactors != NULL)
372 {
66eaf2eb 373 freeAllFactors(syncState->traceNb, analysisData->graphsData->allFactors);
08365995
BP
374 }
375
376 free(analysisData->graphsData);
377 }
378
379 free(syncState->analysisData);
380 syncState->analysisData= NULL;
381}
382
383
384/*
385 * Perform analysis on an event pair.
386 *
387 * Args:
388 * syncState container for synchronization data
10341d26 389 * message structure containing the events
08365995 390 */
10341d26 391static void analyzeMessageCHull(SyncState* const syncState, Message* const message)
08365995
BP
392{
393 AnalysisDataCHull* analysisData;
394 Point* newPoint;
395 HullType hullType;
396 GQueue* hull;
397
398 analysisData= (AnalysisDataCHull*) syncState->analysisData;
399
400 newPoint= malloc(sizeof(Point));
10341d26 401 if (message->inE->traceNum < message->outE->traceNum)
08365995
BP
402 {
403 // CA is inE->traceNum
76be6fc2
BP
404 newPoint->x= message->inE->cpuTime;
405 newPoint->y= message->outE->cpuTime;
08365995 406 hullType= UPPER;
10341d26
BP
407 g_debug("Reception point hullArray[%lu][%lu] x= inE->time= %llu y= outE->time= %llu",
408 message->inE->traceNum, message->outE->traceNum, newPoint->x,
08365995
BP
409 newPoint->y);
410 }
411 else
412 {
413 // CA is outE->traceNum
76be6fc2
BP
414 newPoint->x= message->outE->cpuTime;
415 newPoint->y= message->inE->cpuTime;
08365995 416 hullType= LOWER;
10341d26
BP
417 g_debug("Send point hullArray[%lu][%lu] x= inE->time= %llu y= outE->time= %llu",
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);
709 g_debug("crossProductK(p1= (%llu, %llu), p2= (%llu, %llu), p1= (%llu, %llu), p3= (%llu, %llu))= %g",
710 p1->x, p1->y, p2->x, p2->y, p1->x, p1->y, p3->x, p3->y, result);
711 if (result < fuzzFactor)
712 {
713 return -1;
714 }
715 else if (result > fuzzFactor)
716 {
717 return 1;
718 }
719 else
720 {
721 return 0;
722 }
723}
724
725
726/*
727 * Calculate the k component of the cross product of two vectors.
728 *
729 * Args:
730 * p1, p2: start and end points of the first vector
731 * p3, p4: start and end points of the second vector
732 *
733 * Returns:
734 * the k component of the cross product when considering the two vectors to
735 * be in the i-j plane. The direction (sign) of the result can be useful to
736 * determine the relative orientation of the two vectors.
737 */
738static double crossProductK(const Point const* p1, const Point const* p2,
739 const Point const* p3, const Point const* p4)
740{
741 return ((double) p2->x - p1->x) * ((double) p4->y - p3->y) - ((double)
742 p2->y - p1->y) * ((double) p4->x - p3->x);
743}
744
745
746/*
747 * Free a container of FactorsCHull
748 *
749 * Args:
66eaf2eb
BP
750 * traceNb: number of traces
751 * allFactors: container of FactorsCHull
08365995 752 */
66eaf2eb
BP
753void freeAllFactors(const unsigned int traceNb, FactorsCHull** const
754 allFactors)
08365995
BP
755{
756 unsigned int i, j;
757
66eaf2eb 758 for (i= 0; i < traceNb; i++)
08365995
BP
759 {
760 for (j= 0; j <= i; j++)
761 {
66eaf2eb 762 destroyFactorsCHull(&allFactors[i][j]);
08365995
BP
763 }
764 free(allFactors[i]);
765 }
766 free(allFactors);
767}
768
769
66eaf2eb
BP
770/*
771 * Free a FactorsCHull
772 *
773 * Args:
774 * factorsCHull: container of Factors
775 */
776void destroyFactorsCHull(FactorsCHull* factorsCHull)
777{
778 if (factorsCHull->type == MIDDLE || factorsCHull->type ==
779 INCOMPLETE || factorsCHull->type == ABSENT)
780 {
781 free(factorsCHull->min);
782 free(factorsCHull->max);
783 }
784 else if (factorsCHull->type == SCREWED)
785 {
786 if (factorsCHull->min != NULL)
787 {
788 free(factorsCHull->min);
789 }
790 if (factorsCHull->max != NULL)
791 {
792 free(factorsCHull->max);
793 }
794 }
795
796 if (factorsCHull->type == EXACT || factorsCHull->type == MIDDLE ||
797 factorsCHull->type == FALLBACK)
798 {
799 free(factorsCHull->approx);
800 }
801}
802
803
08365995
BP
804/*
805 * Analyze the convex hulls to determine the synchronization factors between
806 * each pair of trace.
807 *
808 * Args:
809 * syncState container for synchronization data.
810 *
811 * Returns:
812 * FactorsCHull*[TraceNum][TraceNum] array. See the documentation for the
813 * member allFactors of AnalysisStatsCHull.
814 */
66eaf2eb 815FactorsCHull** calculateAllFactors(SyncState* const syncState)
08365995
BP
816{
817 unsigned int traceNumA, traceNumB;
818 FactorsCHull** allFactors;
819 AnalysisDataCHull* analysisData;
820
821 analysisData= (AnalysisDataCHull*) syncState->analysisData;
822
823 // Allocate allFactors and calculate min and max
824 allFactors= malloc(syncState->traceNb * sizeof(FactorsCHull*));
825 for (traceNumA= 0; traceNumA < syncState->traceNb; traceNumA++)
826 {
827 allFactors[traceNumA]= malloc((traceNumA + 1) * sizeof(FactorsCHull));
828
829 allFactors[traceNumA][traceNumA].type= EXACT;
830 allFactors[traceNumA][traceNumA].approx= malloc(sizeof(Factors));
831 allFactors[traceNumA][traceNumA].approx->drift= 1.;
832 allFactors[traceNumA][traceNumA].approx->offset= 0.;
833
834 for (traceNumB= 0; traceNumB < traceNumA; traceNumB++)
835 {
836 unsigned int i;
837 GQueue* cs, * cr;
838 const struct
839 {
840 LineType lineType;
841 size_t factorsOffset;
842 } loopValues[]= {
843 {MINIMUM, offsetof(FactorsCHull, min)},
844 {MAXIMUM, offsetof(FactorsCHull, max)}
845 };
846
847 cr= analysisData->hullArray[traceNumB][traceNumA];
848 cs= analysisData->hullArray[traceNumA][traceNumB];
849
850 for (i= 0; i < sizeof(loopValues) / sizeof(*loopValues); i++)
851 {
852 g_debug("allFactors[%u][%u].%s = calculateFactorsExact(cr= hullArray[%u][%u], cs= hullArray[%u][%u], %s)",
853 traceNumA, traceNumB, loopValues[i].factorsOffset ==
854 offsetof(FactorsCHull, min) ? "min" : "max", traceNumB,
855 traceNumA, traceNumA, traceNumB, loopValues[i].lineType ==
856 MINIMUM ? "MINIMUM" : "MAXIMUM");
857 *((Factors**) ((void*) &allFactors[traceNumA][traceNumB] +
858 loopValues[i].factorsOffset))=
859 calculateFactorsExact(cr, cs, loopValues[i].lineType);
860 }
861 }
862 }
863
864 // Calculate approx when possible
865 for (traceNumA= 0; traceNumA < syncState->traceNb; traceNumA++)
866 {
867 for (traceNumB= 0; traceNumB < traceNumA; traceNumB++)
868 {
869 FactorsCHull* factorsCHull;
870
871 factorsCHull= &allFactors[traceNumA][traceNumB];
872 if (factorsCHull->min == NULL && factorsCHull->max == NULL)
873 {
874 factorsCHull->type= FALLBACK;
875 calculateFactorsFallback(analysisData->hullArray[traceNumB][traceNumA],
876 analysisData->hullArray[traceNumA][traceNumB],
877 &allFactors[traceNumA][traceNumB]);
878 }
879 else if (factorsCHull->min != NULL && factorsCHull->max != NULL)
880 {
881 if (factorsCHull->min->drift != -INFINITY &&
882 factorsCHull->max->drift != INFINITY)
883 {
884 factorsCHull->type= MIDDLE;
885 calculateFactorsMiddle(factorsCHull);
886 }
887 else if (factorsCHull->min->drift != -INFINITY ||
888 factorsCHull->max->drift != INFINITY)
889 {
890 factorsCHull->type= INCOMPLETE;
891 }
892 else
893 {
894 factorsCHull->type= ABSENT;
895 }
896 }
897 else
898 {
899 //g_assert_not_reached();
900 factorsCHull->type= SCREWED;
901 }
902 }
903 }
904
905 return allFactors;
906}
907
908
909/* Calculate approximative factors based on minimum and maximum limits. The
910 * best approximation to make is the interior bissector of the angle formed by
911 * the minimum and maximum lines.
912 *
913 * The formulae used come from [Haddad, Yoram: Performance dans les systèmes
914 * répartis: des outils pour les mesures, Université de Paris-Sud, Centre
915 * d'Orsay, September 1988] Section 6.1 p.44
916 *
917 * The reasoning for choosing this estimator comes from [Duda, A., Harrus, G.,
918 * Haddad, Y., and Bernard, G.: Estimating global time in distributed systems,
919 * Proc. 7th Int. Conf. on Distributed Computing Systems, Berlin, volume 18,
920 * 1987] p.303
921 *
922 * Args:
923 * factors: contains the min and max limits, used to store the result
924 */
66eaf2eb 925void calculateFactorsMiddle(FactorsCHull* const factors)
08365995
BP
926{
927 double amin, amax, bmin, bmax, bhat;
928
929 amin= factors->max->offset;
930 amax= factors->min->offset;
931 bmin= factors->min->drift;
932 bmax= factors->max->drift;
933
934 g_assert_cmpfloat(bmax, >, bmin);
935
936 factors->approx= malloc(sizeof(Factors));
937 bhat= (bmax * bmin - 1. + sqrt(1. + pow(bmax, 2.) * pow(bmin, 2.) +
938 pow(bmax, 2.) + pow(bmin, 2.))) / (bmax + bmin);
939 factors->approx->offset= amax - (amax - amin) / 2. * (pow(bhat, 2.) + 1.)
940 / (1. + bhat * bmax);
941 factors->approx->drift= bhat;
942 factors->accuracy= bmax - bmin;
943}
944
945
946/*
947 * Analyze the convex hulls to determine the minimum or maximum
948 * synchronization factors between one pair of trace.
949 *
950 * This implements and improves upon the algorithm in [Haddad, Yoram:
951 * Performance dans les systèmes répartis: des outils pour les mesures,
952 * Université de Paris-Sud, Centre d'Orsay, September 1988] Section 6.2 p.47
953 *
954 * Some degenerate cases are possible:
955 * 1) the result is unbounded. In that case, when searching for the maximum
956 * factors, result->drift= INFINITY; result->offset= -INFINITY. When
957 * searching for the minimum factors, it is the opposite. It is not
958 * possible to improve the situation with this data.
959 * 2) no line can be above the upper hull and below the lower hull. This is
960 * because the hulls intersect each other or are reversed. This means that
961 * an assertion was false. Most probably, the clocks are not linear. It is
962 * possible to repeat the search with another algorithm that will find a
963 * "best effort" approximation. See calculateFactorsApprox().
964 *
965 * Args:
966 * cu: the upper half-convex hull, the line must pass above this
967 * and touch it in one point
968 * cl: the lower half-convex hull, the line must pass below this
969 * and touch it in one point
970 * lineType: search for minimum or maximum factors
971 *
972 * Returns:
973 * If a result is found, a struct Factors is allocated, filed with the
974 * result and returned
975 * NULL otherwise, degenerate case 2 is in effect
976 */
977static Factors* calculateFactorsExact(GQueue* const cu, GQueue* const cl, const
978 LineType lineType)
979{
980 GQueue* c1, * c2;
981 unsigned int i1, i2;
982 Point* p1, * p2;
983 double inversionFactor;
984 Factors* result;
985
986 g_debug("calculateFactorsExact(cu= %p, cl= %p, %s)", cu, cl, lineType ==
987 MINIMUM ? "MINIMUM" : "MAXIMUM");
988
989 if (lineType == MINIMUM)
990 {
991 c1= cl;
992 c2= cu;
993 inversionFactor= -1.;
994 }
995 else
996 {
997 c1= cu;
998 c2= cl;
999 inversionFactor= 1.;
1000 }
1001
1002 i1= 0;
1003 i2= c2->length - 1;
1004
1005 // Check for degenerate case 1
1006 if (c1->length == 0 || c2->length == 0 || ((Point*) g_queue_peek_nth(c1,
1007 i1))->x >= ((Point*) g_queue_peek_nth(c2, i2))->x)
1008 {
1009 result= malloc(sizeof(Factors));
1010 if (lineType == MINIMUM)
1011 {
1012 result->drift= -INFINITY;
1013 result->offset= INFINITY;
1014 }
1015 else
1016 {
1017 result->drift= INFINITY;
1018 result->offset= -INFINITY;
1019 }
1020
1021 return result;
1022 }
1023
1024 do
1025 {
1026 while
1027 (
1028 (int) i2 - 1 > 0
1029 && crossProductK(
1030 g_queue_peek_nth(c1, i1),
1031 g_queue_peek_nth(c2, i2),
1032 g_queue_peek_nth(c1, i1),
1033 g_queue_peek_nth(c2, i2 - 1)) * inversionFactor < 0.
1034 )
1035 {
1036 if (((Point*) g_queue_peek_nth(c1, i1))->x
1037 < ((Point*) g_queue_peek_nth(c2, i2 - 1))->x)
1038 {
1039 i2--;
1040 }
1041 else
1042 {
1043 // Degenerate case 2
1044 return NULL;
1045 }
1046 }
1047 while
1048 (
1049 i1 + 1 < c1->length - 1
1050 && crossProductK(
1051 g_queue_peek_nth(c1, i1),
1052 g_queue_peek_nth(c2, i2),
1053 g_queue_peek_nth(c1, i1 + 1),
1054 g_queue_peek_nth(c2, i2)) * inversionFactor < 0.
1055 )
1056 {
1057 if (((Point*) g_queue_peek_nth(c1, i1 + 1))->x
1058 < ((Point*) g_queue_peek_nth(c2, i2))->x)
1059 {
1060 i1++;
1061 }
1062 else
1063 {
1064 // Degenerate case 2
1065 return NULL;
1066 }
1067 }
1068 } while
1069 (
1070 (int) i2 - 1 > 0
1071 && crossProductK(
1072 g_queue_peek_nth(c1, i1),
1073 g_queue_peek_nth(c2, i2),
1074 g_queue_peek_nth(c1, i1),
1075 g_queue_peek_nth(c2, i2 - 1)) * inversionFactor < 0.
1076 );
1077
1078 p1= g_queue_peek_nth(c1, i1);
1079 p2= g_queue_peek_nth(c2, i2);
1080
1081 g_debug("Resulting points are: c1[i1]: x= %llu y= %llu c2[i2]: x= %llu y= %llu",
1082 p1->x, p1->y, p2->x, p2->y);
1083
1084 result= malloc(sizeof(Factors));
1085 result->drift= slope(p1, p2);
1086 result->offset= intercept(p1, p2);
1087
1088 g_debug("Resulting factors are: drift= %g offset= %g", result->drift, result->offset);
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.084118 seconds and 4 git commands to generate.