Commit | Line | Data |
---|---|---|
5745c0a3 FG |
1 | /******************************************************************************* |
2 | * Copyright (c) 2015 École Polytechnique de Montréal | |
3 | * | |
4 | * All rights reserved. This program and the accompanying materials are made | |
5 | * 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 | * Francis Giraldeau - Initial implementation and API | |
11 | * Geneviève Bastien - Fixes and improvements | |
12 | *******************************************************************************/ | |
13 | ||
14 | package org.eclipse.tracecompass.tmf.core.tests.synchronization; | |
15 | ||
16 | import static org.junit.Assert.assertEquals; | |
17 | import static org.junit.Assert.assertNotNull; | |
18 | import static org.junit.Assert.assertTrue; | |
c338f3eb GB |
19 | import static org.junit.Assert.fail; |
20 | ||
21 | import java.io.File; | |
22 | import java.io.FileInputStream; | |
23 | import java.io.FileOutputStream; | |
24 | import java.io.IOException; | |
25 | import java.io.ObjectInputStream; | |
26 | import java.io.ObjectOutputStream; | |
27 | import java.util.Arrays; | |
5745c0a3 FG |
28 | |
29 | import org.eclipse.tracecompass.internal.tmf.core.synchronization.TmfTimestampTransformLinear; | |
30 | import org.eclipse.tracecompass.internal.tmf.core.synchronization.TmfTimestampTransformLinearFast; | |
31 | import org.eclipse.tracecompass.tmf.core.synchronization.ITmfTimestampTransform; | |
32 | import org.junit.Test; | |
c338f3eb GB |
33 | import org.junit.runner.RunWith; |
34 | import org.junit.runners.Parameterized; | |
35 | import org.junit.runners.Parameterized.Parameters; | |
5745c0a3 FG |
36 | |
37 | /** | |
38 | * Tests for {@link TmfTimestampTransformLinearFast} | |
39 | * | |
40 | * @author Geneviève Bastien | |
41 | */ | |
c338f3eb | 42 | @RunWith(Parameterized.class) |
5745c0a3 FG |
43 | public class TsTransformFastTest { |
44 | ||
45 | private static final long ts = 1361657893526374091L; | |
46 | ||
c338f3eb GB |
47 | private static interface IFastTransformFactory { |
48 | public TmfTimestampTransformLinearFast create(double alpha, double beta); | |
49 | } | |
50 | ||
51 | private static final IFastTransformFactory fNewObject = (a, b) -> { | |
52 | return new TmfTimestampTransformLinearFast(a, b); | |
53 | }; | |
54 | ||
55 | private static final IFastTransformFactory fDeserialized = (a, b) -> { | |
56 | TmfTimestampTransformLinearFast tt = new TmfTimestampTransformLinearFast(a, b); | |
57 | /* Serialize the object */ | |
58 | String filePath = null; | |
59 | try { | |
60 | File temp = File.createTempFile("serialSyncAlgo", ".tmp"); | |
61 | filePath = temp.getAbsolutePath(); | |
62 | } catch (IOException e) { | |
63 | fail("Could not create temporary file for serialization"); | |
64 | } | |
65 | assertNotNull(filePath); | |
66 | ||
67 | try (FileOutputStream fileOut = new FileOutputStream(filePath); | |
68 | ObjectOutputStream out = new ObjectOutputStream(fileOut);) { | |
69 | out.writeObject(tt); | |
70 | } catch (IOException e) { | |
71 | fail("Error serializing the synchronization algorithm " + e.getMessage()); | |
72 | } | |
73 | ||
74 | TmfTimestampTransformLinearFast deserialTt = null; | |
75 | /* De-Serialize the object */ | |
76 | try (FileInputStream fileIn = new FileInputStream(filePath); | |
77 | ObjectInputStream in = new ObjectInputStream(fileIn);) { | |
78 | deserialTt = (TmfTimestampTransformLinearFast) in.readObject(); | |
79 | } catch (IOException | ClassNotFoundException e) { | |
80 | fail("Error de-serializing the synchronization algorithm " + e.getMessage()); | |
81 | } | |
82 | return deserialTt; | |
83 | }; | |
84 | ||
85 | private final IFastTransformFactory fTransformFactory; | |
86 | ||
87 | /** | |
88 | * Constructor | |
89 | * | |
90 | * @param name | |
91 | * The name of this parameterized test | |
92 | * @param factory | |
93 | * Factory to create the timestamp transform | |
94 | */ | |
95 | public TsTransformFastTest(String name, IFastTransformFactory factory) { | |
96 | fTransformFactory = factory; | |
97 | } | |
98 | ||
99 | /** | |
100 | * @return the test parameters | |
101 | */ | |
102 | @Parameters(name = "Factory={0}") | |
103 | public static Iterable<Object[]> parameters() { | |
104 | return Arrays.asList(new Object[][] { | |
105 | { "Object", fNewObject }, | |
106 | { "Deserialized", fDeserialized } | |
107 | }); | |
108 | } | |
109 | ||
5745c0a3 FG |
110 | /** |
111 | * Test whether the fast linear transform always yields the same value for | |
112 | * the same timestamp | |
113 | */ | |
114 | @Test | |
115 | public void testFLTRepeatability() { | |
c338f3eb | 116 | TmfTimestampTransformLinearFast fast = fTransformFactory.create(Math.PI, 0); |
5745c0a3 FG |
117 | // Access fDeltaMax to compute the cache range boundaries |
118 | long deltaMax = fast.getDeltaMax(); | |
119 | // Initialize the transform | |
120 | long timestamp = ts - (ts % deltaMax); | |
121 | fast.transform(timestamp); | |
122 | long tsMiss = timestamp + deltaMax; | |
123 | long tsNoMiss = timestamp + deltaMax - 1; | |
124 | ||
125 | // Get the transformed value to a timestamp without cache miss | |
126 | long tsTNoMiss = fast.transform(tsNoMiss); | |
127 | assertEquals(1, fast.getCacheMisses()); | |
128 | ||
129 | // Cause a cache miss | |
130 | fast.transform(tsMiss); | |
131 | assertEquals(2, fast.getCacheMisses()); | |
132 | ||
133 | /* | |
134 | * Get the transformed value of the same previous timestamp after the | |
135 | * miss | |
136 | */ | |
137 | long tsTAfterMiss = fast.transform(tsNoMiss); | |
138 | assertEquals(tsTNoMiss, tsTAfterMiss); | |
139 | } | |
140 | ||
141 | /** | |
142 | * Test that 2 equal fast transform always give the same results for the | |
143 | * same values | |
144 | */ | |
145 | @Test | |
146 | public void testFLTEquivalence() { | |
c338f3eb GB |
147 | TmfTimestampTransformLinearFast fast = fTransformFactory.create(Math.PI, 0); |
148 | TmfTimestampTransformLinearFast fast2 = fTransformFactory.create(Math.PI, 0); | |
5745c0a3 FG |
149 | |
150 | long deltaMax = fast.getDeltaMax(); | |
151 | ||
152 | long start = (ts - (ts % deltaMax) - 10); | |
153 | checkTime(fast, fast2, 20, start, 1); | |
154 | } | |
155 | ||
156 | /** | |
157 | * Test the precision of the fast timestamp transform compared to the | |
158 | * original transform. | |
159 | */ | |
160 | @Test | |
161 | public void testFastTransformPrecision() { | |
162 | TmfTimestampTransformLinear precise = new TmfTimestampTransformLinear(Math.PI, 0); | |
c338f3eb | 163 | TmfTimestampTransformLinearFast fast = fTransformFactory.create(Math.PI, 0); |
5745c0a3 FG |
164 | int samples = 100; |
165 | long start = (long) Math.pow(10, 18); | |
166 | long end = Long.MAX_VALUE; | |
167 | int step = (int) ((end - start) / (samples * Math.PI)); | |
168 | checkTime(precise, fast, samples, start, step); | |
169 | assertEquals(samples, fast.getCacheMisses()); | |
170 | ||
171 | // check that rescale is done only when required | |
172 | // assumes tsBitWidth == 30 | |
173 | // test forward and backward timestamps | |
174 | samples = 1000; | |
175 | int[] directions = new int[] { 1, -1 }; | |
176 | for (Integer direction : directions) { | |
177 | for (int i = 0; i <= 30; i++) { | |
178 | fast.resetScaleStats(); | |
179 | step = (1 << i) * direction; | |
180 | checkTime(precise, fast, samples, start, step); | |
181 | assertTrue(String.format("samples: %d scale misses: %d", | |
182 | samples, fast.getCacheMisses()), samples >= fast.getCacheMisses()); | |
183 | } | |
184 | } | |
5745c0a3 FG |
185 | } |
186 | ||
187 | /** | |
c338f3eb GB |
188 | * Test that fast transform produces the same result for small and large |
189 | * slopes. | |
5745c0a3 FG |
190 | */ |
191 | @Test | |
192 | public void testFastTransformSlope() { | |
193 | int[] dir = new int[] { 1, -1 }; | |
194 | long start = (1 << 30); | |
195 | for (int ex = -9; ex <= 9; ex++) { | |
196 | for (int d = 0; d < dir.length; d++) { | |
197 | double slope = Math.pow(10.0, ex); | |
198 | TmfTimestampTransformLinear precise = new TmfTimestampTransformLinear(slope, 0); | |
c338f3eb | 199 | TmfTimestampTransformLinearFast fast = fTransformFactory.create(slope, 0); |
5745c0a3 FG |
200 | checkTime(precise, fast, 1000, start, dir[d]); |
201 | } | |
202 | } | |
203 | } | |
204 | ||
c338f3eb GB |
205 | /** |
206 | * Test that fast transform produces the same result with a slope and | |
207 | * offset, for small and large values | |
208 | */ | |
209 | @Test | |
210 | public void testFastTransformSlopeAndOffset() { | |
211 | double offset = 54321.0; | |
212 | double slope = Math.pow(10.0, 4); | |
213 | for (int ex = 0; ex <= Long.SIZE - 1; ex++) { | |
214 | long start = 1 << ex; | |
215 | TmfTimestampTransformLinear precise = new TmfTimestampTransformLinear(slope, offset); | |
216 | TmfTimestampTransformLinearFast fast = fTransformFactory.create(slope, offset); | |
217 | checkTime(precise, fast, 5, start, 1); | |
218 | } | |
219 | } | |
220 | ||
5745c0a3 FG |
221 | /** |
222 | * Check that the proper exception are raised for illegal slopes | |
223 | */ | |
224 | @Test | |
225 | public void testFastTransformArguments() { | |
c338f3eb GB |
226 | double[] slopes = new double[] { -1.0, ((double) Integer.MAX_VALUE) + 1, 1e-10 }; |
227 | for (double slope : slopes) { | |
5745c0a3 FG |
228 | Exception exception = null; |
229 | try { | |
c338f3eb | 230 | fTransformFactory.create(slope, 0.0); |
5745c0a3 FG |
231 | } catch (IllegalArgumentException e) { |
232 | exception = e; | |
233 | } | |
234 | assertNotNull(exception); | |
235 | } | |
236 | } | |
237 | ||
238 | private static void checkTime(ITmfTimestampTransform precise, ITmfTimestampTransform fast, | |
239 | int samples, long start, long step) { | |
240 | long prev = 0; | |
241 | for (int i = 0; i < samples; i++) { | |
242 | long time = start + i * step; | |
243 | long exp = precise.transform(time); | |
244 | long act = fast.transform(time); | |
245 | long err = act - exp; | |
246 | // allow only two ns of error | |
c338f3eb | 247 | assertTrue("start: " + start + " [" + err + "]", Math.abs(err) < 3); |
5745c0a3 FG |
248 | if (i > 0) { |
249 | if (step > 0) { | |
250 | assertTrue("monotonic error" + act + " " + prev, act >= prev); | |
251 | } else if (step < 0) { | |
252 | assertTrue("monotonic ", act <= prev); | |
253 | } | |
254 | } | |
255 | prev = act; | |
256 | } | |
257 | } | |
258 | ||
259 | } |