tmf: Introduce the ITmfStatistics interface
authorAlexandre Montplaisir <alexmonthy@voxpopuli.im>
Thu, 27 Sep 2012 20:51:39 +0000 (16:51 -0400)
committerAlexandre Montplaisir <alexmonthy@voxpopuli.im>
Fri, 5 Oct 2012 19:46:47 +0000 (15:46 -0400)
With this, any type of ITmfTrace can now define its own
statistics provider. This can then be used to populate views
like the Histogram or the Statistics view.

A base implementation is proposed in TmfStatistics (and used by
TmfTrace), and it uses a state system for its backend. That
state system is completely contained in the TmfStatistics object,
so that it's not confused with any "real" state system that could
be present in the trace.

Change-Id: Ia0bf807cdbed28f9a6ebd47509412d4ea35f99cd
Signed-off-by: Alexandre Montplaisir <alexmonthy@voxpopuli.im>
Reviewed-on: https://git.eclipse.org/r/7986

org.eclipse.linuxtools.tmf.core/META-INF/MANIFEST.MF
org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/ctfadaptor/CtfTmfTrace.java
org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/statistics/ITmfStatistics.java [new file with mode: 0644]
org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/statistics/StatsStateProvider.java [new file with mode: 0644]
org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/statistics/TmfStatistics.java [new file with mode: 0644]
org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/ITmfTrace.java
org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/TmfTrace.java

index 9ac143a567fdc1b7aa2cb502c085fa0ee9395426..ca197f0ae0c8cf68cbd419a930b2a40e77dac9c6 100644 (file)
@@ -31,6 +31,7 @@ Export-Package: org.eclipse.linuxtools.internal.tmf.core;x-friends:="org.eclipse
  org.eclipse.linuxtools.tmf.core.signal,
  org.eclipse.linuxtools.tmf.core.statesystem,
  org.eclipse.linuxtools.tmf.core.statevalue,
+ org.eclipse.linuxtools.tmf.core.statistics,
  org.eclipse.linuxtools.tmf.core.trace,
  org.eclipse.linuxtools.tmf.core.uml2sd,
  org.eclipse.linuxtools.tmf.core.util
