/*******************************************************************************
- * Copyright (c) 2011, 2012 Ericsson
+ * Copyright (c) 2011, 2013 Ericsson
*
* All rights reserved. This program and the accompanying materials are
* made available under the terms of the Eclipse Public License v1.0 which
* Bernd Hufmann - Implementation of new interfaces/listeners and support for
* time stamp in any order
* Francois Chouinard - Moved from LTTng to TMF
+ * Francois Chouinard - Added support for empty initial buckets
+ * Patrick Tasse - Support selection range
*******************************************************************************/
package org.eclipse.linuxtools.tmf.ui.views.histogram;
import org.eclipse.core.runtime.ListenerList;
/**
- * <b><u>HistogramDataModel</u></b>
- * <p>
- * Histogram-independent data model with the following characteristics:
+ * Histogram-independent data model.
+ *
+ * It has the following characteristics:
* <ul>
* <li>The <i>basetime</i> is the timestamp of the first event
* <li>There is a fixed number (<i>n</i>) of buckets of uniform duration
* respect to to the number of pixels in the actual histogram, we should achieve
* a nice result when visualizing the histogram.
* <p>
- * TODO: Add filter support for more refined event counting (e.g. by trace,
- * event type, etc.)
- * <p>
- * TODO: Cut-off eccentric values? TODO: Support for going back in time?
+ *
+ * @version 2.0
+ * @author Francois Chouinard
*/
public class HistogramDataModel implements IHistogramDataModel {
// Constants
// ------------------------------------------------------------------------
- // The default number of buckets
+ /**
+ * The default number of buckets
+ */
public static final int DEFAULT_NUMBER_OF_BUCKETS = 16 * 1000;
+ /**
+ * Number of events after which listeners will be notified.
+ */
public static final int REFRESH_FREQUENCY = DEFAULT_NUMBER_OF_BUCKETS;
// ------------------------------------------------------------------------
private long fFirstBucketTime; // could be negative when analyzing events with descending order!!!
private long fFirstEventTime;
private long fLastEventTime;
- private long fCurrentEventTime;
+ private long fSelectionBegin;
+ private long fSelectionEnd;
private long fTimeLimit;
// Private listener lists
// Constructors
// ------------------------------------------------------------------------
+ /**
+ * Default constructor with default number of buckets.
+ */
public HistogramDataModel() {
- this(DEFAULT_NUMBER_OF_BUCKETS);
+ this(0, DEFAULT_NUMBER_OF_BUCKETS);
+ }
+
+ /**
+ * Default constructor with default number of buckets.
+ * @param startTime The histogram start time
+ * @since 2.0
+ */
+ public HistogramDataModel(long startTime) {
+ this(startTime, DEFAULT_NUMBER_OF_BUCKETS);
}
+ /**
+ * Constructor with non-default number of buckets.
+ * @param nbBuckets A number of buckets.
+ */
public HistogramDataModel(int nbBuckets) {
+ this(0, nbBuckets);
+ }
+
+ /**
+ * Constructor with non-default 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];
fModelListeners = new ListenerList();
clear();
}
+ /**
+ * Copy constructor.
+ * @param other A model to copy.
+ */
public HistogramDataModel(HistogramDataModel other) {
fNbBuckets = other.fNbBuckets;
fBuckets = Arrays.copyOf(other.fBuckets, fNbBuckets);
- fBucketDuration = Math.max(other.fBucketDuration,1);
+ fBucketDuration = Math.max(other.fBucketDuration, 1);
fNbEvents = other.fNbEvents;
fLastBucket = other.fLastBucket;
fFirstBucketTime = other.fFirstBucketTime;
fFirstEventTime = other.fFirstEventTime;
fLastEventTime = other.fLastEventTime;
- fCurrentEventTime = other.fCurrentEventTime;
+ fSelectionBegin = other.fSelectionBegin;
+ fSelectionEnd = other.fSelectionEnd;
fTimeLimit = other.fTimeLimit;
fModelListeners = new ListenerList();
Object[] listeners = other.fModelListeners.getListeners();
// Accessors
// ------------------------------------------------------------------------
+ /**
+ * Returns the number of events in the data model.
+ * @return number of events.
+ */
public long getNbEvents() {
return fNbEvents;
}
+ /**
+ * 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
+ */
public long getBucketDuration() {
return fBucketDuration;
}
+ /**
+ * Returns the time value of the first bucket in the model.
+ * @return time of first bucket.
+ */
public long getFirstBucketTime() {
return fFirstBucketTime;
}
+ /**
+ * Returns the time of the first event in the model.
+ * @return time of first event.
+ */
public long getStartTime() {
return fFirstEventTime;
}
+ /**
+ * Sets the model start 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) {
+ fFirstBucketTime = fFirstEventTime = fLastEventTime = startTime;
+ fBucketDuration = 1;
+ updateEndTime();
+ while (endTime >= fTimeLimit) {
+ mergeBuckets();
+ }
+ }
+
+ /**
+ * Returns the time of the last event in the model.
+ * @return the time of last event.
+ */
public long getEndTime() {
return fLastEventTime;
}
+ /**
+ * 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
public long getCurrentEventTime() {
- return fCurrentEventTime;
+ return fSelectionBegin;
+ }
+
+ /**
+ * Returns the begin time of the current selection in the model.
+ * @return the begin time of the current selection.
+ * @since 3.0
+ */
+ public long getSelectionBegin() {
+ return fSelectionBegin;
}
+ /**
+ * Returns the end time of the current selection in the model.
+ * @return the end time of the current selection.
+ * @since 3.0
+ */
+ public long getSelectionEnd() {
+ return fSelectionEnd;
+ }
+
+ /**
+ * Returns the time limit with is: start time + nbBuckets * bucketDuration
+ * @return the time limit.
+ */
public long getTimeLimit() {
return fTimeLimit;
}
// Listener handling
// ------------------------------------------------------------------------
+ /**
+ * Add a listener to the model to be informed about model changes.
+ * @param listener A listener to add.
+ */
public void addHistogramListener(IHistogramModelListener listener) {
fModelListeners.add(listener);
}
+ /**
+ * Remove a given model listener.
+ * @param listener A listener to remove.
+ */
public void removeHistogramListener(IHistogramModelListener listener) {
fModelListeners.remove(listener);
}
+ // Notify listeners (always)
private void fireModelUpdateNotification() {
fireModelUpdateNotification(0);
}
+ // Notify listener on boundary
private void fireModelUpdateNotification(long count) {
if ((count % REFRESH_FREQUENCY) == 0) {
Object[] listeners = fModelListeners.getListeners();
/**
* Clear the histogram model.
+ * @see org.eclipse.linuxtools.tmf.ui.views.distribution.model.IBaseDistributionModel#clear()
*/
@Override
public void clear() {
fNbEvents = 0;
fFirstBucketTime = 0;
fLastEventTime = 0;
- fCurrentEventTime = 0;
+ fSelectionBegin = 0;
+ fSelectionEnd = 0;
fLastBucket = 0;
- fBucketDuration = 1; // 1ns
+ fBucketDuration = 1;
updateEndTime();
fireModelUpdateNotification();
}
/**
- * Sets the current event time
+ * Sets the current event time (no notification of listeners)
*
- * @param timestamp
+ * @param timestamp A time stamp to set.
+ * @deprecated As of 2.1, use {@link #setSelection(long, long)}
*/
+ @Deprecated
public void setCurrentEvent(long timestamp) {
- fCurrentEventTime = timestamp;
+ fSelectionBegin = timestamp;
+ fSelectionEnd = timestamp;
}
/**
- * Sets the current event time
+ * Sets the current event time with notification of listeners
*
- * @param timestamp
+ * @param timestamp A time stamp to set.
+ * @deprecated As of 2.1, use {@link #setSelectionNotifyListeners(long, long)}
*/
+ @Deprecated
public void setCurrentEventNotifyListeners(long timestamp) {
- fCurrentEventTime = timestamp;
+ fSelectionBegin = timestamp;
+ fSelectionEnd = timestamp;
+ fireModelUpdateNotification();
+ }
+
+ /**
+ * Sets the current selection time range (no notification of listeners)
+ *
+ * @param beginTime The selection begin time.
+ * @param endTime The selection end time.
+ * @since 3.0
+ */
+ public void setSelection(long beginTime, long endTime) {
+ fSelectionBegin = beginTime;
+ fSelectionEnd = endTime;
+ }
+
+ /**
+ * Sets the current selection time range with notification of listeners
+ *
+ * @param beginTime The selection begin time.
+ * @param endTime The selection end time.
+ * @since 3.0
+ */
+ public void setSelectionNotifyListeners(long beginTime, long endTime) {
+ fSelectionBegin = beginTime;
+ fSelectionEnd = endTime;
fireModelUpdateNotification();
}
/**
* Add event to the correct bucket, compacting the if needed.
*
- * @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
public void countEvent(long eventCount, long timestamp) {
}
// Set the start/end time if not already done
- if ((fLastBucket == 0) && (fBuckets[0] == 0) && (timestamp > 0)) {
+ if ((fFirstBucketTime == 0) && (fLastBucket == 0) && (fBuckets[0] == 0) && (timestamp > 0)) {
fFirstBucketTime = timestamp;
fFirstEventTime = timestamp;
updateEndTime();
/**
* Scale the model data to the width, height and bar width requested.
*
- * @param width
- * @param height
- * @param barWidth
- * @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)
*/
@Override
public HistogramScaledData scaleTo(int width, int height, int barWidth) {
}
fBucketDuration = Math.max(fBucketDuration, 1);
- // Set the current event index in the scaled histogram
- if ((fCurrentEventTime >= fFirstBucketTime) && (fCurrentEventTime <= fLastEventTime)) {
- result.fCurrentBucket = (int) ((fCurrentEventTime - fFirstBucketTime) / fBucketDuration) / bucketsPerBar;
+ // Set selection begin and end index in the scaled histogram
+ if (fSelectionBegin < fFirstBucketTime) {
+ result.fSelectionBeginBucket = -1;
+ } else if (fSelectionBegin > fLastEventTime) {
+ result.fSelectionBeginBucket = fLastBucket;
+ } else {
+ result.fSelectionBeginBucket = (int) ((fSelectionBegin - fFirstBucketTime) / fBucketDuration) / bucketsPerBar;
+ }
+ if (fSelectionEnd < fFirstBucketTime) {
+ result.fSelectionEndBucket = -1;
+ } else if (fSelectionEnd > fLastEventTime) {
+ result.fSelectionEndBucket = fLastBucket;
} else {
- result.fCurrentBucket = HistogramScaledData.OUT_OF_RANGE_BUCKET;
+ result.fSelectionEndBucket = (int) ((fSelectionEnd - fFirstBucketTime) / fBucketDuration) / bucketsPerBar;
}
result.fFirstBucketTime = fFirstBucketTime;