ctf: Add the symbol-mapping file of the cyg-profile trace
[deliverable/tracecompass.git] / org.eclipse.tracecompass.tmf.core / src / org / eclipse / tracecompass / internal / tmf / core / synchronization / SyncAlgorithmFullyIncremental.java
CommitLineData
51c08015 1/*******************************************************************************
ed902a2b 2 * Copyright (c) 2013, 2014 École Polytechnique de Montréal
51c08015
GB
3 *
4 * All rights reserved. This program and the accompanying materials are made
5 * available under the terms of the Eclipse Public License v1.0 which
6 * accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
8 *
9 * Contributors:
10 * Geneviève Bastien - Initial implementation and API
11 * Francis Giraldeau - Transform computation using synchronization graph
12 *******************************************************************************/
13
2bdf0193 14package org.eclipse.tracecompass.internal.tmf.core.synchronization;
51c08015
GB
15
16import java.io.IOException;
a1ff9910 17import java.io.ObjectInputStream;
51c08015
GB
18import java.io.Serializable;
19import java.math.BigDecimal;
20import java.math.MathContext;
21import java.util.Collection;
22import java.util.LinkedHashMap;
23import java.util.LinkedList;
24import java.util.List;
25import java.util.Map;
26
2bdf0193
AM
27import org.eclipse.tracecompass.internal.tmf.core.synchronization.graph.SyncSpanningTree;
28import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
29import org.eclipse.tracecompass.tmf.core.event.matching.TmfEventDependency;
30import org.eclipse.tracecompass.tmf.core.synchronization.ITmfTimestampTransform;
31import org.eclipse.tracecompass.tmf.core.synchronization.Messages;
32import org.eclipse.tracecompass.tmf.core.synchronization.SynchronizationAlgorithm;
33import org.eclipse.tracecompass.tmf.core.synchronization.TimestampTransformFactory;
34import org.eclipse.tracecompass.tmf.core.timestamp.ITmfTimestamp;
35import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
51c08015
GB
36
37/**
38 * Class implementing fully incremental trace synchronization approach as
39 * described in
40 *
41 * Masoume Jabbarifar, Michel Dagenais and Alireza Shameli-Sendi,
42 * "Streaming Mode Incremental Clock Synchronization"
43 *
44 * Since the algorithm itself applies to two traces, it is implemented in a
45 * private class, while this public class manages the synchronization between
46 * all traces.
47 *
48 * @author Geneviève Bastien
49 */
50public class SyncAlgorithmFullyIncremental extends SynchronizationAlgorithm {
51
52 /**
53 * Auto-generated serial UID
54 */
55 private static final long serialVersionUID = -1782788842774838830L;
56
57 private static final MathContext fMc = MathContext.DECIMAL128;
58
59 /** @Serial */
60 private final List<ConvexHull> fSyncs;
61
a1ff9910 62 private transient SyncSpanningTree fTree = null;
51c08015
GB
63
64 /**
65 * Initialization of the attributes
66 */
67 public SyncAlgorithmFullyIncremental() {
68 fSyncs = new LinkedList<>();
69 }
70
71 /**
72 * Function called after all matching has been done, to do any post-match
73 * treatment. For this class, it calculates stats, while the data is
74 * available
75 */
76 @Override
77 public void matchingEnded() {
78 getStats();
79 }
80
81 @Override
82 public void init(Collection<ITmfTrace> traces) {
83 ITmfTrace[] traceArr = traces.toArray(new ITmfTrace[traces.size()]);
84 fSyncs.clear();
85 /* Create a convex hull for all trace pairs */
86 // FIXME: is it necessary to make ConvexHull for every pairs up-front?
87 // The ConvexHull seems to be created on the fly in processMatch().
88 for (int i = 0; i < traceArr.length; i++) {
89 for (int j = i + 1; j < traceArr.length; j++) {
2c2fcd6b
GB
90 if (!traceArr[i].getHostId().equals(traceArr[j].getHostId())) {
91 ConvexHull algo = new ConvexHull(traceArr[i].getHostId(), traceArr[j].getHostId());
92 fSyncs.add(algo);
93 }
51c08015
GB
94 }
95 }
96 }
97
98 @Override
99 protected void processMatch(TmfEventDependency match) {
100 String host1 = match.getSourceEvent().getTrace().getHostId();
101 String host2 = match.getDestinationEvent().getTrace().getHostId();
102
103 /* Process only if source and destination are different */
104 if (host1.equals(host2)) {
105 return;
106 }
107
108 /* Check if a convex hull algorithm already exists for these 2 hosts */
109 ConvexHull algo = null;
110 for (ConvexHull traceSync : fSyncs) {
111 if (traceSync.isForHosts(host1, host2)) {
112 algo = traceSync;
113 }
114 }
115 if (algo == null) {
116 algo = new ConvexHull(host1, host2);
117 fSyncs.add(algo);
118 }
119 algo.processMatch(match);
120 invalidateSyncGraph();
121 }
122
123 private void invalidateSyncGraph() {
124 fTree = null;
125 }
126
127 @Override
128 public ITmfTimestampTransform getTimestampTransform(ITmfTrace trace) {
129 return getTimestampTransform(trace.getHostId());
130 }
131
132 @Override
133 public ITmfTimestampTransform getTimestampTransform(String hostId) {
134 SyncSpanningTree tree = getSyncTree();
135 return tree.getTimestampTransform(hostId);
136 }
137
138 /**
139 * Each convex hull computes the synchronization between 2 given hosts. A
140 * synchronization can be done on multiple hosts that may not all
141 * communicate with each other. We must use another algorithm to determine
142 * which host will be the reference node and what synchronization formula
143 * will be used between each host and this reference node.
144 *
145 * For example, take traces a, b and c where a and c talk to b but do not
146 * know each other ({@literal a <-> b <-> c}). The convex hulls will contain
147 * the formulae between their 2 traces, but if a is the reference node, then
148 * the resulting formula of c would be the composition of {@literal a <-> b}
149 * and {@literal b <-> c}
150 *
151 * @return The synchronization spanning tree for this synchronization
152 */
153 private SyncSpanningTree getSyncTree() {
154 if (fTree == null) {
155 fTree = new SyncSpanningTree();
156 for (ConvexHull traceSync : fSyncs) {
157 SyncQuality q = traceSync.getQuality();
158 if (q == SyncQuality.ACCURATE || q == SyncQuality.APPROXIMATE) {
159 String from = traceSync.getReferenceHost();
160 String to = traceSync.getOtherHost();
161 fTree.addSynchronization(from, to, traceSync.getTimestampTransform(to), traceSync.getAccuracy());
162 }
163 }
164 }
165 return fTree;
166 }
167
168 @Override
169 public SyncQuality getSynchronizationQuality(ITmfTrace trace1, ITmfTrace trace2) {
170 for (ConvexHull traceSync : fSyncs) {
171 if (traceSync.isForHosts(trace1.getHostId(), trace2.getHostId())) {
172 return traceSync.getQuality();
173 }
174 }
175 return SyncQuality.ABSENT;
176 }
177
178 @Override
179 public boolean isTraceSynced(String hostId) {
180 ITmfTimestampTransform t = getTimestampTransform(hostId);
181 return !t.equals(TimestampTransformFactory.getDefaultTransform());
182 }
183
184 @Override
185 public Map<String, Map<String, Object>> getStats() {
186 /*
187 * TODO: Stats, while still accurate, may be misleading now that the
188 * sync tree changes synchronization formula. The stats should use the
189 * tree instead
190 */
191 Map<String, Map<String, Object>> statmap = new LinkedHashMap<>();
192 for (ConvexHull traceSync : fSyncs) {
193 statmap.put(traceSync.getReferenceHost() + " <==> " + traceSync.getOtherHost(), traceSync.getStats()); //$NON-NLS-1$
194 }
195 return statmap;
196 }
197
198 @Override
199 public String toString() {
200 StringBuilder b = new StringBuilder();
201 b.append(getClass().getSimpleName() + " "); //$NON-NLS-1$
202 b.append(fSyncs);
203 return b.toString();
204 }
205
206 /**
207 * This is the actual synchronization algorithm between two traces using
208 * convex hull
209 */
210 private class ConvexHull implements Serializable {
211
212 private static final long serialVersionUID = 8309351175030935291L;
213
a1ff9910
GB
214 private final String fReferenceHost;
215 private final String fOtherHost;
216
217 /**
218 * Slopes and ordinate at origin of respectively fLmin, fLmax and the
219 * bisector
220 */
221 private BigDecimal fAlphamin, fBetamax, fAlphamax, fBetamin, fAlpha, fBeta;
222 private int fNbMatches, fNbAccurateMatches;
223 private SyncQuality fQuality;
224
51c08015
GB
225 /**
226 * The list of meaningful points on the upper hull (received by the
227 * reference trace, below in a graph)
228 */
a1ff9910 229 private transient LinkedList<SyncPoint> fUpperBoundList = new LinkedList<>();
51c08015
GB
230 /**
231 * The list of meaninful points on the lower hull (sent by the reference
232 * trace, above in a graph)
233 */
a1ff9910 234 private transient LinkedList<SyncPoint> fLowerBoundList = new LinkedList<>();
51c08015
GB
235
236 /** Points forming the line with maximum slope */
a1ff9910 237 private transient SyncPoint[] fLmax = new SyncPoint[2];
51c08015 238 /** Points forming the line with minimum slope */
a1ff9910 239 private transient SyncPoint[] fLmin = new SyncPoint[2];
51c08015 240
a1ff9910 241 private transient Map<String, Object> fStats = new LinkedHashMap<>();
51c08015
GB
242
243 /**
244 * Initialization of the attributes
245 *
246 * @param host1
247 * ID of the first host
248 * @param host2
249 * ID of the second host
250 */
251 public ConvexHull(String host1, String host2) {
252 if (host1.compareTo(host2) > 0) {
253 fReferenceHost = host2;
254 fOtherHost = host1;
255 } else {
256 fReferenceHost = host1;
257 fOtherHost = host2;
258 }
51c08015
GB
259 fAlpha = BigDecimal.ONE;
260 fAlphamax = BigDecimal.ONE;
261 fAlphamin = BigDecimal.ONE;
262 fBeta = BigDecimal.ZERO;
263 fBetamax = BigDecimal.ZERO;
264 fBetamin = BigDecimal.ZERO;
265 fNbMatches = 0;
266 fNbAccurateMatches = 0;
267 fQuality = SyncQuality.ABSENT; // default quality
268 }
269
270 protected void processMatch(TmfEventDependency match) {
271
272 LinkedList<SyncPoint> boundList, otherBoundList;
273
274 SyncPoint[] line, otherLine;
275 SyncPoint p;
276 int inversionFactor = 1;
277 boolean qualify = false;
278 fNbMatches++;
279
280 /* Initialize data depending on the which hull the match is part of */
281 if (match.getSourceEvent().getTrace().getHostId().compareTo(match.getDestinationEvent().getTrace().getHostId()) > 0) {
282 boundList = fUpperBoundList;
283 otherBoundList = fLowerBoundList;
284 line = fLmin;
285 otherLine = fLmax;
286 p = new SyncPoint(match.getDestinationEvent(), match.getSourceEvent());
287 inversionFactor = 1;
288 } else {
289 boundList = fLowerBoundList;
290 otherBoundList = fUpperBoundList;
291 line = fLmax;
292 otherLine = fLmin;
293 p = new SyncPoint(match.getSourceEvent(), match.getDestinationEvent());
294 inversionFactor = -1;
295 }
296
297 /*
298 * Does the message qualify for the hull, or is in on the wrong side
299 * of the reference line
300 */
301 if ((line[0] == null) || (line[1] == null) || (p.crossProduct(line[0], line[1]) * inversionFactor > 0)) {
302 /*
303 * If message qualifies, verify if points need to be removed
304 * from the hull and add the new point as the maximum reference
305 * point for the line. Also clear the stats that are not good
306 * anymore
307 */
308 fNbAccurateMatches++;
309 qualify = true;
310 removeUselessPoints(p, boundList, inversionFactor);
311 line[1] = p;
312 fStats.clear();
313 }
314
315 /*
316 * Adjust the boundary of the reference line and if one of the
317 * reference point of the other line was removed from the hull, also
318 * adjust the other line
319 */
320 adjustBound(line, otherBoundList, inversionFactor);
321 if ((otherLine[1] != null) && !boundList.contains(otherLine[0])) {
322 adjustBound(otherLine, boundList, inversionFactor * -1);
323 }
324
325 if (qualify) {
326 approximateSync();
327 }
328
329 }
330
331 /**
332 * Calculates slopes and ordinate at origin of fLmax and fLmin to obtain
333 * and approximation of the synchronization at this time
334 */
335 private void approximateSync() {
336
337 /**
338 * Line slopes functions
339 *
340 * Lmax = alpha_max T + beta_min
341 *
342 * Lmin = alpha_min T + beta_max
343 */
344 if ((fLmax[0] != null) || (fLmin[0] != null)) {
345 /**
346 * Do not recalculate synchronization after it is failed. We
347 * keep the last not failed result.
348 */
349 if (getQuality() != SyncQuality.FAIL) {
350 BigDecimal alphamax = fLmax[1].getAlpha(fLmax[0]);
351 BigDecimal alphamin = fLmin[1].getAlpha(fLmin[0]);
352 SyncQuality quality = null;
353
354 if ((fLmax[0] == null) || (fLmin[0] == null)) {
355 quality = SyncQuality.APPROXIMATE;
356 }
357 else if (alphamax.compareTo(alphamin) > 0) {
358 quality = SyncQuality.ACCURATE;
359 } else {
360 /* Lines intersect, not good */
361 quality = SyncQuality.FAIL;
362 }
363 /*
364 * Only calculate sync if this match does not cause failure
365 * of synchronization
366 */
367 if (quality != SyncQuality.FAIL) {
368 fAlphamax = alphamax;
369 fBetamin = fLmax[1].getBeta(fAlphamax);
370 fAlphamin = alphamin;
371 fBetamax = fLmin[1].getBeta(fAlphamin);
372 fAlpha = fAlphamax.add(fAlphamin).divide(BigDecimal.valueOf(2), fMc);
373 fBeta = fBetamin.add(fBetamax).divide(BigDecimal.valueOf(2), fMc);
374 }
375 setQuality(quality);
376 }
377 } else if (((fLmax[0] == null) && (fLmin[1] == null))
378 || ((fLmax[1] == null) && (fLmin[0] == null))) {
379 /* Either there is no upper hull point or no lower hull */
380 setQuality(SyncQuality.INCOMPLETE);
381 }
382 }
383
384 /*
385 * Verify if the line should be adjusted to be more accurate give the
386 * hull
387 */
388 private void adjustBound(SyncPoint[] line, LinkedList<SyncPoint> otherBoundList, int inversionFactor) {
389 SyncPoint minPoint = null, nextPoint;
390 boolean finishedSearch = false;
391
392 /*
393 * Find in the other bound, the origin point of the line, start from
394 * the beginning if the point was lost
395 */
396 int i = Math.max(0, otherBoundList.indexOf(line[0]));
397
398 while ((i < otherBoundList.size() - 1) && !finishedSearch) {
399 minPoint = otherBoundList.get(i);
400 nextPoint = otherBoundList.get(i + 1);
401
402 /*
403 * If the rotation (cross-product) is not optimal, move to next
404 * point as reference for the line (if available)
405 *
406 * Otherwise, the current minPoint is the minPoint of the line
407 */
408 if (minPoint.crossProduct(nextPoint, line[1]) * inversionFactor > 0) {
409 if (nextPoint.getTimeX() < line[1].getTimeX()) {
410 i++;
411 } else {
412 line[0] = null;
413 finishedSearch = true;
414 }
415 } else {
416 line[0] = minPoint;
417 finishedSearch = true;
418 }
419 }
420
421 if (line[0] == null) {
422 line[0] = minPoint;
423 }
424
425 /* Make sure point 0 is before point 1 */
426 if ((line[0] != null) && (line[0].getTimeX() > line[1].getTimeX())) {
427 line[0] = null;
428 }
429 }
430
431 /*
432 * When a point qualifies to be in a hull, we verify if any of the
433 * existing points need to be removed from the hull
434 */
435 private void removeUselessPoints(final SyncPoint p, final LinkedList<SyncPoint> boundList, final int inversionFactor) {
436
437 boolean checkRemove = true;
438
439 while (checkRemove && boundList.size() >= 2) {
440 if (p.crossProduct(boundList.get(boundList.size() - 2), boundList.getLast()) * inversionFactor > 0) {
441 boundList.removeLast();
442 } else {
443 checkRemove = false;
444 }
445 }
446 boundList.addLast(p);
447 }
448
449 public ITmfTimestampTransform getTimestampTransform(String hostId) {
450 if (hostId.equals(fOtherHost) && (getQuality() == SyncQuality.ACCURATE || getQuality() == SyncQuality.APPROXIMATE || getQuality() == SyncQuality.FAIL)) {
451 /* alpha: beta => 1 / fAlpha, -1 * fBeta / fAlpha); */
452 return TimestampTransformFactory.createLinear(BigDecimal.ONE.divide(fAlpha, fMc), BigDecimal.valueOf(-1).multiply(fBeta).divide(fAlpha, fMc));
453 }
454 return TimestampTransformFactory.getDefaultTransform();
455 }
456
457 public SyncQuality getQuality() {
458 return fQuality;
459 }
460
461 public BigDecimal getAccuracy() {
462 return fAlphamax.subtract(fAlphamin);
463 }
464
465 public Map<String, Object> getStats() {
466 if (fStats.size() == 0) {
467 String syncQuality;
468 switch (getQuality()) {
469 case ABSENT:
470 syncQuality = Messages.SyncAlgorithmFullyIncremental_absent;
471 break;
472 case ACCURATE:
473 syncQuality = Messages.SyncAlgorithmFullyIncremental_accurate;
474 break;
475 case APPROXIMATE:
476 syncQuality = Messages.SyncAlgorithmFullyIncremental_approx;
477 break;
478 case INCOMPLETE:
479 syncQuality = Messages.SyncAlgorithmFullyIncremental_incomplete;
480 break;
481 case FAIL:
482 default:
483 syncQuality = Messages.SyncAlgorithmFullyIncremental_fail;
484 break;
485 }
486
487 fStats.put(Messages.SyncAlgorithmFullyIncremental_refhost, fReferenceHost);
488 fStats.put(Messages.SyncAlgorithmFullyIncremental_otherhost, fOtherHost);
489 fStats.put(Messages.SyncAlgorithmFullyIncremental_quality, syncQuality);
490 fStats.put(Messages.SyncAlgorithmFullyIncremental_alpha, fAlpha);
491 fStats.put(Messages.SyncAlgorithmFullyIncremental_beta, fBeta);
492 fStats.put(Messages.SyncAlgorithmFullyIncremental_ub, (fUpperBoundList.size() == 0) ? Messages.SyncAlgorithmFullyIncremental_NA : fUpperBoundList.size());
493 fStats.put(Messages.SyncAlgorithmFullyIncremental_lb, (fLowerBoundList.size() == 0) ? Messages.SyncAlgorithmFullyIncremental_NA : fLowerBoundList.size());
494 fStats.put(Messages.SyncAlgorithmFullyIncremental_accuracy, getAccuracy().doubleValue());
495 fStats.put(Messages.SyncAlgorithmFullyIncremental_nbmatch, (fNbMatches == 0) ? Messages.SyncAlgorithmFullyIncremental_NA : fNbMatches);
496 fStats.put(Messages.SyncAlgorithmFullyIncremental_nbacc, (fNbAccurateMatches == 0) ? Messages.SyncAlgorithmFullyIncremental_NA : fNbAccurateMatches);
497 fStats.put(Messages.SyncAlgorithmFullyIncremental_refformula, Messages.SyncAlgorithmFullyIncremental_T_ + fReferenceHost);
498 fStats.put(Messages.SyncAlgorithmFullyIncremental_otherformula, fAlpha + Messages.SyncAlgorithmFullyIncremental_mult + Messages.SyncAlgorithmFullyIncremental_T_ + fReferenceHost + Messages.SyncAlgorithmFullyIncremental_add + fBeta);
499 }
500 return fStats;
501
502 }
503
504 public String getReferenceHost() {
505 return fReferenceHost;
506 }
507
508 public String getOtherHost() {
509 return fOtherHost;
510 }
511
512 public boolean isForHosts(String hostId1, String hostId2) {
513 return ((fReferenceHost.equals(hostId1) && fOtherHost.equals(hostId2)) || (fReferenceHost.equals(hostId2) && fOtherHost.equals(hostId1)));
514 }
515
a1ff9910
GB
516 private void readObject(ObjectInputStream stream)
517 throws IOException, ClassNotFoundException {
518 stream.defaultReadObject();
519
520 /* Initialize transient fields */
521 fUpperBoundList = new LinkedList<>();
522 fLowerBoundList = new LinkedList<>();
523 fLmax = new SyncPoint[2];
524 fLmin = new SyncPoint[2];
525 fStats = new LinkedHashMap<>();
51c08015
GB
526 }
527
528 @SuppressWarnings("nls")
529 @Override
530 public String toString() {
531 StringBuilder b = new StringBuilder();
532 b.append("Between " + fReferenceHost + " and " + fOtherHost + " [");
533 b.append(" alpha " + fAlpha + " beta " + fBeta + " ]");
534 return b.toString();
535 }
536
537 private void setQuality(SyncQuality fQuality) {
538 this.fQuality = fQuality;
539 }
540
541 }
542
543 /**
544 * Private class representing a point to synchronize on a graph. The x axis
545 * is the timestamp of the event from the reference trace while the y axis
546 * is the timestamp of the event on the other trace
547 */
548 private class SyncPoint {
549 private final ITmfTimestamp x, y;
550
551 public SyncPoint(ITmfEvent ex, ITmfEvent ey) {
552 x = ex.getTimestamp();
553 y = ey.getTimestamp();
554 }
555
556 public long getTimeX() {
557 return x.getValue();
558 }
559
560 /**
561 * Calculate a cross product of 3 points:
562 *
563 * If the cross-product < 0, then p, pa, pb are clockwise
564 *
565 * If the cross-product > 0, then p, pa, pb are counter-clockwise
566 *
567 * If cross-product == 0, then they are in a line
568 *
569 * @param pa
570 * First point
571 * @param pb
572 * Second point
573 * @return The cross product
574 */
575 public long crossProduct(SyncPoint pa, SyncPoint pb) {
576 long cp = ((pa.x.getValue() - x.getValue()) * (pb.y.getValue() - y.getValue()) - (pa.y.getValue() - y.getValue()) * (pb.x.getValue() - x.getValue()));
577 return cp;
578 }
579
580 /*
581 * Gets the alpha (slope) between two points
582 */
583 public BigDecimal getAlpha(SyncPoint p1) {
584 if (p1 == null) {
585 return BigDecimal.ONE;
586 }
587 BigDecimal deltay = BigDecimal.valueOf(y.getValue() - p1.y.getValue());
588 BigDecimal deltax = BigDecimal.valueOf(x.getValue() - p1.x.getValue());
589 if (deltax.equals(BigDecimal.ZERO)) {
590 return BigDecimal.ONE;
591 }
592 return deltay.divide(deltax, fMc);
593 }
594
595 /*
596 * Get the beta value (when x = 0) of the line given alpha
597 */
598 public BigDecimal getBeta(BigDecimal alpha) {
599 return BigDecimal.valueOf(y.getValue()).subtract(alpha.multiply(BigDecimal.valueOf(x.getValue()), fMc));
600 }
601
602 @Override
603 public String toString() {
604 return String.format("%s (%s, %s)", this.getClass().getCanonicalName(), x, y); //$NON-NLS-1$
605 }
606 }
607
51c08015 608}
This page took 0.115744 seconds and 5 git commands to generate.