index b8a36b3ab5b4aebd18672869ac2c80b1b3163840..8d9bf4f9687770e29e96d301617f79a6eeb37e88 100644 (file)
@@ -79,7 +79,6 @@ public class CtfTmfTrace extends TmfTrace implements ITmfEventParser {
          * because the super needs to know the cache size.
          */
         setCacheSize();
-        super.initTrace(resource, path, eventType);
 
         @SuppressWarnings("unused")
         CtfTmfEventType type;
@@ -109,6 +108,8 @@ public class CtfTmfTrace extends TmfTrace implements ITmfEventParser {
             throw new TmfTraceException(e.getMessage(), e);
         }
 
+        super.initTrace(resource, path, eventType);
+
         //FIXME This should be called via the ExperimentUpdated signal
         buildStateSystem();
 
diff --git a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/statistics/ITmfStatistics.java b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/statistics/ITmfStatistics.java
new file mode 100644 (file)
index 0000000..d02b767
--- /dev/null
@@ -0,0 +1,66 @@
+/*******************************************************************************
+ * Copyright (c) 2012 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *   Alexandre Montplaisir - Initial API
+ ******************************************************************************/
+
+package org.eclipse.linuxtools.tmf.core.statistics;
+
+import java.util.Map;
+
+import org.eclipse.linuxtools.tmf.core.event.ITmfTimestamp;
+
+/**
+ * Provider for statistics, which is assigned to a trace. This can be used to
+ * populate views like the Statistics View or the Histogram.
+ *
+ * @author Alexandre Montplaisir
+ * @since 2.0
+ */
+public interface ITmfStatistics {
+
+    /**
+     * Return the total number of events in the trace.
+     *
+     * @return The total number of events
+     */
+    public long getEventsTotal();
+
+    /**
+     * Return a Map of the total events in the trace, per event type. The event
+     * type should come from ITmfEvent.getType().getName().
+     *
+     * @return The map of <event_type, count>, for the whole trace
+     */
+    public Map<String, Long> getEventTypesTotal();
+
+    /**
+     * Retrieve the number of events in the trace in a given time interval.
+     *
+     * @param start
+     *            Start time of the time range
+     * @param end
+     *            End time of the time range
+     * @return The number of events found
+     */
+    public long getEventsInRange(ITmfTimestamp start, ITmfTimestamp end);
+
+    /**
+     * Retrieve the number of events in the trace, per event type, in a given
+     * time interval.
+     *
+     * @param start
+     *            Start time of the time range
+     * @param end
+     *            End time of the time range
+     * @return The map of <event_type, count>, for the given time range
+     */
+    public Map<String, Long> getEventTypesInRange(ITmfTimestamp start,
+            ITmfTimestamp end);
+}
diff --git a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/statistics/StatsStateProvider.java b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/statistics/StatsStateProvider.java
new file mode 100644 (file)
index 0000000..7cff450
--- /dev/null
@@ -0,0 +1,95 @@
+/*******************************************************************************
+ * Copyright (c) 2012 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *   Alexandre Montplaisir - Initial API and implementation
+ ******************************************************************************/
+
+package org.eclipse.linuxtools.tmf.core.statistics;
+
+import org.eclipse.linuxtools.tmf.core.event.ITmfEvent;
+import org.eclipse.linuxtools.tmf.core.exceptions.AttributeNotFoundException;
+import org.eclipse.linuxtools.tmf.core.exceptions.StateValueTypeException;
+import org.eclipse.linuxtools.tmf.core.exceptions.TimeRangeException;
+import org.eclipse.linuxtools.tmf.core.statesystem.AbstractStateChangeInput;
+import org.eclipse.linuxtools.tmf.core.statesystem.ITmfStateSystemBuilder;
+import org.eclipse.linuxtools.tmf.core.statistics.TmfStatistics.Attributes;
+import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace;
+
+/**
+ * The state provider for traces statistics. It should work with any type of
+ * trace TMF can handle.
+ *
+ * The resulting attribute tree will look like this:
+ *
+ * <root>
+ *   \-- event_types
+ *        |-- <event name 1>
+ *        |-- <event name 2>
+ *        |-- <event name 3>
+ *       ...
+ *
+ * And each <event name>'s value will be an integer, representing how many times
+ * this particular event type has been seen in the trace so far.
+ *
+ * @author Alexandre Montplaisir
+ * @version 1.0
+ */
+class StatsStateProvider extends AbstractStateChangeInput {
+
+    /* Commonly-used attributes */
+    private int typeAttribute = -1;
+
+    /**
+     * Constructor
+    *
+     * @param trace
+     *            The trace for which we build this state system
+     */
+    public StatsStateProvider(ITmfTrace trace) {
+        super(trace, ITmfEvent.class ,"TMF Statistics"); //$NON-NLS-1$
+    }
+
+    @Override
+    public void assignTargetStateSystem(ITmfStateSystemBuilder ssb) {
+        super.assignTargetStateSystem(ssb);
+
+        /* Setup common locations */
+        typeAttribute = ss.getQuarkAbsoluteAndAdd(Attributes.EVENT_TYPES);
+    }
+
+    @Override
+    protected void eventHandle(ITmfEvent event) {
+        int quark;
+
+        final long ts = event.getTimestamp().getValue();
+        final String eventName = event.getType().getName();
+
+        try {
+
+            /* Number of events of each type, globally */
+            quark = ss.getQuarkRelativeAndAdd(typeAttribute, eventName);
+            ss.incrementAttribute(ts, quark);
+
+//            /* Number of events per CPU */
+//            quark = ss.getQuarkRelativeAndAdd(currentCPUNode, Attributes.STATISTICS, Attributes.EVENT_TYPES, eventName);
+//            ss.incrementAttribute(ts, quark);
+//
+//            /* Number of events per process */
+//            quark = ss.getQuarkRelativeAndAdd(currentThreadNode, Attributes.STATISTICS, Attributes.EVENT_TYPES, eventName);
+//            ss.incrementAttribute(ts, quark);
+
+        } catch (StateValueTypeException e) {
+            e.printStackTrace();
+        } catch (TimeRangeException e) {
+            e.printStackTrace();
+        } catch (AttributeNotFoundException e) {
+            e.printStackTrace();
+        }
+    }
+}
diff --git a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/statistics/TmfStatistics.java b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/statistics/TmfStatistics.java
new file mode 100644 (file)
index 0000000..960b2ae
--- /dev/null
@@ -0,0 +1,243 @@
+/*******************************************************************************
+ * Copyright (c) 2012 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *   Alexandre Montplaisir - Initial API and implementation
+ ******************************************************************************/
+
+package org.eclipse.linuxtools.tmf.core.statistics;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.linuxtools.tmf.core.TmfCommonConstants;
+import org.eclipse.linuxtools.tmf.core.event.ITmfTimestamp;
+import org.eclipse.linuxtools.tmf.core.exceptions.AttributeNotFoundException;
+import org.eclipse.linuxtools.tmf.core.exceptions.StateValueTypeException;
+import org.eclipse.linuxtools.tmf.core.exceptions.TimeRangeException;
+import org.eclipse.linuxtools.tmf.core.exceptions.TmfTraceException;
+import org.eclipse.linuxtools.tmf.core.interval.ITmfStateInterval;
+import org.eclipse.linuxtools.tmf.core.statesystem.IStateChangeInput;
+import org.eclipse.linuxtools.tmf.core.statesystem.ITmfStateSystem;
+import org.eclipse.linuxtools.tmf.core.statesystem.StateSystemManager;
+import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace;
+
+/**
+ * Default implementation of an ITmfStatisticsProvider. It uses a state system
+ * underneath to store its information.
+ *
+ * @author Alexandre Montplaisir
+ * @since 2.0
+ */
+
+public class TmfStatistics  implements ITmfStatistics {
+
+    /* Filename the "statistics state history" file will have */
+    private static final String STATS_STATE_FILENAME = "statistics.ht"; //$NON-NLS-1$
+
+    /*
+     * The state system that's used to stored the statistics. It's hidden from
+     * the trace, so that it doesn't conflict with ITmfTrace.getStateSystem()
+     * (which is something else!)
+     */
+    private final ITmfStateSystem stats;
+
+    /**
+     * Constructor
+     *
+     * @param trace
+     *            The trace for which we build these statistics
+     * @throws TmfTraceException
+     *             If something went wrong trying to initialize the statistics
+     */
+    public TmfStatistics(ITmfTrace trace) throws TmfTraceException {
+        /* Set up the path to the history tree file we'll use */
+        IResource resource = trace.getResource();
+        String supplDirectory = null;
+
+        try {
+            // get the directory where the history file will be stored.
+            supplDirectory = resource.getPersistentProperty(TmfCommonConstants.TRACE_SUPPLEMENTARY_FOLDER);
+        } catch (CoreException e) {
+            throw new TmfTraceException(e.toString(), e);
+        }
+
+        final File htFile = new File(supplDirectory + File.separator + STATS_STATE_FILENAME);
+        final IStateChangeInput htInput = new StatsStateProvider(trace);
+
+        this.stats = StateSystemManager.loadStateHistory(htFile, htInput, false);
+    }
+
+    // ------------------------------------------------------------------------
+    // ITmfStatisticsProvider
+    // ------------------------------------------------------------------------
+
+    @Override
+    public long getEventsTotal() {
+        /*
+         * The total itself is not stored in the state, so we will do a
+         * "event types" query then add the contents manually.
+         */
+        Map<String, Long> map = getEventTypesTotal();
+        long total = 0;
+        for (long count : map.values()) {
+            total += count;
+        }
+        return total;
+    }
+
+    @Override
+    public Map<String, Long> getEventTypesTotal() {
+        Map<String, Long> map = new HashMap<String, Long>();
+        long endTime = stats.getCurrentEndTime(); //shouldn't need to check it...
+
+        try {
+            /* Get the list of quarks, one for each even type in the database */
+            int quark = stats.getQuarkAbsolute(Attributes.EVENT_TYPES);
+            List<Integer> quarks = stats.getSubAttributes(quark, false);
+
+            /* Since we want the total we can look only at the end */
+            List<ITmfStateInterval> endState = stats.queryFullState(endTime);
+
+            String curEventName;
+            long eventCount;
+            for (int typeQuark : quarks) {
+                curEventName = stats.getAttributeName(typeQuark);
+                eventCount = endState.get(typeQuark).getStateValue().unboxInt();
+                map.put(curEventName, eventCount);
+            }
+
+        } catch (TimeRangeException e) {
+            /* Ignore silently */
+        } catch (AttributeNotFoundException e) {
+            e.printStackTrace();
+        } catch (StateValueTypeException e) {
+            e.printStackTrace();
+        }
+        return map;
+    }
+
+    @Override
+    public long getEventsInRange(ITmfTimestamp start, ITmfTimestamp end) {
+        /*
+         * The total itself is not stored in the state, so we will do a
+         * "event types" query then add the contents manually.
+         */
+        Map<String, Long> map = getEventTypesInRange(start, end);
+        long total = 0;
+        for (long count : map.values()) {
+            total += count;
+        }
+        return total;
+    }
+
+    @Override
+    public Map<String, Long> getEventTypesInRange(ITmfTimestamp start, ITmfTimestamp end) {
+        Map<String, Long> map = new HashMap<String, Long>();
+
+        /* Make sure the start/end times are within the state history, so we
+         * don't get TimeRange exceptions.
+         */
+        long startTimestamp = checkStartTime(start.getValue());
+        long endTimestamp = checkEndTime(end.getValue());
+
+        try {
+            /* Get the list of quarks, one for each even type in the database */
+            int quark = stats.getQuarkAbsolute(Attributes.EVENT_TYPES);
+            List<Integer> quarks = stats.getSubAttributes(quark, false);
+
+            /*
+             * Get the complete states (in our case, event counts) at the start
+             * time and end time of the requested time range.
+             */
+            List<ITmfStateInterval> startState = stats.queryFullState(startTimestamp);
+            List<ITmfStateInterval> endState = stats.queryFullState(endTimestamp);
+
+            /* Save the relevant information in the map we will be returning */
+            String curEventName;
+            long countAtStart, countAtEnd, eventCount;
+            for (int typeQuark : quarks) {
+                curEventName = stats.getAttributeName(typeQuark);
+                countAtStart = startState.get(typeQuark).getStateValue().unboxInt();
+                countAtEnd = endState.get(typeQuark).getStateValue().unboxInt();
+
+                /*
+                 * The default value for the statistics is 0, rather than the
+                 * value -1 used by the state system for non-initialized state.
+                 */
+                if (startTimestamp == stats.getStartTime() || countAtStart == -1) {
+                    countAtStart = 0;
+                }
+
+                /*
+                 * Workaround a bug in the state system where requests for the
+                 * very last state change will give -1. Send the request 1ns
+                 * before the end of the trace and add the last event to the
+                 * count.
+                 */
+                if (countAtEnd < 0) {
+                    ITmfStateInterval realInterval = stats.querySingleState(endTimestamp - 1, typeQuark);
+                    countAtEnd = realInterval.getStateValue().unboxInt() + 1;
+                }
+
+                /*
+                 * If after this it is still at -1, it's because no event of
+                 * this type happened during the requested time range.
+                 */
+                if (countAtEnd < 0) {
+                    countAtEnd = 0;
+                }
+
+                eventCount = countAtEnd - countAtStart;
+                map.put(curEventName, eventCount);
+            }
+        } catch (TimeRangeException e) {
+            /*
+             * If a request is made for an invalid time range, we will ignore it
+             * silently and not add any information to the map.
+             */
+        } catch (AttributeNotFoundException e) {
+            /*
+             * These other exceptions would show a logic problem however, so
+             * they should not happen.
+             */
+            e.printStackTrace();
+        } catch (StateValueTypeException e) {
+            e.printStackTrace();
+        }
+        return map;
+    }
+
+    private long checkStartTime(long start) {
+        if (start < stats.getStartTime()) {
+            return stats.getStartTime();
+        }
+        return start;
+    }
+
+    private long checkEndTime(long end) {
+        if (end > stats.getCurrentEndTime()) {
+            return stats.getCurrentEndTime();
+        }
+        return end;
+    }
+
+
+    /**
+     * The attribute names that are used in the state provider
+     */
+    public static class Attributes {
+
+        /** event_types */
+        public static final String EVENT_TYPES = "event_types"; //$NON-NLS-1$<
+    }
+}
index e6b862de58c2b1d2d7c164c1fec89ce876231e44..72f89aff00ee471fcb8edd44a3b71ffcfb9ab6a3 100644 (file)
@@ -21,6 +21,7 @@ import org.eclipse.linuxtools.tmf.core.event.ITmfTimestamp;
 import org.eclipse.linuxtools.tmf.core.event.TmfTimeRange;
 import org.eclipse.linuxtools.tmf.core.exceptions.TmfTraceException;
 import org.eclipse.linuxtools.tmf.core.statesystem.ITmfStateSystem;
+import org.eclipse.linuxtools.tmf.core.statistics.ITmfStatistics;
 
 /**
  * The event stream structure in TMF. In its basic form, a trace has:
@@ -172,6 +173,12 @@ public interface ITmfTrace extends ITmfDataProvider {
      */
     public int getCacheSize();
 
+    /**
+     * @return The statistics provider for this trace
+     * @since 2.0
+     */
+    public ITmfStatistics getStatistics();
+
     /**
      * @return The state system that is associated with this trace
      * @since 2.0
index dcbf0dbc7c82067fc62114a61367039b6b517c94..a90ce1dd7e240f870d61d788611483e4a8320f4a 100644 (file)
@@ -26,6 +26,8 @@ import org.eclipse.linuxtools.tmf.core.exceptions.TmfTraceException;
 import org.eclipse.linuxtools.tmf.core.request.ITmfDataRequest;
 import org.eclipse.linuxtools.tmf.core.request.ITmfEventRequest;
 import org.eclipse.linuxtools.tmf.core.statesystem.ITmfStateSystem;
+import org.eclipse.linuxtools.tmf.core.statistics.ITmfStatistics;
+import org.eclipse.linuxtools.tmf.core.statistics.TmfStatistics;
 
 /**
  * Abstract implementation of ITmfTrace.
@@ -85,6 +87,9 @@ public abstract class TmfTrace extends TmfEventProvider implements ITmfTrace {
     // The trace parser
     private ITmfEventParser fParser;
 
+    // The trace's statistics
+    private ITmfStatistics fStatistics;
+
     // ------------------------------------------------------------------------
     // Construction
     // ------------------------------------------------------------------------
@@ -222,6 +227,8 @@ public abstract class TmfTrace extends TmfEventProvider implements ITmfTrace {
             }
         }
         super.init(traceName, type);
+
+        buildStatistics();
     }
 
     /**
@@ -244,6 +251,20 @@ public abstract class TmfTrace extends TmfEventProvider implements ITmfTrace {
         getIndexer().buildIndex(0, TmfTimeRange.ETERNITY, waitForCompletion);
     }
 
+    /**
+     * The default implementation of TmfTrace uses a TmfStatistics backend.
+     * Override this if you want to specify another type (or none at all).
+     *
+     * @since 2.0
+     */
+    protected void buildStatistics() throws TmfTraceException {
+        /*
+         * Initialize the statistics provider, but only if a Resource has been
+         * set (so we don't build it for experiments, for unit tests, etc.)
+         */
+        fStatistics = (fResource == null ? null : new TmfStatistics(this) );
+    }
+
     /**
      * Clears the trace
      */
@@ -314,6 +335,14 @@ public abstract class TmfTrace extends TmfEventProvider implements ITmfTrace {
         return fParser;
     }
 
+    /**
+     * @since 2.0
+     */
+    @Override
+    public ITmfStatistics getStatistics() {
+        return fStatistics;
+    }
+
     /**
      * @since 2.0
      */
@@ -549,7 +578,9 @@ public abstract class TmfTrace extends TmfEventProvider implements ITmfTrace {
             if (fNbEvents <= rank) {
                 fNbEvents = rank + 1;
             }
-            fIndexer.updateIndex(context, timestamp);
+            if (fIndexer != null) {
+                fIndexer.updateIndex(context, timestamp);
+            }
         }
     }
 
This page took 0.033335 seconds and 5 git commands to generate.