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