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