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