import org.eclipse.linuxtools.tmf.core.timestamp.ITmfTimestamp;
import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimeRange;
import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimestamp;
+import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace;
+import org.eclipse.linuxtools.tmf.ui.views.histogram.HistogramBucket;
import org.eclipse.linuxtools.tmf.ui.views.histogram.HistogramDataModel;
import org.eclipse.linuxtools.tmf.ui.views.histogram.HistogramScaledData;
import org.eclipse.linuxtools.tmf.ui.views.histogram.IHistogramModelListener;
private static final double DELTA = 1e-15;
+ private final static HistogramBucket _0 = new HistogramBucket(new int[] {0});
+ private final static HistogramBucket _1 = new HistogramBucket(new int[] {1});
+ private final static HistogramBucket _2 = new HistogramBucket(new int[] {2});
+ private final static HistogramBucket _4 = new HistogramBucket(new int[] {4});
+ private final static HistogramBucket _9 = new HistogramBucket(new int[] {9});
+ private final static HistogramBucket _20 = new HistogramBucket(new int[] {20});
+ private final static HistogramBucket _24 = new HistogramBucket(new int[] {24});
+
/**
* Test method for {@link HistogramDataModel#HistogramDataModel()}.
*/
testModelConsistency(model, HistogramDataModel.DEFAULT_NUMBER_OF_BUCKETS,0, 1, 0 , 0 , 0 , HistogramDataModel.DEFAULT_NUMBER_OF_BUCKETS);
}
+ /**
+ * Test method for {@link HistogramDataModel#HistogramDataModel(HistogramDataModel)}.
+ */
+ @Test
+ public void testHistogramDataModelCopyConstructor() {
+ HistogramDataModel model = new HistogramDataModel();
+ HistogramDataModel copy = new HistogramDataModel(model);
+ testModelConsistency(copy, HistogramDataModel.DEFAULT_NUMBER_OF_BUCKETS,0, 1, 0 , 0 , 0 , HistogramDataModel.DEFAULT_NUMBER_OF_BUCKETS);
+ }
+
/**
* Test method for {@link HistogramDataModel#HistogramDataModel(int)}.
*/
}
/**
- * Test methods for {@link HistogramDataModel#countEvent(long,long)}.
+ * Test methods for {@link HistogramDataModel#countEvent(long,long, ITmfTrace)}.
*/
@Test
public void testClear() {
final int nbBuckets = 100;
HistogramDataModel model = new HistogramDataModel(nbBuckets);
- model.countEvent(0, -1);
+ model.countEvent(0, -1, null);
testModelConsistency(model, nbBuckets, 0, 1, 0, 0, 0, nbBuckets);
}
/**
- * Test methods for {@link HistogramDataModel#countEvent(long,long)}.
+ * Test methods for {@link HistogramDataModel#countEvent(long,long, ITmfTrace)}.
*/
@Test
public void testCountEvent_0() {
final int nbBuckets = 100;
HistogramDataModel model = new HistogramDataModel(nbBuckets);
- model.countEvent(0, -1);
+ model.countEvent(0, -1, null);
testModelConsistency(model, nbBuckets, 0, 1, 0, 0, 0, nbBuckets);
}
/**
- * Test methods for {@link HistogramDataModel#countEvent(long,long)} and
+ * Test methods for {@link HistogramDataModel#countEvent(long,long, ITmfTrace)} and
* {@link HistogramDataModel#scaleTo(int,int,int)}.
*/
@Test
HistogramScaledData result = model.scaleTo(nbBuckets, maxHeight, 1);
for (int i = 0; i < result.fData.length; i++) {
- assertEquals(0, result.fData[i]);
+ assertEquals(_0, result.fData[i]);
}
testModelConsistency(model, nbBuckets, 0, 1, 0, 0, 0, nbBuckets);
}
/**
- * Test methods for {@link HistogramDataModel#countEvent(long,long)} and
+ * Test methods for {@link HistogramDataModel#countEvent(long,long, ITmfTrace)} and
* {@link HistogramDataModel#scaleTo(int,int,int)}.
*/
@Test
final int maxHeight = 10;
HistogramDataModel model = new HistogramDataModel(nbBuckets);
- model.countEvent(0, 1);
+ model.countEvent(0, 1, null);
HistogramScaledData result = model.scaleTo(nbBuckets, maxHeight, 1);
- assertEquals(1, result.fData[0]);
+ assertEquals(_1, result.fData[0]);
assertArrayEqualsInt(0, result.fData,1);
}
/**
- * Test methods for {@link HistogramDataModel#countEvent(long,long)} and
+ * Test methods for {@link HistogramDataModel#countEvent(long,long, ITmfTrace)} and
* {@link HistogramDataModel#scaleTo(int,int,int)}.
*/
@Test
}
/**
- * Test methods for {@link HistogramDataModel#countEvent(long,long)} and
+ * Test methods for {@link HistogramDataModel#countEvent(long,long,ITmfTrace)} and
* {@link HistogramDataModel#scaleTo(int,int,int)}.
*/
@Test
HistogramDataModel model = new HistogramDataModel(nbBuckets);
// to different to call elsewhere
for (int i = 0; i < nbBuckets; i++) {
- model.countEvent(i, i);
- model.countEvent(i + 1, i);
+ model.countEvent(i, i, null);
+ model.countEvent(i + 1, i, null);
}
HistogramScaledData result = model.scaleTo(nbBuckets, maxHeight, 1);
/**
- * Test methods for {@link HistogramDataModel#countEvent(long,long)} and
+ * Test methods for {@link HistogramDataModel#countEvent(long,long,ITmfTrace)} and
* {@link HistogramDataModel#scaleTo(int,int,int)}.
*/
@Test
HistogramDataModel model = new HistogramDataModel(nbBuckets);
for (int i = startTime; i < startTime + nbBuckets; i++) {
- model.countEvent(i, i);
+ model.countEvent(i, i, null);
}
HistogramScaledData result = model.scaleTo(nbBuckets, maxHeight, 1);
final int nbBuckets = 10;
final int maxHeight = 10;
final int nbEvents = nbBuckets / 2;
- final int[] expectedResult = new int[] { 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 };
+ final HistogramBucket[] expectedResult = new HistogramBucket[] { _1, _1, _1, _1, _1, _0, _0, _0, _0, _0 };
HistogramDataModel model = new HistogramDataModel(nbBuckets);
countEventsInModel(nbEvents, model);
final int nbBuckets = 10;
final int maxHeight = 10;
final int nbEvents = nbBuckets;
- final int[] expectedResult = new int[] { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
+ final HistogramBucket[] expectedResult = new HistogramBucket[] { _1, _1, _1, _1, _1, _1, _1, _1, _1, _1 };
HistogramDataModel model = new HistogramDataModel(nbBuckets);
countEventsInModel(nbEvents, model);
final int nbBuckets = 10;
final int maxHeight = 10;
final int nbEvents = 2 * nbBuckets;
- final int[] expectedResult = new int[] { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 };
+ final HistogramBucket[] expectedResult = new HistogramBucket[] { _2, _2, _2, _2, _2, _2, _2, _2, _2, _2 };
HistogramDataModel model = new HistogramDataModel(nbBuckets);
countEventsInModel(nbEvents, model);
final int nbBuckets = 10;
final int maxHeight = 10;
final int nbEvents = 3 * nbBuckets;
- final int[] expectedResult = new int[] { 4, 4, 4, 4, 4, 4, 4, 2, 0, 0 };
+ final HistogramBucket[] expectedResult = new HistogramBucket[] { _4, _4, _4, _4, _4, _4, _4, _2, _0, _0 };
HistogramDataModel model = new HistogramDataModel(nbBuckets);
countEventsInModel(nbEvents, model);
final int nbBuckets = 100;
final int maxHeight = 20;
final int nbEvents = 2 * nbBuckets;
- final int[] expectedResult = new int[] { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20 };
+ final HistogramBucket[] expectedResult = new HistogramBucket[] { _20, _20, _20, _20, _20, _20, _20, _20, _20, _20 };
HistogramDataModel model = new HistogramDataModel(nbBuckets);
countEventsInModel(nbEvents, model);
final int nbBuckets = 100;
final int maxHeight = 24;
final int nbEvents = 2 * nbBuckets + 1;
- final int[] expectedResult = new int[] { 24, 24, 24, 24, 24, 24, 24, 24, 9, 0 };
+ final HistogramBucket[] expectedResult = new HistogramBucket[] { _24, _24, _24, _24, _24, _24, _24, _24, _9, _0 };
HistogramDataModel model = new HistogramDataModel(nbBuckets);
countEventsInModel(nbEvents, model);
// -> buckets per bar = 50 / 2 + 1 = 26
// -> first entry in expected result is 26 * 4 = 104
// -> second entry in expected result is 22 * 4 + 9 = 97
- final int[] expectedResult = new int[] { 104, 97 };
+ final HistogramBucket[] expectedResult = new HistogramBucket[] { new HistogramBucket(new int[] {104}) , new HistogramBucket(new int[] {97}) };
HistogramDataModel model = new HistogramDataModel(nbBuckets);
countEventsInModel(nbEvents, model);
// buckets in (model) per bar = last bucket id / nbBars + 1 (plus 1 to
// cover all used buckets)
// -> buckets per bar = 50 / 10 + 1 = 6
- final int[] expectedResult = new int[] { 21, 24, 24, 24, 24, 24, 24, 24, 12, 0 };
+ final HistogramBucket[] expectedResult = new HistogramBucket[] { new HistogramBucket(new int[] {21}), _24, _24, _24, _24, _24, _24, _24, new HistogramBucket(new int[] {12}), _0 };
HistogramDataModel model = new HistogramDataModel(nbBuckets);
countInvertedEvents(nbEvents, model);
private static void countInvertedEvents(final int nbEvents, HistogramDataModel model) {
for (int i = nbEvents - 1; i >= 0; i--) {
- model.countEvent(i, i);
+ model.countEvent(i, i, null);
}
}
final int nbLostEvents_0 = 4;
final int nbLostEvents_1 = 9;
final int nbCombinedEvents = nbEvents + 2;
- final int[] expectedResult = new int[] { 4, 4, 4, 4, 4, 4, 4, 2, 0, 0 };
+ final HistogramBucket[] expectedResult = new HistogramBucket[] { _4, _4, _4, _4, _4, _4, _4, _2, _0, _0 };
final int[] expectedLostEventsResult = new int[] { 0, 2, 2, 0, 3, 3, 3, 0, 0, 0 };
HistogramDataModel model = new HistogramDataModel(nbBuckets);
private static void countEventsInModel(final int nbEvents, HistogramDataModel model, int offset, int startTime) {
for (int i = startTime; i < nbEvents + startTime; i++) {
- model.countEvent(i + offset, i);
+ model.countEvent(i + offset, i, null);
}
}
assertEquals(timeLimit, model.getTimeLimit());
}
- private static void assertArrayEqualsInt(final int val , int[] result) {
+ private static void assertArrayEqualsInt(final int val , HistogramBucket[] result) {
assertArrayEqualsInt(val, result, 0);
}
- private static void assertArrayEqualsInt(final int val , int[] result, int startVal ) {
+ private static void assertArrayEqualsInt(final int val , HistogramBucket[] result, int startVal ) {
for (int i = startVal; i < result.length; i++) {
- assertEquals(val, result[i]);
+ assertEquals(val, result[i].getNbEvents());
}
}
public static final String IMG_UI_FOLLOW_ARROW_FORWARD = ICONS_PATH + "elcl16/follow_arrow_fwd.gif";
public static final String IMG_UI_FOLLOW_ARROW_BACKWARD = ICONS_PATH + "elcl16/follow_arrow_bwd.gif";
public static final String IMG_UI_SHOW_LOST_EVENTS = ICONS_PATH + "elcl16/hide_lost_events.gif";
+ public static final String IMG_UI_SHOW_HIST_TRACES = ICONS_PATH + "elcl16/show_hist_traces.gif";
/* eview16 */
public static final String IMG_UI_SEQ_DIAGRAM_OBJ = ICONS_PATH + "eview16/sequencediagram_view.gif";
* Bernd Hufmann - Changed to updated histogram data model
* Francois Chouinard - Reformat histogram labels on format change
* Patrick Tasse - Support selection range
+ * Xavier Raynaud - Support multi-trace coloring
*******************************************************************************/
package org.eclipse.linuxtools.tmf.ui.views.histogram;
private final Color fFillColor = Display.getCurrent().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND);
// Application colors, they need to be disposed
+ private final Color[] fHistoBarColors = new Color[] {new Color(Display.getDefault(), 90, 90, 255), // blue
+ new Color(Display.getDefault(), 0, 240, 0), // green
+ new Color(Display.getDefault(), 255, 0, 0), // red
+ new Color(Display.getDefault(), 0, 255, 255), // cyan
+ new Color(Display.getDefault(), 255, 80, 255), // magenta
+ new Color(Display.getDefault(), 200, 200, 0), // yellow
+ new Color(Display.getDefault(), 200, 150, 0), // brown
+ new Color(Display.getDefault(), 150, 255, 150), // light green
+ new Color(Display.getDefault(), 200, 80, 80), // dark red
+ new Color(Display.getDefault(), 30, 150, 150), // dark cyan
+ new Color(Display.getDefault(), 200, 200, 255), // light blue
+ new Color(Display.getDefault(), 0, 120, 0), // dark green
+ new Color(Display.getDefault(), 255, 150, 150), // lighter red
+ new Color(Display.getDefault(), 140, 80, 140), // dark magenta
+ new Color(Display.getDefault(), 150, 100, 50), // brown
+ new Color(Display.getDefault(), 255, 80, 80), // light red
+ new Color(Display.getDefault(), 200, 200, 200), // light grey
+ new Color(Display.getDefault(), 255, 200, 80), // orange
+ new Color(Display.getDefault(), 255, 255, 80), // pale yellow
+ new Color(Display.getDefault(), 255, 200, 200), // pale red
+ new Color(Display.getDefault(), 255, 200, 255), // pale magenta
+ new Color(Display.getDefault(), 255, 255, 200), // pale pale yellow
+ new Color(Display.getDefault(), 200, 255, 255), // pale pale blue
+ };
private final Color fTimeRangeColor = new Color(Display.getCurrent(), 255, 128, 0);
- private final Color fHistoBarColor = new Color(Display.getDefault(), 74, 112, 139);
private final Color fLostEventColor = new Color(Display.getCurrent(), 208, 62, 120);
// Drag states
*/
private int fOffset = 0;
+ /**
+ * show the traces or not
+ * @since 3.0
+ */
+ static boolean showTraces = true;
+
// ------------------------------------------------------------------------
// Construction
// ------------------------------------------------------------------------
*/
public void dispose() {
TmfSignalManager.deregister(this);
-
- fHistoBarColor.dispose();
fLostEventColor.dispose();
+ for (Color c : fHistoBarColors) {
+ c.dispose();
+ }
fTimeRangeColor.dispose();
fFont.dispose();
fDataModel.removeHistogramListener(this);
return fMaxNbEventsText;
}
+ /**
+ * Return <code>true</code> if the traces must be displayed in the histogram,
+ * <code>false</code> otherwise.
+ * @return whether the traces should be displayed
+ * @since 3.0
+ */
+ public boolean showTraces() {
+ return showTraces && fDataModel.getNbTraces() < getMaxNbTraces();
+ }
+
+ /**
+ * Returns the maximum number of traces the histogram can display with separate colors.
+ * If there is more traces, histogram will use only one color to display them.
+ * @return the maximum number of traces the histogram can display.
+ * @since 3.0
+ */
+ public int getMaxNbTraces() {
+ return fHistoBarColors.length;
+ }
+
+ /**
+ * Returns the color used to display the trace at the given index.
+ * @param traceIndex a trace index
+ * @return a {@link Color}
+ * @since 3.0
+ */
+ public Color getTraceColor(int traceIndex) {
+ return fHistoBarColors[traceIndex % fHistoBarColors.length];
+ }
+
// ------------------------------------------------------------------------
// Operations
// ------------------------------------------------------------------------
}
}
- /**
- * Increase the histogram bucket corresponding to [timestamp]
- *
- * @param eventCount The new event count
- * @param timestamp The latest timestamp
- */
- public void countEvent(final long eventCount, final long timestamp) {
- fDataModel.countEvent(eventCount, timestamp);
- }
-
/**
* Sets the current selection time range and refresh the display
*
case SWT.HOME:
index = 0;
- while (index < fScaledData.fLastBucket && fScaledData.fData[index] == 0) {
+ while (index < fScaledData.fLastBucket && fScaledData.fData[index].isEmpty()) {
index++;
}
if (index < fScaledData.fLastBucket) {
case SWT.ARROW_RIGHT:
index = Math.max(0, fScaledData.fSelectionBeginBucket + 1);
- while (index < fScaledData.fWidth && fScaledData.fData[index] == 0) {
+ while (index < fScaledData.fWidth && fScaledData.fData[index].isEmpty()) {
index++;
}
if (index < fScaledData.fLastBucket) {
case SWT.END:
index = fScaledData.fLastBucket;
- while (index >= 0 && fScaledData.fData[index] == 0) {
+ while (index >= 0 && fScaledData.fData[index].isEmpty()) {
index--;
}
if (index >= 0) {
case SWT.ARROW_LEFT:
index = Math.min(fScaledData.fLastBucket - 1, fScaledData.fSelectionBeginBucket - 1);
- while (index >= 0 && fScaledData.fData[index] == 0) {
+ while (index >= 0 && fScaledData.fData[index].isEmpty()) {
index--;
}
if (index >= 0) {
// Draw the histogram bars
final int limit = width < scaledData.fWidth ? width : scaledData.fWidth;
double factor = HistogramScaledData.hideLostEvents ? scaledData.fScalingFactor : scaledData.fScalingFactorCombined;
+ final boolean showTracesColors = showTraces();
for (int i = 0; i < limit; i++) {
- final int value = (int) Math.ceil(scaledData.fData[i] * factor);
+ HistogramBucket hb = scaledData.fData[i];
+ int totalNbEvents = hb.getNbEvents();
+ int value = (int) Math.ceil(totalNbEvents * factor);
int x = i + fOffset;
// in Linux, the last pixel in a line is not drawn,
}
// then draw normal events second, to overwrite that extra pixel
- imageGC.setForeground(fHistoBarColor);
- imageGC.drawLine(x, height - value, x, height);
+ if (!hb.isEmpty()) {
+ if (showTracesColors) {
+ for (int traceIndex = 0; traceIndex < hb.getNbTraces(); traceIndex++) {
+ int nbEventsForTrace = hb.getNbEvent(traceIndex);
+ if (nbEventsForTrace > 0) {
+ Color c = fHistoBarColors[traceIndex % fHistoBarColors.length];
+ imageGC.setForeground(c);
+ imageGC.drawLine(x, height - value, x, height);
+ totalNbEvents -= nbEventsForTrace;
+ value = (int) Math.ceil(totalNbEvents * scaledData.fScalingFactor);
+ }
+ }
+ } else {
+ Color c = fHistoBarColors[0];
+ imageGC.setForeground(c);
+ imageGC.drawLine(x, height - value, x, height);
+ }
+ }
}
// Draw the selection bars
startTime = 0;
}
final long endTime = fScaledData.getBucketEndTime(index);
- final int nbEvents = (index >= 0) ? fScaledData.fData[index] : 0;
+ final int nbEvents = (index >= 0) ? fScaledData.fData[index].getNbEvents() : 0;
final String newLine = System.getProperty("line.separator"); //$NON-NLS-1$
final StringBuffer buffer = new StringBuffer();
int selectionBeginBucket = Math.min(fScaledData.fSelectionBeginBucket, fScaledData.fSelectionEndBucket);
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2014 Kalray
+ *
+ * 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:
+ * Xavier Raynaud - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.linuxtools.tmf.ui.views.histogram;
+
+import java.util.Arrays;
+
+/**
+ * This class counts events for a particular time range, taking into account origin of the event.
+ * @author Xavier Raynaud
+ * @since 3.0
+ */
+public class HistogramBucket {
+
+ private int fNbEvents = 0;
+ private int fEvents[];
+
+ /**
+ * Constructor
+ * @param traceCount number of traces of the experiment.
+ */
+ public HistogramBucket(int traceCount) {
+ fEvents = new int[traceCount];
+ }
+
+ /**
+ * Constructor
+ * @param values list of values
+ */
+ public HistogramBucket(int... values) {
+ fEvents = values;
+ for (int i: fEvents) {
+ fNbEvents +=i;
+ }
+ }
+
+ /**
+ * Copy Constructor
+ * @param b a HistogramBucket to copy
+ */
+ public HistogramBucket(HistogramBucket b) {
+ add(b);
+ }
+
+ /**
+ * Merge Constructor
+ * @param b1 a HistogramBucket
+ * @param b2 another HistogramBucket
+ */
+ public HistogramBucket(HistogramBucket b1, HistogramBucket b2) {
+ add(b1);
+ add(b2);
+ }
+
+ /**
+ * @return the number of events in this bucket
+ */
+ public int getNbEvents() {
+ return fNbEvents;
+ }
+
+ /**
+ * Add an event in this bucket
+ * @param traceIndex a trace index - see {@link HistogramDataModel#setTraces}.
+ */
+ public void addEvent(int traceIndex) {
+ this.fNbEvents++;
+ ensureCapacity(traceIndex+1);
+ fEvents[traceIndex]++;
+ }
+
+ private void ensureCapacity(int len) {
+ if (fEvents == null) {
+ fEvents = new int[len];
+ } else if (fEvents.length<len) {
+ int[] oldArray = fEvents;
+ fEvents = new int[len];
+ System.arraycopy(oldArray, 0, fEvents, 0, oldArray.length);
+ }
+ }
+
+ /**
+ * Gets the number of event in this bucket belonging to given trace
+ * @param traceIndex a trace index
+ * @return the number of events in this bucket belonging to the given trace
+ */
+ public int getNbEvent(int traceIndex) {
+ if (fEvents == null || fEvents.length<= traceIndex) {
+ return 0;
+ }
+ return fEvents[traceIndex];
+ }
+
+ /**
+ * @return the number of traces in this bucket
+ */
+ public int getNbTraces() {
+ if (fEvents == null) {
+ return 0;
+ }
+ return fEvents.length;
+ }
+
+ /**
+ * Merge the given bucket in this one.
+ * @param histogramBucket a bucket to merge in this one.
+ */
+ public void add(HistogramBucket histogramBucket) {
+ if (histogramBucket != null && histogramBucket.fNbEvents != 0) {
+ fNbEvents += histogramBucket.fNbEvents;
+ ensureCapacity(histogramBucket.fEvents.length);
+ for (int i = 0; i<histogramBucket.fEvents.length; i++) {
+ fEvents[i] += histogramBucket.fEvents[i];
+ }
+ }
+ }
+
+ /**
+ * @return <code>true</code> if this bucket contains no event, <code>false</code> otherwise.
+ */
+ public boolean isEmpty() {
+ return fNbEvents == 0;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + Arrays.hashCode(fEvents);
+ result = prime * result + fNbEvents;
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ HistogramBucket other = (HistogramBucket) obj;
+ if (fNbEvents != other.fNbEvents) {
+ return false;
+ }
+ if (fNbEvents != 0 && !Arrays.equals(fEvents, other.fEvents)) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(fNbEvents);
+ sb.append(": "); //$NON-NLS-1$
+ sb.append(Arrays.toString(fEvents));
+ return sb.toString();
+ }
+
+}
* Francois Chouinard - Added support for empty initial buckets
* Patrick Tasse - Support selection range
* Jean-Christian Kouamé, Simon Delisle - Added support to manage lost events
+ * Xavier Raynaud - Support multi-trace coloring
*******************************************************************************/
package org.eclipse.linuxtools.tmf.ui.views.histogram;
import java.util.Arrays;
+import java.util.LinkedHashMap;
+import java.util.Map;
import org.eclipse.core.runtime.ListenerList;
import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimeRange;
+import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace;
+import org.eclipse.linuxtools.tmf.core.trace.TmfTraceManager;
/**
* Histogram-independent data model.
// Attributes
// ------------------------------------------------------------------------
+ // Trace management
+ private ITmfTrace fTrace = null;
+ private final Map<ITmfTrace, Integer> fTraceMap = new LinkedHashMap<>();
+
// Bucket management
private final int fNbBuckets;
- private final long[] fBuckets;
+ private final HistogramBucket[] fBuckets;
private final long[] fLostEventsBuckets;
private long fBucketDuration;
private long fNbEvents;
public HistogramDataModel(long startTime, int nbBuckets) {
fFirstBucketTime = fFirstEventTime = fEndTime = startTime;
fNbBuckets = nbBuckets;
- fBuckets = new long[nbBuckets];
+ fBuckets = new HistogramBucket[nbBuckets];
fLostEventsBuckets = new long[nbBuckets];
fModelListeners = new ListenerList();
clear();
*/
public HistogramDataModel(HistogramDataModel other) {
fNbBuckets = other.fNbBuckets;
- fBuckets = Arrays.copyOf(other.fBuckets, fNbBuckets);
+ fBuckets = new HistogramBucket[fNbBuckets];
+ for (int i = 0; i < fNbBuckets; i++) {
+ fBuckets[i] = new HistogramBucket(other.fBuckets[i]);
+ }
fLostEventsBuckets = Arrays.copyOf(other.fLostEventsBuckets, fNbBuckets);
fBucketDuration = Math.max(other.fBucketDuration, 1);
fNbEvents = other.fNbEvents;
return fFirstEventTime;
}
+ /**
+ * Sets the trace of this model.
+ * @param trace - a {@link ITmfTrace}
+ * @since 3.0
+ */
+ public void setTrace(ITmfTrace trace) {
+ this.fTrace = trace;
+ fTraceMap.clear();
+ ITmfTrace[] traces = TmfTraceManager.getTraceSet(fTrace);
+ if (traces != null) {
+ int i = 0;
+ for (ITmfTrace tr : traces) {
+ fTraceMap.put(tr, i);
+ i++;
+ }
+ }
+ }
+
+ /**
+ * Gets the trace of this model.
+ * @return a {@link ITmfTrace}
+ * @since 3.0
+ */
+ public ITmfTrace getTrace() {
+ return this.fTrace;
+ }
+
+ /**
+ * Gets the traces names of this model.
+ * @return an array of trace names
+ * @since 3.0
+ */
+ public String[] getTraceNames() {
+ ITmfTrace[] traces = TmfTraceManager.getTraceSet(fTrace);
+ if (traces == null) {
+ return new String[0];
+ }
+ String[] traceNames = new String[traces.length];
+ int i = 0;
+ for (ITmfTrace tr : traces) {
+ traceNames[i] = tr.getName();
+ i++;
+ }
+ return traceNames;
+ }
+
+ /**
+ * Gets the number of traces of this model.
+ * @return the number of traces of this model.
+ * @since 3.0
+ */
+ public int getNbTraces() {
+ ITmfTrace[] traces = TmfTraceManager.getTraceSet(fTrace);
+ if (traces == null) {
+ return 1; //
+ }
+ return traces.length;
+ }
+
/**
* Sets the model start time
*
*/
@Override
public void clear() {
- Arrays.fill(fBuckets, 0);
+ Arrays.fill(fBuckets, null);
Arrays.fill(fLostEventsBuckets, 0);
fNbEvents = 0;
fFirstBucketTime = 0;
* The current event Count (for notification purposes)
* @param timestamp
* The timestamp of the event to count
- *
+ * @param trace
+ * The event trace
+ * @since 3.0
*/
@Override
- public void countEvent(long eventCount, long timestamp) {
+ public void countEvent(long eventCount, long timestamp, ITmfTrace trace) {
// Validate
if (timestamp < 0) {
}
// Set the start/end time if not already done
- if ((fFirstBucketTime == 0) && (fLastBucket == 0) && (fBuckets[0] == 0) && (timestamp > 0)) {
+ if ((fFirstBucketTime == 0) && (fLastBucket == 0) && (fBuckets[0] == null) && (timestamp > 0)) {
fFirstBucketTime = timestamp;
fFirstEventTime = timestamp;
updateEndTime();
// Increment the right bucket
int index = (int) ((timestamp - fFirstBucketTime) / fBucketDuration);
- fBuckets[index]++;
+ if (fBuckets[index] == null) {
+ fBuckets[index] = new HistogramBucket(getNbTraces());
+ }
+ Integer traceIndex = fTraceMap.get(trace);
+ if (traceIndex == null) {
+ traceIndex = 0;
+ }
+ fBuckets[index].addEvent(traceIndex);
fNbEvents++;
if (fLastBucket < index) {
fLastBucket = index;
for (int i = 0; i < nbBars; i++) {
int count = 0;
int countLostEvent = 0;
+ result.fData[i] = new HistogramBucket(getNbTraces());
for (int j = i * bucketsPerBar; j < ((i + 1) * bucketsPerBar); j++) {
if (fNbBuckets <= j) {
break;
}
- count += fBuckets[j];
+ if (fBuckets[j] != null) {
+ count += fBuckets[j].getNbEvents();
+ result.fData[i].add(fBuckets[j]);
+ }
countLostEvent += fLostEventsBuckets[j];
}
- result.fData[i] = count;
result.fLostEventsData[i] = countLostEvent;
result.fLastBucket = i;
if (result.fMaxValue < count) {
private void mergeBuckets() {
for (int i = 0; i < (fNbBuckets / 2); i++) {
- fBuckets[i] = fBuckets[2 * i] + fBuckets[(2 * i) + 1];
+ fBuckets[i] = new HistogramBucket(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(fBuckets, fNbBuckets / 2, fNbBuckets, null);
Arrays.fill(fLostEventsBuckets, fNbBuckets / 2, fNbBuckets, 0);
fBucketDuration *= 2;
updateEndTime();
private void moveBuckets(int offset) {
for (int i = fNbBuckets - 1; i >= offset; i--) {
- fBuckets[i] = fBuckets[i - offset];
+ fBuckets[i] = new HistogramBucket(fBuckets[i - offset]);
fLostEventsBuckets[i] = fLostEventsBuckets[i - offset];
}
for (int i = 0; i < offset; i++) {
- fBuckets[i] = 0;
+ fBuckets[i] = null;
fLostEventsBuckets[i] = 0;
}
}
* Francois Chouinard - Cleanup and refactoring
* Francois Chouinard - Moved from LTTng to TMF
* Simon Delisle - Added a new parameter to the constructor
+ * Xavier Raynaud - Support multi-trace coloring
*******************************************************************************/
package org.eclipse.linuxtools.tmf.ui.views.histogram;
} else { /* handle lost event */
long timestamp = event.getTimestamp().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
- fHistogram.countEvent(getNbRead(), timestamp);
+ fHistogram.countEvent(getNbRead(), timestamp, event.getTrace());
}
}
}
* Francois Chouinard - Moved from LTTng to TMF
* Patrick Tasse - Support selection range
* Jean-Christian Kouamé - Support to manage lost events
+ * Xavier Raynaud - Support multi-trace coloring
*******************************************************************************/
package org.eclipse.linuxtools.tmf.ui.views.histogram;
/**
* Array of scaled values
*/
- public int[] fData;
+ public HistogramBucket[] fData;
/**
* Array of scaled values combined including the lost events.
* This array contains the number of lost events for each bar in the histogram
* @since 2.2
*/
public static volatile boolean hideLostEvents = false;
+
// ------------------------------------------------------------------------
// Constructor
// ------------------------------------------------------------------------
fWidth = width;
fHeight = height;
fBarWidth = barWidth;
- fData = new int[width / fBarWidth];
+ fData = new HistogramBucket[width / fBarWidth];
fLostEventsData = new int[width / fBarWidth];
fBucketDuration = 1;
fMaxValue = 0;
* Francois Chouinard - Cleanup and refactoring
* Francois Chouinard - Moved from LTTng to TMF
* Patrick Tasse - Update for mouse wheel zoom
+ * Xavier Raynaud - Support multi-trace coloring
*******************************************************************************/
package org.eclipse.linuxtools.tmf.ui.views.histogram;
import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimeRange;
import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimestamp;
import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace;
+import org.eclipse.linuxtools.tmf.core.trace.TmfTraceManager;
import org.eclipse.linuxtools.tmf.ui.views.TmfView;
import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.CLabel;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseWheelListener;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
+import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.ui.IActionBars;
private static TimeRangeHistogram fTimeRangeHistogram;
private HistogramRequest fTimeRangeRequest;
+ // Legend area
+ private Composite fLegendArea;
+ private Image[] fLegendImages;
+
// Throttlers for the time sync and time-range sync signals
private final TmfSignalThrottler fTimeSyncThrottle;
private final TmfSignalThrottler fTimeRangeSyncThrottle;
// Action for toggle showing the lost events
private Action hideLostEventsAction;
+ // Action for toggle showing the traces
+ private Action showTraceAction;
// ------------------------------------------------------------------------
// Constructor
// Histogram
fFullTraceHistogram = new FullTraceHistogram(this, fullRangeComposite);
+ fLegendArea = new Composite(viewComposite, SWT.FILL);
+ fLegendArea.setLayoutData(new GridData(SWT.BEGINNING, SWT.BEGINNING, true, false, 2, 1));
+ fLegendArea.setLayout(new RowLayout());
+
// Add mouse wheel listener to time span control
MouseWheelListener listener = fFullTraceHistogram.getZoom();
fTimeSpanControl.addMouseWheelListener(listener);
return hideLostEventsAction;
}
+ /**
+ * get the show trace action
+ *
+ * @return The action object
+ * @since 3.0
+ */
+ public Action getShowTraceAction() {
+ if (showTraceAction == null) {
+ /* show lost events */
+ showTraceAction = new Action(Messages.HistogramView_showTraces, IAction.AS_CHECK_BOX) {
+ @Override
+ public void run() {
+ Histogram.showTraces = showTraceAction.isChecked();
+ fFullTraceHistogram.fCanvas.redraw();
+ fTimeRangeHistogram.fCanvas.redraw();
+ updateLegendArea();
+ }
+ };
+ showTraceAction.setChecked(true);
+ showTraceAction.setText(Messages.HistogramView_showTraces);
+ showTraceAction.setToolTipText(Messages.HistogramView_showTraces);
+ showTraceAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_SHOW_HIST_TRACES));
+ }
+ return showTraceAction;
+ }
+
// ------------------------------------------------------------------------
// Operations
// ------------------------------------------------------------------------
fSelectionEndControl.setValue(Long.MIN_VALUE);
fTimeSpanControl.setValue(Long.MIN_VALUE);
+
+ for (Control c: fLegendArea.getChildren()) {
+ c.dispose();
+ }
+ if (fLegendImages != null) {
+ for (Image i: fLegendImages) {
+ i.dispose();
+ }
+ }
+ fLegendImages = null;
+ fLegendArea.layout();
+ fLegendArea.getParent().layout();
}
/**
fTimeRangeHistogram.setFullRange(fTraceStartTime, fTraceEndTime);
fTimeRangeHistogram.setTimeRange(startTime, duration);
fTimeRangeHistogram.setSelection(selectionBeginTime, selectionEndTime);
+ fTimeRangeHistogram.fDataModel.setTrace(fTrace);
if ((fFullTraceRequest != null) && !fFullTraceRequest.isCompleted()) {
fFullTraceRequest.cancel();
fFullTraceHistogram.setFullRange(fTraceStartTime, fTraceEndTime);
fFullTraceHistogram.setTimeRange(startTime, duration);
fFullTraceHistogram.setSelection(selectionBeginTime, selectionEndTime);
+ fFullTraceHistogram.fDataModel.setTrace(fTrace);
fWindowStartTime = startTime;
fWindowSpan = duration;
fTimeSpanControl.setValue(duration);
+ ITmfTrace[] traces = TmfTraceManager.getTraceSet(fTrace);
+ if (traces != null) {
+ this.showTraceAction.setEnabled(traces.length < fFullTraceHistogram.getMaxNbTraces());
+ }
+ updateLegendArea();
+
if (!fullRange.equals(TmfTimeRange.NULL_RANGE)) {
sendTimeRangeRequest(startTime, startTime + duration);
sendFullRangeRequest(fullRange);
}
}
+ private void updateLegendArea() {
+ for (Control c: fLegendArea.getChildren()) {
+ c.dispose();
+ }
+ if (fLegendImages != null) {
+ for (Image i: fLegendImages) {
+ i.dispose();
+ }
+ }
+ fLegendImages = null;
+ if (fFullTraceHistogram.showTraces()) {
+ ITmfTrace[] traces = TmfTraceManager.getTraceSet(fTrace);
+ fLegendImages = new Image[traces.length];
+ int traceIndex = 0;
+ for (ITmfTrace trace : traces) {
+ fLegendImages[traceIndex] = new Image(fLegendArea.getDisplay(), 16, 16);
+ GC gc = new GC(fLegendImages[traceIndex]);
+ gc.setBackground(fFullTraceHistogram.getTraceColor(traceIndex));
+ gc.fillRectangle(0, 0, 15, 15);
+ gc.setForeground(fLegendArea.getDisplay().getSystemColor(SWT.COLOR_BLACK));
+ gc.drawRectangle(0, 0, 15, 15);
+ gc.dispose();
+
+ CLabel label = new CLabel(fLegendArea, SWT.NONE);
+ label.setText(trace.getName());
+ label.setImage(fLegendImages[traceIndex]);
+ traceIndex++;
+ }
+ }
+ fLegendArea.layout();
+ fLegendArea.getParent().layout();
+ }
+
private void updateDisplayedSelectionTime(long beginTime, long endTime) {
fSelectionBeginTime = beginTime;
fSelectionEndTime = endTime;
private void contributeToActionBars() {
IActionBars bars = getViewSite().getActionBars();
bars.getToolBarManager().add(getShowLostEventsAction());
+ bars.getToolBarManager().add(getShowTraceAction());
bars.getToolBarManager().add(new Separator());
}
* Contributors:
* Bernd Hufmann - Initial API and implementation
* Francois Chouinard - Moved from LTTng to TMF
+ * Xavier Raynaud - Support multi-trace coloring
*******************************************************************************/
package org.eclipse.linuxtools.tmf.ui.views.histogram;
+import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace;
import org.eclipse.linuxtools.tmf.ui.views.distribution.model.IBaseDistributionModel;
/**
*
* @param eventCount the event to count
* @param timestamp the timestamp of the event to count
+ * @param trace the trace corresponding to given events
+ * @since 3.0
*/
- void countEvent(long eventCount, long timestamp);
+ void countEvent(long eventCount, long timestamp, ITmfTrace trace);
+
/**
* Scale the model data to the width, height and bar width requested.
*
private static final String BUNDLE_NAME = "org.eclipse.linuxtools.tmf.ui.views.histogram.messages"; //$NON-NLS-1$
+ /**
+ * @since 3.0
+ */
+ public static String HistogramView_showTraces;
+
/**
* @since 2.2
*/
###############################################################################
HistogramView_hideLostEvents=Hide Lost Events
+HistogramView_showTraces=Activate Trace Coloring
HistogramView_selectionStartLabel=Selection Start
HistogramView_selectionEndLabel=Selection End
HistogramView_windowSpanLabel=Window Span