tmf : Update the histogram to handle lost events correctly
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf.ui / src / org / eclipse / linuxtools / tmf / ui / views / histogram / HistogramDataModel.java
index a59b178fa5531ac418e809673017b4fe6d23d7ba..f14b1b2a1f17dd0e9276515003dab80fd5fc56b9 100644 (file)
@@ -13,6 +13,7 @@
  *   Francois Chouinard - Moved from LTTng to TMF
  *   Francois Chouinard - Added support for empty initial buckets
  *   Patrick Tasse - Support selection range
+ *   Jean-Christian Kouamé, Simon Delisle - Added support to manage lost events
  *******************************************************************************/
 
 package org.eclipse.linuxtools.tmf.ui.views.histogram;
@@ -20,6 +21,7 @@ package org.eclipse.linuxtools.tmf.ui.views.histogram;
 import java.util.Arrays;
 
 import org.eclipse.core.runtime.ListenerList;
+import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimeRange;
 
 /**
  * Histogram-independent data model.
@@ -49,10 +51,10 @@ import org.eclipse.core.runtime.ListenerList;
  * be fed to the model in any order. If an event has a timestamp less than the
  * <i>basetime</i>, the buckets will be moved to the right to account for the
  * new smaller timestamp. The new <i>basetime</i> is a multiple of the bucket
- * duration smaller then the previous <i>basetime</i>. Note that the <i>basetime</i>
- * might not be anymore a timestamp of an event. If necessary, the buckets will
- * be compacted before moving to the right. This might be necessary to not
- * loose any event counts at the end of the buckets array.
+ * duration smaller then the previous <i>basetime</i>. Note that the
+ * <i>basetime</i> might no longer be the timestamp of an event. If necessary,
+ * the buckets will be compacted before moving to the right. This might be
+ * necessary to not lose any event counts at the end of the buckets array.
  * <p>
  * The mapping from the model to the UI is performed by the <i>scaleTo()</i>
  * method. By keeping the number of buckets <i>n</i> relatively large with
@@ -70,7 +72,7 @@ public class HistogramDataModel implements IHistogramDataModel {
     // ------------------------------------------------------------------------
 
     /**
-     *  The default number of buckets
+     * The default number of buckets
      */
     public static final int DEFAULT_NUMBER_OF_BUCKETS = 16 * 1000;
 
