ss: Add a StateSystemUtils for advanced queries
[deliverable/tracecompass.git] / org.eclipse.tracecompass.tmf.core / src / org / eclipse / tracecompass / internal / tmf / core / statesystem / mipmap / TmfStateSystemOperations.java
1 /*******************************************************************************
2 * Copyright (c) 2013, 2014 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 * Jean-Christian Kouamé - Initial API and implementation
11 * Patrick Tasse - Updates to mipmap feature
12 ******************************************************************************/
13
14 package org.eclipse.tracecompass.internal.tmf.core.statesystem.mipmap;
15
16 import java.util.ArrayList;
17 import java.util.List;
18
19 import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem;
20 import org.eclipse.tracecompass.statesystem.core.StateSystemUtils;
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;
27 import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue.Type;
28 import org.eclipse.tracecompass.statesystem.core.statevalue.TmfStateValue;
29
30
31 /**
32 * This class implements additional statistical operations that can be
33 * performed on attributes of the state system.
34 *
35 * @author Patrick Tassé
36 * @since 3.0
37 */
38 public final class TmfStateSystemOperations {
39
40 private TmfStateSystemOperations() {}
41
42 /**
43 * Return the maximum value of an attribute over a time range
44 *
45 * @param ss
46 * The state system to query
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
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
61 */
62 public static ITmfStateValue queryRangeMax(ITmfStateSystem ss, long t1, long t2, int quark)
63 throws AttributeNotFoundException, TimeRangeException, StateValueTypeException {
64 ITmfStateValue max = TmfStateValue.nullValue();
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();
84 }
85 break;
86
87 case NULL:
88 case STRING:
89 default:
90 throw new StateValueTypeException();
91 }
92 }
93 return max;
94 }
95
96 /**
97 * Return the minimum value of an attribute over a time range
98 *
99 * @param ss
100 * The state system to query
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
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
115 */
116 public static ITmfStateValue queryRangeMin(ITmfStateSystem ss,
117 long t1, long t2, int quark)
118 throws AttributeNotFoundException, TimeRangeException, StateValueTypeException {
119 ITmfStateValue min = TmfStateValue.nullValue();
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();
139 }
140 break;
141
142 case NULL:
143 case STRING:
144 default:
145 throw new StateValueTypeException();
146 }
147 }
148 return min;
149 }
150
151 /**
152 * Return the weighted average value of an attribute over a time range
153 *
154 * @param ss
155 * The state system to query
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
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
170 */
171 public static double queryRangeAverage(ITmfStateSystem ss, long t1, long t2, int quark)
172 throws AttributeNotFoundException, TimeRangeException, StateValueTypeException {
173 double avg = 0.0;
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();
181 }
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));
194 }
195 }
196 }
197 return avg;
198 }
199
200 private static List<ITmfStateInterval> queryAttributeRange(ITmfStateSystem ss,
201 long t1, long t2, int baseQuark, String featureString)
202 throws AttributeNotFoundException, TimeRangeException, StateValueTypeException {
203 TimeRange timeRange = new TimeRange(t1, t2);
204 int mipmapQuark = -1;
205 List<ITmfStateInterval> intervals = new ArrayList<>();
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 {
217 for (ITmfStateInterval interval : StateSystemUtils.queryHistoryRange(ss, baseQuark, t1, t2)) {
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();
227 queryMipmapAttributeRange(ss, 0, levelMax, baseQuark, mipmapQuark, timeRange, intervals);
228 return intervals;
229
230 } catch (StateValueTypeException e) {
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$
234 } catch (StateSystemDisposedException e) {
235 /* We are shutting down, ignore the operation */
236 }
237 return intervals;
238 }
239
240 private static void queryMipmapAttributeRange(ITmfStateSystem ss,
241 int currentLevel, int levelMax, int baseQuark, int mipmapQuark,
242 TimeRange timeRange, List<ITmfStateInterval> intervals)
243 throws AttributeNotFoundException, TimeRangeException {
244 int level = currentLevel;
245 TimeRange range = timeRange;
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 {
254 if (range.getFirst() == range.getSecond()) {
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 }
273 queryMipmapAttributeRange(ss, level, levelMax, baseQuark, mipmapQuark, range, intervals);
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
303 queryMipmapAttributeRange(ss, level, levelMax, baseQuark,
304 mipmapQuark, range, intervals);
305
306 } catch (StateSystemDisposedException e) {
307 /* We are shutting down, ignore the operation */
308 }
309 }
310
311 private static TimeRange updateTimeRange(TimeRange timeRange,
312 ITmfStateInterval currentLevelInterval) {
313 if (currentLevelInterval.getEndTime() >= timeRange.getSecond()) {
314 return null;
315 }
316 long startTime = Math.max(timeRange.getFirst(),
317 Math.min(currentLevelInterval.getEndTime() + 1, timeRange.getSecond()));
318 return new TimeRange(startTime, timeRange.getSecond());
319 }
320
321 private static boolean isFullyOverlapped(TimeRange range,
322 ITmfStateInterval interval) {
323 if (range.getFirst() >= range.getSecond() ||
324 interval.getStartTime() >= interval.getEndTime()) {
325 return false;
326 }
327 if (range.getFirst() <= interval.getStartTime() &&
328 range.getSecond() >= interval.getEndTime()) {
329 return true;
330 }
331 return false;
332 }
333 }
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 }
This page took 0.04125 seconds and 6 git commands to generate.