1 /*******************************************************************************
2 * Copyright (c) 2009, 2010, 2011, 2012 Ericsson
4 * All rights reserved. This program and the accompanying materials are
5 * made available under the terms of the Eclipse Public License v1.0 which
6 * accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 * William Bourque - Initial API and implementation
11 * Yuriy Vashchuk - GUI reorganisation, simplification and some related code improvements.
12 * Yuriy Vashchuk - Histograms optimisation.
13 * Yuriy Vashchuk - Histogram Canvas Heritage correction
14 * Francois Chouinard - Cleanup and refactoring
15 * Francois Chouinard - Moved from LTTng to TMF
16 *******************************************************************************/
18 package org
.eclipse
.linuxtools
.tmf
.ui
.views
.histogram
;
20 import org
.eclipse
.linuxtools
.tmf
.core
.event
.ITmfEvent
;
21 import org
.eclipse
.linuxtools
.tmf
.core
.event
.ITmfTimestamp
;
22 import org
.eclipse
.linuxtools
.tmf
.core
.event
.TmfTimeRange
;
23 import org
.eclipse
.linuxtools
.tmf
.core
.event
.TmfTimestamp
;
24 import org
.eclipse
.linuxtools
.tmf
.core
.request
.ITmfDataRequest
.ExecutionType
;
25 import org
.eclipse
.linuxtools
.tmf
.core
.request
.TmfDataRequest
;
26 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfExperimentRangeUpdatedSignal
;
27 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfExperimentSelectedSignal
;
28 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfExperimentUpdatedSignal
;
29 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfRangeSynchSignal
;
30 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfSignalHandler
;
31 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfSignalManager
;
32 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfTimeSynchSignal
;
33 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.TmfExperiment
;
34 import org
.eclipse
.linuxtools
.tmf
.ui
.views
.TmfView
;
35 import org
.eclipse
.swt
.SWT
;
36 import org
.eclipse
.swt
.layout
.GridData
;
37 import org
.eclipse
.swt
.layout
.GridLayout
;
38 import org
.eclipse
.swt
.widgets
.Composite
;
41 * The purpose of this view is to provide graphical time distribution statistics about the experiment/trace events.
43 * The view is composed of two histograms and two controls:
45 * <li>an event distribution histogram for the whole experiment;
46 * <li>an event distribution histogram for current time window (window span);
47 * <li>the timestamp of the currently selected event;
48 * <li>the window span (size of the time window of the smaller histogram).
50 * The histograms x-axis show their respective time range.
53 * @author Francois Chouinard
55 public class HistogramView
extends TmfView
{
57 // ------------------------------------------------------------------------
59 // ------------------------------------------------------------------------
62 * The view ID as defined in plugin.xml
64 public static final String ID
= "org.eclipse.linuxtools.tmf.ui.views.histogram"; //$NON-NLS-1$
67 * The initial window span (in nanoseconds)
69 public static final long INITIAL_WINDOW_SPAN
= (1L * 100 * 1000 * 1000); // .1sec
72 private final byte TIME_SCALE
= Histogram
.TIME_SCALE
;
74 // ------------------------------------------------------------------------
76 // ------------------------------------------------------------------------
79 private Composite fParent
;
81 // The current experiment
82 private TmfExperiment
<ITmfEvent
> fCurrentExperiment
;
84 // Current timestamp/time window
85 private long fExperimentStartTime
;
86 private long fExperimentEndTime
;
87 private long fWindowStartTime
;
88 private long fWindowEndTime
;
89 private long fWindowSpan
= INITIAL_WINDOW_SPAN
;
90 private long fCurrentTimestamp
;
93 private HistogramTextControl fCurrentEventTimeControl
;
94 private HistogramTextControl fTimeSpanControl
;
96 // Histogram/request for the full trace range
97 private static FullTraceHistogram fFullTraceHistogram
;
98 private HistogramRequest fFullTraceRequest
;
100 // Histogram/request for the selected time range
101 private static TimeRangeHistogram fTimeRangeHistogram
;
102 private HistogramRequest fTimeRangeRequest
;
104 // ------------------------------------------------------------------------
106 // ------------------------------------------------------------------------
109 * Default constructor
111 public HistogramView() {
116 public void dispose() {
117 if ((fTimeRangeRequest
!= null) && !fTimeRangeRequest
.isCompleted()) {
118 fTimeRangeRequest
.cancel();
120 if ((fFullTraceRequest
!= null) && !fFullTraceRequest
.isCompleted()) {
121 fFullTraceRequest
.cancel();
123 fFullTraceHistogram
.dispose();
124 fTimeRangeHistogram
.dispose();
128 // ------------------------------------------------------------------------
130 // ------------------------------------------------------------------------
133 @SuppressWarnings("unchecked")
134 public void createPartControl(Composite parent
) {
139 final String currentEventLabel
= Messages
.HistogramView_currentEventLabel
;
140 final String windowSpanLabel
= Messages
.HistogramView_windowSpanLabel
;
142 // --------------------------------------------------------------------
143 // Set the HistogramView layout
144 // --------------------------------------------------------------------
146 Composite viewComposite
= new Composite(fParent
, SWT
.FILL
);
147 GridLayout gridLayout
= new GridLayout();
148 gridLayout
.numColumns
= 2;
149 gridLayout
.horizontalSpacing
= 5;
150 gridLayout
.verticalSpacing
= 0;
151 gridLayout
.marginHeight
= 0;
152 gridLayout
.marginWidth
= 0;
153 viewComposite
.setLayout(gridLayout
);
155 // Use all available space
156 GridData gridData
= new GridData();
157 gridData
.horizontalAlignment
= SWT
.FILL
;
158 gridData
.verticalAlignment
= SWT
.FILL
;
159 gridData
.grabExcessHorizontalSpace
= true;
160 viewComposite
.setLayoutData(gridData
);
162 // --------------------------------------------------------------------
164 // --------------------------------------------------------------------
166 Composite controlsComposite
= new Composite(viewComposite
, SWT
.FILL
);
167 gridLayout
= new GridLayout();
168 gridLayout
.numColumns
= 2;
169 gridLayout
.marginHeight
= 0;
170 gridLayout
.marginWidth
= 0;
171 gridLayout
.horizontalSpacing
= 5;
172 gridLayout
.verticalSpacing
= 0;
173 gridLayout
.makeColumnsEqualWidth
= true;
174 gridLayout
.marginLeft
= 5;
175 gridLayout
.marginRight
= 5;
176 controlsComposite
.setLayout(gridLayout
);
178 // Current event time control
179 gridData
= new GridData();
180 gridData
.horizontalAlignment
= SWT
.CENTER
;
181 gridData
.verticalAlignment
= SWT
.CENTER
;
182 fCurrentEventTimeControl
= new HistogramCurrentTimeControl(this, controlsComposite
, SWT
.BORDER
, SWT
.NONE
,
183 currentEventLabel
, HistogramUtils
.nanosecondsToString(0L));
184 fCurrentEventTimeControl
.setLayoutData(gridData
);
186 // Window span time control
187 gridData
= new GridData();
188 gridData
.horizontalAlignment
= SWT
.CENTER
;
189 gridData
.verticalAlignment
= SWT
.CENTER
;
190 fTimeSpanControl
= new HistogramTimeRangeControl(this, controlsComposite
, SWT
.BORDER
, SWT
.NONE
,
191 windowSpanLabel
, HistogramUtils
.nanosecondsToString(0L));
192 fTimeSpanControl
.setLayoutData(gridData
);
194 // --------------------------------------------------------------------
195 // Time range histogram
196 // --------------------------------------------------------------------
198 Composite timeRangeComposite
= new Composite(viewComposite
, SWT
.FILL
);
199 gridLayout
= new GridLayout();
200 gridLayout
.numColumns
= 1;
201 gridLayout
.marginHeight
= 0;
202 gridLayout
.marginWidth
= 0;
203 gridLayout
.marginTop
= 5;
204 gridLayout
.horizontalSpacing
= 0;
205 gridLayout
.verticalSpacing
= 0;
206 gridLayout
.marginLeft
= 5;
207 gridLayout
.marginRight
= 5;
208 timeRangeComposite
.setLayout(gridLayout
);
210 // Use remaining horizontal space
211 gridData
= new GridData();
212 gridData
.horizontalAlignment
= SWT
.FILL
;
213 gridData
.verticalAlignment
= SWT
.FILL
;
214 gridData
.grabExcessHorizontalSpace
= true;
215 timeRangeComposite
.setLayoutData(gridData
);
218 fTimeRangeHistogram
= new TimeRangeHistogram(this, timeRangeComposite
);
220 // --------------------------------------------------------------------
221 // Full range histogram
222 // --------------------------------------------------------------------
224 Composite fullRangeComposite
= new Composite(viewComposite
, SWT
.FILL
);
225 gridLayout
= new GridLayout();
226 gridLayout
.numColumns
= 1;
227 gridLayout
.marginHeight
= 0;
228 gridLayout
.marginWidth
= 0;
229 gridLayout
.marginTop
= 5;
230 gridLayout
.horizontalSpacing
= 0;
231 gridLayout
.verticalSpacing
= 0;
232 gridLayout
.marginLeft
= 5;
233 gridLayout
.marginRight
= 5;
234 fullRangeComposite
.setLayout(gridLayout
);
236 // Use remaining horizontal space
237 gridData
= new GridData();
238 gridData
.horizontalAlignment
= SWT
.FILL
;
239 gridData
.verticalAlignment
= SWT
.FILL
;
240 gridData
.horizontalSpan
= 2;
241 gridData
.grabExcessHorizontalSpace
= true;
242 fullRangeComposite
.setLayoutData(gridData
);
245 fFullTraceHistogram
= new FullTraceHistogram(this, fullRangeComposite
);
247 // Load the experiment if present
248 fCurrentExperiment
= (TmfExperiment
<ITmfEvent
>) TmfExperiment
.getCurrentExperiment();
249 if (fCurrentExperiment
!= null) {
255 @SuppressWarnings("unchecked")
256 public void setFocus() {
257 TmfExperiment
<ITmfEvent
> experiment
= (TmfExperiment
<ITmfEvent
>) TmfExperiment
.getCurrentExperiment();
258 if ((experiment
!= null) && (experiment
!= fCurrentExperiment
)) {
259 fCurrentExperiment
= experiment
;
260 initializeHistograms();
265 // ------------------------------------------------------------------------
267 // ------------------------------------------------------------------------
270 * Returns the time range of the current selected window (base on default time scale).
272 * @return the time range of current selected window.
274 public TmfTimeRange
getTimeRange() {
275 return new TmfTimeRange(new TmfTimestamp(fWindowStartTime
, TIME_SCALE
), new TmfTimestamp(fWindowEndTime
,
279 // ------------------------------------------------------------------------
281 // ------------------------------------------------------------------------
284 * Broadcast TmfSignal about new current time value.
285 * @param newTime the new current time.
287 public void updateCurrentEventTime(long newTime
) {
288 if (fCurrentExperiment
!= null) {
289 TmfTimeRange timeRange
= new TmfTimeRange(new TmfTimestamp(newTime
, TIME_SCALE
), TmfTimestamp
.BIG_CRUNCH
);
290 HistogramRequest request
= new HistogramRequest(fTimeRangeHistogram
.getDataModel(), timeRange
, 0, 1, 0, ExecutionType
.FOREGROUND
) {
292 public void handleData(ITmfEvent event
) {
294 TmfTimeSynchSignal signal
= new TmfTimeSynchSignal(this, event
.getTimestamp());
295 TmfSignalManager
.dispatchSignal(signal
);
299 fCurrentExperiment
.sendRequest(request
);
304 * Broadcast TmfSignal about new selected time range.
305 * @param startTime the new start time
306 * @param endTime the new end time
308 public void updateTimeRange(long startTime
, long endTime
) {
309 if (fCurrentExperiment
!= null) {
310 // Build the new time range; keep the current time
311 TmfTimeRange timeRange
= new TmfTimeRange(new TmfTimestamp(startTime
, TIME_SCALE
), new TmfTimestamp(
312 endTime
, TIME_SCALE
));
313 TmfTimestamp currentTime
= new TmfTimestamp(fCurrentTimestamp
, TIME_SCALE
);
315 fTimeSpanControl
.setValue(endTime
- startTime
);
317 // Send the FW signal
318 TmfRangeSynchSignal signal
= new TmfRangeSynchSignal(this, timeRange
, currentTime
);
319 TmfSignalManager
.dispatchSignal(signal
);
324 * Broadcast TmfSignal about new selected time range.
325 * @param newDuration new duration (relative to current start time)
327 public synchronized void updateTimeRange(long newDuration
) {
328 if (fCurrentExperiment
!= null) {
329 long delta
= newDuration
- fWindowSpan
;
330 long newStartTime
= fWindowStartTime
+ (delta
/ 2);
331 setNewRange(newStartTime
, newDuration
);
335 private void setNewRange(long startTime
, long duration
) {
336 if (startTime
< fExperimentStartTime
) {
337 startTime
= fExperimentStartTime
;
340 long endTime
= startTime
+ duration
;
341 if( endTime
< startTime
) {
342 endTime
= fExperimentEndTime
;
343 startTime
= fExperimentStartTime
;
345 if (endTime
> fExperimentEndTime
) {
346 endTime
= fExperimentEndTime
;
347 if ((endTime
- duration
) > fExperimentStartTime
) {
348 startTime
= endTime
- duration
;
350 startTime
= fExperimentStartTime
;
353 updateTimeRange(startTime
, endTime
);
356 // ------------------------------------------------------------------------
358 // ------------------------------------------------------------------------
361 * Handles experiment selected signal. Loads histogram if new experiment time range is not
362 * equal <code>TmfTimeRange.NULL_RANGE</code>
363 * @param signal the experiment selected signal
366 @SuppressWarnings("unchecked")
367 public void experimentSelected(TmfExperimentSelectedSignal
<ITmfEvent
> signal
) {
368 assert (signal
!= null);
369 fCurrentExperiment
= (TmfExperiment
<ITmfEvent
>) signal
.getExperiment();
373 private void loadExperiment() {
374 initializeHistograms();
379 * Handles experiment range updated signal. Extends histogram according to the new time range. If a
380 * HistogramRequest is already ongoing, it will be cancelled and a new request with the new range
383 * @param signal the experiment range updated signal
386 public void experimentRangeUpdated(TmfExperimentRangeUpdatedSignal signal
) {
388 if (signal
.getExperiment() != fCurrentExperiment
) {
392 boolean drawTimeRangeHistogram
= fExperimentStartTime
== 0;
393 TmfTimeRange fullRange
= signal
.getRange();
395 fExperimentStartTime
= fullRange
.getStartTime().normalize(0, -9).getValue();
396 fExperimentEndTime
= fullRange
.getEndTime().normalize(0, -9).getValue();
398 fFullTraceHistogram
.setFullRange(fExperimentStartTime
, fExperimentEndTime
);
399 fTimeRangeHistogram
.setFullRange(fExperimentStartTime
, fExperimentEndTime
);
401 if (drawTimeRangeHistogram
) {
402 fCurrentTimestamp
= fExperimentStartTime
;
403 fCurrentEventTimeControl
.setValue(fCurrentTimestamp
);
404 fFullTraceHistogram
.setTimeRange(fExperimentStartTime
, INITIAL_WINDOW_SPAN
);
405 fTimeRangeHistogram
.setTimeRange(fExperimentStartTime
, INITIAL_WINDOW_SPAN
);
406 sendTimeRangeRequest(fExperimentStartTime
, fExperimentStartTime
+ INITIAL_WINDOW_SPAN
);
409 sendFullRangeRequest(fullRange
);
413 * Handles the experiment updated signal. Used to update time limits (start and end time)
414 * @param signal the experiment updated signal
417 public void experimentUpdated(TmfExperimentUpdatedSignal signal
) {
418 if (signal
.getExperiment() != fCurrentExperiment
) {
421 TmfTimeRange fullRange
= signal
.getExperiment().getTimeRange();
422 fExperimentStartTime
= fullRange
.getStartTime().normalize(0, -9).getValue();
423 fExperimentEndTime
= fullRange
.getEndTime().normalize(0, -9).getValue();
425 fFullTraceHistogram
.setFullRange(fExperimentStartTime
, fExperimentEndTime
);
426 fTimeRangeHistogram
.setFullRange(fExperimentStartTime
, fExperimentEndTime
);
430 * Handles the current time updated signal. Sets the current time in the time range
431 * histogram as well as the full histogram.
433 * @param signal the signal to process
436 public void currentTimeUpdated(TmfTimeSynchSignal signal
) {
437 // Because this can't happen :-)
438 assert (signal
!= null);
440 // Update the selected event time
441 ITmfTimestamp currentTime
= signal
.getCurrentTime();
442 fCurrentTimestamp
= currentTime
.normalize(0, -9).getValue();
444 // Notify the relevant widgets
445 fFullTraceHistogram
.setCurrentEvent(fCurrentTimestamp
);
446 fTimeRangeHistogram
.setCurrentEvent(fCurrentTimestamp
);
447 fCurrentEventTimeControl
.setValue(fCurrentTimestamp
);
451 * Updates the current time range in the time range histogram and full range histogram.
452 * @param signal the signal to process
455 public void timeRangeUpdated(TmfRangeSynchSignal signal
) {
456 // Because this can't happen :-)
457 assert (signal
!= null);
459 if (fCurrentExperiment
!= null) {
460 // Update the time range
461 fWindowStartTime
= signal
.getCurrentRange().getStartTime().normalize(0, -9).getValue();
462 fWindowEndTime
= signal
.getCurrentRange().getEndTime().normalize(0, -9).getValue();
463 fWindowSpan
= fWindowEndTime
- fWindowStartTime
;
465 // Notify the relevant widgets
466 sendTimeRangeRequest(fWindowStartTime
, fWindowEndTime
);
467 fFullTraceHistogram
.setTimeRange(fWindowStartTime
, fWindowSpan
);
468 fTimeSpanControl
.setValue(fWindowSpan
);
472 // ------------------------------------------------------------------------
474 // ------------------------------------------------------------------------
476 private void initializeHistograms() {
477 TmfTimeRange fullRange
= updateExperimentTimeRange(fCurrentExperiment
);
479 fTimeRangeHistogram
.clear();
480 fTimeRangeHistogram
.setFullRange(fExperimentStartTime
, fExperimentEndTime
);
481 fTimeRangeHistogram
.setTimeRange(fExperimentStartTime
, INITIAL_WINDOW_SPAN
);
482 fTimeRangeHistogram
.setCurrentEvent(fExperimentStartTime
);
484 fFullTraceHistogram
.clear();
485 fFullTraceHistogram
.setFullRange(fExperimentStartTime
, fExperimentEndTime
);
486 fFullTraceHistogram
.setTimeRange(fExperimentStartTime
, INITIAL_WINDOW_SPAN
);
487 fFullTraceHistogram
.setCurrentEvent(fExperimentStartTime
);
489 fWindowStartTime
= fExperimentStartTime
;
490 fWindowSpan
= INITIAL_WINDOW_SPAN
;
491 fWindowEndTime
= fWindowStartTime
+ fWindowSpan
;
493 fCurrentEventTimeControl
.setValue(fExperimentStartTime
);
494 fTimeSpanControl
.setValue(fWindowSpan
);
496 if (!fullRange
.equals(TmfTimeRange
.NULL_RANGE
)) {
497 sendTimeRangeRequest(fExperimentStartTime
, fExperimentStartTime
+ fWindowSpan
);
498 sendFullRangeRequest(fullRange
);
502 private TmfTimeRange
updateExperimentTimeRange(TmfExperiment
<ITmfEvent
> experiment
) {
503 fExperimentStartTime
= 0;
504 fExperimentEndTime
= 0;
505 fCurrentTimestamp
= 0;
507 TmfTimeRange timeRange
= fCurrentExperiment
.getTimeRange();
508 if (!timeRange
.equals(TmfTimeRange
.NULL_RANGE
)) {
509 fExperimentStartTime
= timeRange
.getStartTime().normalize(0, -9).getValue();
510 fExperimentEndTime
= timeRange
.getEndTime().normalize(0, -9).getValue();
511 fCurrentTimestamp
= fExperimentStartTime
;
516 private void sendTimeRangeRequest(long startTime
, long endTime
) {
517 if ((fTimeRangeRequest
!= null) && !fTimeRangeRequest
.isCompleted()) {
518 fTimeRangeRequest
.cancel();
520 TmfTimestamp startTS
= new TmfTimestamp(startTime
, TIME_SCALE
);
521 TmfTimestamp endTS
= new TmfTimestamp(endTime
, TIME_SCALE
);
522 TmfTimeRange timeRange
= new TmfTimeRange(startTS
, endTS
);
524 fTimeRangeHistogram
.clear();
525 fTimeRangeHistogram
.setTimeRange(startTime
, endTime
- startTime
);
527 int cacheSize
= fCurrentExperiment
.getCacheSize();
528 fTimeRangeRequest
= new HistogramRequest(fTimeRangeHistogram
.getDataModel(), timeRange
, 0, TmfDataRequest
.ALL_DATA
, cacheSize
, ExecutionType
.FOREGROUND
);
529 fCurrentExperiment
.sendRequest(fTimeRangeRequest
);
532 private void sendFullRangeRequest(TmfTimeRange fullRange
) {
533 if ((fFullTraceRequest
!= null) && !fFullTraceRequest
.isCompleted()) {
534 fFullTraceRequest
.cancel();
536 int cacheSize
= fCurrentExperiment
.getCacheSize();
537 fFullTraceRequest
= new HistogramRequest(fFullTraceHistogram
.getDataModel(), fullRange
, (int) fFullTraceHistogram
.fDataModel
.getNbEvents(),
538 TmfDataRequest
.ALL_DATA
, cacheSize
, ExecutionType
.BACKGROUND
);
539 fCurrentExperiment
.sendRequest(fFullTraceRequest
);