NEW - bug 302486: [LTTng] Feature: Time synchronization
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf / src / org / eclipse / linuxtools / tmf / event / TmfTimestamp.java
CommitLineData
8c8bf09f
ASL
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 *******************************************************************************/
12
13package org.eclipse.linuxtools.tmf.event;
14
15
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>
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
31 * timestamps in different scales). Default: 0.
32 * </ul>
33 * In short:
34 * <ul>
35 * </ul>
36 * To allow synchronization of timestamps from different reference clocks,
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).
40 * <p>
41 * Notice that the adjusted timestamp value could be negative e.g. for events
42 * that occurred before t0 wrt the reference clock.
43 */
44public class TmfTimestamp implements Cloneable {
45
46 // ------------------------------------------------------------------------
47 // Attributes
48 // ------------------------------------------------------------------------
49
50 protected long fValue; // The timestamp raw value
51 protected byte fScale; // The time scale
52 protected long fPrecision; // The value precision (tolerance)
53
54 // ------------------------------------------------------------------------
55 // Constants
56 // ------------------------------------------------------------------------
57
58 // The beginning and end of time
59 public static final TmfTimestamp BigBang = new TmfTimestamp(Long.MIN_VALUE, Byte.MAX_VALUE, 0);
60 public static final TmfTimestamp BigCrunch = new TmfTimestamp(Long.MAX_VALUE, Byte.MAX_VALUE, 0);
61 public static final TmfTimestamp Zero = new TmfTimestamp(0, (byte) 0, 0);
62
63 /*
64 * A java <code>long</code> has a maximum of 19 significant digits.
65 * (-9,223,372,036,854,775,808 .. +9,223,372,036,854,775,807)
66 *
67 * It is therefore useless to try to synchronize 2 timestamps whose
68 * difference in scale exceeds that value.
69 */
70 private int MAX_SCALING = 19;
71
72 // ------------------------------------------------------------------------
73 // Constructors
74 // ------------------------------------------------------------------------
75
76 /**
77 * Default constructor
78 */
79 public TmfTimestamp() {
80 this(0, (byte) 0, 0);
81 }
82
83 /**
84 * Simple constructor with value only
85 */
86 public TmfTimestamp(long value) {
87 this(value, (byte) 0, 0);
88 }
89
90 /**
91 * Simple constructor with value and scale
92 *
93 * @param value
94 * @param scale
95 */
96 public TmfTimestamp(long value, byte scale) {
97 this(value, scale, 0);
98 }
99
100 /**
101 * Constructor with value, scale and precision
102 *
103 * @param value
104 * @param scale
105 * @param precision
106 */
107 public TmfTimestamp(long value, byte scale, long precision) {
108 fValue = value;
109 fScale = scale;
110 fPrecision = Math.abs(precision);
111 }
112
113 /**
114 * Copy constructor
115 *
116 * @param other
117 */
118 public TmfTimestamp(TmfTimestamp other) {
119 if (other == null)
120 throw new IllegalArgumentException();
121 fValue = other.fValue;
122 fScale = other.fScale;
123 fPrecision = other.fPrecision;
124 }
125
126 // ------------------------------------------------------------------------
127 // Accessors
128 // ------------------------------------------------------------------------
129
130 /**
131 * @return the timestamp value
132 */
133 public long getValue() {
134 return fValue;
135 }
136
137 /**
138 * @return the timestamp scale
139 */
140 public byte getScale() {
141 return fScale;
142 }
143
144 /**
145 * @return the timestamp value precision
146 */
147 public long getPrecision() {
148 return fPrecision;
149 }
150
151 // ------------------------------------------------------------------------
152 // Operators
153 // ------------------------------------------------------------------------
154
155 /**
156 * Return a shifted and scaled timestamp.
157 *
158 * Limitation: The scaling is limited to MAX_SCALING orders of magnitude.
159 * The main reason is that the 64 bits value starts to lose any significance
160 * meaning beyond that scale difference and it's not even worth the trouble
161 * to switch to BigDecimal arithmetics.
162 *
163 * @param offset the shift value (in the same scale as newScale)
164 * @param newScale the new timestamp scale
165 * @return the synchronized timestamp in the new scale
166 * @throws ArithmeticException
167 */
168 public TmfTimestamp synchronize(long offset, byte newScale) throws ArithmeticException {
169
170 long newValue = fValue;
171 long newPrecision = fPrecision;
172
173 // Determine the scaling factor
174 if (fScale != newScale) {
175 int scaleDiff = Math.abs(fScale - newScale);
176 // Let's try to be realistic...
177 if (scaleDiff > MAX_SCALING) {
178 throw new ArithmeticException("Scaling exception");
179 }
180 // Not pretty...
181 long scalingFactor = 1;
182 for (int i = 0; i < scaleDiff; i++) {
183 scalingFactor *= 10;
184 }
185 if (newScale < fScale) {
186 newValue *= scalingFactor;
187 newPrecision *= scalingFactor;
188 } else {
189 newValue /= scalingFactor;
190 newPrecision /= scalingFactor;
191 }
192 }
193
194 return new TmfTimestamp(newValue + offset, newScale, newPrecision);
195 }
196
197 /**
198 * Compute the adjustment, in the reference scale, needed to synchronize
199 * this timestamp with a reference timestamp.
200 *
201 * @param reference the reference timestamp to synchronize with
202 * @param scale the scale of the adjustment
203 * @return the adjustment term in the reference time scale
204 * @throws ArithmeticException
205 */
206 public long getAdjustment(TmfTimestamp reference, byte scale) throws ArithmeticException {
207 TmfTimestamp ts1 = synchronize(0, scale);
208 TmfTimestamp ts2 = reference.synchronize(0, scale);
209 return ts2.fValue - ts1.fValue;
210 }
211
212 /**
213 * Compare with another timestamp
214 *
215 * @param other the other timestamp
216 * @param withinPrecision indicates if precision is to be take into consideration
217 * @return -1: this timestamp is lower (i.e. anterior)
218 * 0: timestamps are equal (within precision if requested)
219 * 1: this timestamp is higher (i.e. posterior)
220 */
221 public int compareTo(final TmfTimestamp other, boolean withinPrecision) {
222
223 // If values have the same time scale, perform the comparison
224 if (fScale == other.fScale) {
225 if (withinPrecision) {
226 if ((fValue + fPrecision) < (other.fValue - other.fPrecision))
227 return -1;
228 if ((fValue - fPrecision) > (other.fValue + other.fPrecision))
229 return 1;
230 return 0;
231 }
232 return (fValue == other.fValue) ? 0 : (fValue < other.fValue) ? -1 : 1;
233 }
234
235 // If values have different time scales, adjust to the finest one and
236 // then compare. If the scaling difference is too large, revert to
237 // some heuristics. Hopefully, nobody will try to compare galactic and
238 // quantic clock events...
239 if (Math.abs(fScale - other.fScale) > MAX_SCALING) {
240 return simpleCompare(other);
241 }
242
243 byte newScale = (fScale < other.fScale) ? fScale : other.fScale;
244 try {
245 TmfTimestamp ts1 = this.synchronize(0, newScale);
246 TmfTimestamp ts2 = other.synchronize(0, newScale);
247 return ts1.compareTo(ts2, withinPrecision);
248 } catch (ArithmeticException e) {
249 return simpleCompare(other);
250 }
251 }
252
253 private int simpleCompare(final TmfTimestamp other) {
254 if ((fValue == 0) || (other.fValue == 0)) {
255 return (fValue == other.fValue) ? 0
256 : (fValue < other.fValue) ? -1 : 1;
257 }
258 if ((fValue > 0) && (other.fValue > 0)) {
259 return (fScale < other.fScale) ? -1 : 1;
260 }
261 if ((fValue < 0) && (other.fValue < 0)) {
262 return (fScale > other.fScale) ? -1 : 1;
263 }
264 return (fValue < 0) ? -1 : 1;
265 }
266
267 // ------------------------------------------------------------------------
268 // Object
269 // ------------------------------------------------------------------------
270
271 @Override
272 public int hashCode() {
273 int result = 17;
274 result = 37 * result + (int) (fValue ^ (fValue >>> 32));
275 result = 37 * result + fScale;
276 result = 37 * result + (int) (fPrecision ^ (fPrecision >>> 32));
277 return result;
278 }
279
280 @Override
281 public boolean equals(Object other) {
282 if (!(other instanceof TmfTimestamp))
283 return false;
284 TmfTimestamp o = (TmfTimestamp) other;
285 return compareTo(o, false) == 0;
286 }
287
288 @Override
289 public String toString() {
290 return "[TmfTimestamp(" + fValue + "," + fScale + "," + fPrecision + ")]";
291 }
292
293 @Override
294 public TmfTimestamp clone() {
295 TmfTimestamp clone = null;
296 try {
297 clone = (TmfTimestamp) super.clone();
298 clone.fValue = fValue;
299 clone.fScale = fScale;
300 clone.fPrecision = fPrecision;
301 } catch (CloneNotSupportedException e) {
302 }
303 return clone;
304 }
305
306}
This page took 0.034441 seconds and 5 git commands to generate.