1 /*******************************************************************************
2 * Copyright (c) 2009, 2010 Ericsson
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
10 * Francois Chouinard - Initial API and implementation
11 * Thomas Gatterweh - Updated scaling / synchronization
12 *******************************************************************************/
14 package org
.eclipse
.linuxtools
.tmf
.event
;
18 * <b><u>TmfTimestamp</u></b>
20 * The fundamental time reference in the TMF.
22 * It provides a generic timestamp implementation in its most basic form:
24 * <li>timestamp = [value] * 10**[scale] +/- [precision]
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.
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).
42 * Notice that the adjusted timestamp value could be negative e.g. for events
43 * that occurred before t0 wrt the reference clock.
45 public class TmfTimestamp
implements Cloneable
{
47 // ------------------------------------------------------------------------
49 // ------------------------------------------------------------------------
51 protected long fValue
; // The timestamp raw value
52 protected byte fScale
; // The time scale
53 protected long fPrecision
; // The value precision (tolerance)
55 // ------------------------------------------------------------------------
57 // ------------------------------------------------------------------------
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);
64 // ------------------------------------------------------------------------
66 // ------------------------------------------------------------------------
71 public TmfTimestamp() {
76 * Simple constructor with value only
78 public TmfTimestamp(long value
) {
79 this(value
, (byte) 0, 0);
83 * Simple constructor with value and scale
88 public TmfTimestamp(long value
, byte scale
) {
89 this(value
, scale
, 0);
93 * Constructor with value, scale and precision
99 public TmfTimestamp(long value
, byte scale
, long precision
) {
102 fPrecision
= Math
.abs(precision
);
110 public TmfTimestamp(TmfTimestamp other
) {
112 throw new IllegalArgumentException();
113 fValue
= other
.fValue
;
114 fScale
= other
.fScale
;
115 fPrecision
= other
.fPrecision
;
118 // ------------------------------------------------------------------------
120 // ------------------------------------------------------------------------
123 * @return the timestamp value
125 public long getValue() {
130 * @return the timestamp scale
132 public byte getScale() {
137 * @return the timestamp value precision
139 public long getPrecision() {
143 // ------------------------------------------------------------------------
145 // ------------------------------------------------------------------------
148 * Return a shifted and scaled timestamp.
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.
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
160 public TmfTimestamp
synchronize(long offset
, byte newScale
) throws ArithmeticException
{
162 long newValue
= fValue
;
163 long newPrecision
= fPrecision
;
165 // Handle the easy case
166 if (fScale
== newScale
&& offset
== 0)
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");
176 // Adjust the timestamp
177 long scalingFactor
= scalingFactors
[scaleDiff
];
178 if (newScale
< fScale
) {
179 newValue
*= scalingFactor
;
180 newPrecision
*= scalingFactor
;
182 newValue
/= scalingFactor
;
183 newPrecision
/= scalingFactor
;
188 newValue
= (newValue
< Long
.MIN_VALUE
- offset
) ? Long
.MIN_VALUE
: newValue
+ offset
;
190 newValue
= (newValue
> Long
.MAX_VALUE
- offset
) ? Long
.MAX_VALUE
: newValue
+ offset
;
193 return new TmfTimestamp(newValue
, newScale
, newPrecision
);
196 private static final long scalingFactors
[] = new long[] {
215 1000000000000000000L,
218 private static final long scalingLimits
[] = new long[] {
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,
240 public static long getScalingFactor(byte scale
)
242 return scalingFactors
[scale
];
246 * Compute the adjustment, in the reference scale, needed to synchronize
247 * this timestamp with a reference timestamp.
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
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
;
261 * Compare with another timestamp
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)
269 public int compareTo(final TmfTimestamp other
, boolean withinPrecision
) {
271 // If values have the same time scale, perform the comparison
272 if (fScale
== other
.fScale
) {
274 return compareWithinPrecision(this.fValue
, this.fPrecision
, other
.fValue
, other
.fPrecision
);
276 return compareNoPrecision(this.fValue
, other
.fValue
);
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
);
285 if (scaleDiff
< scalingFactors
.length
) {
286 factor
= scalingFactors
[scaleDiff
];
287 limit
= scalingLimits
[scaleDiff
];
290 limit
= 0; // !!! 0 can always be scaled!!!
293 if (fScale
< other
.fScale
) {
294 // this has finer scale, so other should be scaled
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
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
306 return compareNoPrecision(this.fValue
, other
.fValue
* factor
);
308 // other has finer scale, so this should be scaled
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
314 return compareWithinPrecision(this.fValue
* factor
,
315 this.fPrecision
* factor
, other
.fValue
,
317 else if (this.fValue
> limit
|| this.fValue
< -limit
)
318 return this.fValue
> 0 ?
+1 : -1; // we exceed scaling limit
320 return compareNoPrecision(this.fValue
* factor
, other
.fValue
);
324 private static int compareNoPrecision(long thisValue
, long otherValue
) {
325 return (thisValue
== otherValue
) ?
0 : (thisValue
< otherValue
) ?
-1 : 1;
328 private static int compareWithinPrecision(long thisValue
, long thisPrecision
, long otherValue
, long otherPrecision
) {
329 if ((thisValue
+ thisPrecision
) < (otherValue
- otherPrecision
))
331 if ((thisValue
- thisPrecision
) > (otherValue
+ otherPrecision
))
336 // ------------------------------------------------------------------------
338 // ------------------------------------------------------------------------
341 public int hashCode() {
343 result
= 37 * result
+ (int) (fValue ^
(fValue
>>> 32));
344 result
= 37 * result
+ fScale
;
345 result
= 37 * result
+ (int) (fPrecision ^
(fPrecision
>>> 32));
350 public boolean equals(Object other
) {
351 if (!(other
instanceof TmfTimestamp
))
353 TmfTimestamp o
= (TmfTimestamp
) other
;
354 return compareTo(o
, false) == 0;
358 public String
toString() {
359 return "[TmfTimestamp(" + fValue
+ "," + fScale
+ "," + fPrecision
+ ")]";
363 public TmfTimestamp
clone() {
364 TmfTimestamp clone
= null;
366 clone
= (TmfTimestamp
) super.clone();
367 clone
.fValue
= fValue
;
368 clone
.fScale
= fScale
;
369 clone
.fPrecision
= fPrecision
;
370 } catch (CloneNotSupportedException e
) {