diff --git a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/statistics/TmfStateStatistics.java b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/statistics/TmfStateStatistics.java index f47d27764f..a11ca57be4 100644 --- a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/statistics/TmfStateStatistics.java +++ b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/statistics/TmfStateStatistics.java @@ -17,16 +17,24 @@ import java.util.ArrayList; import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.tracecompass.common.core.log.TraceCompassLog; +import org.eclipse.tracecompass.common.core.log.TraceCompassLogUtils.FlowScopeLog; +import org.eclipse.tracecompass.common.core.log.TraceCompassLogUtils.FlowScopeLogBuilder; import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem; import org.eclipse.tracecompass.statesystem.core.exceptions.StateSystemDisposedException; import org.eclipse.tracecompass.statesystem.core.interval.ITmfStateInterval; +import com.google.common.collect.Lists; + /** * Implementation of ITmfStatistics which uses a state history for storing its * information. In reality, it uses two state histories, one for "event totals" @@ -52,6 +60,8 @@ public class TmfStateStatistics implements ITmfStatistics { /** The state system for event types */ private final ITmfStateSystem fTypesStats; + private static final @NonNull Logger LOGGER = TraceCompassLog.getLogger(TmfStateStatistics.class); + // ------------------------------------------------------------------------ // Constructors // ------------------------------------------------------------------------ @@ -103,16 +113,42 @@ public void dispose() { if (fTotalsStats.isCancelled()) { return list; } - - long prevTotal = (timeRequested[0] == fTotalsStats.getStartTime()) ? 0 : getEventCountAt(timeRequested[0] - 1); + final int quark = fTotalsStats.optQuarkAbsolute(Attributes.TOTAL); + if (quark == ITmfStateSystem.INVALID_ATTRIBUTE) { + return Collections.emptyList(); + } + List times = new ArrayList<>(); for (int i = 0; i < timeRequested.length; i++) { - long curTotal = getEventCountAt(timeRequested[i]); - long count = curTotal - prevTotal; - list.add(count); - prevTotal = curTotal; + if (timeRequested[i] > fTotalsStats.getCurrentEndTime()) { + times.add(fTotalsStats.getCurrentEndTime()); + break; + } + times.add(timeRequested[i]); + } + try (FlowScopeLog log = new FlowScopeLogBuilder(LOGGER, Level.FINE, "StateStatistics:histogramQuery").build()) { //$NON-NLS-1$ + Iterable<@NonNull ITmfStateInterval> intervals = fTotalsStats.query2D(Collections.singletonList(quark), times); + List<@NonNull ITmfStateInterval> sortedIntervals = Lists.newArrayList(intervals); + sortedIntervals.sort(Comparator.comparingLong(ITmfStateInterval::getStartTime)); + int j = 0; + long previousTotal; + if (!sortedIntervals.isEmpty() && fTotalsStats.getStartTime() != sortedIntervals.get(0).getStartTime()) { + previousTotal = sortedIntervals.get(0).getValueInt(); + } else { + previousTotal = 0; + } + for (int i = 0; i < timeRequested.length; i++) { + while (j < sortedIntervals.size() - 1 && sortedIntervals.get(j).getEndTime() < timeRequested[i]) { + j++; + } + long count = sortedIntervals.get(j).getValueInt() - previousTotal; + list.add(count); + previousTotal = sortedIntervals.get(j).getValueInt(); + } + return list; + } catch (StateSystemDisposedException e) { + /* Assume there is no events, nothing will be put in the histogram. */ + return Collections.emptyList(); } - - return list; } @Override @@ -181,15 +217,15 @@ public long getEventsInRange(long start, long end) { public Map getEventTypesInRange(long start, long end) { /* - * Make sure the start/end times are within the state history, so we don't get - * TimeRange exceptions. + * Make sure the start/end times are within the state history, so we + * don't get TimeRange exceptions. */ long startTime = Long.max(start, fTypesStats.getStartTime()); long endTime = Long.min(end, fTypesStats.getCurrentEndTime()); if (endTime < startTime) { /* - * The start/end times do not intersect this state system range. Return the - * empty map. + * The start/end times do not intersect this state system range. + * Return the empty map. */ return Collections.emptyMap(); } @@ -198,8 +234,9 @@ public Map getEventTypesInRange(long start, long end) { int quark = fTypesStats.optQuarkAbsolute(Attributes.EVENT_TYPES); if (quark == ITmfStateSystem.INVALID_ATTRIBUTE) { /* - * The state system does not (yet?) have the needed attributes, it probably - * means there are no events counted yet. Return the empty map. + * The state system does not (yet?) have the needed attributes, it + * probably means there are no events counted yet. Return the empty + * map. */ return Collections.emptyMap(); } @@ -233,7 +270,9 @@ public Map getEventTypesInRange(long start, long end) { } } catch (StateSystemDisposedException e) { - /* Assume there is no (more) events, nothing will be put in the map. */ + /* + * Assume there is no (more) events, nothing will be put in the map. + */ } return map; } @@ -255,7 +294,9 @@ private long getEventCountAt(long timestamp) { try { return extractCount(fTotalsStats.querySingleState(ts, quark).getValue()); } catch (StateSystemDisposedException e) { - /* Assume there is no (more) events, nothing will be put in the map. */ + /* + * Assume there is no (more) events, nothing will be put in the map. + */ return 0; } } @@ -278,8 +319,11 @@ public static class Attributes { /** event_types */ public static final String EVENT_TYPES = "event_types"; //$NON-NLS-1$ - /** lost_events - * @since 2.0*/ + /** + * lost_events + * + * @since 2.0 + */ public static final String LOST_EVENTS = "lost_events"; //$NON-NLS-1$ } }