2010-11-09 Francois Chouinard <fchouinard@gmail.com> Contribution for Bug315307
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf / src / org / eclipse / linuxtools / tmf / event / TmfTimestamp.java
CommitLineData
8c8bf09f 1/*******************************************************************************
cbd4ad82 2 * Copyright (c) 2009, 2010 Ericsson
8c8bf09f
ASL
3 *
4 * All rights reserved. This program and the accompanying materials are
5 * made 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:
1f506a43 10 * Francois Chouinard - Initial API and implementation
023761c4 11 * Thomas Gatterweh - Updated scaling / synchronization
8c8bf09f
ASL
12 *******************************************************************************/
13
14package org.eclipse.linuxtools.tmf.event;
15
8c8bf09f
ASL
16/**
17 * <b><u>TmfTimestamp</u></b>
18 * <p>
19 * The fundamental time reference in the TMF.
20 * <p>
21 * It provides a generic timestamp implementation in its most basic form:
22 * <ul>
cbd4ad82
FC
23 * <li>timestamp = [value] * 10**[scale] +/- [precision]
24 * </ul>
25 * Where:
26 * <ul>
27 * <li>[value] is an unstructured integer value
28 * <li>[scale] is the magnitude of the value wrt some application-specific
29 * base unit (e.g. the second)
30 * <li>[precision] indicates the error on the value (useful for comparing
1f506a43 31 * timestamps in different scales). Default: 0.
8c8bf09f 32 * </ul>
cbd4ad82
FC
33 * In short:
34 * <ul>
35 * </ul>
28b94d61 36 * To allow synchronization of timestamps from different reference clocks,
cbd4ad82
FC
37 * there is a possibility to "adjust" the timestamp by changing its scale
38 * (traces of different time scale) and/or by adding an offset to its value
39 * (clock drift between traces).
8c8bf09f 40 * <p>
28b94d61
FC
41 * Notice that the adjusted timestamp value could be negative e.g. for events
42 * that occurred before t0 wrt the reference clock.
8c8bf09f 43 */
ff4ed569 44public class TmfTimestamp implements Cloneable {
98029bc9 45
cbd4ad82 46 // ------------------------------------------------------------------------
8c8bf09f 47 // Attributes
cbd4ad82 48 // ------------------------------------------------------------------------
8c8bf09f 49
cbd4ad82 50 protected long fValue; // The timestamp raw value
28b94d61
FC
51 protected byte fScale; // The time scale
52 protected long fPrecision; // The value precision (tolerance)
8c8bf09f 53
cbd4ad82 54 // ------------------------------------------------------------------------
8c8bf09f 55 // Constants
cbd4ad82 56 // ------------------------------------------------------------------------
8c8bf09f
ASL
57
58 // The beginning and end of time
146a887c 59 public static final TmfTimestamp BigBang = new TmfTimestamp(Long.MIN_VALUE, Byte.MAX_VALUE, 0);
8c8bf09f 60 public static final TmfTimestamp BigCrunch = new TmfTimestamp(Long.MAX_VALUE, Byte.MAX_VALUE, 0);
e31e01e8 61 public static final TmfTimestamp Zero = new TmfTimestamp(0, (byte) 0, 0);
8c8bf09f 62
cbd4ad82 63 // ------------------------------------------------------------------------
8c8bf09f 64 // Constructors
cbd4ad82 65 // ------------------------------------------------------------------------
8c8bf09f
ASL
66
67 /**
28b94d61 68 * Default constructor
8c8bf09f
ASL
69 */
70 public TmfTimestamp() {
71 this(0, (byte) 0, 0);
72 }
73
1f506a43 74 /**
28b94d61 75 * Simple constructor with value only
1f506a43
FC
76 */
77 public TmfTimestamp(long value) {
78 this(value, (byte) 0, 0);
79 }
80
8c8bf09f 81 /**
28b94d61 82 * Simple constructor with value and scale
8c8bf09f 83 *
1f506a43
FC
84 * @param value
85 * @param scale
8c8bf09f
ASL
86 */
87 public TmfTimestamp(long value, byte scale) {
88 this(value, scale, 0);
89 }
90
91 /**
28b94d61 92 * Constructor with value, scale and precision
8c8bf09f 93 *
1f506a43
FC
94 * @param value
95 * @param scale
96 * @param precision
8c8bf09f
ASL
97 */
98 public TmfTimestamp(long value, byte scale, long precision) {
99 fValue = value;
100 fScale = scale;
101 fPrecision = Math.abs(precision);
102 }
103
104 /**
28b94d61 105 * Copy constructor
8c8bf09f 106 *
1f506a43 107 * @param other
8c8bf09f
ASL
108 */
109 public TmfTimestamp(TmfTimestamp other) {
cbd4ad82
FC
110 if (other == null)
111 throw new IllegalArgumentException();
28b94d61
FC
112 fValue = other.fValue;
113 fScale = other.fScale;
114 fPrecision = other.fPrecision;
8c8bf09f
ASL
115 }
116
cbd4ad82 117 // ------------------------------------------------------------------------
8c8bf09f 118 // Accessors
cbd4ad82 119 // ------------------------------------------------------------------------
8c8bf09f
ASL
120
121 /**
28b94d61 122 * @return the timestamp value
8c8bf09f
ASL
123 */
124 public long getValue() {
125 return fValue;
126 }
127
128 /**
28b94d61 129 * @return the timestamp scale
8c8bf09f
ASL
130 */
131 public byte getScale() {
132 return fScale;
133 }
134
135 /**
28b94d61 136 * @return the timestamp value precision
8c8bf09f
ASL
137 */
138 public long getPrecision() {
139 return fPrecision;
140 }
141
cbd4ad82 142 // ------------------------------------------------------------------------
8c8bf09f 143 // Operators
cbd4ad82 144 // ------------------------------------------------------------------------
4ab33d2b 145
8c8bf09f
ASL
146 /**
147 * Return a shifted and scaled timestamp.
148 *
149 * Limitation: The scaling is limited to MAX_SCALING orders of magnitude.
150 * The main reason is that the 64 bits value starts to lose any significance
151 * meaning beyond that scale difference and it's not even worth the trouble
152 * to switch to BigDecimal arithmetics.
153 *
cbd4ad82
FC
154 * @param offset the shift value (in the same scale as newScale)
155 * @param newScale the new timestamp scale
156 * @return the synchronized timestamp in the new scale
157 * @throws ArithmeticException
8c8bf09f 158 */
cbd4ad82 159 public TmfTimestamp synchronize(long offset, byte newScale) throws ArithmeticException {
8c8bf09f 160
023761c4 161 long newValue = fValue;
8c8bf09f
ASL
162 long newPrecision = fPrecision;
163
023761c4
FC
164 // Handle the easy case
165 if (fScale == newScale && offset == 0)
166 return this;
167
8c8bf09f
ASL
168 // Determine the scaling factor
169 if (fScale != newScale) {
170 int scaleDiff = Math.abs(fScale - newScale);
171 // Let's try to be realistic...
023761c4 172 if (scaleDiff >= scalingFactors.length) {
3b38ea61 173 throw new ArithmeticException("Scaling exception"); //$NON-NLS-1$
8c8bf09f 174 }
023761c4
FC
175 // Adjust the timestamp
176 long scalingFactor = scalingFactors[scaleDiff];
8c8bf09f
ASL
177 if (newScale < fScale) {
178 newValue *= scalingFactor;
179 newPrecision *= scalingFactor;
180 } else {
181 newValue /= scalingFactor;
182 newPrecision /= scalingFactor;
183 }
184 }
185
023761c4
FC
186 if (offset < 0) {
187 newValue = (newValue < Long.MIN_VALUE - offset) ? Long.MIN_VALUE : newValue + offset;
188 } else {
189 newValue = (newValue > Long.MAX_VALUE - offset) ? Long.MAX_VALUE : newValue + offset;
190 }
191
192 return new TmfTimestamp(newValue, newScale, newPrecision);
8c8bf09f
ASL
193 }
194
023761c4
FC
195 private static final long scalingFactors[] = new long[] {
196 1L,
197 10L,
198 100L,
199 1000L,
200 10000L,
201 100000L,
202 1000000L,
203 10000000L,
204 100000000L,
205 1000000000L,
206 10000000000L,
207 100000000000L,
208 1000000000000L,
209 10000000000000L,
210 100000000000000L,
211 1000000000000000L,
212 10000000000000000L,
213 100000000000000000L,
214 1000000000000000000L,
215 };
216
217 private static final long scalingLimits[] = new long[] {
218 Long.MAX_VALUE / 1L,
219 Long.MAX_VALUE / 10L,
220 Long.MAX_VALUE / 100L,
221 Long.MAX_VALUE / 1000L,
222 Long.MAX_VALUE / 10000L,
223 Long.MAX_VALUE / 100000L,
224 Long.MAX_VALUE / 1000000L,
225 Long.MAX_VALUE / 10000000L,
226 Long.MAX_VALUE / 100000000L,
227 Long.MAX_VALUE / 1000000000L,
228 Long.MAX_VALUE / 10000000000L,
229 Long.MAX_VALUE / 100000000000L,
230 Long.MAX_VALUE / 1000000000000L,
231 Long.MAX_VALUE / 10000000000000L,
232 Long.MAX_VALUE / 100000000000000L,
233 Long.MAX_VALUE / 1000000000000000L,
234 Long.MAX_VALUE / 10000000000000000L,
235 Long.MAX_VALUE / 100000000000000000L,
236 Long.MAX_VALUE / 1000000000000000000L,
237 };
238
239 public static long getScalingFactor(byte scale)
240 {
241 return scalingFactors[scale];
242 }
243
8c8bf09f
ASL
244 /**
245 * Compute the adjustment, in the reference scale, needed to synchronize
1f506a43 246 * this timestamp with a reference timestamp.
8c8bf09f 247 *
cbd4ad82
FC
248 * @param reference the reference timestamp to synchronize with
249 * @param scale the scale of the adjustment
28b94d61 250 * @return the adjustment term in the reference time scale
cbd4ad82 251 * @throws ArithmeticException
8c8bf09f 252 */
cbd4ad82
FC
253 public long getAdjustment(TmfTimestamp reference, byte scale) throws ArithmeticException {
254 TmfTimestamp ts1 = synchronize(0, scale);
255 TmfTimestamp ts2 = reference.synchronize(0, scale);
256 return ts2.fValue - ts1.fValue;
8c8bf09f
ASL
257 }
258
259 /**
260 * Compare with another timestamp
261 *
cbd4ad82
FC
262 * @param other the other timestamp
263 * @param withinPrecision indicates if precision is to be take into consideration
264 * @return -1: this timestamp is lower (i.e. anterior)
28b94d61 265 * 0: timestamps are equal (within precision if requested)
cbd4ad82 266 * 1: this timestamp is higher (i.e. posterior)
8c8bf09f
ASL
267 */
268 public int compareTo(final TmfTimestamp other, boolean withinPrecision) {
269
023761c4
FC
270 // If values have the same time scale, perform the comparison
271 if (fScale == other.fScale) {
272 if (withinPrecision)
273 return compareWithinPrecision(this.fValue, this.fPrecision, other.fValue, other.fPrecision);
274 else
275 return compareNoPrecision(this.fValue, other.fValue);
276 }
8c8bf09f 277
023761c4
FC
278 // If values have different time scales, adjust to the finest one and
279 // then compare. If the scaling difference is too large, revert to
280 // some heuristics. Hopefully, nobody will try to compare galactic and
281 // quantic clock events...
282 int scaleDiff = Math.abs(fScale - other.fScale);
283 long factor, limit;
284 if (scaleDiff < scalingFactors.length) {
285 factor = scalingFactors[scaleDiff];
286 limit = scalingLimits[scaleDiff];
287 } else {
288 factor = 0;
289 limit = 0; // !!! 0 can always be scaled!!!
290 }
f3a4c7f4 291
023761c4
FC
292 if (fScale < other.fScale) {
293 // this has finer scale, so other should be scaled
294 if (withinPrecision)
295 if (other.fValue > limit || other.fValue < -limit
296 || other.fPrecision > limit
297 || other.fPrecision < -limit)
298 return other.fValue > 0 ? -1 : +1; // other exceeds scaling limit
299 else
300 return compareWithinPrecision(this.fValue, this.fPrecision,
301 other.fValue * factor, other.fPrecision * factor);
302 else if (other.fValue > limit || other.fValue < -limit)
303 return other.fValue > 0 ? -1 : +1; // other exceeds scaling limit
304 else
305 return compareNoPrecision(this.fValue, other.fValue * factor);
306 } else {
307 // other has finer scale, so this should be scaled
308 if (withinPrecision)
309 if (this.fValue > limit || this.fValue < -limit
310 || this.fPrecision > limit || this.fPrecision < -limit)
311 return this.fValue > 0 ? +1 : -1; // we exceed scaling limit
312 else
313 return compareWithinPrecision(this.fValue * factor,
314 this.fPrecision * factor, other.fValue,
315 other.fPrecision);
316 else if (this.fValue > limit || this.fValue < -limit)
317 return this.fValue > 0 ? +1 : -1; // we exceed scaling limit
318 else
319 return compareNoPrecision(this.fValue * factor, other.fValue);
320 }
8c8bf09f
ASL
321 }
322
023761c4
FC
323 private static int compareNoPrecision(long thisValue, long otherValue) {
324 return (thisValue == otherValue) ? 0 : (thisValue < otherValue) ? -1 : 1;
325 }
326
327 private static int compareWithinPrecision(long thisValue, long thisPrecision, long otherValue, long otherPrecision) {
328 if ((thisValue + thisPrecision) < (otherValue - otherPrecision))
329 return -1;
330 if ((thisValue - thisPrecision) > (otherValue + otherPrecision))
331 return 1;
332 return 0;
f3a4c7f4
FC
333 }
334
cbd4ad82
FC
335 // ------------------------------------------------------------------------
336 // Object
337 // ------------------------------------------------------------------------
28b94d61 338
8c8bf09f 339 @Override
cbd4ad82
FC
340 public int hashCode() {
341 int result = 17;
342 result = 37 * result + (int) (fValue ^ (fValue >>> 32));
343 result = 37 * result + fScale;
344 result = 37 * result + (int) (fPrecision ^ (fPrecision >>> 32));
345 return result;
346 }
347
348 @Override
8c8bf09f 349 public boolean equals(Object other) {
cbd4ad82
FC
350 if (!(other instanceof TmfTimestamp))
351 return false;
352 TmfTimestamp o = (TmfTimestamp) other;
353 return compareTo(o, false) == 0;
8c8bf09f
ASL
354 }
355
1f506a43 356 @Override
3b38ea61 357 @SuppressWarnings("nls")
1f506a43 358 public String toString() {
28b94d61 359 return "[TmfTimestamp(" + fValue + "," + fScale + "," + fPrecision + ")]";
1f506a43
FC
360 }
361
ff4ed569
FC
362 @Override
363 public TmfTimestamp clone() {
364 TmfTimestamp clone = null;
365 try {
366 clone = (TmfTimestamp) super.clone();
367 clone.fValue = fValue;
368 clone.fScale = fScale;
369 clone.fPrecision = fPrecision;
370 } catch (CloneNotSupportedException e) {
371 }
372 return clone;
373 }
374
023761c4 375}
This page took 0.046136 seconds and 5 git commands to generate.