Perform factor reduction as a modular step
[lttv.git] / lttv / lttv / sync / event_analysis_chull.c
CommitLineData
08365995 1/* This file is part of the Linux Trace Toolkit viewer
277e5b53 2 * Copyright (C) 2009, 2010 Benjamin Poirier <benjamin.poirier@polymtl.ca>
08365995 3 *
277e5b53
BP
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation, either version 2.1 of the License, or (at
7 * your option) any later version.
08365995 8 *
277e5b53
BP
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
12 * License for more details.
08365995 13 *
277e5b53
BP
14 * You should have received a copy of the GNU Lesser General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
08365995
BP
16 */
17#define _ISOC99_SOURCE
18
19#ifdef HAVE_CONFIG_H
20#include <config.h>
21#endif
22
23#include <errno.h>
053b4b77 24#include <inttypes.h>
08365995
BP
25#include <math.h>
26#include <float.h>
27#include <stdlib.h>
28#include <stdio.h>
2f076594 29#include <string.h>
08365995
BP
30#include <unistd.h>
31
2bd4b3e4 32#include "sync_chain.h"
08365995
BP
33
34#include "event_analysis_chull.h"
35
36
08365995
BP
37typedef enum
38{
39 LOWER,
40 UPPER
41} HullType;
42
43
44typedef enum
45{
46 MINIMUM,
47 MAXIMUM
48} LineType;
49
50
51// Functions common to all analysis modules
52static void initAnalysisCHull(SyncState* const syncState);
53static void destroyAnalysisCHull(SyncState* const syncState);
54
10341d26
BP
55static void analyzeMessageCHull(SyncState* const syncState, Message* const
56 message);
0a87ec9a 57static AllFactors* finalizeAnalysisCHull(SyncState* const syncState);
08365995 58static void printAnalysisStatsCHull(SyncState* const syncState);
8d7d16dd
BP
59static void writeAnalysisGraphsPlotsCHull(SyncState* const syncState, const
60 unsigned int i, const unsigned int j);
08365995
BP
61
62// Functions specific to this module
08365995
BP
63static void openGraphFiles(SyncState* const syncState);
64static void closeGraphFiles(SyncState* const syncState);
65static void writeGraphFiles(SyncState* const syncState);
66static void gfDumpHullToFile(gpointer data, gpointer userData);
67
68static void grahamScan(GQueue* const hull, Point* const newPoint, const
69 HullType type);
70static int jointCmp(const Point* const p1, const Point* const p2, const Point*
71 const p3) __attribute__((pure));
72static double crossProductK(const Point const* p1, const Point const* p2,
73 const Point const* p3, const Point const* p4) __attribute__((pure));
08365995
BP
74static Factors* calculateFactorsExact(GQueue* const cu, GQueue* const cl, const
75 LineType lineType) __attribute__((pure));
08365995 76static void calculateFactorsFallback(GQueue* const cr, GQueue* const cs,
0a87ec9a 77 PairFactors* const result);
08365995
BP
78static double slope(const Point* const p1, const Point* const p2)
79 __attribute__((pure));
80static double intercept(const Point* const p1, const Point* const p2)
81 __attribute__((pure));
08365995
BP
82static double verticalDistance(Point* p1, Point* p2, Point* const point)
83 __attribute__((pure));
08365995
BP
84
85static void gfPointDestroy(gpointer data, gpointer userData);
86
87
88static AnalysisModule analysisModuleCHull= {
89 .name= "chull",
90 .initAnalysis= &initAnalysisCHull,
91 .destroyAnalysis= &destroyAnalysisCHull,
10341d26 92 .analyzeMessage= &analyzeMessageCHull,
08365995
BP
93 .finalizeAnalysis= &finalizeAnalysisCHull,
94 .printAnalysisStats= &printAnalysisStatsCHull,
467066ee 95 .graphFunctions= {
c6356aa7 96 .writeTraceTraceForePlots= &writeAnalysisGraphsPlotsCHull,
467066ee 97 }
08365995
BP
98};
99
c6356aa7 100
08365995
BP
101/*
102 * Analysis module registering function
103 */
2f961b65 104void registerAnalysisCHull()
08365995
BP
105{
106 g_queue_push_tail(&analysisModules, &analysisModuleCHull);
107}
108
109
110/*
111 * Analysis init function
112 *
113 * This function is called at the beginning of a synchronization run for a set
114 * of traces.
115 *
116 * Allocate some of the analysis specific data structures
117 *
118 * Args:
119 * syncState container for synchronization data.
120 * This function allocates or initializes these analysisData
121 * members:
122 * hullArray
123 * dropped
124 */
125static void initAnalysisCHull(SyncState* const syncState)
126{
127 unsigned int i, j;
128 AnalysisDataCHull* analysisData;
129
130 analysisData= malloc(sizeof(AnalysisDataCHull));
131 syncState->analysisData= analysisData;
132
133 analysisData->hullArray= malloc(syncState->traceNb * sizeof(GQueue**));
134 for (i= 0; i < syncState->traceNb; i++)
135 {
136 analysisData->hullArray[i]= malloc(syncState->traceNb * sizeof(GQueue*));
137
138 for (j= 0; j < syncState->traceNb; j++)
139 {
140 analysisData->hullArray[i][j]= g_queue_new();
141 }
142 }
143
144 if (syncState->stats)
145 {
146 analysisData->stats= malloc(sizeof(AnalysisStatsCHull));
147 analysisData->stats->dropped= 0;
148 analysisData->stats->allFactors= NULL;
149 }
150
8d7d16dd 151 if (syncState->graphsStream)
08365995
BP
152 {
153 analysisData->graphsData= malloc(sizeof(AnalysisGraphsDataCHull));
154 openGraphFiles(syncState);
155 analysisData->graphsData->allFactors= NULL;
156 }
157}
158
159
160/*
161 * Create and open files used to store convex hull points to genereate
162 * graphs. Allocate and populate array to store file pointers.
163 *
164 * Args:
165 * syncState: container for synchronization data
166 */
167static void openGraphFiles(SyncState* const syncState)
168{
169 unsigned int i, j;
170 int retval;
171 char* cwd;
172 char name[31];
173 AnalysisDataCHull* analysisData;
174
175 analysisData= (AnalysisDataCHull*) syncState->analysisData;
176
1d597550 177 cwd= changeToGraphsDir(syncState->graphsDir);
08365995
BP
178
179 analysisData->graphsData->hullPoints= malloc(syncState->traceNb *
180 sizeof(FILE**));
181 for (i= 0; i < syncState->traceNb; i++)
182 {
183 analysisData->graphsData->hullPoints[i]= malloc(syncState->traceNb *
184 sizeof(FILE*));
185 for (j= 0; j < syncState->traceNb; j++)
186 {
187 if (i != j)
188 {
189 retval= snprintf(name, sizeof(name),
190 "analysis_chull-%03u_to_%03u.data", j, i);
191 if (retval > sizeof(name) - 1)
192 {
193 name[sizeof(name) - 1]= '\0';
194 }
195 if ((analysisData->graphsData->hullPoints[i][j]= fopen(name, "w")) ==
196 NULL)
197 {
198 g_error(strerror(errno));
199 }
200 }
201 }
202 }
203
204 retval= chdir(cwd);
205 if (retval == -1)
206 {
207 g_error(strerror(errno));
208 }
209 free(cwd);
210}
211
212
213/*
214 * Write hull points to files to generate graphs.
215 *
216 * Args:
217 * syncState: container for synchronization data
218 */
219static void writeGraphFiles(SyncState* const syncState)
220{
221 unsigned int i, j;
222 AnalysisDataCHull* analysisData;
223
224 analysisData= (AnalysisDataCHull*) syncState->analysisData;
225
226 for (i= 0; i < syncState->traceNb; i++)
227 {
228 for (j= 0; j < syncState->traceNb; j++)
229 {
230 if (i != j)
231 {
232 g_queue_foreach(analysisData->hullArray[i][j],
233 &gfDumpHullToFile,
234 analysisData->graphsData->hullPoints[i][j]);
235 }
236 }
237 }
238}
239
240
241/*
242 * A GFunc for g_queue_foreach. Write a hull point to a file used to generate
243 * graphs
244 *
245 * Args:
246 * data: Point*, point to write to the file
247 * userData: FILE*, file pointer where to write the point
248 */
249static void gfDumpHullToFile(gpointer data, gpointer userData)
250{
251 Point* point;
252
253 point= (Point*) data;
053b4b77 254 fprintf((FILE*) userData, "%20" PRIu64 " %20" PRIu64 "\n", point->x, point->y);
08365995
BP
255}
256
257
258/*
259 * Close files used to store convex hull points to generate graphs.
260 * Deallocate array to store file pointers.
261 *
262 * Args:
263 * syncState: container for synchronization data
264 */
265static void closeGraphFiles(SyncState* const syncState)
266{
267 unsigned int i, j;
268 AnalysisDataCHull* analysisData;
269 int retval;
270
271 analysisData= (AnalysisDataCHull*) syncState->analysisData;
272
273 if (analysisData->graphsData->hullPoints == NULL)
274 {
275 return;
276 }
277
278 for (i= 0; i < syncState->traceNb; i++)
279 {
280 for (j= 0; j < syncState->traceNb; j++)
281 {
282 if (i != j)
283 {
284 retval= fclose(analysisData->graphsData->hullPoints[i][j]);
285 if (retval != 0)
286 {
287 g_error(strerror(errno));
288 }
289 }
290 }
291 free(analysisData->graphsData->hullPoints[i]);
292 }
293 free(analysisData->graphsData->hullPoints);
294 analysisData->graphsData->hullPoints= NULL;
295}
296
297
298/*
299 * Analysis destroy function
300 *
301 * Free the analysis specific data structures
302 *
303 * Args:
304 * syncState container for synchronization data.
305 * This function deallocates these analysisData members:
306 * hullArray
307 * stDev
308 */
309static void destroyAnalysisCHull(SyncState* const syncState)
310{
311 unsigned int i, j;
312 AnalysisDataCHull* analysisData;
313
314 analysisData= (AnalysisDataCHull*) syncState->analysisData;
315
316 if (analysisData == NULL)
317 {
318 return;
319 }
320
321 for (i= 0; i < syncState->traceNb; i++)
322 {
323 for (j= 0; j < syncState->traceNb; j++)
324 {
b2da0724
BP
325 g_queue_foreach(analysisData->hullArray[i][j], gfPointDestroy,
326 NULL);
6ce8ceac 327 g_queue_free(analysisData->hullArray[i][j]);
08365995
BP
328 }
329 free(analysisData->hullArray[i]);
330 }
331 free(analysisData->hullArray);
332
333 if (syncState->stats)
334 {
b2da0724 335 freeAllFactors(analysisData->stats->allFactors, syncState->traceNb);
08365995
BP
336
337 free(analysisData->stats);
338 }
339
8d7d16dd 340 if (syncState->graphsStream)
08365995
BP
341 {
342 if (analysisData->graphsData->hullPoints != NULL)
343 {
344 closeGraphFiles(syncState);
345 }
346
b2da0724
BP
347 freeAllFactors(analysisData->graphsData->allFactors,
348 syncState->traceNb);
08365995
BP
349
350 free(analysisData->graphsData);
351 }
352
353 free(syncState->analysisData);
354 syncState->analysisData= NULL;
355}
356
357
358/*
359 * Perform analysis on an event pair.
360 *
361 * Args:
362 * syncState container for synchronization data
10341d26 363 * message structure containing the events
08365995 364 */
10341d26 365static void analyzeMessageCHull(SyncState* const syncState, Message* const message)
08365995
BP
366{
367 AnalysisDataCHull* analysisData;
368 Point* newPoint;
369 HullType hullType;
370 GQueue* hull;
371
372 analysisData= (AnalysisDataCHull*) syncState->analysisData;
373
374 newPoint= malloc(sizeof(Point));
10341d26 375 if (message->inE->traceNum < message->outE->traceNum)
08365995
BP
376 {
377 // CA is inE->traceNum
76be6fc2
BP
378 newPoint->x= message->inE->cpuTime;
379 newPoint->y= message->outE->cpuTime;
08365995 380 hullType= UPPER;
053b4b77
BP
381 g_debug("Reception point hullArray[%lu][%lu] "
382 "x= inE->time= %" PRIu64 " y= outE->time= %" PRIu64,
10341d26 383 message->inE->traceNum, message->outE->traceNum, newPoint->x,
08365995
BP
384 newPoint->y);
385 }
386 else
387 {
388 // CA is outE->traceNum
76be6fc2
BP
389 newPoint->x= message->outE->cpuTime;
390 newPoint->y= message->inE->cpuTime;
08365995 391 hullType= LOWER;
053b4b77
BP
392 g_debug("Send point hullArray[%lu][%lu] "
393 "x= inE->time= %" PRIu64 " y= outE->time= %" PRIu64,
10341d26 394 message->inE->traceNum, message->outE->traceNum, newPoint->x,
08365995
BP
395 newPoint->y);
396 }
397
398 hull=
10341d26 399 analysisData->hullArray[message->inE->traceNum][message->outE->traceNum];
08365995
BP
400
401 if (hull->length >= 1 && newPoint->x < ((Point*)
402 g_queue_peek_tail(hull))->x)
403 {
404 if (syncState->stats)
405 {
406 analysisData->stats->dropped++;
407 }
408
409 free(newPoint);
410 }
411 else
412 {
413 grahamScan(hull, newPoint, hullType);
414 }
415}
416
417
418/*
419 * Construct one half of a convex hull from abscissa-sorted points
420 *
421 * Args:
422 * hull: the points already in the hull
423 * newPoint: a new point to consider
424 * type: which half of the hull to construct
425 */
426static void grahamScan(GQueue* const hull, Point* const newPoint, const
427 HullType type)
428{
429 int inversionFactor;
430
431 g_debug("grahamScan(hull (length: %u), newPoint, %s)", hull->length, type
432 == LOWER ? "LOWER" : "UPPER");
433
434 if (type == LOWER)
435 {
436 inversionFactor= 1;
437 }
438 else
439 {
440 inversionFactor= -1;
441 }
442
443 if (hull->length >= 2)
444 {
445 g_debug("jointCmp(hull[%u], hull[%u], newPoint) * inversionFactor = %d * %d = %d",
446 hull->length - 2,
447 hull->length - 1,
448 jointCmp(g_queue_peek_nth(hull, hull->length - 2),
449 g_queue_peek_tail(hull), newPoint),
450 inversionFactor,
451 jointCmp(g_queue_peek_nth(hull, hull->length - 2),
452 g_queue_peek_tail(hull), newPoint) * inversionFactor);
453 }
454 while (hull->length >= 2 && jointCmp(g_queue_peek_nth(hull, hull->length -
455 2), g_queue_peek_tail(hull), newPoint) * inversionFactor <= 0)
456 {
457 g_debug("Removing hull[%u]", hull->length);
458 free((Point*) g_queue_pop_tail(hull));
459
460 if (hull->length >= 2)
461 {
462 g_debug("jointCmp(hull[%u], hull[%u], newPoint) * inversionFactor = %d * %d = %d",
463 hull->length - 2,
464 hull->length - 1,
465 jointCmp(g_queue_peek_nth(hull, hull->length - 2),
466 g_queue_peek_tail(hull), newPoint),
467 inversionFactor,
468 jointCmp(g_queue_peek_nth(hull, hull->length - 2),
469 g_queue_peek_tail(hull), newPoint) * inversionFactor);
470 }
471 }
472 g_queue_push_tail(hull, newPoint);
473}
474
475
476/*
477 * Finalize the factor calculations
478 *
479 * Args:
480 * syncState container for synchronization data.
481 *
482 * Returns:
0a87ec9a
BP
483 * AllFactors* synchronization factors for each trace pair, the caller is
484 * responsible for freeing the structure
08365995 485 */
0a87ec9a 486static AllFactors* finalizeAnalysisCHull(SyncState* const syncState)
08365995
BP
487{
488 AnalysisDataCHull* analysisData;
0a87ec9a 489 AllFactors* allFactors;
08365995
BP
490
491 analysisData= (AnalysisDataCHull*) syncState->analysisData;
492
8d7d16dd 493 if (syncState->graphsStream && analysisData->graphsData->hullPoints != NULL)
08365995
BP
494 {
495 writeGraphFiles(syncState);
496 closeGraphFiles(syncState);
497 }
498
499 allFactors= calculateAllFactors(syncState);
500
0a87ec9a 501 if (syncState->stats)
08365995 502 {
0a87ec9a
BP
503 allFactors->refCount++;
504 analysisData->stats->allFactors= allFactors;
08365995 505 }
0a87ec9a
BP
506
507 if (syncState->graphsStream)
08365995 508 {
0a87ec9a
BP
509 allFactors->refCount++;
510 analysisData->graphsData->allFactors= allFactors;
08365995
BP
511 }
512
0a87ec9a 513 return allFactors;
08365995
BP
514}
515
516
517/*
518 * Print statistics related to analysis. Must be called after
519 * finalizeAnalysis.
520 *
521 * Args:
522 * syncState container for synchronization data.
523 */
524static void printAnalysisStatsCHull(SyncState* const syncState)
525{
526 AnalysisDataCHull* analysisData;
527 unsigned int i, j;
528
529 if (!syncState->stats)
530 {
531 return;
532 }
533
534 analysisData= (AnalysisDataCHull*) syncState->analysisData;
535
536 printf("Convex hull analysis stats:\n");
537 printf("\tout of order packets dropped from analysis: %u\n",
538 analysisData->stats->dropped);
539
540 printf("\tNumber of points in convex hulls:\n");
541
542 for (i= 0; i < syncState->traceNb; i++)
543 {
544 for (j= i + 1; j < syncState->traceNb; j++)
545 {
546 printf("\t\t%3d - %-3d: lower half-hull %-5u upper half-hull %-5u\n",
547 i, j, analysisData->hullArray[j][i]->length,
548 analysisData->hullArray[i][j]->length);
549 }
550 }
551
552 printf("\tIndividual synchronization factors:\n");
553
554 for (i= 0; i < syncState->traceNb; i++)
555 {
556 for (j= i + 1; j < syncState->traceNb; j++)
557 {
0a87ec9a 558 PairFactors* factorsCHull;
08365995 559
0a87ec9a 560 factorsCHull= &analysisData->stats->allFactors->pairFactors[j][i];
ce3dcf0e
BP
561 printf("\t\t%3d - %-3d: %s", i, j,
562 approxNames[factorsCHull->type]);
08365995
BP
563
564 if (factorsCHull->type == EXACT)
565 {
ce3dcf0e 566 printf(" a0= % 7g a1= 1 %c %7g\n",
08365995
BP
567 factorsCHull->approx->offset,
568 factorsCHull->approx->drift < 0. ? '-' : '+',
569 fabs(factorsCHull->approx->drift));
570 }
0a87ec9a 571 else if (factorsCHull->type == ACCURATE)
08365995 572 {
0a87ec9a 573 printf("\n\t\t a0: % 7g to % 7g (delta= %7g)\n",
08365995
BP
574 factorsCHull->max->offset, factorsCHull->min->offset,
575 factorsCHull->min->offset - factorsCHull->max->offset);
576 printf("\t\t a1: 1 %+7g to %+7g (delta= %7g)\n",
577 factorsCHull->min->drift - 1., factorsCHull->max->drift -
578 1., factorsCHull->max->drift - factorsCHull->min->drift);
579 }
0a87ec9a 580 else if (factorsCHull->type == APPROXIMATE)
08365995 581 {
ce3dcf0e 582 printf(" a0= % 7g a1= 1 %c %7g error= %7g\n",
08365995
BP
583 factorsCHull->approx->offset, factorsCHull->approx->drift
584 - 1. < 0. ? '-' : '+', fabs(factorsCHull->approx->drift -
585 1.), factorsCHull->accuracy);
586 }
587 else if (factorsCHull->type == INCOMPLETE)
588 {
ce3dcf0e 589 printf("\n");
08365995
BP
590
591 if (factorsCHull->min->drift != -INFINITY)
592 {
593 printf("\t\t min: a0: % 7g a1: 1 %c %7g\n",
594 factorsCHull->min->offset, factorsCHull->min->drift -
595 1. < 0 ? '-' : '+', fabs(factorsCHull->min->drift -
596 1.));
597 }
598 if (factorsCHull->max->drift != INFINITY)
599 {
600 printf("\t\t max: a0: % 7g a1: 1 %c %7g\n",
601 factorsCHull->max->offset, factorsCHull->max->drift -
602 1. < 0 ? '-' : '+', fabs(factorsCHull->max->drift -
603 1.));
604 }
605 }
606 else if (factorsCHull->type == SCREWED)
607 {
ce3dcf0e 608 printf("\n");
08365995
BP
609
610 if (factorsCHull->min != NULL && factorsCHull->min->drift != -INFINITY)
611 {
612 printf("\t\t min: a0: % 7g a1: 1 %c %7g\n",
613 factorsCHull->min->offset, factorsCHull->min->drift -
614 1. < 0 ? '-' : '+', fabs(factorsCHull->min->drift -
615 1.));
616 }
617 if (factorsCHull->max != NULL && factorsCHull->max->drift != INFINITY)
618 {
619 printf("\t\t max: a0: % 7g a1: 1 %c %7g\n",
620 factorsCHull->max->offset, factorsCHull->max->drift -
621 1. < 0 ? '-' : '+', fabs(factorsCHull->max->drift -
622 1.));
623 }
624 }
625 else if (factorsCHull->type == ABSENT)
626 {
ce3dcf0e 627 printf("\n");
08365995
BP
628 }
629 else
630 {
631 g_assert_not_reached();
632 }
633 }
634 }
635}
636
637
638/*
639 * A GFunc for g_queue_foreach()
640 *
641 * Args:
642 * data Point*, point to destroy
643 * user_data NULL
644 */
645static void gfPointDestroy(gpointer data, gpointer userData)
646{
647 Point* point;
648
649 point= (Point*) data;
650 free(point);
651}
652
653
654/*
655 * Find out if a sequence of three points constitutes a "left turn" or a
656 * "right turn".
657 *
658 * Args:
659 * p1, p2, p3: The three points.
660 *
661 * Returns:
662 * < 0 right turn
663 * 0 colinear (unlikely result since this uses floating point
664 * arithmetic)
665 * > 0 left turn
666 */
667static int jointCmp(const Point const* p1, const Point const* p2, const
668 Point const* p3)
669{
670 double result;
671 const double fuzzFactor= 0.;
672
673 result= crossProductK(p1, p2, p1, p3);
053b4b77
BP
674 g_debug("crossProductK(p1= (%" PRIu64 ", %" PRIu64 "), "
675 "p2= (%" PRIu64 ", %" PRIu64 "), p1= (%" PRIu64 ", %" PRIu64 "), "
676 "p3= (%" PRIu64 ", %" PRIu64 "))= %g",
08365995
BP
677 p1->x, p1->y, p2->x, p2->y, p1->x, p1->y, p3->x, p3->y, result);
678 if (result < fuzzFactor)
679 {
680 return -1;
681 }
682 else if (result > fuzzFactor)
683 {
684 return 1;
685 }
686 else
687 {
688 return 0;
689 }
690}
691
692
693/*
694 * Calculate the k component of the cross product of two vectors.
695 *
696 * Args:
697 * p1, p2: start and end points of the first vector
698 * p3, p4: start and end points of the second vector
699 *
700 * Returns:
701 * the k component of the cross product when considering the two vectors to
702 * be in the i-j plane. The direction (sign) of the result can be useful to
703 * determine the relative orientation of the two vectors.
704 */
705static double crossProductK(const Point const* p1, const Point const* p2,
706 const Point const* p3, const Point const* p4)
707{
708 return ((double) p2->x - p1->x) * ((double) p4->y - p3->y) - ((double)
709 p2->y - p1->y) * ((double) p4->x - p3->x);
710}
711
712
08365995
BP
713/*
714 * Analyze the convex hulls to determine the synchronization factors between
715 * each pair of trace.
716 *
717 * Args:
718 * syncState container for synchronization data.
719 *
720 * Returns:
0a87ec9a
BP
721 * AllFactors*, see the documentation for the member allFactors of
722 * AnalysisStatsCHull.
08365995 723 */
0a87ec9a 724AllFactors* calculateAllFactors(SyncState* const syncState)
08365995
BP
725{
726 unsigned int traceNumA, traceNumB;
0a87ec9a 727 AllFactors* allFactors;
08365995
BP
728 AnalysisDataCHull* analysisData;
729
730 analysisData= (AnalysisDataCHull*) syncState->analysisData;
731
732 // Allocate allFactors and calculate min and max
0a87ec9a 733 allFactors= createAllFactors(syncState->traceNb);
08365995
BP
734 for (traceNumA= 0; traceNumA < syncState->traceNb; traceNumA++)
735 {
08365995
BP
736 for (traceNumB= 0; traceNumB < traceNumA; traceNumB++)
737 {
738 unsigned int i;
739 GQueue* cs, * cr;
740 const struct
741 {
742 LineType lineType;
743 size_t factorsOffset;
744 } loopValues[]= {
0a87ec9a
BP
745 {MINIMUM, offsetof(PairFactors, min)},
746 {MAXIMUM, offsetof(PairFactors, max)}
08365995
BP
747 };
748
749 cr= analysisData->hullArray[traceNumB][traceNumA];
750 cs= analysisData->hullArray[traceNumA][traceNumB];
751
752 for (i= 0; i < sizeof(loopValues) / sizeof(*loopValues); i++)
753 {
0a87ec9a
BP
754 g_debug("allFactors[%u][%u].%s = calculateFactorsExact(cr= "
755 "hullArray[%u][%u], cs= hullArray[%u][%u], %s)",
08365995 756 traceNumA, traceNumB, loopValues[i].factorsOffset ==
0a87ec9a 757 offsetof(PairFactors, min) ? "min" : "max", traceNumB,
08365995
BP
758 traceNumA, traceNumA, traceNumB, loopValues[i].lineType ==
759 MINIMUM ? "MINIMUM" : "MAXIMUM");
0a87ec9a
BP
760 *((Factors**) ((void*)
761 &allFactors->pairFactors[traceNumA][traceNumB] +
08365995
BP
762 loopValues[i].factorsOffset))=
763 calculateFactorsExact(cr, cs, loopValues[i].lineType);
764 }
765 }
766 }
767
768 // Calculate approx when possible
769 for (traceNumA= 0; traceNumA < syncState->traceNb; traceNumA++)
770 {
771 for (traceNumB= 0; traceNumB < traceNumA; traceNumB++)
772 {
0a87ec9a 773 PairFactors* factorsCHull;
08365995 774
0a87ec9a 775 factorsCHull= &allFactors->pairFactors[traceNumA][traceNumB];
08365995
BP
776 if (factorsCHull->min == NULL && factorsCHull->max == NULL)
777 {
0a87ec9a 778 factorsCHull->type= APPROXIMATE;
08365995
BP
779 calculateFactorsFallback(analysisData->hullArray[traceNumB][traceNumA],
780 analysisData->hullArray[traceNumA][traceNumB],
0a87ec9a 781 &allFactors->pairFactors[traceNumA][traceNumB]);
08365995
BP
782 }
783 else if (factorsCHull->min != NULL && factorsCHull->max != NULL)
784 {
785 if (factorsCHull->min->drift != -INFINITY &&
786 factorsCHull->max->drift != INFINITY)
787 {
0a87ec9a 788 factorsCHull->type= ACCURATE;
08365995
BP
789 calculateFactorsMiddle(factorsCHull);
790 }
791 else if (factorsCHull->min->drift != -INFINITY ||
792 factorsCHull->max->drift != INFINITY)
793 {
794 factorsCHull->type= INCOMPLETE;
795 }
796 else
797 {
798 factorsCHull->type= ABSENT;
799 }
800 }
801 else
802 {
803 //g_assert_not_reached();
804 factorsCHull->type= SCREWED;
805 }
806 }
807 }
808
809 return allFactors;
810}
811
812
813/* Calculate approximative factors based on minimum and maximum limits. The
814 * best approximation to make is the interior bissector of the angle formed by
815 * the minimum and maximum lines.
816 *
817 * The formulae used come from [Haddad, Yoram: Performance dans les systèmes
818 * répartis: des outils pour les mesures, Université de Paris-Sud, Centre
819 * d'Orsay, September 1988] Section 6.1 p.44
820 *
821 * The reasoning for choosing this estimator comes from [Duda, A., Harrus, G.,
822 * Haddad, Y., and Bernard, G.: Estimating global time in distributed systems,
823 * Proc. 7th Int. Conf. on Distributed Computing Systems, Berlin, volume 18,
824 * 1987] p.303
825 *
826 * Args:
827 * factors: contains the min and max limits, used to store the result
828 */
0a87ec9a 829void calculateFactorsMiddle(PairFactors* const factors)
08365995
BP
830{
831 double amin, amax, bmin, bmax, bhat;
832
833 amin= factors->max->offset;
834 amax= factors->min->offset;
835 bmin= factors->min->drift;
836 bmax= factors->max->drift;
837
48b641c1 838 g_assert_cmpfloat(bmax, >=, bmin);
08365995
BP
839
840 factors->approx= malloc(sizeof(Factors));
841 bhat= (bmax * bmin - 1. + sqrt(1. + pow(bmax, 2.) * pow(bmin, 2.) +
842 pow(bmax, 2.) + pow(bmin, 2.))) / (bmax + bmin);
843 factors->approx->offset= amax - (amax - amin) / 2. * (pow(bhat, 2.) + 1.)
844 / (1. + bhat * bmax);
845 factors->approx->drift= bhat;
846 factors->accuracy= bmax - bmin;
847}
848
849
850/*
851 * Analyze the convex hulls to determine the minimum or maximum
852 * synchronization factors between one pair of trace.
853 *
854 * This implements and improves upon the algorithm in [Haddad, Yoram:
855 * Performance dans les systèmes répartis: des outils pour les mesures,
856 * Université de Paris-Sud, Centre d'Orsay, September 1988] Section 6.2 p.47
857 *
858 * Some degenerate cases are possible:
859 * 1) the result is unbounded. In that case, when searching for the maximum
860 * factors, result->drift= INFINITY; result->offset= -INFINITY. When
861 * searching for the minimum factors, it is the opposite. It is not
862 * possible to improve the situation with this data.
863 * 2) no line can be above the upper hull and below the lower hull. This is
864 * because the hulls intersect each other or are reversed. This means that
865 * an assertion was false. Most probably, the clocks are not linear. It is
866 * possible to repeat the search with another algorithm that will find a
867 * "best effort" approximation. See calculateFactorsApprox().
868 *
869 * Args:
870 * cu: the upper half-convex hull, the line must pass above this
871 * and touch it in one point
872 * cl: the lower half-convex hull, the line must pass below this
873 * and touch it in one point
874 * lineType: search for minimum or maximum factors
875 *
876 * Returns:
877 * If a result is found, a struct Factors is allocated, filed with the
878 * result and returned
879 * NULL otherwise, degenerate case 2 is in effect
880 */
881static Factors* calculateFactorsExact(GQueue* const cu, GQueue* const cl, const
882 LineType lineType)
883{
884 GQueue* c1, * c2;
885 unsigned int i1, i2;
886 Point* p1, * p2;
887 double inversionFactor;
888 Factors* result;
889
890 g_debug("calculateFactorsExact(cu= %p, cl= %p, %s)", cu, cl, lineType ==
891 MINIMUM ? "MINIMUM" : "MAXIMUM");
892
893 if (lineType == MINIMUM)
894 {
895 c1= cl;
896 c2= cu;
897 inversionFactor= -1.;
898 }
899 else
900 {
901 c1= cu;
902 c2= cl;
903 inversionFactor= 1.;
904 }
905
906 i1= 0;
907 i2= c2->length - 1;
908
909 // Check for degenerate case 1
910 if (c1->length == 0 || c2->length == 0 || ((Point*) g_queue_peek_nth(c1,
911 i1))->x >= ((Point*) g_queue_peek_nth(c2, i2))->x)
912 {
913 result= malloc(sizeof(Factors));
914 if (lineType == MINIMUM)
915 {
916 result->drift= -INFINITY;
917 result->offset= INFINITY;
918 }
919 else
920 {
921 result->drift= INFINITY;
922 result->offset= -INFINITY;
923 }
924
925 return result;
926 }
927
928 do
929 {
930 while
931 (
932 (int) i2 - 1 > 0
933 && crossProductK(
934 g_queue_peek_nth(c1, i1),
935 g_queue_peek_nth(c2, i2),
936 g_queue_peek_nth(c1, i1),
937 g_queue_peek_nth(c2, i2 - 1)) * inversionFactor < 0.
938 )
939 {
940 if (((Point*) g_queue_peek_nth(c1, i1))->x
941 < ((Point*) g_queue_peek_nth(c2, i2 - 1))->x)
942 {
943 i2--;
944 }
945 else
946 {
947 // Degenerate case 2
948 return NULL;
949 }
950 }
951 while
952 (
953 i1 + 1 < c1->length - 1
954 && crossProductK(
955 g_queue_peek_nth(c1, i1),
956 g_queue_peek_nth(c2, i2),
957 g_queue_peek_nth(c1, i1 + 1),
958 g_queue_peek_nth(c2, i2)) * inversionFactor < 0.
959 )
960 {
961 if (((Point*) g_queue_peek_nth(c1, i1 + 1))->x
962 < ((Point*) g_queue_peek_nth(c2, i2))->x)
963 {
964 i1++;
965 }
966 else
967 {
968 // Degenerate case 2
969 return NULL;
970 }
971 }
972 } while
973 (
974 (int) i2 - 1 > 0
975 && crossProductK(
976 g_queue_peek_nth(c1, i1),
977 g_queue_peek_nth(c2, i2),
978 g_queue_peek_nth(c1, i1),
979 g_queue_peek_nth(c2, i2 - 1)) * inversionFactor < 0.
980 );
981
982 p1= g_queue_peek_nth(c1, i1);
983 p2= g_queue_peek_nth(c2, i2);
984
053b4b77
BP
985 g_debug("Resulting points are: c1[i1]: x= %" PRIu64 " y= %" PRIu64
986 " c2[i2]: x= %" PRIu64 " y= %" PRIu64 "", p1->x, p1->y, p2->x, p2->y);
08365995
BP
987
988 result= malloc(sizeof(Factors));
989 result->drift= slope(p1, p2);
990 result->offset= intercept(p1, p2);
991
053b4b77
BP
992 g_debug("Resulting factors are: drift= %g offset= %g", result->drift,
993 result->offset);
08365995
BP
994
995 return result;
996}
997
998
999/*
1000 * Analyze the convex hulls to determine approximate synchronization factors
1001 * between one pair of trace when there is no line that can fit in the
1002 * corridor separating them.
1003 *
1004 * This implements the algorithm in [Ashton, P.: Algorithms for Off-line Clock
1005 * Synchronisation, University of Canterbury, December 1995, 26] Section 4.2.2
1006 * p.7
1007 *
1008 * For each point p1 in cr
1009 * For each point p2 in cs
1010 * errorMin= 0
1011 * Calculate the line paramaters
1012 * For each point p3 in each convex hull
1013 * If p3 is on the wrong side of the line
1014 * error+= distance
1015 * If error < errorMin
1016 * Update results
1017 *
1018 * Args:
1019 * cr: the upper half-convex hull
1020 * cs: the lower half-convex hull
1021 * result: a pointer to the pre-allocated struct where the results
1022 * will be stored
1023 */
1024static void calculateFactorsFallback(GQueue* const cr, GQueue* const cs,
0a87ec9a 1025 PairFactors* const result)
08365995
BP
1026{
1027 unsigned int i, j, k;
1028 double errorMin;
1029 Factors* approx;
1030
1031 errorMin= INFINITY;
1032 approx= malloc(sizeof(Factors));
1033
1034 for (i= 0; i < cs->length; i++)
1035 {
1036 for (j= 0; j < cr->length; j++)
1037 {
1038 double error;
1039 Point p1, p2;
1040
1041 error= 0.;
1042
1043 if (((Point*) g_queue_peek_nth(cs, i))->x < ((Point*)g_queue_peek_nth(cr, j))->x)
1044 {
1045 p1= *(Point*)g_queue_peek_nth(cs, i);
1046 p2= *(Point*)g_queue_peek_nth(cr, j);
1047 }
1048 else
1049 {
1050 p1= *(Point*)g_queue_peek_nth(cr, j);
1051 p2= *(Point*)g_queue_peek_nth(cs, i);
1052 }
1053
1054 // The lower hull should be above the point
1055 for (k= 0; k < cs->length; k++)
1056 {
1057 if (jointCmp(&p1, &p2, g_queue_peek_nth(cs, k)) < 0.)
1058 {
1059 error+= verticalDistance(&p1, &p2, g_queue_peek_nth(cs, k));
1060 }
1061 }
1062
1063 // The upper hull should be below the point
1064 for (k= 0; k < cr->length; k++)
1065 {
1066 if (jointCmp(&p1, &p2, g_queue_peek_nth(cr, k)) > 0.)
1067 {
1068 error+= verticalDistance(&p1, &p2, g_queue_peek_nth(cr, k));
1069 }
1070 }
1071
1072 if (error < errorMin)
1073 {
1074 g_debug("Fallback: i= %u j= %u is a better match (error= %g)", i, j, error);
1075 approx->drift= slope(&p1, &p2);
1076 approx->offset= intercept(&p1, &p2);
1077 errorMin= error;
1078 }
1079 }
1080 }
1081
1082 result->approx= approx;
1083 result->accuracy= errorMin;
1084}
1085
1086
1087/*
1088 * Calculate the vertical distance between a line and a point
1089 *
1090 * Args:
1091 * p1, p2: Two points defining the line
1092 * point: a point
1093 *
1094 * Return:
1095 * the vertical distance
1096 */
1097static double verticalDistance(Point* p1, Point* p2, Point* const point)
1098{
1099 return fabs(slope(p1, p2) * point->x + intercept(p1, p2) - point->y);
1100}
1101
1102
1103/*
1104 * Calculate the slope between two points
1105 *
1106 * Args:
1107 * p1, p2 the two points
1108 *
1109 * Returns:
1110 * the slope
1111 */
1112static double slope(const Point* const p1, const Point* const p2)
1113{
1114 return ((double) p2->y - p1->y) / (p2->x - p1->x);
1115}
1116
1117
1118/* Calculate the y-intercept of a line that passes by two points
1119 *
1120 * Args:
1121 * p1, p2 the two points
1122 *
1123 * Returns:
1124 * the y-intercept
1125 */
1126static double intercept(const Point* const p1, const Point* const p2)
1127{
1128 return ((double) p2->y * p1->x - (double) p1->y * p2->x) / ((double) p1->x - p2->x);
1129}
1130
1131
08365995
BP
1132/*
1133 * Write the analysis-specific graph lines in the gnuplot script.
1134 *
1135 * Args:
08365995
BP
1136 * syncState: container for synchronization data
1137 * i: first trace number
1138 * j: second trace number, garanteed to be larger than i
1139 */
8d7d16dd
BP
1140void writeAnalysisGraphsPlotsCHull(SyncState* const syncState, const unsigned
1141 int i, const unsigned int j)
08365995
BP
1142{
1143 AnalysisDataCHull* analysisData;
0a87ec9a 1144 PairFactors* factorsCHull;
08365995
BP
1145
1146 analysisData= (AnalysisDataCHull*) syncState->analysisData;
1147
8d7d16dd 1148 fprintf(syncState->graphsStream,
08365995
BP
1149 "\t\"analysis_chull-%1$03d_to_%2$03d.data\" "
1150 "title \"Lower half-hull\" with linespoints "
1151 "linecolor rgb \"#015a01\" linetype 4 pointtype 8 pointsize 0.8, \\\n"
1152 "\t\"analysis_chull-%2$03d_to_%1$03d.data\" "
1153 "title \"Upper half-hull\" with linespoints "
1154 "linecolor rgb \"#003366\" linetype 4 pointtype 10 pointsize 0.8, \\\n",
1155 i, j);
1156
0a87ec9a 1157 factorsCHull= &analysisData->graphsData->allFactors->pairFactors[j][i];
08365995
BP
1158 if (factorsCHull->type == EXACT)
1159 {
8d7d16dd 1160 fprintf(syncState->graphsStream,
08365995
BP
1161 "\t%7g + %7g * x "
1162 "title \"Exact conversion\" with lines "
1163 "linecolor rgb \"black\" linetype 1, \\\n",
1164 factorsCHull->approx->offset, factorsCHull->approx->drift);
1165 }
0a87ec9a 1166 else if (factorsCHull->type == ACCURATE)
08365995 1167 {
8d7d16dd 1168 fprintf(syncState->graphsStream,
08365995
BP
1169 "\t%.2f + %.10f * x "
1170 "title \"Min conversion\" with lines "
1171 "linecolor rgb \"black\" linetype 5, \\\n",
1172 factorsCHull->min->offset, factorsCHull->min->drift);
8d7d16dd 1173 fprintf(syncState->graphsStream,
08365995
BP
1174 "\t%.2f + %.10f * x "
1175 "title \"Max conversion\" with lines "
1176 "linecolor rgb \"black\" linetype 8, \\\n",
1177 factorsCHull->max->offset, factorsCHull->max->drift);
8d7d16dd 1178 fprintf(syncState->graphsStream,
08365995
BP
1179 "\t%.2f + %.10f * x "
1180 "title \"Middle conversion\" with lines "
66eaf2eb 1181 "linecolor rgb \"black\" linetype 1, \\\n",
08365995
BP
1182 factorsCHull->approx->offset, factorsCHull->approx->drift);
1183 }
0a87ec9a 1184 else if (factorsCHull->type == APPROXIMATE)
08365995 1185 {
8d7d16dd 1186 fprintf(syncState->graphsStream,
08365995
BP
1187 "\t%.2f + %.10f * x "
1188 "title \"Fallback conversion\" with lines "
1189 "linecolor rgb \"gray60\" linetype 1, \\\n",
1190 factorsCHull->approx->offset, factorsCHull->approx->drift);
1191 }
1192 else if (factorsCHull->type == INCOMPLETE)
1193 {
1194 if (factorsCHull->min->drift != -INFINITY)
1195 {
8d7d16dd 1196 fprintf(syncState->graphsStream,
08365995
BP
1197 "\t%.2f + %.10f * x "
1198 "title \"Min conversion\" with lines "
1199 "linecolor rgb \"black\" linetype 5, \\\n",
1200 factorsCHull->min->offset, factorsCHull->min->drift);
1201 }
1202
1203 if (factorsCHull->max->drift != INFINITY)
1204 {
8d7d16dd 1205 fprintf(syncState->graphsStream,
08365995
BP
1206 "\t%.2f + %.10f * x "
1207 "title \"Max conversion\" with lines "
1208 "linecolor rgb \"black\" linetype 8, \\\n",
1209 factorsCHull->max->offset, factorsCHull->max->drift);
1210 }
1211 }
1212 else if (factorsCHull->type == SCREWED)
1213 {
1214 if (factorsCHull->min != NULL && factorsCHull->min->drift != -INFINITY)
1215 {
8d7d16dd 1216 fprintf(syncState->graphsStream,
08365995
BP
1217 "\t%.2f + %.10f * x "
1218 "title \"Min conversion\" with lines "
1219 "linecolor rgb \"black\" linetype 5, \\\n",
1220 factorsCHull->min->offset, factorsCHull->min->drift);
1221 }
1222
1223 if (factorsCHull->max != NULL && factorsCHull->max->drift != INFINITY)
1224 {
8d7d16dd 1225 fprintf(syncState->graphsStream,
08365995
BP
1226 "\t%.2f + %.10f * x "
1227 "title \"Max conversion\" with lines "
1228 "linecolor rgb \"black\" linetype 8, \\\n",
1229 factorsCHull->max->offset, factorsCHull->max->drift);
1230 }
1231 }
1232 else if (factorsCHull->type == ABSENT)
1233 {
1234 }
1235 else
1236 {
1237 g_assert_not_reached();
1238 }
1239}
This page took 0.075948 seconds and 4 git commands to generate.