Remove unused g_info definitions
[lttv.git] / lttv / lttv / sync / event_analysis_linreg.c
CommitLineData
70407e86
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
19// for INFINITY in math.h
20#define _ISOC99_SOURCE
21
22#ifdef HAVE_CONFIG_H
23#include <config.h>
24#endif
25
26#include <math.h>
27#include <stdio.h>
28#include <stdlib.h>
29
2bd4b3e4 30#include "sync_chain.h"
70407e86
BP
31
32#include "event_analysis_linreg.h"
33
34
70407e86
BP
35// Functions common to all analysis modules
36static void initAnalysisLinReg(SyncState* const syncState);
37static void destroyAnalysisLinReg(SyncState* const syncState);
38
10341d26 39static void analyzeExchangeLinReg(SyncState* const syncState, Exchange* const exchange);
70407e86
BP
40static GArray* finalizeAnalysisLinReg(SyncState* const syncState);
41static void printAnalysisStatsLinReg(SyncState* const syncState);
8d7d16dd
BP
42static void writeAnalysisGraphsPlotsLinReg(SyncState* const syncState, const
43 unsigned int i, const unsigned int j);
70407e86
BP
44
45// Functions specific to this module
08365995 46static void registerAnalysisLinReg() __attribute__((constructor (102)));
70407e86
BP
47
48static void finalizeLSA(SyncState* const syncState);
49static void doGraphProcessing(SyncState* const syncState);
50static GArray* calculateFactors(SyncState* const syncState);
51static void shortestPath(Fit* const* const fitArray, const unsigned int
52 traceNum, const unsigned int traceNb, double* const distances,
53 unsigned int* const previousVertex);
54static double sumDistances(const double* const distances, const unsigned int
55 traceNb);
56static void reduceFactors(Fit* const* const fitArray, const unsigned int* const
57 previousVertex, const unsigned int traceNum, double* const drift,
58 double* const offset, double* const stDev);
59
60// Graph-related Glib functions
61static void gfGraphDestroy(gpointer data, gpointer user_data);
62static gint gcfGraphTraceCompare(gconstpointer a, gconstpointer b);
63
64
65static AnalysisModule analysisModuleLinReg= {
66 .name= "linreg",
67 .initAnalysis= &initAnalysisLinReg,
68 .destroyAnalysis= &destroyAnalysisLinReg,
70407e86
BP
69 .analyzeExchange= &analyzeExchangeLinReg,
70 .finalizeAnalysis= &finalizeAnalysisLinReg,
71 .printAnalysisStats= &printAnalysisStatsLinReg,
467066ee 72 .graphFunctions= {
c6356aa7 73 .writeTraceTraceForePlots= &writeAnalysisGraphsPlotsLinReg,
467066ee 74 }
70407e86
BP
75};
76
77
78/*
79 * Analysis module registering function
80 */
81static void registerAnalysisLinReg()
82{
83 g_queue_push_tail(&analysisModules, &analysisModuleLinReg);
84}
85
86
87/*
88 * Analysis init function
89 *
90 * This function is called at the beginning of a synchronization run for a set
91 * of traces.
92 *
93 * Allocate some of the analysis specific data structures
94 *
95 * Args:
96 * syncState container for synchronization data.
97 * This function allocates these analysisData members:
98 * fitArray
99 * stDev
100 */
101static void initAnalysisLinReg(SyncState* const syncState)
102{
103 unsigned int i;
104 AnalysisDataLinReg* analysisData;
105
106 analysisData= malloc(sizeof(AnalysisDataLinReg));
107 syncState->analysisData= analysisData;
108
109 analysisData->fitArray= malloc(syncState->traceNb * sizeof(Fit*));
110 for (i= 0; i < syncState->traceNb; i++)
111 {
112 analysisData->fitArray[i]= calloc(syncState->traceNb, sizeof(Fit));
113 }
114
115 if (syncState->stats)
116 {
117 analysisData->stDev= malloc(sizeof(double) * syncState->traceNb);
118 }
119}
120
121
122/*
123 * Analysis destroy function
124 *
125 * Free the analysis specific data structures
126 *
127 * Args:
128 * syncState container for synchronization data.
129 * This function deallocates these analysisData members:
130 * fitArray
131 * graphList
132 * stDev
133 */
134static void destroyAnalysisLinReg(SyncState* const syncState)
135{
136 unsigned int i;
137 AnalysisDataLinReg* analysisData;
138
139 analysisData= (AnalysisDataLinReg*) syncState->analysisData;
140
141 if (analysisData == NULL)
142 {
143 return;
144 }
145
146 for (i= 0; i < syncState->traceNb; i++)
147 {
148 free(analysisData->fitArray[i]);
149 }
150 free(analysisData->fitArray);
151
152 g_queue_foreach(analysisData->graphList, &gfGraphDestroy, NULL);
153 g_queue_free(analysisData->graphList);
154
155 if (syncState->stats)
156 {
157 free(analysisData->stDev);
158 }
159
160 free(syncState->analysisData);
161 syncState->analysisData= NULL;
162}
163
164
165/*
166 * Perform analysis on a series of event pairs.
167 *
70407e86
BP
168 * Args:
169 * syncState container for synchronization data
10341d26 170 * exchange structure containing the many events
70407e86 171 */
10341d26 172static void analyzeExchangeLinReg(SyncState* const syncState, Exchange* const exchange)
70407e86
BP
173{
174 unsigned int ni, nj;
175 double dji, eji;
176 double timoy;
177 Fit* fit;
10341d26 178 Message* ackedMessage;
70407e86
BP
179 AnalysisDataLinReg* analysisData;
180
181 g_debug("Synchronization calculation, ");
182 g_debug("%d acked packets - using last one, ",
10341d26 183 g_queue_get_length(exchange->acks));
70407e86
BP
184
185 analysisData= (AnalysisDataLinReg*) syncState->analysisData;
10341d26 186 ackedMessage= g_queue_peek_tail(exchange->acks);
70407e86
BP
187
188 // Calculate the intermediate values for the
189 // least-squares analysis
76be6fc2
BP
190 dji= ((double) ackedMessage->inE->cpuTime - (double) ackedMessage->outE->cpuTime
191 + (double) exchange->message->outE->cpuTime - (double)
192 exchange->message->inE->cpuTime) / 2;
193 eji= fabs((double) ackedMessage->inE->cpuTime - (double)
194 ackedMessage->outE->cpuTime - (double) exchange->message->outE->cpuTime +
195 (double) exchange->message->inE->cpuTime) / 2;
196 timoy= ((double) ackedMessage->outE->cpuTime + (double)
197 exchange->message->inE->cpuTime) / 2;
10341d26
BP
198 ni= ackedMessage->outE->traceNum;
199 nj= ackedMessage->inE->traceNum;
70407e86
BP
200 fit= &analysisData->fitArray[nj][ni];
201
202 fit->n++;
203 fit->st+= timoy;
204 fit->st2+= pow(timoy, 2);
205 fit->sd+= dji;
206 fit->sd2+= pow(dji, 2);
207 fit->std+= timoy * dji;
208
209 g_debug("intermediate values: dji= %f ti moy= %f "
210 "ni= %u nj= %u fit: n= %u st= %f st2= %f sd= %f "
211 "sd2= %f std= %f, ", dji, timoy, ni, nj, fit->n,
212 fit->st, fit->st2, fit->sd, fit->sd2, fit->std);
213}
214
215
216/*
217 * Finalize the factor calculations
218 *
219 * The least squares analysis is finalized and finds the factors directly
220 * between each pair of traces that had events together. The traces are
221 * aranged in a graph, a reference trace is chosen and the factors between
222 * this reference and every other trace is calculated. Sometimes it is
223 * necessary to use many graphs when there are "islands" of independent
224 * traces.
225 *
226 * Args:
227 * syncState container for synchronization data.
228 *
229 * Returns:
230 * Factors[traceNb] synchronization factors for each trace
231 */
232static GArray* finalizeAnalysisLinReg(SyncState* const syncState)
233{
234 GArray* factors;
235
236 // Finalize the processing
237 finalizeLSA(syncState);
238
239 // Find a reference node and structure nodes in a graph
240 doGraphProcessing(syncState);
241
242 /* Calculate the resulting offset and drift between each trace and its
243 * reference
244 */
245 factors= calculateFactors(syncState);
246
247 return factors;
248}
249
250
251/*
252 * Print statistics related to analysis. Must be called after
253 * finalizeAnalysis.
254 *
255 * Args:
256 * syncState container for synchronization data.
257 */
258static void printAnalysisStatsLinReg(SyncState* const syncState)
259{
260 unsigned int i, j;
261 AnalysisDataLinReg* analysisData;
262
263 if (!syncState->stats)
264 {
265 return;
266 }
267
268 analysisData= (AnalysisDataLinReg*) syncState->analysisData;
269
270 printf("Linear regression analysis stats:\n");
271
272 printf("\tIndividual synchronization factors:\n");
273
274 for (j= 0; j < syncState->traceNb; j++)
275 {
276 for (i= 0; i < j; i++)
277 {
278 Fit* fit;
279
280 fit= &analysisData->fitArray[j][i];
281 printf("\t\t%3d - %-3d: ", i, j);
282 printf("a0= % 7g a1= 1 %c %7g accuracy %7g\n", fit->d0, fit->x <
283 0. ? '-' : '+', fabs(fit->x), fit->e);
284
285 fit= &analysisData->fitArray[i][j];
286 printf("\t\t%3d - %-3d: ", j, i);
287 printf("a0= % 7g a1= 1 %c %7g accuracy %7g\n", fit->d0, fit->x <
288 0. ? '-' : '+', fabs(fit->x), fit->e);
289 }
290 }
291
292 printf("\tTree:\n");
293 for (i= 0; i < syncState->traceNb; i++)
294 {
295 GList* result;
296
297 result= g_queue_find_custom(analysisData->graphList, &i,
298 &gcfGraphTraceCompare);
299 if (result != NULL)
300 {
301 Graph* graph;
302
303 graph= (Graph*) result->data;
304
305 printf("\t\ttrace %u reference %u previous vertex ", i,
306 graph->reference);
307
308 if (i == graph->reference)
309 {
310 printf("- ");
311 }
312 else
313 {
314 printf("%u ", graph->previousVertex[i]);
315 }
316
317 printf("stdev= %g\n", analysisData->stDev[i]);
318 }
319 else
320 {
321 g_error("Trace %d not part of a graph\n", i);
322 }
323 }
324}
325
326
327/*
328 * Finalize the least-squares analysis. The intermediate values in the fit
329 * array are used to calculate the drift and the offset between each pair of
330 * nodes based on their exchanges.
331 *
332 * Args:
333 * syncState: container for synchronization data.
334 */
335static void finalizeLSA(SyncState* const syncState)
336{
337 unsigned int i, j;
338 AnalysisDataLinReg* analysisData;
339
340 analysisData= (AnalysisDataLinReg*) syncState->analysisData;
341
342 for (i= 0; i < syncState->traceNb; i++)
343 {
344 for (j= 0; j < syncState->traceNb; j++)
345 {
346 if (i != j)
347 {
348 Fit* fit;
349 double delta;
350
351 fit= &analysisData->fitArray[i][j];
352
353 delta= fit->n * fit->st2 - pow(fit->st, 2);
354 fit->x= (fit->n * fit->std - fit->st * fit->sd) / delta;
355 fit->d0= (fit->st2 * fit->sd - fit->st * fit->std) / delta;
356 fit->e= sqrt((fit->sd2 - (fit->n * pow(fit->std, 2) +
357 pow(fit->sd, 2) * fit->st2 - 2 * fit->st * fit->sd
358 * fit->std) / delta) / (fit->n - 2));
359
360 g_debug("[i= %u j= %u]\n", i, j);
361 g_debug("n= %d st= %g st2= %g sd= %g sd2= %g std= %g\n",
362 fit->n, fit->st, fit->st2, fit->sd, fit->sd2, fit->std);
363 g_debug("xij= %g d0ij= %g e= %g\n", fit->x, fit->d0, fit->e);
364 g_debug("(xji= %g d0ji= %g)\n", -fit->x / (1 + fit->x),
365 -fit->d0 / (1 + fit->x));
366 }
367 }
368 }
369}
370
371
372/*
373 * Structure nodes in graphs of nodes that had exchanges. Each graph has a
374 * reference node, the one that can reach the others with the smallest
375 * cummulative error.
376 *
377 * Args:
378 * syncState: container for synchronization data.
379 * This function allocates these analysisData members:
380 * graphList
381 */
382static void doGraphProcessing(SyncState* const syncState)
383{
384 unsigned int i, j;
385 double* distances;
386 unsigned int* previousVertex;
387 AnalysisDataLinReg* analysisData;
388
389 analysisData= (AnalysisDataLinReg*) syncState->analysisData;
390
391 distances= malloc(syncState->traceNb * sizeof(double));
392 previousVertex= malloc(syncState->traceNb * sizeof(unsigned int));
393 analysisData->graphList= g_queue_new();
394
395 for (i= 0; i < syncState->traceNb; i++)
396 {
397 double errorSum;
398 GList* result;
399
400 // Perform shortest path search
401 g_debug("shortest path trace %d\ndistances: ", i);
402 shortestPath(analysisData->fitArray, i, syncState->traceNb, distances,
403 previousVertex);
404
405 for (j= 0; j < syncState->traceNb; j++)
406 {
407 g_debug("%g, ", distances[j]);
408 }
409 g_debug("\npreviousVertex: ");
410 for (j= 0; j < syncState->traceNb; j++)
411 {
412 g_debug("%u, ", previousVertex[j]);
413 }
414 g_debug("\n");
415
416 // Group in graphs nodes that have exchanges
417 errorSum= sumDistances(distances, syncState->traceNb);
418 result= g_queue_find_custom(analysisData->graphList, &i,
419 &gcfGraphTraceCompare);
420 if (result != NULL)
421 {
422 Graph* graph;
423
424 g_debug("found graph\n");
425 graph= (Graph*) result->data;
426 if (errorSum < graph->errorSum)
427 {
428 g_debug("adding to graph\n");
429 graph->errorSum= errorSum;
430 free(graph->previousVertex);
431 graph->previousVertex= previousVertex;
432 graph->reference= i;
433 previousVertex= malloc(syncState->traceNb * sizeof(unsigned
434 int));
435 }
436 }
437 else
438 {
439 Graph* newGraph;
440
441 g_debug("creating new graph\n");
442 newGraph= malloc(sizeof(Graph));
443 newGraph->errorSum= errorSum;
444 newGraph->previousVertex= previousVertex;
445 newGraph->reference= i;
446 previousVertex= malloc(syncState->traceNb * sizeof(unsigned int));
447
448 g_queue_push_tail(analysisData->graphList, newGraph);
449 }
450 }
451
452 free(previousVertex);
453 free(distances);
454}
455
456
457/*
458 * Calculate the resulting offset and drift between each trace and its
459 * reference.
460 *
461 * Args:
462 * syncState: container for synchronization data.
463 *
464 * Returns:
465 * Factors[traceNb] synchronization factors for each trace
466 */
467static GArray* calculateFactors(SyncState* const syncState)
468{
469 unsigned int i;
470 AnalysisDataLinReg* analysisData;
471 GArray* factors;
472
473 analysisData= (AnalysisDataLinReg*) syncState->analysisData;
474 factors= g_array_sized_new(FALSE, FALSE, sizeof(Factors),
475 syncState->traceNb);
08365995 476 g_array_set_size(factors, syncState->traceNb);
70407e86
BP
477
478 // Calculate the resulting offset and drift between each trace and its
479 // reference
480 for (i= 0; i < syncState->traceNb; i++)
481 {
482 GList* result;
483
484 result= g_queue_find_custom(analysisData->graphList, &i,
485 &gcfGraphTraceCompare);
486 if (result != NULL)
487 {
488 Graph* graph;
489 double stDev;
490 Factors* traceFactors;
491
492 graph= (Graph*) result->data;
493 traceFactors= &g_array_index(factors, Factors, i);
494
495 reduceFactors(analysisData->fitArray, graph->previousVertex, i,
496 &traceFactors->drift, &traceFactors->offset, &stDev);
497
498 if (syncState->stats)
499 {
500 analysisData->stDev[i]= stDev;
501 }
502 }
503 else
504 {
505 g_error("Trace %d not part of a graph\n", i);
506 }
507 }
508
509 return factors;
510}
511
512
513/*
514 * Single-source shortest path search to find the path with the lowest error to
515 * convert one node's time to another.
516 * Uses Dijkstra's algorithm
517 *
518 * Args:
519 * fitArray: array with the regression parameters
520 * traceNum: reference node
521 * traceNb: number of traces = number of nodes
522 * distances: array of computed distance from source node to node i,
523 * INFINITY if i is unreachable, preallocated to the number of
524 * nodes
525 * previousVertex: previous vertex from a node i on the way to the source,
526 * UINT_MAX if i is not on the way or is the source,
527 * preallocated to the number of nodes
528 */
529static void shortestPath(Fit* const* const fitArray, const unsigned int
530 traceNum, const unsigned int traceNb, double* const distances, unsigned
531 int* const previousVertex)
532{
533 bool* visited;
534 unsigned int i, j;
535
536 visited= malloc(traceNb * sizeof(bool));
537
538 for (i= 0; i < traceNb; i++)
539 {
540 const Fit* fit;
541
542 visited[i]= false;
543
544 fit= &fitArray[traceNum][i];
545 g_debug("fitArray[traceNum= %u][i= %u]->n = %u\n", traceNum, i, fit->n);
546 if (fit->n > 0)
547 {
548 distances[i]= fit->e;
549 previousVertex[i]= traceNum;
550 }
551 else
552 {
553 distances[i]= INFINITY;
554 previousVertex[i]= UINT_MAX;
555 }
556 }
557 visited[traceNum]= true;
558
559 for (j= 0; j < traceNb; j++)
560 {
561 g_debug("(%d, %u, %g), ", visited[j], previousVertex[j], distances[j]);
562 }
563 g_debug("\n");
564
565 for (i= 0; i < traceNb - 2; i++)
566 {
567 unsigned int v;
568 double dvMin;
569
570 dvMin= INFINITY;
571 for (j= 0; j < traceNb; j++)
572 {
573 if (visited[j] == false && distances[j] < dvMin)
574 {
575 v= j;
576 dvMin= distances[j];
577 }
578 }
579
580 g_debug("v= %u dvMin= %g\n", v, dvMin);
581
582 if (dvMin != INFINITY)
583 {
584 visited[v]= true;
585
586 for (j= 0; j < traceNb; j++)
587 {
588 const Fit* fit;
589
590 fit= &fitArray[v][j];
591 if (visited[j] == false && fit->n > 0 && distances[v] + fit->e
592 < distances[j])
593 {
594 distances[j]= distances[v] + fit->e;
595 previousVertex[j]= v;
596 }
597 }
598 }
599 else
600 {
601 break;
602 }
603
604 for (j= 0; j < traceNb; j++)
605 {
606 g_debug("(%d, %u, %g), ", visited[j], previousVertex[j], distances[j]);
607 }
608 g_debug("\n");
609 }
610
611 free(visited);
612}
613
614
615/*
616 * Cummulate the distances between a reference node and the other nodes
617 * reachable from it in a graph.
618 *
619 * Args:
620 * distances: array of shortest path distances, with UINT_MAX for
621 * unreachable nodes
622 * traceNb: number of nodes = number of traces
623 */
624static double sumDistances(const double* const distances, const unsigned int traceNb)
625{
626 unsigned int i;
627 double result;
628
629 result= 0;
630 for (i= 0; i < traceNb; i++)
631 {
632 if (distances[i] != INFINITY)
633 {
634 result+= distances[i];
635 }
636 }
637
638 return result;
639}
640
641
642/*
643 * Cummulate the time correction factors between two nodes accross a graph
644 *
645 * With traceNum i, reference node r:
646 * tr= (1 + Xri) * ti + D0ri
647 * = drift * ti + offset
648 *
649 * Args:
650 * fitArray: array with the regression parameters
651 * previousVertex: previous vertex from a node i on the way to the source,
652 * UINT_MAX if i is not on the way or is the source,
653 * preallocated to the number of nodes
654 * traceNum: end node, the reference depends on previousVertex
655 * drift: drift factor
656 * offset: offset factor
657 */
658static void reduceFactors(Fit* const* const fitArray, const unsigned int* const
659 previousVertex, const unsigned int traceNum, double* const drift, double*
660 const offset, double* const stDev)
661{
662 if (previousVertex[traceNum] == UINT_MAX)
663 {
664 *drift= 1.;
665 *offset= 0.;
666 *stDev= 0.;
667 }
668 else
669 {
670 const Fit* fit;
671 double cummDrift, cummOffset, cummStDev;
672 unsigned int pv;
673
674 pv= previousVertex[traceNum];
675
676 fit= &fitArray[pv][traceNum];
677 reduceFactors(fitArray, previousVertex, pv, &cummDrift, &cummOffset,
678 &cummStDev);
679
680 *drift= cummDrift * (1 + fit->x);
681 *offset= cummDrift * fit->d0 + cummOffset;
682 *stDev= fit->x * cummStDev + fit->e;
683 }
684}
685
686
687/*
688 * A GFunc for g_queue_foreach()
689 *
690 * Args:
691 * data Graph*, graph to destroy
692 * user_data NULL
693 */
694static void gfGraphDestroy(gpointer data, gpointer user_data)
695{
696 Graph* graph;
697
698 graph= (Graph*) data;
699
700 free(graph->previousVertex);
701 free(graph);
702}
703
704
705/*
706 * A GCompareFunc for g_queue_find_custom()
707 *
708 * Args:
709 * a: Graph* graph
710 * b: unsigned int* traceNum
711 *
712 * Returns:
713 * 0 if graph contains traceNum
714 */
715static gint gcfGraphTraceCompare(gconstpointer a, gconstpointer b)
716{
717 Graph* graph;
718 unsigned int traceNum;
719
720 graph= (Graph*) a;
721 traceNum= *(unsigned int *) b;
722
723 if (graph->previousVertex[traceNum] != UINT_MAX)
724 {
725 return 0;
726 }
727 else if (graph->reference == traceNum)
728 {
729 return 0;
730 }
731 else
732 {
733 return 1;
734 }
735}
736
08365995
BP
737
738/*
739 * Write the analysis-specific graph lines in the gnuplot script.
740 *
741 * Args:
08365995
BP
742 * syncState: container for synchronization data
743 * i: first trace number, on the x axis
744 * j: second trace number, garanteed to be larger than i
745 */
8d7d16dd
BP
746void writeAnalysisGraphsPlotsLinReg(SyncState* const syncState, const unsigned
747 int i, const unsigned int j)
08365995
BP
748{
749 AnalysisDataLinReg* analysisData;
750 Fit* fit;
751
752 analysisData= (AnalysisDataLinReg*) syncState->analysisData;
753 fit= &analysisData->fitArray[j][i];
754
8d7d16dd 755 fprintf(syncState->graphsStream,
08365995
BP
756 "\t%7g + %7g * x "
757 "title \"Linreg conversion\" with lines "
758 "linecolor rgb \"gray60\" linetype 1, \\\n",
759 fit->d0, 1. + fit->x);
760}
This page took 0.052004 seconds and 4 git commands to generate.