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 // ------------------------------------------------------------------------
61 // The view ID as defined in plugin.xml
62 public static final String ID
= "org.eclipse.linuxtools.tmf.ui.views.histogram"; //$NON-NLS-1$
64 // The initial window span (in nanoseconds)
65 public static final long INITIAL_WINDOW_SPAN
= (1L * 100 * 1000 * 1000); // .1sec
68 private final byte TIME_SCALE
= Histogram
.TIME_SCALE
;
70 // ------------------------------------------------------------------------
72 // ------------------------------------------------------------------------
75 private Composite fParent
;
77 // The current experiment
78 private TmfExperiment
<ITmfEvent
> fCurrentExperiment
;
80 // Current timestamp/time window
81 private long fExperimentStartTime
;
82 private long fExperimentEndTime
;
83 private long fWindowStartTime
;
84 private long fWindowEndTime
;
85 private long fWindowSpan
= INITIAL_WINDOW_SPAN
;
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 // ------------------------------------------------------------------------
104 public HistogramView() {
109 public void dispose() {
110 if (fTimeRangeRequest
!= null && !fTimeRangeRequest
.isCompleted()) {
111 fTimeRangeRequest
.cancel();
113 if (fFullTraceRequest
!= null && !fFullTraceRequest
.isCompleted()) {
114 fFullTraceRequest
.cancel();
116 fFullTraceHistogram
.dispose();
117 fTimeRangeHistogram
.dispose();
121 // ------------------------------------------------------------------------
123 // ------------------------------------------------------------------------
126 @SuppressWarnings("unchecked")
127 public void createPartControl(Composite parent
) {
132 final String currentEventLabel
= Messages
.HistogramView_currentEventLabel
;
133 final String windowSpanLabel
= Messages
.HistogramView_windowSpanLabel
;
135 // --------------------------------------------------------------------
136 // Set the HistogramView layout
137 // --------------------------------------------------------------------
139 Composite viewComposite
= new Composite(fParent
, SWT
.FILL
);
140 GridLayout gridLayout
= new GridLayout();
141 gridLayout
.numColumns
= 2;
142 gridLayout
.horizontalSpacing
= 5;
143 gridLayout
.verticalSpacing
= 0;
144 gridLayout
.marginHeight
= 0;
145 gridLayout
.marginWidth
= 0;
146 viewComposite
.setLayout(gridLayout
);
148 // Use all available space
149 GridData gridData
= new GridData();
150 gridData
.horizontalAlignment
= SWT
.FILL
;
151 gridData
.verticalAlignment
= SWT
.FILL
;
152 gridData
.grabExcessHorizontalSpace
= true;
153 viewComposite
.setLayoutData(gridData
);
155 // --------------------------------------------------------------------
157 // --------------------------------------------------------------------
159 Composite controlsComposite
= new Composite(viewComposite
, SWT
.FILL
);
160 gridLayout
= new GridLayout();
161 gridLayout
.numColumns
= 2;
162 gridLayout
.marginHeight
= 0;
163 gridLayout
.marginWidth
= 0;
164 gridLayout
.horizontalSpacing
= 5;
165 gridLayout
.verticalSpacing
= 0;
166 gridLayout
.makeColumnsEqualWidth
= true;
167 gridLayout
.marginLeft
= 5;
168 gridLayout
.marginRight
= 5;
169 controlsComposite
.setLayout(gridLayout
);
171 // Current event time control
172 gridData
= new GridData();
173 gridData
.horizontalAlignment
= SWT
.CENTER
;
174 gridData
.verticalAlignment
= SWT
.CENTER
;
175 fCurrentEventTimeControl
= new HistogramCurrentTimeControl(this, controlsComposite
, SWT
.BORDER
, SWT
.NONE
,
176 currentEventLabel
, HistogramUtils
.nanosecondsToString(0L));
177 fCurrentEventTimeControl
.setLayoutData(gridData
);
179 // Window span time control
180 gridData
= new GridData();
181 gridData
.horizontalAlignment
= SWT
.CENTER
;
182 gridData
.verticalAlignment
= SWT
.CENTER
;
183 fTimeSpanControl
= new HistogramTimeRangeControl(this, controlsComposite
, SWT
.BORDER
, SWT
.NONE
,
184 windowSpanLabel
, HistogramUtils
.nanosecondsToString(0L));
185 fTimeSpanControl
.setLayoutData(gridData
);
187 // --------------------------------------------------------------------
188 // Time range histogram
189 // --------------------------------------------------------------------
191 Composite timeRangeComposite
= new Composite(viewComposite
, SWT
.FILL
);
192 gridLayout
= new GridLayout();
193 gridLayout
.numColumns
= 1;
194 gridLayout
.marginHeight
= 0;
195 gridLayout
.marginWidth
= 0;
196 gridLayout
.marginTop
= 5;
197 gridLayout
.horizontalSpacing
= 0;
198 gridLayout
.verticalSpacing
= 0;
199 gridLayout
.marginLeft
= 5;
200 gridLayout
.marginRight
= 5;
201 timeRangeComposite
.setLayout(gridLayout
);
203 // Use remaining horizontal space
204 gridData
= new GridData();
205 gridData
.horizontalAlignment
= SWT
.FILL
;
206 gridData
.verticalAlignment
= SWT
.FILL
;
207 gridData
.grabExcessHorizontalSpace
= true;
208 timeRangeComposite
.setLayoutData(gridData
);
211 fTimeRangeHistogram
= new TimeRangeHistogram(this, timeRangeComposite
);
213 // --------------------------------------------------------------------
214 // Full range histogram
215 // --------------------------------------------------------------------
217 Composite fullRangeComposite
= new Composite(viewComposite
, SWT
.FILL
);
218 gridLayout
= new GridLayout();
219 gridLayout
.numColumns
= 1;
220 gridLayout
.marginHeight
= 0;
221 gridLayout
.marginWidth
= 0;
222 gridLayout
.marginTop
= 5;
223 gridLayout
.horizontalSpacing
= 0;
224 gridLayout
.verticalSpacing
= 0;
225 gridLayout
.marginLeft
= 5;
226 gridLayout
.marginRight
= 5;
227 fullRangeComposite
.setLayout(gridLayout
);
229 // Use remaining horizontal space
230 gridData
= new GridData();
231 gridData
.horizontalAlignment
= SWT
.FILL
;
232 gridData
.verticalAlignment
= SWT
.FILL
;
233 gridData
.horizontalSpan
= 2;
234 gridData
.grabExcessHorizontalSpace
= true;
235 fullRangeComposite
.setLayoutData(gridData
);
238 fFullTraceHistogram
= new FullTraceHistogram(this, fullRangeComposite
);
240 // Load the experiment if present
241 fCurrentExperiment
= (TmfExperiment
<ITmfEvent
>) TmfExperiment
.getCurrentExperiment();
242 if (fCurrentExperiment
!= null)
247 @SuppressWarnings("unchecked")
248 public void setFocus() {
249 TmfExperiment
<ITmfEvent
> experiment
= (TmfExperiment
<ITmfEvent
>) TmfExperiment
.getCurrentExperiment();
250 if ((experiment
!= null) && (experiment
!= fCurrentExperiment
)) {
251 fCurrentExperiment
= experiment
;
252 initializeHistograms();
257 // ------------------------------------------------------------------------
259 // ------------------------------------------------------------------------
261 public TmfTimeRange
getTimeRange() {
262 return new TmfTimeRange(new TmfTimestamp(fWindowStartTime
, TIME_SCALE
), new TmfTimestamp(fWindowEndTime
,
266 // ------------------------------------------------------------------------
268 // ------------------------------------------------------------------------
270 public void updateCurrentEventTime(long newTime
) {
271 if (fCurrentExperiment
!= null) {
272 TmfTimeRange timeRange
= new TmfTimeRange(new TmfTimestamp(newTime
, TIME_SCALE
), TmfTimestamp
.BIG_CRUNCH
);
273 HistogramRequest request
= new HistogramRequest(fTimeRangeHistogram
.getDataModel(), timeRange
, 0, 1, 0, ExecutionType
.FOREGROUND
) {
275 public void handleData(ITmfEvent event
) {
277 TmfTimeSynchSignal signal
= new TmfTimeSynchSignal(this, event
.getTimestamp());
278 TmfSignalManager
.dispatchSignal(signal
);
282 fCurrentExperiment
.sendRequest(request
);
286 public void updateTimeRange(long startTime
, long endTime
) {
287 if (fCurrentExperiment
!= null) {
288 // Build the new time range; keep the current time
289 TmfTimeRange timeRange
= new TmfTimeRange(new TmfTimestamp(startTime
, TIME_SCALE
), new TmfTimestamp(
290 endTime
, TIME_SCALE
));
291 TmfTimestamp currentTime
= new TmfTimestamp(fCurrentTimestamp
, TIME_SCALE
);
293 fTimeSpanControl
.setValue(endTime
- startTime
);
295 // Send the FW signal
296 TmfRangeSynchSignal signal
= new TmfRangeSynchSignal(this, timeRange
, currentTime
);
297 TmfSignalManager
.dispatchSignal(signal
);
301 public synchronized void updateTimeRange(long newDuration
) {
302 if (fCurrentExperiment
!= null) {
303 long delta
= newDuration
- fWindowSpan
;
304 long newStartTime
= fWindowStartTime
+ delta
/ 2;
305 setNewRange(newStartTime
, newDuration
);
309 private void setNewRange(long startTime
, long duration
) {
310 if (startTime
< fExperimentStartTime
)
311 startTime
= fExperimentStartTime
;
313 long endTime
= startTime
+ duration
;
314 if (endTime
> fExperimentEndTime
) {
315 endTime
= fExperimentEndTime
;
316 if (endTime
- duration
> fExperimentStartTime
)
317 startTime
= endTime
- duration
;
319 startTime
= fExperimentStartTime
;
322 updateTimeRange(startTime
, endTime
);
325 // ------------------------------------------------------------------------
327 // ------------------------------------------------------------------------
330 @SuppressWarnings("unchecked")
331 public void experimentSelected(TmfExperimentSelectedSignal
<ITmfEvent
> signal
) {
332 assert (signal
!= null);
333 fCurrentExperiment
= (TmfExperiment
<ITmfEvent
>) signal
.getExperiment();
337 private void loadExperiment() {
338 initializeHistograms();
343 public void experimentRangeUpdated(TmfExperimentRangeUpdatedSignal signal
) {
345 if (signal
.getExperiment() != fCurrentExperiment
) {
349 boolean drawTimeRangeHistogram
= fExperimentStartTime
== 0;
350 TmfTimeRange fullRange
= signal
.getRange();
352 fExperimentStartTime
= fullRange
.getStartTime().getValue();
353 fExperimentEndTime
= fullRange
.getEndTime().getValue();
355 fFullTraceHistogram
.setFullRange(fExperimentStartTime
, fExperimentEndTime
);
356 fTimeRangeHistogram
.setFullRange(fExperimentStartTime
, fExperimentEndTime
);
358 if (drawTimeRangeHistogram
) {
359 fCurrentTimestamp
= fExperimentStartTime
;
360 fCurrentEventTimeControl
.setValue(fCurrentTimestamp
);
361 fFullTraceHistogram
.setTimeRange(fExperimentStartTime
, INITIAL_WINDOW_SPAN
);
362 fTimeRangeHistogram
.setTimeRange(fExperimentStartTime
, INITIAL_WINDOW_SPAN
);
363 sendTimeRangeRequest(fExperimentStartTime
, fExperimentStartTime
+ INITIAL_WINDOW_SPAN
);
366 sendFullRangeRequest(fullRange
);
370 public void experimentUpdated(TmfExperimentUpdatedSignal signal
) {
371 if (signal
.getExperiment() != fCurrentExperiment
) {
374 TmfTimeRange fullRange
= signal
.getExperiment().getTimeRange();
375 fExperimentStartTime
= fullRange
.getStartTime().getValue();
376 fExperimentEndTime
= fullRange
.getEndTime().getValue();
378 fFullTraceHistogram
.setFullRange(fExperimentStartTime
, fExperimentEndTime
);
379 fTimeRangeHistogram
.setFullRange(fExperimentStartTime
, fExperimentEndTime
);
383 public void currentTimeUpdated(TmfTimeSynchSignal signal
) {
384 // Because this can't happen :-)
385 assert (signal
!= null);
387 // Update the selected event time
388 ITmfTimestamp currentTime
= signal
.getCurrentTime();
389 fCurrentTimestamp
= currentTime
.getValue();
391 // Notify the relevant widgets
392 fFullTraceHistogram
.setCurrentEvent(fCurrentTimestamp
);
393 fTimeRangeHistogram
.setCurrentEvent(fCurrentTimestamp
);
394 fCurrentEventTimeControl
.setValue(fCurrentTimestamp
);
398 public void timeRangeUpdated(TmfRangeSynchSignal signal
) {
399 // Because this can't happen :-)
400 assert (signal
!= null);
402 if (fCurrentExperiment
!= null) {
403 // Update the time range
404 fWindowStartTime
= signal
.getCurrentRange().getStartTime().getValue();
405 fWindowEndTime
= signal
.getCurrentRange().getEndTime().getValue();
406 fWindowSpan
= fWindowEndTime
- fWindowStartTime
;
408 // Notify the relevant widgets
409 sendTimeRangeRequest(fWindowStartTime
, fWindowEndTime
);
410 fFullTraceHistogram
.setTimeRange(fWindowStartTime
, fWindowSpan
);
411 fTimeSpanControl
.setValue(fWindowSpan
);
415 // ------------------------------------------------------------------------
417 // ------------------------------------------------------------------------
419 private void initializeHistograms() {
420 TmfTimeRange fullRange
= updateExperimentTimeRange(fCurrentExperiment
);
422 fTimeRangeHistogram
.clear();
423 fTimeRangeHistogram
.setFullRange(fExperimentStartTime
, fExperimentEndTime
);
424 fTimeRangeHistogram
.setTimeRange(fExperimentStartTime
, INITIAL_WINDOW_SPAN
);
425 fTimeRangeHistogram
.setCurrentEvent(fExperimentStartTime
);
427 fFullTraceHistogram
.clear();
428 fFullTraceHistogram
.setFullRange(fExperimentStartTime
, fExperimentEndTime
);
429 fFullTraceHistogram
.setTimeRange(fExperimentStartTime
, INITIAL_WINDOW_SPAN
);
430 fFullTraceHistogram
.setCurrentEvent(fExperimentStartTime
);
432 fWindowStartTime
= fExperimentStartTime
;
433 fWindowSpan
= INITIAL_WINDOW_SPAN
;
434 fWindowEndTime
= fWindowStartTime
+ fWindowSpan
;
436 fCurrentEventTimeControl
.setValue(fExperimentStartTime
);
437 fTimeSpanControl
.setValue(fWindowSpan
);
439 if (!fullRange
.equals(TmfTimeRange
.NULL_RANGE
)) {
440 sendTimeRangeRequest(fExperimentStartTime
, fExperimentStartTime
+ fWindowSpan
);
441 sendFullRangeRequest(fullRange
);
445 private TmfTimeRange
updateExperimentTimeRange(TmfExperiment
<ITmfEvent
> experiment
) {
446 fExperimentStartTime
= 0;
447 fExperimentEndTime
= 0;
448 fCurrentTimestamp
= 0;
450 TmfTimeRange timeRange
= fCurrentExperiment
.getTimeRange();
451 if (!timeRange
.equals(TmfTimeRange
.NULL_RANGE
)) {
452 fExperimentStartTime
= timeRange
.getStartTime().getValue();
453 fExperimentEndTime
= timeRange
.getEndTime().getValue();
454 fCurrentTimestamp
= fExperimentStartTime
;
459 private void sendTimeRangeRequest(long startTime
, long endTime
) {
460 if (fTimeRangeRequest
!= null && !fTimeRangeRequest
.isCompleted()) {
461 fTimeRangeRequest
.cancel();
463 TmfTimestamp startTS
= new TmfTimestamp(startTime
, TIME_SCALE
);
464 TmfTimestamp endTS
= new TmfTimestamp(endTime
, TIME_SCALE
);
465 TmfTimeRange timeRange
= new TmfTimeRange(startTS
, endTS
);
467 fTimeRangeHistogram
.clear();
468 fTimeRangeHistogram
.setTimeRange(startTime
, endTime
- startTime
);
470 int cacheSize
= fCurrentExperiment
.getCacheSize();
471 fTimeRangeRequest
= new HistogramRequest(fTimeRangeHistogram
.getDataModel(), timeRange
, 0, TmfDataRequest
.ALL_DATA
, cacheSize
, ExecutionType
.FOREGROUND
);
472 fCurrentExperiment
.sendRequest(fTimeRangeRequest
);
475 private void sendFullRangeRequest(TmfTimeRange fullRange
) {
476 if (fFullTraceRequest
!= null && !fFullTraceRequest
.isCompleted()) {
477 fFullTraceRequest
.cancel();
479 int cacheSize
= fCurrentExperiment
.getCacheSize();
480 fFullTraceRequest
= new HistogramRequest(fFullTraceHistogram
.getDataModel(), fullRange
, (int) fFullTraceHistogram
.fDataModel
.getNbEvents(),
481 TmfDataRequest
.ALL_DATA
, cacheSize
, ExecutionType
.BACKGROUND
);
482 fCurrentExperiment
.sendRequest(fFullTraceRequest
);