@@ -86,6 +88,7 @@ public class HistogramDataModel implements IHistogramDataModel {
     // Bucket management
     private final int fNbBuckets;
     private final long[] fBuckets;
+    private final long[] fLostEventsBuckets;
     private long fBucketDuration;
     private long fNbEvents;
     private int fLastBucket;
@@ -114,7 +117,9 @@ public class HistogramDataModel implements IHistogramDataModel {
 
     /**
      * Default constructor with default number of buckets.
-     * @param startTime The histogram start time
+     *
+     * @param startTime
+     *            The histogram start time
      * @since 2.0
      */
     public HistogramDataModel(long startTime) {
@@ -123,7 +128,9 @@ public class HistogramDataModel implements IHistogramDataModel {
 
     /**
      * Constructor with non-default number of buckets.
-     * @param nbBuckets A number of buckets.
+     *
+     * @param nbBuckets
+     *            A number of buckets.
      */
     public HistogramDataModel(int nbBuckets) {
         this(0, nbBuckets);
@@ -131,25 +138,32 @@ public class HistogramDataModel implements IHistogramDataModel {
 
     /**
      * Constructor with non-default number of buckets.
-     * @param startTime the histogram start time
-     * @param nbBuckets A number of buckets.
+     *
+     * @param startTime
+     *            the histogram start time
+     * @param nbBuckets
+     *            A number of buckets.
      * @since 2.0
      */
     public HistogramDataModel(long startTime, int nbBuckets) {
         fFirstBucketTime = fFirstEventTime = fLastEventTime = startTime;
         fNbBuckets = nbBuckets;
         fBuckets = new long[nbBuckets];
+        fLostEventsBuckets = new long[nbBuckets];
         fModelListeners = new ListenerList();
         clear();
     }
 
     /**
      * Copy constructor.
-     * @param other A model to copy.
+     *
+     * @param other
+     *            A model to copy.
      */
     public HistogramDataModel(HistogramDataModel other) {
         fNbBuckets = other.fNbBuckets;
         fBuckets = Arrays.copyOf(other.fBuckets, fNbBuckets);
+        fLostEventsBuckets = Arrays.copyOf(other.fLostEventsBuckets, fNbBuckets);
         fBucketDuration = Math.max(other.fBucketDuration, 1);
         fNbEvents = other.fNbEvents;
         fLastBucket = other.fLastBucket;
@@ -172,6 +186,7 @@ public class HistogramDataModel implements IHistogramDataModel {
 
     /**
      * Returns the number of events in the data model.
+     *
      * @return number of events.
      */
     public long getNbEvents() {
@@ -180,22 +195,25 @@ public class HistogramDataModel implements IHistogramDataModel {
 
     /**
      * Returns the number of buckets in the model.
+     *
      * @return number of buckets.
      */
     public int getNbBuckets() {
         return fNbBuckets;
     }
 
-   /**
-    * Returns the current bucket duration.
-    * @return bucket duration
-    */
+    /**
+     * Returns the current bucket duration.
+     *
+     * @return bucket duration
+     */
     public long getBucketDuration() {
         return fBucketDuration;
     }
 
     /**
      * Returns the time value of the first bucket in the model.
+     *
      * @return time of first bucket.
      */
     public long getFirstBucketTime() {
@@ -204,6 +222,7 @@ public class HistogramDataModel implements IHistogramDataModel {
 
     /**
      * Returns the time of the first event in the model.
+     *
      * @return time of first event.
      */
     public long getStartTime() {
@@ -212,8 +231,11 @@ public class HistogramDataModel implements IHistogramDataModel {
 
     /**
      * Sets the model start time
-     * @param startTime the histogram range start time
-     * @param endTime the histogram range end time
+     *
+     * @param startTime
+     *            the histogram range start time
+     * @param endTime
+     *            the histogram range end time
      * @since 2.0
      */
     public void setTimeRange(long startTime, long endTime) {
@@ -227,6 +249,7 @@ public class HistogramDataModel implements IHistogramDataModel {
 
     /**
      * Returns the time of the last event in the model.
+     *
      * @return the time of last event.
      */
     public long getEndTime() {
@@ -235,8 +258,10 @@ public class HistogramDataModel implements IHistogramDataModel {
 
     /**
      * Returns the time of the current event in the model.
+     *
      * @return the time of the current event.
-     * @deprecated As of 2.1, use {@link #getSelectionBegin()} and {@link #getSelectionEnd()}
+     * @deprecated As of 2.1, use {@link #getSelectionBegin()} and
+     *             {@link #getSelectionEnd()}
      */
     @Deprecated
     public long getCurrentEventTime() {
@@ -245,6 +270,7 @@ public class HistogramDataModel implements IHistogramDataModel {
 
     /**
      * Returns the begin time of the current selection in the model.
+     *
      * @return the begin time of the current selection.
      * @since 2.1
      */
@@ -254,6 +280,7 @@ public class HistogramDataModel implements IHistogramDataModel {
 
     /**
      * Returns the end time of the current selection in the model.
+     *
      * @return the end time of the current selection.
      * @since 2.1
      */
@@ -263,6 +290,7 @@ public class HistogramDataModel implements IHistogramDataModel {
 
     /**
      * Returns the time limit with is: start time + nbBuckets * bucketDuration
+     *
      * @return the time limit.
      */
     public long getTimeLimit() {
@@ -275,7 +303,9 @@ public class HistogramDataModel implements IHistogramDataModel {
 
     /**
      * Add a listener to the model to be informed about model changes.
-     * @param listener A listener to add.
+     *
+     * @param listener
+     *            A listener to add.
      */
     public void addHistogramListener(IHistogramModelListener listener) {
         fModelListeners.add(listener);
@@ -283,7 +313,9 @@ public class HistogramDataModel implements IHistogramDataModel {
 
     /**
      * Remove a given model listener.
-     * @param listener A listener to remove.
+     *
+     * @param listener
+     *            A listener to remove.
      */
     public void removeHistogramListener(IHistogramModelListener listener) {
         fModelListeners.remove(listener);
@@ -316,11 +348,13 @@ public class HistogramDataModel implements IHistogramDataModel {
 
     /**
      * Clear the histogram model.
+     *
      * @see org.eclipse.linuxtools.tmf.ui.views.distribution.model.IBaseDistributionModel#clear()
      */
     @Override
     public void clear() {
         Arrays.fill(fBuckets, 0);
+        Arrays.fill(fLostEventsBuckets, 0);
         fNbEvents = 0;
         fFirstBucketTime = 0;
         fLastEventTime = 0;
@@ -335,7 +369,8 @@ public class HistogramDataModel implements IHistogramDataModel {
     /**
      * Sets the current event time (no notification of listeners)
      *
-     * @param timestamp A time stamp to set.
+     * @param timestamp
+     *            A time stamp to set.
      * @deprecated As of 2.1, use {@link #setSelection(long, long)}
      */
     @Deprecated
@@ -347,8 +382,10 @@ public class HistogramDataModel implements IHistogramDataModel {
     /**
      * Sets the current event time with notification of listeners
      *
-     * @param timestamp A time stamp to set.
-     * @deprecated As of 2.1, use {@link #setSelectionNotifyListeners(long, long)}
+     * @param timestamp
+     *            A time stamp to set.
+     * @deprecated As of 2.1, use
+     *             {@link #setSelectionNotifyListeners(long, long)}
      */
     @Deprecated
     public void setCurrentEventNotifyListeners(long timestamp) {
@@ -360,8 +397,10 @@ public class HistogramDataModel implements IHistogramDataModel {
     /**
      * Sets the current selection time range (no notification of listeners)
      *
-     * @param beginTime The selection begin time.
-     * @param endTime The selection end time.
+     * @param beginTime
+     *            The selection begin time.
+     * @param endTime
+     *            The selection end time.
      * @since 2.1
      */
     public void setSelection(long beginTime, long endTime) {
@@ -372,8 +411,10 @@ public class HistogramDataModel implements IHistogramDataModel {
     /**
      * Sets the current selection time range with notification of listeners
      *
-     * @param beginTime The selection begin time.
-     * @param endTime The selection end time.
+     * @param beginTime
+     *            The selection begin time.
+     * @param endTime
+     *            The selection end time.
      * @since 2.1
      */
     public void setSelectionNotifyListeners(long beginTime, long endTime) {
@@ -385,8 +426,10 @@ public class HistogramDataModel implements IHistogramDataModel {
     /**
      * Add event to the correct bucket, compacting the if needed.
      *
-     * @param eventCount The current event Count (for notification purposes)
-     * @param timestamp The timestamp of the event to count
+     * @param eventCount
+     *            The current event Count (for notification purposes)
+     * @param timestamp
+     *            The timestamp of the event to count
      *
      */
     @Override
@@ -425,7 +468,7 @@ public class HistogramDataModel implements IHistogramDataModel {
             int offset = getOffset(timestamp);
 
             // Compact as needed
-            while((fLastBucket + offset) >= fNbBuckets) {
+            while ((fLastBucket + offset) >= fNbBuckets) {
                 mergeBuckets();
                 offset = getOffset(timestamp);
             }
@@ -434,7 +477,7 @@ public class HistogramDataModel implements IHistogramDataModel {
 
             fLastBucket = fLastBucket + offset;
 
-            fFirstBucketTime = fFirstBucketTime - (offset*fBucketDuration);
+            fFirstBucketTime = fFirstBucketTime - (offset * fBucketDuration);
             updateEndTime();
         }
 
@@ -449,21 +492,72 @@ public class HistogramDataModel implements IHistogramDataModel {
         fireModelUpdateNotification(eventCount);
     }
 
+    /**
+     * Add lost event to the correct bucket, compacting the if needed.
+     *
+     * @param timeRange
+     *            time range of a lost event
+     * @param nbLostEvents
+     *            the number of lost events
+     * @param fullRange
+     *            Full range or time range for histogram request
+     * @since 2.1
+     */
+    public void countLostEvent(TmfTimeRange timeRange, long nbLostEvents, boolean fullRange) {
+
+        // Validate
+        if (timeRange.getStartTime().getValue() < 0 || timeRange.getEndTime().getValue() < 0) {
+            return;
+        }
+
+        // Compact as needed
+        if (fullRange) {
+            while (timeRange.getEndTime().getValue() >= fTimeLimit) {
+                mergeBuckets();
+            }
+        }
+
+        int indexStart = (int) ((timeRange.getStartTime().getValue() - fFirstBucketTime) / fBucketDuration);
+        int indexEnd = (int) ((timeRange.getEndTime().getValue() - fFirstBucketTime) / fBucketDuration);
+        int nbBucketRange = (indexEnd - indexStart) + 1;
+
+        int lostEventPerBucket = (int) Math.ceil((double) nbLostEvents / nbBucketRange);
+        long lastLostCol = Math.max(1, nbLostEvents - lostEventPerBucket * (nbBucketRange - 1));
+
+        // Increment the right bucket, bear in mind that ranges make it almost certain that some lost events are out of range
+        for (int index = indexStart; index <= indexEnd && index < fLostEventsBuckets.length; index++) {
+            if (index == (indexStart + nbBucketRange - 1)) {
+                fLostEventsBuckets[index] += lastLostCol;
+            } else {
+                fLostEventsBuckets[index] += lostEventPerBucket;
+            }
+        }
+
+        fNbEvents++;
+
+        fireModelUpdateNotification(nbLostEvents);
+    }
+
     /**
      * Scale the model data to the width, height and bar width requested.
      *
-     * @param width A width of the histogram canvas
-     * @param height A height of the histogram canvas
-     * @param barWidth A width (in pixel) of a histogram bar
-     * @return the result array of size [width] and where the highest value doesn't exceed [height]
+     * @param width
+     *            A width of the histogram canvas
+     * @param height
+     *            A height of the histogram canvas
+     * @param barWidth
+     *            A width (in pixel) of a histogram bar
+     * @return the result array of size [width] and where the highest value
+     *         doesn't exceed [height]
      *
-     * @see org.eclipse.linuxtools.tmf.ui.views.histogram.IHistogramDataModel#scaleTo(int, int, int)
+     * @see org.eclipse.linuxtools.tmf.ui.views.histogram.IHistogramDataModel#scaleTo(int,
+     *      int, int)
      */
     @Override
     public HistogramScaledData scaleTo(int width, int height, int barWidth) {
         // Basic validation
-        if ((width <= 0) ||  (height <= 0) || (barWidth <= 0))
-         {
+        if ((width <= 0) || (height <= 0) || (barWidth <= 0))
+        {
             throw new AssertionError("Invalid histogram dimensions (" + width + "x" + height + ", barWidth=" + barWidth + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
         }
 
@@ -475,26 +569,35 @@ public class HistogramDataModel implements IHistogramDataModel {
 
         int nbBars = width / barWidth;
         int bucketsPerBar = (fLastBucket / nbBars) + 1;
-        result.fBucketDuration = Math.max(bucketsPerBar * fBucketDuration,1);
+        result.fBucketDuration = Math.max(bucketsPerBar * fBucketDuration, 1);
         for (int i = 0; i < nbBars; i++) {
             int count = 0;
+            int countLostEvent = 0;
             for (int j = i * bucketsPerBar; j < ((i + 1) * bucketsPerBar); j++) {
                 if (fNbBuckets <= j) {
                     break;
                 }
                 count += fBuckets[j];
+                countLostEvent += fLostEventsBuckets[j];
             }
             result.fData[i] = count;
+            result.fLostEventsData[i] = countLostEvent;
             result.fLastBucket = i;
             if (result.fMaxValue < count) {
                 result.fMaxValue = count;
             }
+            if (result.fMaxCombinedValue < count + countLostEvent) {
+                result.fMaxCombinedValue = count + countLostEvent;
+            }
         }
 
         // Scale vertically
         if (result.fMaxValue > 0) {
             result.fScalingFactor = (double) height / result.fMaxValue;
         }
+        if (result.fMaxCombinedValue > 0) {
+            result.fScalingFactorCombined = (double) height / result.fMaxCombinedValue;
+        }
 
         fBucketDuration = Math.max(fBucketDuration, 1);
         // Set selection begin and end index in the scaled histogram
@@ -529,20 +632,24 @@ public class HistogramDataModel implements IHistogramDataModel {
     private void mergeBuckets() {
         for (int i = 0; i < (fNbBuckets / 2); i++) {
             fBuckets[i] = fBuckets[2 * i] + fBuckets[(2 * i) + 1];
+            fLostEventsBuckets[i] = fLostEventsBuckets[2 * i] + fLostEventsBuckets[(2 * i) + 1];
         }
         Arrays.fill(fBuckets, fNbBuckets / 2, fNbBuckets, 0);
+        Arrays.fill(fLostEventsBuckets, fNbBuckets / 2, fNbBuckets, 0);
         fBucketDuration *= 2;
         updateEndTime();
         fLastBucket = (fNbBuckets / 2) - 1;
     }
 
     private void moveBuckets(int offset) {
-        for(int i = fNbBuckets - 1; i >= offset; i--) {
-            fBuckets[i] = fBuckets[i-offset];
+        for (int i = fNbBuckets - 1; i >= offset; i--) {
+            fBuckets[i] = fBuckets[i - offset];
+            fLostEventsBuckets[i] = fLostEventsBuckets[i - offset];
         }
 
         for (int i = 0; i < offset; i++) {
             fBuckets[i] = 0;
+            fLostEventsBuckets[i] = 0;
         }
     }
 
@@ -553,5 +660,4 @@ public class HistogramDataModel implements IHistogramDataModel {
         }
         return offset;
     }
-
 }
This page took 0.029856 seconds and 5 git commands to generate.