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