| /******************************************************************************* |
| * Copyright (c) 2013, 2015 Ericsson |
| * |
| * All rights reserved. This program and the accompanying materials are |
| * made available under the terms of the Eclipse Public License 2.0 which |
| * accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * Jean-Christian Kouamé - Initial API and implementation |
| * Patrick Tasse - Updates to mipmap feature |
| ******************************************************************************/ |
| |
| package org.eclipse.tracecompass.internal.tmf.core.statesystem.mipmap; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem; |
| import org.eclipse.tracecompass.statesystem.core.StateSystemUtils; |
| import org.eclipse.tracecompass.statesystem.core.exceptions.AttributeNotFoundException; |
| import org.eclipse.tracecompass.statesystem.core.exceptions.StateSystemDisposedException; |
| import org.eclipse.tracecompass.statesystem.core.exceptions.StateValueTypeException; |
| import org.eclipse.tracecompass.statesystem.core.exceptions.TimeRangeException; |
| import org.eclipse.tracecompass.statesystem.core.interval.ITmfStateInterval; |
| import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue; |
| import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue.Type; |
| import org.eclipse.tracecompass.statesystem.core.statevalue.TmfStateValue; |
| |
| |
| /** |
| * This class implements additional statistical operations that can be |
| * performed on attributes of the state system. |
| * |
| * @author Patrick Tassé |
| */ |
| public final class TmfStateSystemOperations { |
| |
| private TmfStateSystemOperations() {} |
| |
| /** |
| * Return the maximum value of an attribute over a time range |
| * |
| * @param ss |
| * The state system to query |
| * @param t1 |
| * The start time of the range |
| * @param t2 |
| * The end time of the range |
| * @param quark |
| * The quark of the attribute |
| * @return The maximum value of the attribute in this range |
| * @throws TimeRangeException |
| * If an invalid time range is specified |
| * @throws AttributeNotFoundException |
| * If the specified quark doesn't match an attribute |
| * @throws StateValueTypeException |
| * If the state value type of the attribute does not support the |
| * "Max" operation |
| */ |
| public static ITmfStateValue queryRangeMax(ITmfStateSystem ss, long t1, long t2, int quark) |
| throws AttributeNotFoundException, TimeRangeException, StateValueTypeException { |
| ITmfStateValue max = TmfStateValue.nullValue(); |
| |
| List<ITmfStateInterval> intervals = queryAttributeRange(ss, t1, t2, quark, AbstractTmfMipmapStateProvider.MAX_STRING); |
| if (intervals.isEmpty()) { |
| return TmfStateValue.nullValue(); |
| } |
| for (ITmfStateInterval si : intervals) { |
| ITmfStateValue value = si.getStateValue(); |
| |
| switch (value.getType()) { |
| case DOUBLE: |
| if (max.isNull() || si.getStateValue().unboxDouble() > max.unboxDouble()) { |
| max = si.getStateValue(); |
| } |
| break; |
| |
| case INTEGER: |
| case LONG: |
| if (max.isNull() || si.getStateValue().unboxLong() > max.unboxLong()) { |
| max = si.getStateValue(); |
| } |
| break; |
| |
| case NULL: |
| case STRING: |
| case CUSTOM: |
| default: |
| throw new StateValueTypeException(ss.getSSID() + " Quark:" + quark + ", Type:" + value.getType()); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| } |
| return max; |
| } |
| |
| /** |
| * Return the minimum value of an attribute over a time range |
| * |
| * @param ss |
| * The state system to query |
| * @param t1 |
| * The start time of the range |
| * @param t2 |
| * The end time of the range |
| * @param quark |
| * The quark of the attribute |
| * @return The minimum value of the attribute in this range |
| * @throws TimeRangeException |
| * If an invalid time range is specified |
| * @throws AttributeNotFoundException |
| * If the specified quark doesn't match an attribute |
| * @throws StateValueTypeException |
| * If the state value type of the attribute does not support the |
| * "Min" operation |
| */ |
| public static ITmfStateValue queryRangeMin(ITmfStateSystem ss, |
| long t1, long t2, int quark) |
| throws AttributeNotFoundException, TimeRangeException, StateValueTypeException { |
| ITmfStateValue min = TmfStateValue.nullValue(); |
| |
| List<ITmfStateInterval> intervals = queryAttributeRange(ss, t1, t2, quark, AbstractTmfMipmapStateProvider.MIN_STRING); |
| if (intervals.isEmpty()) { |
| return TmfStateValue.nullValue(); |
| } |
| for (ITmfStateInterval si : intervals) { |
| ITmfStateValue value = si.getStateValue(); |
| |
| switch (value.getType()) { |
| case DOUBLE: |
| if (min.isNull() || si.getStateValue().unboxDouble() < min.unboxDouble()) { |
| min = si.getStateValue(); |
| } |
| break; |
| |
| case INTEGER: |
| case LONG: |
| if (min.isNull() || si.getStateValue().unboxLong() < min.unboxLong()) { |
| min = si.getStateValue(); |
| } |
| break; |
| |
| case NULL: |
| case STRING: |
| case CUSTOM: |
| default: |
| throw new StateValueTypeException(ss.getSSID() + " Quark:" + quark + ", Type:" + value.getType()); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| } |
| return min; |
| } |
| |
| /** |
| * Return the weighted average value of an attribute over a time range |
| * |
| * @param ss |
| * The state system to query |
| * @param t1 |
| * The start time of the range |
| * @param t2 |
| * The end time of the range |
| * @param quark |
| * The quark of the attribute |
| * @return The weighted average value of the attribute in this range |
| * @throws TimeRangeException |
| * If an invalid time range is specified |
| * @throws AttributeNotFoundException |
| * If the specified quark doesn't match an attribute |
| * @throws StateValueTypeException |
| * If the state value type of the attribute does not support the |
| * "Average" operation |
| */ |
| public static double queryRangeAverage(ITmfStateSystem ss, long t1, long t2, int quark) |
| throws AttributeNotFoundException, TimeRangeException, StateValueTypeException { |
| double avg = 0.0; |
| List<ITmfStateInterval> intervals = queryAttributeRange(ss, t1, t2, quark, AbstractTmfMipmapStateProvider.AVG_STRING); |
| if (intervals.isEmpty()) { |
| return 0; |
| } else if (t1 == t2) { |
| ITmfStateValue value = intervals.get(0).getStateValue(); |
| if (value.getType() == Type.DOUBLE) { |
| return value.unboxDouble(); |
| } |
| return value.unboxLong(); |
| } |
| for (ITmfStateInterval si : intervals) { |
| long startTime = Math.max(t1, si.getStartTime()); |
| long endTime = Math.min(t2, si.getEndTime() + 1); |
| long delta = endTime - startTime; |
| if (delta > 0) { |
| ITmfStateValue value = si.getStateValue(); |
| if (value.getType() == Type.DOUBLE) { |
| avg += si.getStateValue().unboxDouble() * ((double) delta / (double) (t2 - t1)); |
| } else { |
| avg += si.getStateValue().unboxLong() * ((double) delta / (double) (t2 - t1)); |
| } |
| } |
| } |
| return avg; |
| } |
| |
| private static List<ITmfStateInterval> queryAttributeRange(ITmfStateSystem ss, |
| long t1, long t2, int baseQuark, String featureString) |
| throws AttributeNotFoundException, TimeRangeException, StateValueTypeException { |
| TimeRange timeRange = new TimeRange(t1, t2); |
| int mipmapQuark = -1; |
| List<ITmfStateInterval> intervals = new ArrayList<>(); |
| try { |
| try { |
| mipmapQuark = ss.getQuarkRelative(baseQuark, featureString); |
| } catch (AttributeNotFoundException e) { |
| /* Not a mipmap attribute, query the base attribute */ |
| if (t1 == t2) { |
| ITmfStateInterval interval = ss.querySingleState(t1, baseQuark); |
| if (!interval.getStateValue().isNull()) { |
| intervals.add(interval); |
| } |
| } else { |
| for (ITmfStateInterval interval : StateSystemUtils.queryHistoryRange(ss, baseQuark, t1, t2)) { |
| if (!interval.getStateValue().isNull()) { |
| intervals.add(interval); |
| } |
| } |
| } |
| return intervals; |
| } |
| ITmfStateInterval maxLevelInterval = ss.querySingleState(timeRange.getSecond(), mipmapQuark); |
| int levelMax = maxLevelInterval.getStateValue().unboxInt(); |
| queryMipmapAttributeRange(ss, 0, levelMax, baseQuark, mipmapQuark, timeRange, intervals); |
| return intervals; |
| |
| } catch (StateValueTypeException e) { |
| /* This is a special case, so we'll add a message to the exception */ |
| throw new StateValueTypeException("State system advertises mipmaps," + //$NON-NLS-1$ |
| " but doesn't actually have them.", e); //$NON-NLS-1$ |
| } catch (StateSystemDisposedException e) { |
| /* We are shutting down, ignore the operation */ |
| } |
| return intervals; |
| } |
| |
| private static void queryMipmapAttributeRange(ITmfStateSystem ss, |
| int currentLevel, int levelMax, int baseQuark, int mipmapQuark, |
| TimeRange timeRange, List<ITmfStateInterval> intervals) |
| throws AttributeNotFoundException, TimeRangeException { |
| int level = currentLevel; |
| TimeRange range = timeRange; |
| ITmfStateInterval currentLevelInterval = null, nextLevelInterval = null; |
| if (range == null || range.getFirst() > range.getSecond()) { |
| return; |
| } |
| if (level > levelMax || level < 0) { |
| return; |
| } |
| try { |
| if (range.getFirst() == range.getSecond()) { |
| level = 0; |
| currentLevelInterval = ss.querySingleState(range.getFirst(), baseQuark); |
| if (!currentLevelInterval.getStateValue().isNull()) { |
| intervals.add(currentLevelInterval); |
| } |
| return; |
| } |
| if (level < levelMax) { |
| int levelQuark = ss.getQuarkRelative(mipmapQuark, String.valueOf(level + 1)); |
| nextLevelInterval = ss.querySingleState(range.getFirst(), levelQuark); |
| } |
| |
| if (nextLevelInterval != null && isFullyOverlapped(range, nextLevelInterval)) { |
| if (nextLevelInterval.getStateValue().isNull()) { |
| range = updateTimeRange(range, nextLevelInterval); |
| } else { |
| level++; |
| } |
| queryMipmapAttributeRange(ss, level, levelMax, baseQuark, mipmapQuark, range, intervals); |
| return; |
| } |
| |
| if (level == 0) { |
| currentLevelInterval = ss.querySingleState(range.getFirst(), baseQuark); |
| } else { |
| int levelQuark = ss.getQuarkRelative(mipmapQuark, String.valueOf(level)); |
| currentLevelInterval = ss.querySingleState(range.getFirst(), levelQuark); |
| } |
| |
| if (isFullyOverlapped(range, currentLevelInterval)) { |
| if (!currentLevelInterval.getStateValue().isNull()) { |
| intervals.add(currentLevelInterval); |
| } |
| range = updateTimeRange(range, currentLevelInterval); |
| } else { |
| if (level == 0) { |
| if (!currentLevelInterval.getStateValue().isNull()) { |
| intervals.add(currentLevelInterval); |
| } |
| range = updateTimeRange(range, currentLevelInterval); |
| } else { |
| level--; |
| } |
| } |
| |
| queryMipmapAttributeRange(ss, level, levelMax, baseQuark, |
| mipmapQuark, range, intervals); |
| |
| } catch (StateSystemDisposedException e) { |
| /* We are shutting down, ignore the operation */ |
| } |
| } |
| |
| private static TimeRange updateTimeRange(TimeRange timeRange, |
| ITmfStateInterval currentLevelInterval) { |
| if (currentLevelInterval.getEndTime() >= timeRange.getSecond()) { |
| return null; |
| } |
| long startTime = Math.max(timeRange.getFirst(), |
| Math.min(currentLevelInterval.getEndTime() + 1, timeRange.getSecond())); |
| return new TimeRange(startTime, timeRange.getSecond()); |
| } |
| |
| private static boolean isFullyOverlapped(TimeRange range, |
| ITmfStateInterval interval) { |
| if (range.getFirst() >= range.getSecond() || |
| interval.getStartTime() >= interval.getEndTime()) { |
| return false; |
| } |
| return (range.getFirst() <= interval.getStartTime() && |
| range.getSecond() >= interval.getEndTime()); |
| } |
| } |
| |
| class TimeRange { |
| |
| private final long a; |
| private final long b; |
| |
| public TimeRange(long first, long second) { |
| a = first; |
| b = second; |
| } |
| |
| public long getFirst() { |
| return a; |
| } |
| |
| public long getSecond() { |
| return b; |
| } |
| } |