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
.TmfExperimentDisposedSignal
;
27 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfExperimentRangeUpdatedSignal
;
28 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfExperimentSelectedSignal
;
29 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfExperimentUpdatedSignal
;
30 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfRangeSynchSignal
;
31 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfSignalHandler
;
32 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfSignalManager
;
33 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfTimeSynchSignal
;
34 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.TmfExperiment
;
35 import org
.eclipse
.linuxtools
.tmf
.ui
.views
.TmfView
;
36 import org
.eclipse
.swt
.SWT
;
37 import org
.eclipse
.swt
.layout
.GridData
;
38 import org
.eclipse
.swt
.layout
.GridLayout
;
39 import org
.eclipse
.swt
.widgets
.Composite
;
42 * The purpose of this view is to provide graphical time distribution statistics about the experiment/trace events.
44 * The view is composed of two histograms and two controls:
46 * <li>an event distribution histogram for the whole experiment;
47 * <li>an event distribution histogram for current time window (window span);
48 * <li>the timestamp of the currently selected event;
49 * <li>the window span (size of the time window of the smaller histogram).
51 * The histograms x-axis show their respective time range.
54 * @author Francois Chouinard
56 public class HistogramView
extends TmfView
{
58 // ------------------------------------------------------------------------
60 // ------------------------------------------------------------------------
63 * The view ID as defined in plugin.xml
65 public static final String ID
= "org.eclipse.linuxtools.tmf.ui.views.histogram"; //$NON-NLS-1$
68 * The initial window span (in nanoseconds)
70 public static final long INITIAL_WINDOW_SPAN
= (1L * 100 * 1000 * 1000); // .1sec
72 // ------------------------------------------------------------------------
74 // ------------------------------------------------------------------------
77 private Composite fParent
;
79 // The current experiment
80 private TmfExperiment fCurrentExperiment
;
82 // Current timestamp/time window - everything in the TIME_SCALE
83 private long fExperimentStartTime
;
84 private long fExperimentEndTime
;
85 private long fWindowStartTime
;
86 private long fWindowEndTime
;
87 private long fWindowSpan
= INITIAL_WINDOW_SPAN
;
88 private long fCurrentTimestamp
;
91 private HistogramTextControl fCurrentEventTimeControl
;
92 private HistogramTextControl fTimeSpanControl
;
94 // Histogram/request for the full trace range
95 private static FullTraceHistogram fFullTraceHistogram
;
96 private HistogramRequest fFullTraceRequest
;
98 // Histogram/request for the selected time range
99 private static TimeRangeHistogram fTimeRangeHistogram
;
100 private HistogramRequest fTimeRangeRequest
;
102 // ------------------------------------------------------------------------
104 // ------------------------------------------------------------------------
107 * Default constructor
109 public HistogramView() {
114 public void dispose() {
115 if ((fTimeRangeRequest
!= null) && !fTimeRangeRequest
.isCompleted()) {
116 fTimeRangeRequest
.cancel();
118 if ((fFullTraceRequest
!= null) && !fFullTraceRequest
.isCompleted()) {
119 fFullTraceRequest
.cancel();
121 fFullTraceHistogram
.dispose();
122 fTimeRangeHistogram
.dispose();
123 fCurrentEventTimeControl
.dispose();
124 fTimeSpanControl
.dispose();
128 // ------------------------------------------------------------------------
130 // ------------------------------------------------------------------------
133 public void createPartControl(Composite parent
) {
138 final String currentEventLabel
= Messages
.HistogramView_currentEventLabel
;
139 final String windowSpanLabel
= Messages
.HistogramView_windowSpanLabel
;
141 // --------------------------------------------------------------------
142 // Set the HistogramView layout
143 // --------------------------------------------------------------------
145 Composite viewComposite
= new Composite(fParent
, SWT
.FILL
);
146 GridLayout gridLayout
= new GridLayout();
147 gridLayout
.numColumns
= 2;
148 gridLayout
.horizontalSpacing
= 5;
149 gridLayout
.verticalSpacing
= 0;
150 gridLayout
.marginHeight
= 0;
151 gridLayout
.marginWidth
= 0;
152 viewComposite
.setLayout(gridLayout
);
154 // Use all available space
155 GridData gridData
= new GridData();
156 gridData
.horizontalAlignment
= SWT
.FILL
;
157 gridData
.verticalAlignment
= SWT
.FILL
;
158 gridData
.grabExcessHorizontalSpace
= true;
159 viewComposite
.setLayoutData(gridData
);
161 // --------------------------------------------------------------------
163 // --------------------------------------------------------------------
165 Composite controlsComposite
= new Composite(viewComposite
, SWT
.FILL
);
166 gridLayout
= new GridLayout();
167 gridLayout
.numColumns
= 2;
168 gridLayout
.marginHeight
= 0;
169 gridLayout
.marginWidth
= 0;
170 gridLayout
.horizontalSpacing
= 5;
171 gridLayout
.verticalSpacing
= 0;
172 gridLayout
.makeColumnsEqualWidth
= false;
173 gridLayout
.marginLeft
= 5;
174 gridLayout
.marginRight
= 5;
175 controlsComposite
.setLayout(gridLayout
);
177 // Current event time control
178 gridData
= new GridData();
179 gridData
.horizontalAlignment
= SWT
.CENTER
;
180 gridData
.verticalAlignment
= SWT
.CENTER
;
181 fCurrentEventTimeControl
= new HistogramCurrentTimeControl(this, controlsComposite
, currentEventLabel
, 0L);
182 fCurrentEventTimeControl
.setLayoutData(gridData
);
183 fCurrentEventTimeControl
.setValue(0L);
185 // Window span time control
186 gridData
= new GridData();
187 gridData
.horizontalAlignment
= SWT
.CENTER
;
188 gridData
.verticalAlignment
= SWT
.CENTER
;
189 fTimeSpanControl
= new HistogramTimeRangeControl(this, controlsComposite
, windowSpanLabel
, 0L);
190 fTimeSpanControl
.setLayoutData(gridData
);
191 fTimeSpanControl
.setValue(0L);
193 // --------------------------------------------------------------------
194 // Time range histogram
195 // --------------------------------------------------------------------
197 Composite timeRangeComposite
= new Composite(viewComposite
, SWT
.FILL
);
198 gridLayout
= new GridLayout();
199 gridLayout
.numColumns
= 1;
200 gridLayout
.marginHeight
= 0;
201 gridLayout
.marginWidth
= 0;
202 gridLayout
.marginTop
= 5;
203 gridLayout
.horizontalSpacing
= 0;
204 gridLayout
.verticalSpacing
= 0;
205 gridLayout
.marginLeft
= 5;
206 gridLayout
.marginRight
= 5;
207 timeRangeComposite
.setLayout(gridLayout
);
209 // Use remaining horizontal space
210 gridData
= new GridData();
211 gridData
.horizontalAlignment
= SWT
.FILL
;
212 gridData
.verticalAlignment
= SWT
.FILL
;
213 gridData
.grabExcessHorizontalSpace
= true;
214 timeRangeComposite
.setLayoutData(gridData
);
217 fTimeRangeHistogram
= new TimeRangeHistogram(this, timeRangeComposite
);
219 // --------------------------------------------------------------------
220 // Full range histogram
221 // --------------------------------------------------------------------
223 Composite fullRangeComposite
= new Composite(viewComposite
, SWT
.FILL
);
224 gridLayout
= new GridLayout();
225 gridLayout
.numColumns
= 1;
226 gridLayout
.marginHeight
= 0;
227 gridLayout
.marginWidth
= 0;
228 gridLayout
.marginTop
= 5;
229 gridLayout
.horizontalSpacing
= 0;
230 gridLayout
.verticalSpacing
= 0;
231 gridLayout
.marginLeft
= 5;
232 gridLayout
.marginRight
= 5;
233 fullRangeComposite
.setLayout(gridLayout
);
235 // Use remaining horizontal space
236 gridData
= new GridData();
237 gridData
.horizontalAlignment
= SWT
.FILL
;
238 gridData
.verticalAlignment
= SWT
.FILL
;
239 gridData
.horizontalSpan
= 2;
240 gridData
.grabExcessHorizontalSpace
= true;
241 fullRangeComposite
.setLayoutData(gridData
);
244 fFullTraceHistogram
= new FullTraceHistogram(this, fullRangeComposite
);
246 // Load the experiment if present
247 fCurrentExperiment
= TmfExperiment
.getCurrentExperiment();
248 if (fCurrentExperiment
!= null) {
254 public void setFocus() {
255 TmfExperiment experiment
= TmfExperiment
.getCurrentExperiment();
256 if ((experiment
!= null) && (experiment
!= fCurrentExperiment
)) {
257 fCurrentExperiment
= experiment
;
258 initializeHistograms();
264 fParent
.layout(true);
267 // ------------------------------------------------------------------------
269 // ------------------------------------------------------------------------
272 * Returns the time range of the current selected window (base on default time scale).
274 * @return the time range of current selected window.
276 public TmfTimeRange
getTimeRange() {
277 return new TmfTimeRange(
278 new TmfTimestamp(fWindowStartTime
, ITmfTimestamp
.NANOSECOND_SCALE
),
279 new TmfTimestamp(fWindowEndTime
, ITmfTimestamp
.NANOSECOND_SCALE
));
282 // ------------------------------------------------------------------------
284 // ------------------------------------------------------------------------
287 * Broadcast TmfSignal about new current time value.
288 * @param newTime the new current time.
290 void updateCurrentEventTime(long newTime
) {
291 if (fCurrentExperiment
!= null) {
292 TmfTimeRange timeRange
= new TmfTimeRange(new TmfTimestamp(newTime
, ITmfTimestamp
.NANOSECOND_SCALE
), TmfTimestamp
.BIG_CRUNCH
);
293 HistogramRequest request
= new HistogramRequest(fTimeRangeHistogram
.getDataModel(), timeRange
, 0, 1, 0, ExecutionType
.FOREGROUND
) {
295 public void handleData(ITmfEvent event
) {
297 TmfTimeSynchSignal signal
= new TmfTimeSynchSignal(this, event
.getTimestamp());
298 TmfSignalManager
.dispatchSignal(signal
);
302 fCurrentExperiment
.sendRequest(request
);
307 * Broadcast TmfSignal about new selected time range.
308 * @param startTime the new start time
309 * @param endTime the new end time
311 void updateTimeRange(long startTime
, long endTime
) {
312 if (fCurrentExperiment
!= null) {
313 // Build the new time range; keep the current time
314 TmfTimeRange timeRange
= new TmfTimeRange(
315 new TmfTimestamp(startTime
, ITmfTimestamp
.NANOSECOND_SCALE
),
316 new TmfTimestamp(endTime
, ITmfTimestamp
.NANOSECOND_SCALE
));
317 ITmfTimestamp currentTime
= new TmfTimestamp(fCurrentTimestamp
, ITmfTimestamp
.NANOSECOND_SCALE
);
318 fTimeSpanControl
.setValue(endTime
- startTime
);
320 // Send the FW signal
321 TmfRangeSynchSignal signal
= new TmfRangeSynchSignal(this, timeRange
, currentTime
);
322 TmfSignalManager
.dispatchSignal(signal
);
327 * Broadcast TmfSignal about new selected time range.
328 * @param newDuration new duration (relative to current start time)
330 public synchronized void updateTimeRange(long newDuration
) {
331 if (fCurrentExperiment
!= null) {
332 long delta
= newDuration
- fWindowSpan
;
333 long newStartTime
= fWindowStartTime
+ (delta
/ 2);
334 setNewRange(newStartTime
, newDuration
);
338 private void setNewRange(long startTime
, long duration
) {
339 if (startTime
< fExperimentStartTime
) {
340 startTime
= fExperimentStartTime
;
343 long endTime
= startTime
+ duration
;
344 if (endTime
> fExperimentEndTime
) {
345 endTime
= fExperimentEndTime
;
346 if ((endTime
- duration
) > fExperimentStartTime
) {
347 startTime
= endTime
- duration
;
349 startTime
= fExperimentStartTime
;
352 updateTimeRange(startTime
, endTime
);
355 // ------------------------------------------------------------------------
357 // ------------------------------------------------------------------------
360 * Handles experiment selected signal. Loads histogram if new experiment time range is not
361 * equal <code>TmfTimeRange.NULL_RANGE</code>
362 * @param signal the experiment selected signal
365 public void experimentSelected(TmfExperimentSelectedSignal signal
) {
366 assert (signal
!= null);
367 fCurrentExperiment
= signal
.getExperiment();
371 private void loadExperiment() {
372 initializeHistograms();
377 * @param signal the incoming signal
381 public void experimentDisposed(TmfExperimentDisposedSignal signal
) {
383 // Kill any running request
384 if ((fTimeRangeRequest
!= null) && !fTimeRangeRequest
.isCompleted()) {
385 fTimeRangeRequest
.cancel();
387 if ((fFullTraceRequest
!= null) && !fFullTraceRequest
.isCompleted()) {
388 fFullTraceRequest
.cancel();
391 // Initialize the internal data
392 fCurrentExperiment
= null;
393 fExperimentStartTime
= 0L;
394 fExperimentEndTime
= 0L;
395 fWindowStartTime
= 0L;
397 fWindowSpan
= INITIAL_WINDOW_SPAN
;
398 fCurrentTimestamp
= 0L;
400 // Clear the UI widgets
401 fFullTraceHistogram
.clear();
402 fTimeRangeHistogram
.clear();
403 fCurrentEventTimeControl
.setValue(0L);
405 fTimeSpanControl
.setValue(0);
409 * Handles experiment range updated signal. Extends histogram according to the new time range. If a
410 * HistogramRequest is already ongoing, it will be cancelled and a new request with the new range
413 * @param signal the experiment range updated signal
416 public void experimentRangeUpdated(TmfExperimentRangeUpdatedSignal signal
) {
418 if (signal
.getExperiment() != fCurrentExperiment
) {
422 boolean drawTimeRangeHistogram
= fExperimentStartTime
== 0;
423 TmfTimeRange fullRange
= signal
.getRange();
425 fExperimentStartTime
= fullRange
.getStartTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
426 fExperimentEndTime
= fullRange
.getEndTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
428 fFullTraceHistogram
.setFullRange(fExperimentStartTime
, fExperimentEndTime
);
429 fTimeRangeHistogram
.setFullRange(fExperimentStartTime
, fExperimentEndTime
);
431 if (drawTimeRangeHistogram
) {
432 fCurrentTimestamp
= fExperimentStartTime
;
433 fCurrentEventTimeControl
.setValue(fCurrentTimestamp
);
434 fFullTraceHistogram
.setTimeRange(fExperimentStartTime
, INITIAL_WINDOW_SPAN
);
435 fTimeRangeHistogram
.setTimeRange(fExperimentStartTime
, INITIAL_WINDOW_SPAN
);
436 sendTimeRangeRequest(fExperimentStartTime
, fExperimentStartTime
+ INITIAL_WINDOW_SPAN
);
439 sendFullRangeRequest(fullRange
);
443 * Handles the experiment updated signal. Used to update time limits (start and end time)
444 * @param signal the experiment updated signal
447 public void experimentUpdated(TmfExperimentUpdatedSignal signal
) {
448 if (signal
.getExperiment() != fCurrentExperiment
) {
451 TmfTimeRange fullRange
= signal
.getExperiment().getTimeRange();
452 fExperimentStartTime
= fullRange
.getStartTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
453 fExperimentEndTime
= fullRange
.getEndTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
455 fFullTraceHistogram
.setFullRange(fExperimentStartTime
, fExperimentEndTime
);
456 fTimeRangeHistogram
.setFullRange(fExperimentStartTime
, fExperimentEndTime
);
460 * Handles the current time updated signal. Sets the current time in the time range
461 * histogram as well as the full histogram.
463 * @param signal the signal to process
466 public void currentTimeUpdated(TmfTimeSynchSignal signal
) {
467 // Because this can't happen :-)
468 assert (signal
!= null);
470 // Update the selected event time
471 ITmfTimestamp currentTime
= signal
.getCurrentTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
);
472 fCurrentTimestamp
= currentTime
.getValue();
474 // Notify the relevant widgets
475 fFullTraceHistogram
.setCurrentEvent(fCurrentTimestamp
);
476 fTimeRangeHistogram
.setCurrentEvent(fCurrentTimestamp
);
477 fCurrentEventTimeControl
.setValue(fCurrentTimestamp
);
481 * Updates the current time range in the time range histogram and full range histogram.
482 * @param signal the signal to process
485 public void timeRangeUpdated(TmfRangeSynchSignal signal
) {
486 // Because this can't happen :-)
487 assert (signal
!= null);
489 if (fCurrentExperiment
!= null) {
490 // Update the time range
491 fWindowStartTime
= signal
.getCurrentRange().getStartTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
492 fWindowEndTime
= signal
.getCurrentRange().getEndTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
493 fWindowSpan
= fWindowEndTime
- fWindowStartTime
;
495 // Notify the relevant widgets
496 sendTimeRangeRequest(fWindowStartTime
, fWindowEndTime
);
497 fFullTraceHistogram
.setTimeRange(fWindowStartTime
, fWindowSpan
);
499 fTimeSpanControl
.setValue(fWindowSpan
);
503 // ------------------------------------------------------------------------
505 // ------------------------------------------------------------------------
507 private void initializeHistograms() {
508 TmfTimeRange fullRange
= updateExperimentTimeRange();
510 fTimeRangeHistogram
.clear();
511 fTimeRangeHistogram
.setFullRange(fExperimentStartTime
, fExperimentEndTime
);
512 fTimeRangeHistogram
.setTimeRange(fExperimentStartTime
, INITIAL_WINDOW_SPAN
);
513 fTimeRangeHistogram
.setCurrentEvent(fExperimentStartTime
);
515 fFullTraceHistogram
.clear();
516 fFullTraceHistogram
.setFullRange(fExperimentStartTime
, fExperimentEndTime
);
517 fFullTraceHistogram
.setTimeRange(fExperimentStartTime
, INITIAL_WINDOW_SPAN
);
518 fFullTraceHistogram
.setCurrentEvent(fExperimentStartTime
);
520 fWindowStartTime
= fExperimentStartTime
;
521 fWindowSpan
= INITIAL_WINDOW_SPAN
;
522 fWindowEndTime
= fWindowStartTime
+ fWindowSpan
;
524 fCurrentEventTimeControl
.setValue(fExperimentStartTime
);
526 fTimeSpanControl
.setValue(fWindowSpan
);
528 if (!fullRange
.equals(TmfTimeRange
.NULL_RANGE
)) {
529 sendTimeRangeRequest(fExperimentStartTime
, fExperimentStartTime
+ fWindowSpan
);
530 sendFullRangeRequest(fullRange
);
534 private TmfTimeRange
updateExperimentTimeRange() {
535 fExperimentStartTime
= 0L;
536 fExperimentEndTime
= 0L;
537 fCurrentTimestamp
= 0L;
539 TmfTimeRange timeRange
= fCurrentExperiment
.getTimeRange();
540 if (!timeRange
.equals(TmfTimeRange
.NULL_RANGE
)) {
541 fExperimentStartTime
= timeRange
.getStartTime().getValue();
542 fExperimentEndTime
= timeRange
.getEndTime().getValue();
543 fCurrentTimestamp
= fExperimentStartTime
;
548 private void sendTimeRangeRequest(long startTime
, long endTime
) {
549 if ((fTimeRangeRequest
!= null) && !fTimeRangeRequest
.isCompleted()) {
550 fTimeRangeRequest
.cancel();
552 TmfTimestamp startTS
= new TmfTimestamp(startTime
, ITmfTimestamp
.NANOSECOND_SCALE
);
553 TmfTimestamp endTS
= new TmfTimestamp(endTime
, ITmfTimestamp
.NANOSECOND_SCALE
);
554 TmfTimeRange timeRange
= new TmfTimeRange(startTS
, endTS
);
556 fTimeRangeHistogram
.clear();
557 fTimeRangeHistogram
.setTimeRange(startTime
, endTime
- startTime
);
559 int cacheSize
= fCurrentExperiment
.getCacheSize();
560 fTimeRangeRequest
= new HistogramRequest(fTimeRangeHistogram
.getDataModel(), timeRange
, 0, TmfDataRequest
.ALL_DATA
, cacheSize
, ExecutionType
.FOREGROUND
);
561 fCurrentExperiment
.sendRequest(fTimeRangeRequest
);
564 private void sendFullRangeRequest(TmfTimeRange fullRange
) {
565 if ((fFullTraceRequest
!= null) && !fFullTraceRequest
.isCompleted()) {
566 fFullTraceRequest
.cancel();
568 int cacheSize
= fCurrentExperiment
.getCacheSize();
569 fFullTraceRequest
= new HistogramRequest(fFullTraceHistogram
.getDataModel(), fullRange
, (int) fFullTraceHistogram
.fDataModel
.getNbEvents(),
570 TmfDataRequest
.ALL_DATA
, cacheSize
, ExecutionType
.BACKGROUND
);
571 fCurrentExperiment
.sendRequest(fFullTraceRequest
);