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
.TmfRangeSynchSignal
;
27 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfSignalHandler
;
28 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfSignalManager
;
29 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfTimeSynchSignal
;
30 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfTraceClosedSignal
;
31 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfTraceOpenedSignal
;
32 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfTraceRangeUpdatedSignal
;
33 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfTraceSelectedSignal
;
34 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfTraceUpdatedSignal
;
35 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.ITmfTrace
;
36 import org
.eclipse
.linuxtools
.tmf
.ui
.editors
.ITmfTraceEditor
;
37 import org
.eclipse
.linuxtools
.tmf
.ui
.views
.TmfView
;
38 import org
.eclipse
.swt
.SWT
;
39 import org
.eclipse
.swt
.layout
.GridData
;
40 import org
.eclipse
.swt
.layout
.GridLayout
;
41 import org
.eclipse
.swt
.widgets
.Composite
;
42 import org
.eclipse
.ui
.IEditorPart
;
45 * The purpose of this view is to provide graphical time distribution statistics about the trace events.
47 * The view is composed of two histograms and two controls:
49 * <li>an event distribution histogram for the whole trace;
50 * <li>an event distribution histogram for current time window (window span);
51 * <li>the timestamp of the currently selected event;
52 * <li>the window span (size of the time window of the smaller histogram).
54 * The histograms x-axis show their respective time range.
57 * @author Francois Chouinard
59 public class HistogramView
extends TmfView
{
61 // ------------------------------------------------------------------------
63 // ------------------------------------------------------------------------
66 * The view ID as defined in plugin.xml
68 public static final String ID
= "org.eclipse.linuxtools.tmf.ui.views.histogram"; //$NON-NLS-1$
70 // ------------------------------------------------------------------------
72 // ------------------------------------------------------------------------
75 private Composite fParent
;
78 private ITmfTrace fTrace
;
80 // Current timestamp/time window - everything in the TIME_SCALE
81 private long fTraceStartTime
;
82 private long fTraceEndTime
;
83 private long fWindowStartTime
;
84 private long fWindowEndTime
;
85 private long fWindowSpan
;
86 private long fCurrentTimestamp
;
89 private HistogramTextControl fCurrentEventTimeControl
;
90 private HistogramTextControl fTimeSpanControl
;
92 // Histogram/request for the full trace range
93 private static FullTraceHistogram fFullTraceHistogram
;
94 private HistogramRequest fFullTraceRequest
;
96 // Histogram/request for the selected time range
97 private static TimeRangeHistogram fTimeRangeHistogram
;
98 private HistogramRequest fTimeRangeRequest
;
100 // ------------------------------------------------------------------------
102 // ------------------------------------------------------------------------
105 * Default constructor
107 public HistogramView() {
112 public void dispose() {
113 if ((fTimeRangeRequest
!= null) && !fTimeRangeRequest
.isCompleted()) {
114 fTimeRangeRequest
.cancel();
116 if ((fFullTraceRequest
!= null) && !fFullTraceRequest
.isCompleted()) {
117 fFullTraceRequest
.cancel();
119 fFullTraceHistogram
.dispose();
120 fTimeRangeHistogram
.dispose();
121 fCurrentEventTimeControl
.dispose();
122 fTimeSpanControl
.dispose();
126 // ------------------------------------------------------------------------
128 // ------------------------------------------------------------------------
131 public void createPartControl(Composite parent
) {
136 final String currentEventLabel
= Messages
.HistogramView_currentEventLabel
;
137 final String windowSpanLabel
= Messages
.HistogramView_windowSpanLabel
;
139 // --------------------------------------------------------------------
140 // Set the HistogramView layout
141 // --------------------------------------------------------------------
143 Composite viewComposite
= new Composite(fParent
, SWT
.FILL
);
144 GridLayout gridLayout
= new GridLayout();
145 gridLayout
.numColumns
= 2;
146 gridLayout
.horizontalSpacing
= 5;
147 gridLayout
.verticalSpacing
= 0;
148 gridLayout
.marginHeight
= 0;
149 gridLayout
.marginWidth
= 0;
150 viewComposite
.setLayout(gridLayout
);
152 // Use all available space
153 GridData gridData
= new GridData();
154 gridData
.horizontalAlignment
= SWT
.FILL
;
155 gridData
.verticalAlignment
= SWT
.FILL
;
156 gridData
.grabExcessHorizontalSpace
= true;
157 viewComposite
.setLayoutData(gridData
);
159 // --------------------------------------------------------------------
161 // --------------------------------------------------------------------
163 Composite controlsComposite
= new Composite(viewComposite
, SWT
.FILL
);
164 gridLayout
= new GridLayout();
165 gridLayout
.numColumns
= 2;
166 gridLayout
.marginHeight
= 0;
167 gridLayout
.marginWidth
= 0;
168 gridLayout
.horizontalSpacing
= 5;
169 gridLayout
.verticalSpacing
= 0;
170 gridLayout
.makeColumnsEqualWidth
= false;
171 gridLayout
.marginLeft
= 5;
172 gridLayout
.marginRight
= 5;
173 controlsComposite
.setLayout(gridLayout
);
175 // Current event time control
176 gridData
= new GridData();
177 gridData
.horizontalAlignment
= SWT
.CENTER
;
178 gridData
.verticalAlignment
= SWT
.CENTER
;
179 fCurrentEventTimeControl
= new HistogramCurrentTimeControl(this, controlsComposite
, currentEventLabel
, 0L);
180 fCurrentEventTimeControl
.setLayoutData(gridData
);
181 fCurrentEventTimeControl
.setValue(Long
.MIN_VALUE
);
183 // Window span time control
184 gridData
= new GridData();
185 gridData
.horizontalAlignment
= SWT
.CENTER
;
186 gridData
.verticalAlignment
= SWT
.CENTER
;
187 fTimeSpanControl
= new HistogramTimeRangeControl(this, controlsComposite
, windowSpanLabel
, 0L);
188 fTimeSpanControl
.setLayoutData(gridData
);
189 fTimeSpanControl
.setValue(Long
.MIN_VALUE
);
191 // --------------------------------------------------------------------
192 // Time range histogram
193 // --------------------------------------------------------------------
195 Composite timeRangeComposite
= new Composite(viewComposite
, SWT
.FILL
);
196 gridLayout
= new GridLayout();
197 gridLayout
.numColumns
= 1;
198 gridLayout
.marginHeight
= 0;
199 gridLayout
.marginWidth
= 0;
200 gridLayout
.marginTop
= 5;
201 gridLayout
.horizontalSpacing
= 0;
202 gridLayout
.verticalSpacing
= 0;
203 gridLayout
.marginLeft
= 5;
204 gridLayout
.marginRight
= 5;
205 timeRangeComposite
.setLayout(gridLayout
);
207 // Use remaining horizontal space
208 gridData
= new GridData();
209 gridData
.horizontalAlignment
= SWT
.FILL
;
210 gridData
.verticalAlignment
= SWT
.FILL
;
211 gridData
.grabExcessHorizontalSpace
= true;
212 timeRangeComposite
.setLayoutData(gridData
);
215 fTimeRangeHistogram
= new TimeRangeHistogram(this, timeRangeComposite
);
217 // --------------------------------------------------------------------
218 // Full range histogram
219 // --------------------------------------------------------------------
221 Composite fullRangeComposite
= new Composite(viewComposite
, SWT
.FILL
);
222 gridLayout
= new GridLayout();
223 gridLayout
.numColumns
= 1;
224 gridLayout
.marginHeight
= 0;
225 gridLayout
.marginWidth
= 0;
226 gridLayout
.marginTop
= 5;
227 gridLayout
.horizontalSpacing
= 0;
228 gridLayout
.verticalSpacing
= 0;
229 gridLayout
.marginLeft
= 5;
230 gridLayout
.marginRight
= 5;
231 fullRangeComposite
.setLayout(gridLayout
);
233 // Use remaining horizontal space
234 gridData
= new GridData();
235 gridData
.horizontalAlignment
= SWT
.FILL
;
236 gridData
.verticalAlignment
= SWT
.FILL
;
237 gridData
.horizontalSpan
= 2;
238 gridData
.grabExcessHorizontalSpace
= true;
239 fullRangeComposite
.setLayoutData(gridData
);
242 fFullTraceHistogram
= new FullTraceHistogram(this, fullRangeComposite
);
244 IEditorPart editor
= getSite().getPage().getActiveEditor();
245 if (editor
instanceof ITmfTraceEditor
) {
246 ITmfTrace trace
= ((ITmfTraceEditor
) editor
).getTrace();
248 traceSelected(new TmfTraceSelectedSignal(this, trace
));
254 public void setFocus() {
255 fFullTraceHistogram
.fCanvas
.setFocus();
259 fParent
.layout(true);
262 // ------------------------------------------------------------------------
264 // ------------------------------------------------------------------------
267 * Returns the current trace handled by the view
269 * @return the current trace
272 public ITmfTrace
getTrace() {
277 * Returns the time range of the current selected window (base on default time scale).
279 * @return the time range of current selected window.
281 public TmfTimeRange
getTimeRange() {
282 return new TmfTimeRange(
283 new TmfTimestamp(fWindowStartTime
, ITmfTimestamp
.NANOSECOND_SCALE
),
284 new TmfTimestamp(fWindowEndTime
, ITmfTimestamp
.NANOSECOND_SCALE
));
287 // ------------------------------------------------------------------------
289 // ------------------------------------------------------------------------
292 * Broadcast TmfSignal about new current time value.
293 * @param newTime the new current time.
295 void updateCurrentEventTime(long newTime
) {
296 if (fTrace
!= null) {
297 TmfTimeRange timeRange
= new TmfTimeRange(new TmfTimestamp(newTime
, ITmfTimestamp
.NANOSECOND_SCALE
), TmfTimestamp
.BIG_CRUNCH
);
298 HistogramRequest request
= new HistogramRequest(fTimeRangeHistogram
.getDataModel(), timeRange
, 0, 1, 0, ExecutionType
.FOREGROUND
) {
300 public void handleData(ITmfEvent event
) {
302 TmfTimeSynchSignal signal
= new TmfTimeSynchSignal(this, event
.getTimestamp());
303 TmfSignalManager
.dispatchSignal(signal
);
307 fTrace
.sendRequest(request
);
312 * Broadcast TmfSignal about new selected time range.
313 * @param startTime the new start time
314 * @param endTime the new end time
316 void updateTimeRange(long startTime
, long endTime
) {
317 if (fTrace
!= null) {
318 // Build the new time range; keep the current time
319 TmfTimeRange timeRange
= new TmfTimeRange(
320 new TmfTimestamp(startTime
, ITmfTimestamp
.NANOSECOND_SCALE
),
321 new TmfTimestamp(endTime
, ITmfTimestamp
.NANOSECOND_SCALE
));
322 ITmfTimestamp currentTime
= new TmfTimestamp(fCurrentTimestamp
, ITmfTimestamp
.NANOSECOND_SCALE
);
323 fTimeSpanControl
.setValue(endTime
- startTime
);
325 // Send the FW signal
326 TmfRangeSynchSignal signal
= new TmfRangeSynchSignal(this, timeRange
, currentTime
);
327 TmfSignalManager
.dispatchSignal(signal
);
332 * Broadcast TmfSignal about new selected time range.
333 * @param newDuration new duration (relative to current start time)
335 public synchronized void updateTimeRange(long newDuration
) {
336 if (fTrace
!= null) {
337 long delta
= newDuration
- fWindowSpan
;
338 long newStartTime
= fWindowStartTime
- (delta
/ 2);
339 setNewRange(newStartTime
, newDuration
);
343 private void setNewRange(long startTime
, long duration
) {
344 long realStart
= startTime
;
346 if (realStart
< fTraceStartTime
) {
347 realStart
= fTraceStartTime
;
350 long endTime
= realStart
+ duration
;
351 if (endTime
> fTraceEndTime
) {
352 endTime
= fTraceEndTime
;
353 if ((endTime
- duration
) > fTraceStartTime
) {
354 realStart
= endTime
- duration
;
356 realStart
= fTraceStartTime
;
359 updateTimeRange(realStart
, endTime
);
362 // ------------------------------------------------------------------------
364 // ------------------------------------------------------------------------
367 * Handles trace opened signal. Loads histogram if new trace time range is not
368 * equal <code>TmfTimeRange.NULL_RANGE</code>
369 * @param signal the trace selected signal
373 public void traceOpened(TmfTraceOpenedSignal signal
) {
374 assert (signal
!= null);
375 fTrace
= signal
.getTrace();
380 * Handles trace selected signal. Loads histogram if new trace time range is not
381 * equal <code>TmfTimeRange.NULL_RANGE</code>
382 * @param signal the trace selected signal
386 public void traceSelected(TmfTraceSelectedSignal signal
) {
387 assert (signal
!= null);
388 if (fTrace
!= signal
.getTrace()) {
389 fTrace
= signal
.getTrace();
394 private void loadTrace() {
395 initializeHistograms();
400 * Handles trace closed signal. Clears the view and data model and cancels requests.
401 * @param signal the trace closed signal
405 public void traceClosed(TmfTraceClosedSignal signal
) {
407 if (signal
.getTrace() != fTrace
) {
411 // Kill any running request
412 if ((fTimeRangeRequest
!= null) && !fTimeRangeRequest
.isCompleted()) {
413 fTimeRangeRequest
.cancel();
415 if ((fFullTraceRequest
!= null) && !fFullTraceRequest
.isCompleted()) {
416 fFullTraceRequest
.cancel();
419 // Initialize the internal data
421 fTraceStartTime
= 0L;
423 fWindowStartTime
= 0L;
426 fCurrentTimestamp
= 0L;
428 // Clear the UI widgets
429 fFullTraceHistogram
.clear();
430 fTimeRangeHistogram
.clear();
431 fCurrentEventTimeControl
.setValue(Long
.MIN_VALUE
);
433 fTimeSpanControl
.setValue(Long
.MIN_VALUE
);
437 * Handles trace range updated signal. Extends histogram according to the new time range. If a
438 * HistogramRequest is already ongoing, it will be cancelled and a new request with the new range
441 * @param signal the trace range updated signal
445 public void traceRangeUpdated(TmfTraceRangeUpdatedSignal signal
) {
447 if (signal
.getTrace() != fTrace
) {
451 TmfTimeRange fullRange
= signal
.getRange();
453 fTraceStartTime
= fullRange
.getStartTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
454 fTraceEndTime
= fullRange
.getEndTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
456 fFullTraceHistogram
.setFullRange(fTraceStartTime
, fTraceEndTime
);
457 fTimeRangeHistogram
.setFullRange(fTraceStartTime
, fTraceEndTime
);
459 sendFullRangeRequest(fullRange
);
463 * Handles the trace updated signal. Used to update time limits (start and end time)
464 * @param signal the trace updated signal
468 public void traceUpdated(TmfTraceUpdatedSignal signal
) {
469 if (signal
.getTrace() != fTrace
) {
472 TmfTimeRange fullRange
= signal
.getTrace().getTimeRange();
473 fTraceStartTime
= fullRange
.getStartTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
474 fTraceEndTime
= fullRange
.getEndTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
476 fFullTraceHistogram
.setFullRange(fTraceStartTime
, fTraceEndTime
);
477 fTimeRangeHistogram
.setFullRange(fTraceStartTime
, fTraceEndTime
);
479 fFullTraceHistogram
.setTimeRange(fTimeRangeHistogram
.getStartTime(), fWindowSpan
);
480 fTimeRangeHistogram
.setTimeRange(fTimeRangeHistogram
.getStartTime(), fWindowSpan
);
482 if ((fFullTraceRequest
!= null) && fFullTraceRequest
.getRange().getEndTime().compareTo(signal
.getRange().getEndTime()) < 0) {
483 sendFullRangeRequest(fullRange
);
488 * Handles the current time updated signal. Sets the current time in the time range
489 * histogram as well as the full histogram.
491 * @param signal the signal to process
494 public void currentTimeUpdated(TmfTimeSynchSignal signal
) {
495 // Because this can't happen :-)
496 assert (signal
!= null);
498 // Update the selected event time
499 ITmfTimestamp currentTime
= signal
.getCurrentTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
);
500 fCurrentTimestamp
= currentTime
.getValue();
502 // Notify the relevant widgets
503 fFullTraceHistogram
.setCurrentEvent(fCurrentTimestamp
);
504 fTimeRangeHistogram
.setCurrentEvent(fCurrentTimestamp
);
505 fCurrentEventTimeControl
.setValue(fCurrentTimestamp
);
509 * Updates the current time range in the time range histogram and full range histogram.
510 * @param signal the signal to process
513 public void timeRangeUpdated(TmfRangeSynchSignal signal
) {
514 // Because this can't happen :-)
515 assert (signal
!= null);
517 if (fTrace
!= null) {
518 // Validate the time range
519 TmfTimeRange range
= signal
.getCurrentRange().getIntersection(fTrace
.getTimeRange());
524 // Update the time range
525 fWindowStartTime
= range
.getStartTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
526 fWindowEndTime
= range
.getEndTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
527 fWindowSpan
= fWindowEndTime
- fWindowStartTime
;
529 // Notify the relevant widgets
530 sendTimeRangeRequest(fWindowStartTime
, fWindowEndTime
);
531 fFullTraceHistogram
.setTimeRange(fWindowStartTime
, fWindowSpan
);
533 fTimeSpanControl
.setValue(fWindowSpan
);
537 // ------------------------------------------------------------------------
539 // ------------------------------------------------------------------------
541 private void initializeHistograms() {
542 TmfTimeRange fullRange
= updateTraceTimeRange();
543 long timestamp
= fTrace
.getCurrentTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
544 long startTime
= fTrace
.getCurrentRange().getStartTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
545 long duration
= fTrace
.getCurrentRange().getEndTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue() - startTime
;
547 if ((fTimeRangeRequest
!= null) && !fTimeRangeRequest
.isCompleted()) {
548 fTimeRangeRequest
.cancel();
550 fTimeRangeHistogram
.clear();
551 fTimeRangeHistogram
.setFullRange(fTraceStartTime
, fTraceEndTime
);
552 fTimeRangeHistogram
.setTimeRange(startTime
, duration
);
553 fTimeRangeHistogram
.setCurrentEvent(timestamp
);
555 if ((fFullTraceRequest
!= null) && !fFullTraceRequest
.isCompleted()) {
556 fFullTraceRequest
.cancel();
558 fFullTraceHistogram
.clear();
559 fFullTraceHistogram
.setFullRange(fTraceStartTime
, fTraceEndTime
);
560 fFullTraceHistogram
.setTimeRange(startTime
, duration
);
561 fFullTraceHistogram
.setCurrentEvent(timestamp
);
563 fWindowStartTime
= startTime
;
564 fWindowSpan
= duration
;
565 fWindowEndTime
= startTime
+ duration
;
567 fCurrentTimestamp
= timestamp
;
568 fCurrentEventTimeControl
.setValue(fCurrentTimestamp
);
570 fTimeSpanControl
.setValue(duration
);
572 if (!fullRange
.equals(TmfTimeRange
.NULL_RANGE
)) {
573 sendTimeRangeRequest(startTime
, startTime
+ duration
);
574 sendFullRangeRequest(fullRange
);
578 private TmfTimeRange
updateTraceTimeRange() {
579 fTraceStartTime
= 0L;
582 TmfTimeRange timeRange
= fTrace
.getTimeRange();
583 if (!timeRange
.equals(TmfTimeRange
.NULL_RANGE
)) {
584 fTraceStartTime
= timeRange
.getStartTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
585 fTraceEndTime
= timeRange
.getEndTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
590 private void sendTimeRangeRequest(long startTime
, long endTime
) {
591 if ((fTimeRangeRequest
!= null) && !fTimeRangeRequest
.isCompleted()) {
592 fTimeRangeRequest
.cancel();
594 TmfTimestamp startTS
= new TmfTimestamp(startTime
, ITmfTimestamp
.NANOSECOND_SCALE
);
595 TmfTimestamp endTS
= new TmfTimestamp(endTime
, ITmfTimestamp
.NANOSECOND_SCALE
);
596 TmfTimeRange timeRange
= new TmfTimeRange(startTS
, endTS
);
598 fTimeRangeHistogram
.clear();
599 fTimeRangeHistogram
.setFullRange(fTraceStartTime
, fTraceEndTime
);
600 fTimeRangeHistogram
.setTimeRange(startTime
, endTime
- startTime
);
602 int cacheSize
= fTrace
.getCacheSize();
603 fTimeRangeRequest
= new HistogramRequest(fTimeRangeHistogram
.getDataModel(), timeRange
, 0, TmfDataRequest
.ALL_DATA
, cacheSize
, ExecutionType
.FOREGROUND
);
604 fTrace
.sendRequest(fTimeRangeRequest
);
607 private void sendFullRangeRequest(TmfTimeRange fullRange
) {
608 if ((fFullTraceRequest
!= null) && !fFullTraceRequest
.isCompleted()) {
609 fFullTraceRequest
.cancel();
611 int cacheSize
= fTrace
.getCacheSize();
612 fFullTraceRequest
= new HistogramRequest(fFullTraceHistogram
.getDataModel(), fullRange
, (int) fFullTraceHistogram
.fDataModel
.getNbEvents(),
613 TmfDataRequest
.ALL_DATA
, cacheSize
, ExecutionType
.BACKGROUND
);
614 fTrace
.sendRequest(fFullTraceRequest
);