Commit | Line | Data |
---|---|---|
8e364f8e | 1 | /******************************************************************************* |
60ae41e1 | 2 | * Copyright (c) 2013, 2014 Ericsson |
8e364f8e PT |
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 | * Jean-Christian Kouamé - Initial API and implementation | |
11 | * Patrick Tasse - Updates to mipmap feature | |
12 | ******************************************************************************/ | |
13 | ||
2bdf0193 | 14 | package org.eclipse.tracecompass.internal.tmf.core.statesystem.mipmap; |
8e364f8e PT |
15 | |
16 | import java.util.ArrayList; | |
17 | import java.util.List; | |
18 | ||
e894a508 | 19 | import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem; |
1dd75589 | 20 | import org.eclipse.tracecompass.statesystem.core.StateSystemUtils; |
e894a508 AM |
21 | import org.eclipse.tracecompass.statesystem.core.exceptions.AttributeNotFoundException; |
22 | import org.eclipse.tracecompass.statesystem.core.exceptions.StateSystemDisposedException; | |
23 | import org.eclipse.tracecompass.statesystem.core.exceptions.StateValueTypeException; | |
24 | import org.eclipse.tracecompass.statesystem.core.exceptions.TimeRangeException; | |
25 | import org.eclipse.tracecompass.statesystem.core.interval.ITmfStateInterval; | |
26 | import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue; | |
e894a508 | 27 | import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue.Type; |
1dd75589 AM |
28 | import org.eclipse.tracecompass.statesystem.core.statevalue.TmfStateValue; |
29 | ||
8e364f8e PT |
30 | |
31 | /** | |
32 | * This class implements additional statistical operations that can be | |
33 | * performed on attributes of the state system. | |
64d15677 AM |
34 | * |
35 | * @author Patrick Tassé | |
c4767854 | 36 | * @since 3.0 |
8e364f8e | 37 | */ |
64d15677 | 38 | public final class TmfStateSystemOperations { |
8e364f8e | 39 | |
64d15677 | 40 | private TmfStateSystemOperations() {} |
8e364f8e PT |
41 | |
42 | /** | |
43 | * Return the maximum value of an attribute over a time range | |
44 | * | |
64d15677 AM |
45 | * @param ss |
46 | * The state system to query | |
8e364f8e PT |
47 | * @param t1 |
48 | * The start time of the range | |
49 | * @param t2 | |
50 | * The end time of the range | |
51 | * @param quark | |
52 | * The quark of the attribute | |
53 | * @return The maximum value of the attribute in this range | |
64d15677 AM |
54 | * @throws TimeRangeException |
55 | * If an invalid time range is specified | |
56 | * @throws AttributeNotFoundException | |
57 | * If the specified quark doesn't match an attribute | |
58 | * @throws StateValueTypeException | |
59 | * If the state value type of the attribute does not support the | |
60 | * "Max" operation | |
8e364f8e | 61 | */ |
64d15677 AM |
62 | public static ITmfStateValue queryRangeMax(ITmfStateSystem ss, long t1, long t2, int quark) |
63 | throws AttributeNotFoundException, TimeRangeException, StateValueTypeException { | |
8e364f8e | 64 | ITmfStateValue max = TmfStateValue.nullValue(); |
64d15677 AM |
65 | |
66 | List<ITmfStateInterval> intervals = queryAttributeRange(ss, t1, t2, quark, AbstractTmfMipmapStateProvider.MAX_STRING); | |
67 | if (intervals.size() == 0) { | |
68 | return TmfStateValue.nullValue(); | |
69 | } | |
70 | for (ITmfStateInterval si : intervals) { | |
71 | ITmfStateValue value = si.getStateValue(); | |
72 | ||
73 | switch (value.getType()) { | |
74 | case DOUBLE: | |
75 | if (max.isNull() || si.getStateValue().unboxDouble() > max.unboxDouble()) { | |
76 | max = si.getStateValue(); | |
77 | } | |
78 | break; | |
79 | ||
80 | case INTEGER: | |
81 | case LONG: | |
82 | if (max.isNull() || si.getStateValue().unboxLong() > max.unboxLong()) { | |
83 | max = si.getStateValue(); | |
8e364f8e | 84 | } |
64d15677 AM |
85 | break; |
86 | ||
87 | case NULL: | |
88 | case STRING: | |
89 | default: | |
90 | throw new StateValueTypeException(); | |
8e364f8e | 91 | } |
8e364f8e PT |
92 | } |
93 | return max; | |
94 | } | |
95 | ||
96 | /** | |
97 | * Return the minimum value of an attribute over a time range | |
98 | * | |
64d15677 AM |
99 | * @param ss |
100 | * The state system to query | |
8e364f8e PT |
101 | * @param t1 |
102 | * The start time of the range | |
103 | * @param t2 | |
104 | * The end time of the range | |
105 | * @param quark | |
106 | * The quark of the attribute | |
107 | * @return The minimum value of the attribute in this range | |
64d15677 AM |
108 | * @throws TimeRangeException |
109 | * If an invalid time range is specified | |
110 | * @throws AttributeNotFoundException | |
111 | * If the specified quark doesn't match an attribute | |
112 | * @throws StateValueTypeException | |
113 | * If the state value type of the attribute does not support the | |
114 | * "Min" operation | |
8e364f8e | 115 | */ |
64d15677 AM |
116 | public static ITmfStateValue queryRangeMin(ITmfStateSystem ss, |
117 | long t1, long t2, int quark) | |
118 | throws AttributeNotFoundException, TimeRangeException, StateValueTypeException { | |
8e364f8e | 119 | ITmfStateValue min = TmfStateValue.nullValue(); |
64d15677 AM |
120 | |
121 | List<ITmfStateInterval> intervals = queryAttributeRange(ss, t1, t2, quark, AbstractTmfMipmapStateProvider.MIN_STRING); | |
122 | if (intervals.size() == 0) { | |
123 | return TmfStateValue.nullValue(); | |
124 | } | |
125 | for (ITmfStateInterval si : intervals) { | |
126 | ITmfStateValue value = si.getStateValue(); | |
127 | ||
128 | switch (value.getType()) { | |
129 | case DOUBLE: | |
130 | if (min.isNull() || si.getStateValue().unboxDouble() < min.unboxDouble()) { | |
131 | min = si.getStateValue(); | |
132 | } | |
133 | break; | |
134 | ||
135 | case INTEGER: | |
136 | case LONG: | |
137 | if (min.isNull() || si.getStateValue().unboxLong() < min.unboxLong()) { | |
138 | min = si.getStateValue(); | |
8e364f8e | 139 | } |
64d15677 AM |
140 | break; |
141 | ||
142 | case NULL: | |
143 | case STRING: | |
144 | default: | |
145 | throw new StateValueTypeException(); | |
8e364f8e | 146 | } |
8e364f8e PT |
147 | } |
148 | return min; | |
149 | } | |
150 | ||
151 | /** | |
152 | * Return the weighted average value of an attribute over a time range | |
153 | * | |
64d15677 AM |
154 | * @param ss |
155 | * The state system to query | |
8e364f8e PT |
156 | * @param t1 |
157 | * The start time of the range | |
158 | * @param t2 | |
159 | * The end time of the range | |
160 | * @param quark | |
161 | * The quark of the attribute | |
162 | * @return The weighted average value of the attribute in this range | |
64d15677 AM |
163 | * @throws TimeRangeException |
164 | * If an invalid time range is specified | |
165 | * @throws AttributeNotFoundException | |
166 | * If the specified quark doesn't match an attribute | |
167 | * @throws StateValueTypeException | |
168 | * If the state value type of the attribute does not support the | |
169 | * "Average" operation | |
8e364f8e | 170 | */ |
64d15677 AM |
171 | public static double queryRangeAverage(ITmfStateSystem ss, long t1, long t2, int quark) |
172 | throws AttributeNotFoundException, TimeRangeException, StateValueTypeException { | |
8e364f8e | 173 | double avg = 0.0; |
64d15677 AM |
174 | List<ITmfStateInterval> intervals = queryAttributeRange(ss, t1, t2, quark, AbstractTmfMipmapStateProvider.AVG_STRING); |
175 | if (intervals.size() == 0) { | |
176 | return 0; | |
177 | } else if (t1 == t2) { | |
178 | ITmfStateValue value = intervals.get(0).getStateValue(); | |
179 | if (value.getType() == Type.DOUBLE) { | |
180 | return value.unboxDouble(); | |
8e364f8e | 181 | } |
64d15677 AM |
182 | return value.unboxLong(); |
183 | } | |
184 | for (ITmfStateInterval si : intervals) { | |
185 | long startTime = Math.max(t1, si.getStartTime()); | |
186 | long endTime = Math.min(t2, si.getEndTime() + 1); | |
187 | long delta = endTime - startTime; | |
188 | if (delta > 0) { | |
189 | ITmfStateValue value = si.getStateValue(); | |
190 | if (value.getType() == Type.DOUBLE) { | |
191 | avg += si.getStateValue().unboxDouble() * ((double) delta / (double) (t2 - t1)); | |
192 | } else { | |
193 | avg += si.getStateValue().unboxLong() * ((double) delta / (double) (t2 - t1)); | |
8e364f8e PT |
194 | } |
195 | } | |
8e364f8e PT |
196 | } |
197 | return avg; | |
198 | } | |
199 | ||
64d15677 AM |
200 | private static List<ITmfStateInterval> queryAttributeRange(ITmfStateSystem ss, |
201 | long t1, long t2, int baseQuark, String featureString) | |
202 | throws AttributeNotFoundException, TimeRangeException, StateValueTypeException { | |
0126a8ca | 203 | TimeRange timeRange = new TimeRange(t1, t2); |
8e364f8e | 204 | int mipmapQuark = -1; |
a4524c1b | 205 | List<ITmfStateInterval> intervals = new ArrayList<>(); |
8e364f8e PT |
206 | try { |
207 | try { | |
208 | mipmapQuark = ss.getQuarkRelative(baseQuark, featureString); | |
209 | } catch (AttributeNotFoundException e) { | |
210 | /* Not a mipmap attribute, query the base attribute */ | |
211 | if (t1 == t2) { | |
212 | ITmfStateInterval interval = ss.querySingleState(t1, baseQuark); | |
213 | if (!interval.getStateValue().isNull()) { | |
214 | intervals.add(interval); | |
215 | } | |
216 | } else { | |
1dd75589 | 217 | for (ITmfStateInterval interval : StateSystemUtils.queryHistoryRange(ss, baseQuark, t1, t2)) { |
8e364f8e PT |
218 | if (!interval.getStateValue().isNull()) { |
219 | intervals.add(interval); | |
220 | } | |
221 | } | |
222 | } | |
223 | return intervals; | |
224 | } | |
225 | ITmfStateInterval maxLevelInterval = ss.querySingleState(timeRange.getSecond(), mipmapQuark); | |
226 | int levelMax = maxLevelInterval.getStateValue().unboxInt(); | |
64d15677 | 227 | queryMipmapAttributeRange(ss, 0, levelMax, baseQuark, mipmapQuark, timeRange, intervals); |
8e364f8e | 228 | return intervals; |
64d15677 | 229 | |
8e364f8e | 230 | } catch (StateValueTypeException e) { |
64d15677 AM |
231 | /* This is a special case, so we'll add a message to the exception */ |
232 | throw new StateValueTypeException("State system advertises mipmaps," + //$NON-NLS-1$ | |
233 | " but doesn't actually have them.", e); //$NON-NLS-1$ | |
8e364f8e | 234 | } catch (StateSystemDisposedException e) { |
64d15677 | 235 | /* We are shutting down, ignore the operation */ |
8e364f8e PT |
236 | } |
237 | return intervals; | |
238 | } | |
239 | ||
64d15677 AM |
240 | private static void queryMipmapAttributeRange(ITmfStateSystem ss, |
241 | int currentLevel, int levelMax, int baseQuark, int mipmapQuark, | |
0126a8ca | 242 | TimeRange timeRange, List<ITmfStateInterval> intervals) |
64d15677 | 243 | throws AttributeNotFoundException, TimeRangeException { |
8e364f8e | 244 | int level = currentLevel; |
0126a8ca | 245 | TimeRange range = timeRange; |
8e364f8e PT |
246 | ITmfStateInterval currentLevelInterval = null, nextLevelInterval = null; |
247 | if (range == null || range.getFirst() > range.getSecond()) { | |
248 | return; | |
249 | } | |
250 | if (level > levelMax || level < 0) { | |
251 | return; | |
252 | } | |
253 | try { | |
0126a8ca | 254 | if (range.getFirst() == range.getSecond()) { |
8e364f8e PT |
255 | level = 0; |
256 | currentLevelInterval = ss.querySingleState(range.getFirst(), baseQuark); | |
257 | if (!currentLevelInterval.getStateValue().isNull()) { | |
258 | intervals.add(currentLevelInterval); | |
259 | } | |
260 | return; | |
261 | } | |
262 | if (level < levelMax) { | |
263 | int levelQuark = ss.getQuarkRelative(mipmapQuark, String.valueOf(level + 1)); | |
264 | nextLevelInterval = ss.querySingleState(range.getFirst(), levelQuark); | |
265 | } | |
266 | ||
267 | if (nextLevelInterval != null && isFullyOverlapped(range, nextLevelInterval)) { | |
268 | if (nextLevelInterval.getStateValue().isNull()) { | |
269 | range = updateTimeRange(range, nextLevelInterval); | |
270 | } else { | |
271 | level++; | |
272 | } | |
64d15677 | 273 | queryMipmapAttributeRange(ss, level, levelMax, baseQuark, mipmapQuark, range, intervals); |
8e364f8e PT |
274 | return; |
275 | } | |
276 | ||
277 | if (level == 0) { | |
278 | currentLevelInterval = ss.querySingleState(range.getFirst(), baseQuark); | |
279 | } else { | |
280 | int levelQuark = ss.getQuarkRelative(mipmapQuark, String.valueOf(level)); | |
281 | currentLevelInterval = ss.querySingleState(range.getFirst(), levelQuark); | |
282 | } | |
283 | ||
284 | if (currentLevelInterval != null && isFullyOverlapped(range, currentLevelInterval)) { | |
285 | if (!currentLevelInterval.getStateValue().isNull()) { | |
286 | intervals.add(currentLevelInterval); | |
287 | } | |
288 | range = updateTimeRange(range, currentLevelInterval); | |
289 | } else { | |
290 | if (level == 0) { | |
291 | if (currentLevelInterval == null) { | |
292 | return; | |
293 | } | |
294 | if (!currentLevelInterval.getStateValue().isNull()) { | |
295 | intervals.add(currentLevelInterval); | |
296 | } | |
297 | range = updateTimeRange(range, currentLevelInterval); | |
298 | } else { | |
299 | level--; | |
300 | } | |
301 | } | |
302 | ||
64d15677 AM |
303 | queryMipmapAttributeRange(ss, level, levelMax, baseQuark, |
304 | mipmapQuark, range, intervals); | |
8e364f8e | 305 | |
8e364f8e | 306 | } catch (StateSystemDisposedException e) { |
64d15677 | 307 | /* We are shutting down, ignore the operation */ |
8e364f8e PT |
308 | } |
309 | } | |
310 | ||
0126a8ca | 311 | private static TimeRange updateTimeRange(TimeRange timeRange, |
64d15677 | 312 | ITmfStateInterval currentLevelInterval) { |
8e364f8e PT |
313 | if (currentLevelInterval.getEndTime() >= timeRange.getSecond()) { |
314 | return null; | |
315 | } | |
64d15677 AM |
316 | long startTime = Math.max(timeRange.getFirst(), |
317 | Math.min(currentLevelInterval.getEndTime() + 1, timeRange.getSecond())); | |
0126a8ca | 318 | return new TimeRange(startTime, timeRange.getSecond()); |
8e364f8e PT |
319 | } |
320 | ||
0126a8ca | 321 | private static boolean isFullyOverlapped(TimeRange range, |
64d15677 AM |
322 | ITmfStateInterval interval) { |
323 | if (range.getFirst() >= range.getSecond() || | |
324 | interval.getStartTime() >= interval.getEndTime()) { | |
8e364f8e PT |
325 | return false; |
326 | } | |
64d15677 AM |
327 | if (range.getFirst() <= interval.getStartTime() && |
328 | range.getSecond() >= interval.getEndTime()) { | |
8e364f8e PT |
329 | return true; |
330 | } | |
331 | return false; | |
332 | } | |
8e364f8e | 333 | } |
0126a8ca AM |
334 | |
335 | class TimeRange { | |
336 | ||
337 | private final long a; | |
338 | private final long b; | |
339 | ||
340 | public TimeRange(long first, long second) { | |
341 | a = first; | |
342 | b = second; | |
343 | } | |
344 | ||
345 | public long getFirst() { | |
346 | return a; | |
347 | } | |
348 | ||
349 | public long getSecond() { | |
350 | return b; | |
351 | } | |
352 | } |