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