Commit | Line | Data |
---|---|---|
e73a4ba5 GB |
1 | /******************************************************************************* |
2 | * Copyright (c) 2013 École Polytechnique de Montréal | |
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 | |
ac29c59b | 11 | * Francis Giraldeau - Transform computation using synchronization graph |
e73a4ba5 GB |
12 | *******************************************************************************/ |
13 | ||
14 | package org.eclipse.linuxtools.tmf.core.synchronization; | |
15 | ||
16 | import java.io.IOException; | |
17 | import java.io.ObjectOutputStream; | |
18 | import java.io.Serializable; | |
19 | import java.math.BigDecimal; | |
20 | import java.math.MathContext; | |
27213c57 | 21 | import java.util.Collection; |
e73a4ba5 GB |
22 | import java.util.LinkedHashMap; |
23 | import java.util.LinkedList; | |
24 | import java.util.List; | |
25 | import java.util.Map; | |
26 | ||
ac29c59b | 27 | import org.eclipse.linuxtools.internal.tmf.core.synchronization.graph.SyncSpanningTree; |
e73a4ba5 GB |
28 | import org.eclipse.linuxtools.tmf.core.event.ITmfEvent; |
29 | import org.eclipse.linuxtools.tmf.core.event.matching.TmfEventDependency; | |
30 | import org.eclipse.linuxtools.tmf.core.timestamp.ITmfTimestamp; | |
31 | import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace; | |
32 | ||
33 | /** | |
34 | * Class implementing fully incremental trace synchronization approach as | |
35 | * described in | |
36 | * | |
37 | * Masoume Jabbarifar, Michel Dagenais and Alireza Shameli-Sendi, | |
38 | * "Streaming Mode Incremental Clock Synchronization" | |
39 | * | |
40 | * Since the algorithm itself applies to two traces, it is implemented in a | |
41 | * private class, while this public class manages the synchronization between | |
42 | * all traces. | |
43 | * | |
44 | * @author Geneviève Bastien | |
45 | * @since 3.0 | |
46 | */ | |
47 | public class SyncAlgorithmFullyIncremental extends SynchronizationAlgorithm { | |
48 | ||
49 | /** | |
50 | * Auto-generated serial UID | |
51 | */ | |
52 | private static final long serialVersionUID = -1782788842774838830L; | |
53 | ||
54 | private static final MathContext fMc = MathContext.DECIMAL128; | |
55 | ||
ac29c59b | 56 | /** @Serial */ |
e73a4ba5 GB |
57 | private final List<ConvexHull> fSyncs; |
58 | ||
ac29c59b FG |
59 | private SyncSpanningTree fTree = null; |
60 | ||
e73a4ba5 GB |
61 | /** |
62 | * Initialization of the attributes | |
63 | */ | |
64 | public SyncAlgorithmFullyIncremental() { | |
a4524c1b | 65 | fSyncs = new LinkedList<>(); |
e73a4ba5 GB |
66 | } |
67 | ||
68 | /** | |
69 | * Function called after all matching has been done, to do any post-match | |
70 | * treatment. For this class, it calculates stats, while the data is | |
71 | * available | |
72 | */ | |
73 | @Override | |
74 | public void matchingEnded() { | |
75 | getStats(); | |
76 | } | |
77 | ||
78 | @Override | |
27213c57 AM |
79 | public void init(Collection<ITmfTrace> traces) { |
80 | ITmfTrace[] traceArr = traces.toArray(new ITmfTrace[traces.size()]); | |
e73a4ba5 GB |
81 | fSyncs.clear(); |
82 | /* Create a convex hull for all trace pairs */ | |
ac29c59b FG |
83 | // FIXME: is it necessary to make ConvexHull for every pairs up-front? |
84 | // The ConvexHull seems to be created on the fly in processMatch(). | |
27213c57 AM |
85 | for (int i = 0; i < traceArr.length; i++) { |
86 | for (int j = i + 1; j < traceArr.length; j++) { | |
578724ed | 87 | ConvexHull algo = new ConvexHull(traceArr[i].getHostId(), traceArr[j].getHostId()); |
e73a4ba5 GB |
88 | fSyncs.add(algo); |
89 | } | |
90 | } | |
91 | } | |
92 | ||
93 | @Override | |
94 | protected void processMatch(TmfEventDependency match) { | |
578724ed GB |
95 | String host1 = match.getSourceEvent().getTrace().getHostId(); |
96 | String host2 = match.getDestinationEvent().getTrace().getHostId(); | |
e73a4ba5 GB |
97 | |
98 | /* Process only if source and destination are different */ | |
578724ed | 99 | if (host1.equals(host2)) { |
e73a4ba5 GB |
100 | return; |
101 | } | |
102 | ||
578724ed | 103 | /* Check if a convex hull algorithm already exists for these 2 hosts */ |
e73a4ba5 GB |
104 | ConvexHull algo = null; |
105 | for (ConvexHull traceSync : fSyncs) { | |
578724ed | 106 | if (traceSync.isForHosts(host1, host2)) { |
e73a4ba5 GB |
107 | algo = traceSync; |
108 | } | |
109 | } | |
110 | if (algo == null) { | |
578724ed | 111 | algo = new ConvexHull(host1, host2); |
e73a4ba5 GB |
112 | fSyncs.add(algo); |
113 | } | |
114 | algo.processMatch(match); | |
ac29c59b FG |
115 | invalidateSyncGraph(); |
116 | } | |
e73a4ba5 | 117 | |
ac29c59b FG |
118 | private void invalidateSyncGraph() { |
119 | fTree = null; | |
e73a4ba5 GB |
120 | } |
121 | ||
122 | @Override | |
123 | public ITmfTimestampTransform getTimestampTransform(ITmfTrace trace) { | |
578724ed | 124 | return getTimestampTransform(trace.getHostId()); |
e73a4ba5 GB |
125 | } |
126 | ||
127 | @Override | |
578724ed | 128 | public ITmfTimestampTransform getTimestampTransform(String hostId) { |
ac29c59b FG |
129 | SyncSpanningTree tree = getSyncTree(); |
130 | return tree.getTimestampTransform(hostId); | |
131 | } | |
132 | ||
133 | /** | |
134 | * Each convex hull computes the synchronization between 2 given hosts. A | |
135 | * synchronization can be done on multiple hosts that may not all | |
136 | * communicate with each other. We must use another algorithm to determine | |
137 | * which host will be the reference node and what synchronization formula | |
138 | * will be used between each host and this reference node. | |
139 | * | |
140 | * For example, take traces a, b and c where a and c talk to b but do not | |
141 | * know each other ({@literal a <-> b <-> c}). The convex hulls will contain | |
142 | * the formulae between their 2 traces, but if a is the reference node, then | |
143 | * the resulting formula of c would be the composition of {@literal a <-> b} | |
144 | * and {@literal b <-> c} | |
145 | * | |
146 | * @return The synchronization spanning tree for this synchronization | |
147 | */ | |
148 | private SyncSpanningTree getSyncTree() { | |
149 | if (fTree == null) { | |
150 | fTree = new SyncSpanningTree(); | |
151 | for (ConvexHull traceSync : fSyncs) { | |
152 | SyncQuality q = traceSync.getQuality(); | |
153 | if (q == SyncQuality.ACCURATE || q == SyncQuality.APPROXIMATE) { | |
154 | String from = traceSync.getReferenceHost(); | |
155 | String to = traceSync.getOtherHost(); | |
156 | fTree.addSynchronization(from, to, traceSync.getTimestampTransform(to), traceSync.getAccuracy()); | |
157 | } | |
e73a4ba5 GB |
158 | } |
159 | } | |
ac29c59b | 160 | return fTree; |
e73a4ba5 GB |
161 | } |
162 | ||
163 | @Override | |
164 | public SyncQuality getSynchronizationQuality(ITmfTrace trace1, ITmfTrace trace2) { | |
165 | for (ConvexHull traceSync : fSyncs) { | |
578724ed | 166 | if (traceSync.isForHosts(trace1.getHostId(), trace2.getHostId())) { |
e73a4ba5 GB |
167 | return traceSync.getQuality(); |
168 | } | |
169 | } | |
170 | return SyncQuality.ABSENT; | |
171 | } | |
172 | ||
173 | @Override | |
578724ed | 174 | public boolean isTraceSynced(String hostId) { |
ac29c59b FG |
175 | ITmfTimestampTransform t = getTimestampTransform(hostId); |
176 | return !t.equals(TimestampTransformFactory.getDefaultTransform()); | |
e73a4ba5 GB |
177 | } |
178 | ||
e73a4ba5 GB |
179 | @Override |
180 | public Map<String, Map<String, Object>> getStats() { | |
ac29c59b FG |
181 | /* |
182 | * TODO: Stats, while still accurate, may be misleading now that the | |
183 | * sync tree changes synchronization formula. The stats should use the | |
184 | * tree instead | |
185 | */ | |
a4524c1b | 186 | Map<String, Map<String, Object>> statmap = new LinkedHashMap<>(); |
e73a4ba5 | 187 | for (ConvexHull traceSync : fSyncs) { |
578724ed | 188 | statmap.put(traceSync.getReferenceHost() + " <==> " + traceSync.getOtherHost(), traceSync.getStats()); //$NON-NLS-1$ |
e73a4ba5 GB |
189 | } |
190 | return statmap; | |
191 | } | |
192 | ||
193 | @Override | |
194 | public String toString() { | |
195 | StringBuilder b = new StringBuilder(); | |
196 | b.append(getClass().getSimpleName() + " "); //$NON-NLS-1$ | |
197 | b.append(fSyncs); | |
198 | return b.toString(); | |
199 | } | |
200 | ||
201 | /** | |
202 | * This is the actual synchronization algorithm between two traces using | |
203 | * convex hull | |
204 | */ | |
205 | private class ConvexHull implements Serializable { | |
206 | ||
207 | private static final long serialVersionUID = 8309351175030935291L; | |
208 | ||
209 | /** | |
210 | * The list of meaningful points on the upper hull (received by the | |
211 | * reference trace, below in a graph) | |
212 | */ | |
a4524c1b | 213 | private final LinkedList<SyncPoint> fUpperBoundList = new LinkedList<>(); |
e73a4ba5 GB |
214 | |
215 | /** | |
216 | * The list of meaninful points on the lower hull (sent by the reference | |
217 | * trace, above in a graph) | |
218 | */ | |
a4524c1b | 219 | private final LinkedList<SyncPoint> fLowerBoundList = new LinkedList<>(); |
e73a4ba5 GB |
220 | |
221 | /** Points forming the line with maximum slope */ | |
222 | private final SyncPoint[] fLmax; | |
223 | ||
224 | /** Points forming the line with minimum slope */ | |
225 | private final SyncPoint[] fLmin; | |
226 | ||
227 | /** | |
228 | * Slopes and ordinate at origin of respectively fLmin, fLmax and the | |
229 | * bisector | |
230 | */ | |
231 | private BigDecimal fAlphamin, fBetamax, fAlphamax, fBetamin, fAlpha, fBeta; | |
232 | ||
233 | private int fNbMatches, fNbAccurateMatches; | |
578724ed | 234 | private String fReferenceHost = "", fOtherHost = ""; //$NON-NLS-1$//$NON-NLS-2$ |
e73a4ba5 GB |
235 | private SyncQuality fQuality; |
236 | ||
a4524c1b | 237 | private Map<String, Object> fStats = new LinkedHashMap<>(); |
e73a4ba5 GB |
238 | |
239 | /** | |
240 | * Initialization of the attributes | |
241 | * | |
578724ed GB |
242 | * @param host1 |
243 | * ID of the first host | |
244 | * @param host2 | |
245 | * ID of the second host | |
e73a4ba5 | 246 | */ |
578724ed GB |
247 | public ConvexHull(String host1, String host2) { |
248 | if (host1.compareTo(host2) > 0) { | |
249 | fReferenceHost = host2; | |
250 | fOtherHost = host1; | |
e73a4ba5 | 251 | } else { |
578724ed GB |
252 | fReferenceHost = host1; |
253 | fOtherHost = host2; | |
e73a4ba5 GB |
254 | } |
255 | fLmax = new SyncPoint[2]; | |
256 | fLmin = new SyncPoint[2]; | |
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; | |
ac29c59b | 265 | fQuality = SyncQuality.ABSENT; // default quality |
e73a4ba5 GB |
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 */ | |
578724ed | 279 | if (match.getSourceEvent().getTrace().getHostId().compareTo(match.getDestinationEvent().getTrace().getHostId()) > 0) { |
e73a4ba5 GB |
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() { | |
ac29c59b | 334 | |
e73a4ba5 GB |
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)) { | |
90d406ef GB |
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); | |
e73a4ba5 GB |
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 */ | |
ac29c59b | 378 | setQuality(SyncQuality.INCOMPLETE); |
e73a4ba5 GB |
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 | ||
578724ed | 447 | public ITmfTimestampTransform getTimestampTransform(String hostId) { |
ac29c59b | 448 | if (hostId.equals(fOtherHost) && (getQuality() == SyncQuality.ACCURATE || getQuality() == SyncQuality.APPROXIMATE || getQuality() == SyncQuality.FAIL)) { |
e73a4ba5 | 449 | /* alpha: beta => 1 / fAlpha, -1 * fBeta / fAlpha); */ |
9ffcda7d | 450 | return TimestampTransformFactory.createLinear(BigDecimal.ONE.divide(fAlpha, fMc), BigDecimal.valueOf(-1).multiply(fBeta).divide(fAlpha, fMc)); |
e73a4ba5 | 451 | } |
9ffcda7d | 452 | return TimestampTransformFactory.getDefaultTransform(); |
e73a4ba5 GB |
453 | } |
454 | ||
455 | public SyncQuality getQuality() { | |
456 | return fQuality; | |
457 | } | |
458 | ||
ac29c59b FG |
459 | public BigDecimal getAccuracy() { |
460 | return fAlphamax.subtract(fAlphamin); | |
461 | } | |
462 | ||
e73a4ba5 GB |
463 | public Map<String, Object> getStats() { |
464 | if (fStats.size() == 0) { | |
465 | String syncQuality; | |
ac29c59b | 466 | switch (getQuality()) { |
e73a4ba5 GB |
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 | ||
578724ed GB |
485 | fStats.put(Messages.SyncAlgorithmFullyIncremental_refhost, fReferenceHost); |
486 | fStats.put(Messages.SyncAlgorithmFullyIncremental_otherhost, fOtherHost); | |
e73a4ba5 GB |
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()); | |
ac29c59b | 492 | fStats.put(Messages.SyncAlgorithmFullyIncremental_accuracy, getAccuracy().doubleValue()); |
e73a4ba5 GB |
493 | fStats.put(Messages.SyncAlgorithmFullyIncremental_nbmatch, (fNbMatches == 0) ? Messages.SyncAlgorithmFullyIncremental_NA : fNbMatches); |
494 | fStats.put(Messages.SyncAlgorithmFullyIncremental_nbacc, (fNbAccurateMatches == 0) ? Messages.SyncAlgorithmFullyIncremental_NA : fNbAccurateMatches); | |
578724ed GB |
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); | |
e73a4ba5 GB |
497 | } |
498 | return fStats; | |
499 | ||
500 | } | |
501 | ||
578724ed GB |
502 | public String getReferenceHost() { |
503 | return fReferenceHost; | |
e73a4ba5 GB |
504 | } |
505 | ||
578724ed GB |
506 | public String getOtherHost() { |
507 | return fOtherHost; | |
e73a4ba5 GB |
508 | } |
509 | ||
578724ed GB |
510 | public boolean isForHosts(String hostId1, String hostId2) { |
511 | return ((fReferenceHost.equals(hostId1) && fOtherHost.equals(hostId2)) || (fReferenceHost.equals(hostId2) && fOtherHost.equals(hostId1))); | |
e73a4ba5 GB |
512 | } |
513 | ||
514 | private void writeObject(ObjectOutputStream s) | |
515 | throws IOException { | |
516 | /* | |
517 | * Remove calculation data because most of it is not serializable. | |
518 | * We have the statistics anyway | |
519 | */ | |
520 | fUpperBoundList.clear(); | |
521 | fLowerBoundList.clear(); | |
522 | fLmin[0] = null; | |
523 | fLmin[1] = null; | |
524 | fLmax[0] = null; | |
525 | fLmax[1] = null; | |
526 | s.defaultWriteObject(); | |
e73a4ba5 GB |
527 | } |
528 | ||
529 | @SuppressWarnings("nls") | |
530 | @Override | |
531 | public String toString() { | |
532 | StringBuilder b = new StringBuilder(); | |
578724ed | 533 | b.append("Between " + fReferenceHost + " and " + fOtherHost + " ["); |
e73a4ba5 GB |
534 | b.append(" alpha " + fAlpha + " beta " + fBeta + " ]"); |
535 | return b.toString(); | |
536 | } | |
ac29c59b FG |
537 | |
538 | private void setQuality(SyncQuality fQuality) { | |
539 | this.fQuality = fQuality; | |
540 | } | |
541 | ||
e73a4ba5 GB |
542 | } |
543 | ||
544 | /** | |
545 | * Private class representing a point to synchronize on a graph. The x axis | |
546 | * is the timestamp of the event from the reference trace while the y axis | |
547 | * is the timestamp of the event on the other trace | |
548 | */ | |
549 | private class SyncPoint { | |
550 | private final ITmfTimestamp x, y; | |
551 | ||
552 | public SyncPoint(ITmfEvent ex, ITmfEvent ey) { | |
553 | x = ex.getTimestamp(); | |
554 | y = ey.getTimestamp(); | |
555 | } | |
556 | ||
557 | public long getTimeX() { | |
558 | return x.getValue(); | |
559 | } | |
560 | ||
561 | /** | |
562 | * Calculate a cross product of 3 points: | |
563 | * | |
564 | * If the cross-product < 0, then p, pa, pb are clockwise | |
565 | * | |
566 | * If the cross-product > 0, then p, pa, pb are counter-clockwise | |
567 | * | |
568 | * If cross-product == 0, then they are in a line | |
569 | * | |
570 | * @param pa | |
571 | * First point | |
572 | * @param pb | |
573 | * Second point | |
574 | * @return The cross product | |
575 | */ | |
576 | public long crossProduct(SyncPoint pa, SyncPoint pb) { | |
577 | long cp = ((pa.x.getValue() - x.getValue()) * (pb.y.getValue() - y.getValue()) - (pa.y.getValue() - y.getValue()) * (pb.x.getValue() - x.getValue())); | |
578 | return cp; | |
579 | } | |
580 | ||
581 | /* | |
582 | * Gets the alpha (slope) between two points | |
583 | */ | |
584 | public BigDecimal getAlpha(SyncPoint p1) { | |
585 | if (p1 == null) { | |
586 | return BigDecimal.ONE; | |
587 | } | |
588 | BigDecimal deltay = BigDecimal.valueOf(y.getValue() - p1.y.getValue()); | |
589 | BigDecimal deltax = BigDecimal.valueOf(x.getValue() - p1.x.getValue()); | |
590 | if (deltax.equals(BigDecimal.ZERO)) { | |
591 | return BigDecimal.ONE; | |
592 | } | |
593 | return deltay.divide(deltax, fMc); | |
594 | } | |
595 | ||
596 | /* | |
597 | * Get the beta value (when x = 0) of the line given alpha | |
598 | */ | |
599 | public BigDecimal getBeta(BigDecimal alpha) { | |
600 | return BigDecimal.valueOf(y.getValue()).subtract(alpha.multiply(BigDecimal.valueOf(x.getValue()), fMc)); | |
601 | } | |
602 | ||
ac29c59b FG |
603 | @Override |
604 | public String toString() { | |
605 | return String.format("%s (%s, %s)", this.getClass().getCanonicalName(), x, y); //$NON-NLS-1$ | |
606 | } | |
607 | } | |
608 | ||
609 | private void writeObject(ObjectOutputStream s) | |
610 | throws IOException { | |
611 | /* | |
612 | * Remove the tree because it is not serializable | |
613 | */ | |
614 | fTree = null; | |
615 | s.defaultWriteObject(); | |
e73a4ba5 GB |
616 | } |
617 | ||
618 | } |