a9407ed113f80a255f6e0dfdac711d9c5faf8f61
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf / src / org / eclipse / linuxtools / tmf / event / TmfTimestamp.java
1 /*******************************************************************************
2 * Copyright (c) 2009, 2010 Ericsson
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:
10 * Francois Chouinard - Initial API and implementation
11 * Thomas Gatterweh - Updated scaling / synchronization
12 *******************************************************************************/
13
14 package org.eclipse.linuxtools.tmf.event;
15
16
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>
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
32 * timestamps in different scales). Default: 0.
33 * </ul>
34 * In short:
35 * <ul>
36 * </ul>
37 * To allow synchronization of timestamps from different reference clocks,
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).
41 * <p>
42 * Notice that the adjusted timestamp value could be negative e.g. for events
43 * that occurred before t0 wrt the reference clock.
44 */
45 public class TmfTimestamp implements Cloneable {
46
47 // ------------------------------------------------------------------------
48 // Attributes
49 // ------------------------------------------------------------------------
50
51 protected long fValue; // The timestamp raw value
52 protected byte fScale; // The time scale
53 protected long fPrecision; // The value precision (tolerance)
54
55 // ------------------------------------------------------------------------
56 // Constants
57 // ------------------------------------------------------------------------
58
59 // The beginning and end of time
60 public static final TmfTimestamp BigBang = new TmfTimestamp(Long.MIN_VALUE, Byte.MAX_VALUE, 0);
61 public static final TmfTimestamp BigCrunch = new TmfTimestamp(Long.MAX_VALUE, Byte.MAX_VALUE, 0);
62 public static final TmfTimestamp Zero = new TmfTimestamp(0, (byte) 0, 0);
63
64 // ------------------------------------------------------------------------
65 // Constructors
66 // ------------------------------------------------------------------------
67
68 /**
69 * Default constructor
70 */
71 public TmfTimestamp() {
72 this(0, (byte) 0, 0);
73 }
74
75 /**
76 * Simple constructor with value only
77 */
78 public TmfTimestamp(long value) {
79 this(value, (byte) 0, 0);
80 }
81
82 /**
83 * Simple constructor with value and scale
84 *
85 * @param value
86 * @param scale
87 */
88 public TmfTimestamp(long value, byte scale) {
89 this(value, scale, 0);
90 }
91
92 /**
93 * Constructor with value, scale and precision
94 *
95 * @param value
96 * @param scale
97 * @param precision
98 */
99 public TmfTimestamp(long value, byte scale, long precision) {
100 fValue = value;
101 fScale = scale;
102 fPrecision = Math.abs(precision);
103 }
104
105 /**
106 * Copy constructor
107 *
108 * @param other
109 */
110 public TmfTimestamp(TmfTimestamp other) {
111 if (other == null)
112 throw new IllegalArgumentException();
113 fValue = other.fValue;
114 fScale = other.fScale;
115 fPrecision = other.fPrecision;
116 }
117
118 // ------------------------------------------------------------------------
119 // Accessors
120 // ------------------------------------------------------------------------
121
122 /**
123 * @return the timestamp value
124 */
125 public long getValue() {
126 return fValue;
127 }
128
129 /**
130 * @return the timestamp scale
131 */
132 public byte getScale() {
133 return fScale;
134 }
135
136 /**
137 * @return the timestamp value precision
138 */
139 public long getPrecision() {
140 return fPrecision;
141 }
142
143 // ------------------------------------------------------------------------
144 // Operators
145 // ------------------------------------------------------------------------
146
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 *
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
159 */
160 public TmfTimestamp synchronize(long offset, byte newScale) throws ArithmeticException {
161
162 long newValue = fValue;
163 long newPrecision = fPrecision;
164
165 // Handle the easy case
166 if (fScale == newScale && offset == 0)
167 return this;
168
169 // Determine the scaling factor
170 if (fScale != newScale) {
171 int scaleDiff = Math.abs(fScale - newScale);
172 // Let's try to be realistic...
173 if (scaleDiff >= scalingFactors.length) {
174 throw new ArithmeticException("Scaling exception");
175 }
176 // Adjust the timestamp
177 long scalingFactor = scalingFactors[scaleDiff];
178 if (newScale < fScale) {
179 newValue *= scalingFactor;
180 newPrecision *= scalingFactor;
181 } else {
182 newValue /= scalingFactor;
183 newPrecision /= scalingFactor;
184 }
185 }
186
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);
194 }
195
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
245 /**
246 * Compute the adjustment, in the reference scale, needed to synchronize
247 * this timestamp with a reference timestamp.
248 *
249 * @param reference the reference timestamp to synchronize with
250 * @param scale the scale of the adjustment
251 * @return the adjustment term in the reference time scale
252 * @throws ArithmeticException
253 */
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;
258 }
259
260 /**
261 * Compare with another timestamp
262 *
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)
266 * 0: timestamps are equal (within precision if requested)
267 * 1: this timestamp is higher (i.e. posterior)
268 */
269 public int compareTo(final TmfTimestamp other, boolean withinPrecision) {
270
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 }
278
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 }
292
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 }
322 }
323
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;
334 }
335
336 // ------------------------------------------------------------------------
337 // Object
338 // ------------------------------------------------------------------------
339
340 @Override
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
350 public boolean equals(Object other) {
351 if (!(other instanceof TmfTimestamp))
352 return false;
353 TmfTimestamp o = (TmfTimestamp) other;
354 return compareTo(o, false) == 0;
355 }
356
357 @Override
358 public String toString() {
359 return "[TmfTimestamp(" + fValue + "," + fScale + "," + fPrecision + ")]";
360 }
361
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
375 }
This page took 0.038601 seconds and 4 git commands to generate.