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 * <b><u>HistogramView</u></b>
43 * The purpose of this view is to provide graphical time distribution statistics about the experiment/trace events.
45 * The view is composed of two histograms and two controls:
47 * <li>an event distribution histogram for the whole experiment;
48 * <li>an event distribution histogram for current time window (window span);
49 * <li>the timestamp of the currently selected event;
50 * <li>the window span (size of the time window of the smaller histogram).
52 * The histograms x-axis show their respective time range.
54 public class HistogramView
extends TmfView
{
56 // ------------------------------------------------------------------------
58 // ------------------------------------------------------------------------
60 // The view ID as defined in plugin.xml
61 public static final String ID
= "org.eclipse.linuxtools.tmf.ui.views.histogram"; //$NON-NLS-1$
63 // The initial window span (in nanoseconds)
64 public static final long INITIAL_WINDOW_SPAN
= (1L * 100 * 1000 * 1000); // .1sec
67 private final byte TIME_SCALE
= Histogram
.TIME_SCALE
;
69 // ------------------------------------------------------------------------
71 // ------------------------------------------------------------------------
74 private Composite fParent
;
76 // The current experiment
77 private TmfExperiment
<ITmfEvent
> fCurrentExperiment
;
79 // Current timestamp/time window
80 private long fExperimentStartTime
;
81 private long fExperimentEndTime
;
82 private long fWindowStartTime
;
83 private long fWindowEndTime
;
84 private long fWindowSpan
= INITIAL_WINDOW_SPAN
;
85 private long fCurrentTimestamp
;
88 private HistogramTextControl fCurrentEventTimeControl
;
89 private HistogramTextControl fTimeSpanControl
;
91 // Histogram/request for the full trace range
92 private static FullTraceHistogram fFullTraceHistogram
;
93 private HistogramRequest fFullTraceRequest
;
95 // Histogram/request for the selected time range
96 private static TimeRangeHistogram fTimeRangeHistogram
;
97 private HistogramRequest fTimeRangeRequest
;
99 // ------------------------------------------------------------------------
101 // ------------------------------------------------------------------------
103 public HistogramView() {
108 public void dispose() {
109 if (fTimeRangeRequest
!= null && !fTimeRangeRequest
.isCompleted()) {
110 fTimeRangeRequest
.cancel();
112 if (fFullTraceRequest
!= null && !fFullTraceRequest
.isCompleted()) {
113 fFullTraceRequest
.cancel();
115 fFullTraceHistogram
.dispose();
116 fTimeRangeHistogram
.dispose();
120 // ------------------------------------------------------------------------
122 // ------------------------------------------------------------------------
125 @SuppressWarnings("unchecked")
126 public void createPartControl(Composite parent
) {
131 final String currentEventLabel
= Messages
.HistogramView_currentEventLabel
;
132 final String windowSpanLabel
= Messages
.HistogramView_windowSpanLabel
;
134 // --------------------------------------------------------------------
135 // Set the HistogramView layout
136 // --------------------------------------------------------------------
138 Composite viewComposite
= new Composite(fParent
, SWT
.FILL
);
139 GridLayout gridLayout
= new GridLayout();
140 gridLayout
.numColumns
= 2;
141 gridLayout
.horizontalSpacing
= 5;
142 gridLayout
.verticalSpacing
= 0;
143 gridLayout
.marginHeight
= 0;
144 gridLayout
.marginWidth
= 0;
145 viewComposite
.setLayout(gridLayout
);
147 // Use all available space
148 GridData gridData
= new GridData();
149 gridData
.horizontalAlignment
= SWT
.FILL
;
150 gridData
.verticalAlignment
= SWT
.FILL
;
151 gridData
.grabExcessHorizontalSpace
= true;
152 viewComposite
.setLayoutData(gridData
);
154 // --------------------------------------------------------------------
156 // --------------------------------------------------------------------
158 Composite controlsComposite
= new Composite(viewComposite
, SWT
.FILL
);
159 gridLayout
= new GridLayout();
160 gridLayout
.numColumns
= 2;
161 gridLayout
.marginHeight
= 0;
162 gridLayout
.marginWidth
= 0;
163 gridLayout
.horizontalSpacing
= 5;
164 gridLayout
.verticalSpacing
= 0;
165 gridLayout
.makeColumnsEqualWidth
= true;
166 gridLayout
.marginLeft
= 5;
167 gridLayout
.marginRight
= 5;
168 controlsComposite
.setLayout(gridLayout
);
170 // Current event time control
171 gridData
= new GridData();
172 gridData
.horizontalAlignment
= SWT
.CENTER
;
173 gridData
.verticalAlignment
= SWT
.CENTER
;
174 fCurrentEventTimeControl
= new HistogramCurrentTimeControl(this, controlsComposite
, SWT
.BORDER
, SWT
.NONE
,
175 currentEventLabel
, HistogramUtils
.nanosecondsToString(0L));
176 fCurrentEventTimeControl
.setLayoutData(gridData
);
178 // Window span time control
179 gridData
= new GridData();
180 gridData
.horizontalAlignment
= SWT
.CENTER
;
181 gridData
.verticalAlignment
= SWT
.CENTER
;
182 fTimeSpanControl
= new HistogramTimeRangeControl(this, controlsComposite
, SWT
.BORDER
, SWT
.NONE
,
183 windowSpanLabel
, HistogramUtils
.nanosecondsToString(0L));
184 fTimeSpanControl
.setLayoutData(gridData
);
186 // --------------------------------------------------------------------
187 // Time range histogram
188 // --------------------------------------------------------------------
190 Composite timeRangeComposite
= new Composite(viewComposite
, SWT
.FILL
);
191 gridLayout
= new GridLayout();
192 gridLayout
.numColumns
= 1;
193 gridLayout
.marginHeight
= 0;
194 gridLayout
.marginWidth
= 0;
195 gridLayout
.marginTop
= 5;
196 gridLayout
.horizontalSpacing
= 0;
197 gridLayout
.verticalSpacing
= 0;
198 gridLayout
.marginLeft
= 5;
199 gridLayout
.marginRight
= 5;
200 timeRangeComposite
.setLayout(gridLayout
);
202 // Use remaining horizontal space
203 gridData
= new GridData();
204 gridData
.horizontalAlignment
= SWT
.FILL
;
205 gridData
.verticalAlignment
= SWT
.FILL
;
206 gridData
.grabExcessHorizontalSpace
= true;
207 timeRangeComposite
.setLayoutData(gridData
);
210 fTimeRangeHistogram
= new TimeRangeHistogram(this, timeRangeComposite
);
212 // --------------------------------------------------------------------
213 // Full range histogram
214 // --------------------------------------------------------------------
216 Composite fullRangeComposite
= new Composite(viewComposite
, SWT
.FILL
);
217 gridLayout
= new GridLayout();
218 gridLayout
.numColumns
= 1;
219 gridLayout
.marginHeight
= 0;
220 gridLayout
.marginWidth
= 0;
221 gridLayout
.marginTop
= 5;
222 gridLayout
.horizontalSpacing
= 0;
223 gridLayout
.verticalSpacing
= 0;
224 gridLayout
.marginLeft
= 5;
225 gridLayout
.marginRight
= 5;
226 fullRangeComposite
.setLayout(gridLayout
);
228 // Use remaining horizontal space
229 gridData
= new GridData();
230 gridData
.horizontalAlignment
= SWT
.FILL
;
231 gridData
.verticalAlignment
= SWT
.FILL
;
232 gridData
.horizontalSpan
= 2;
233 gridData
.grabExcessHorizontalSpace
= true;
234 fullRangeComposite
.setLayoutData(gridData
);
237 fFullTraceHistogram
= new FullTraceHistogram(this, fullRangeComposite
);
239 // Load the experiment if present
240 fCurrentExperiment
= (TmfExperiment
<ITmfEvent
>) TmfExperiment
.getCurrentExperiment();
241 if (fCurrentExperiment
!= null)
246 @SuppressWarnings("unchecked")
247 public void setFocus() {
248 TmfExperiment
<ITmfEvent
> experiment
= (TmfExperiment
<ITmfEvent
>) TmfExperiment
.getCurrentExperiment();
249 if ((experiment
!= null) && (experiment
!= fCurrentExperiment
)) {
250 fCurrentExperiment
= experiment
;
251 initializeHistograms();
256 // ------------------------------------------------------------------------
258 // ------------------------------------------------------------------------
260 public TmfTimeRange
getTimeRange() {
261 return new TmfTimeRange(new TmfTimestamp(fWindowStartTime
, TIME_SCALE
), new TmfTimestamp(fWindowEndTime
,
265 // ------------------------------------------------------------------------
267 // ------------------------------------------------------------------------
269 public void updateCurrentEventTime(long newTime
) {
270 if (fCurrentExperiment
!= null) {
271 TmfTimeRange timeRange
= new TmfTimeRange(new TmfTimestamp(newTime
, TIME_SCALE
), TmfTimestamp
.BIG_CRUNCH
);
272 HistogramRequest request
= new HistogramRequest(fTimeRangeHistogram
.getDataModel(), timeRange
, 0, 1, 0, ExecutionType
.FOREGROUND
) {
274 public void handleData(ITmfEvent event
) {
276 TmfTimeSynchSignal signal
= new TmfTimeSynchSignal(this, event
.getTimestamp());
277 TmfSignalManager
.dispatchSignal(signal
);
281 fCurrentExperiment
.sendRequest(request
);
285 public void updateTimeRange(long startTime
, long endTime
) {
286 if (fCurrentExperiment
!= null) {
287 // Build the new time range; keep the current time
288 TmfTimeRange timeRange
= new TmfTimeRange(new TmfTimestamp(startTime
, TIME_SCALE
), new TmfTimestamp(
289 endTime
, TIME_SCALE
));
290 TmfTimestamp currentTime
= new TmfTimestamp(fCurrentTimestamp
, TIME_SCALE
);
292 fTimeSpanControl
.setValue(endTime
- startTime
);
294 // Send the FW signal
295 TmfRangeSynchSignal signal
= new TmfRangeSynchSignal(this, timeRange
, currentTime
);
296 TmfSignalManager
.dispatchSignal(signal
);
300 public synchronized void updateTimeRange(long newDuration
) {
301 if (fCurrentExperiment
!= null) {
302 long delta
= newDuration
- fWindowSpan
;
303 long newStartTime
= fWindowStartTime
+ delta
/ 2;
304 setNewRange(newStartTime
, newDuration
);
308 private void setNewRange(long startTime
, long duration
) {
309 if (startTime
< fExperimentStartTime
)
310 startTime
= fExperimentStartTime
;
312 long endTime
= startTime
+ duration
;
313 if (endTime
> fExperimentEndTime
) {
314 endTime
= fExperimentEndTime
;
315 if (endTime
- duration
> fExperimentStartTime
)
316 startTime
= endTime
- duration
;
318 startTime
= fExperimentStartTime
;
321 updateTimeRange(startTime
, endTime
);
324 // ------------------------------------------------------------------------
326 // ------------------------------------------------------------------------
329 @SuppressWarnings("unchecked")
330 public void experimentSelected(TmfExperimentSelectedSignal
<ITmfEvent
> signal
) {
331 assert (signal
!= null);
332 fCurrentExperiment
= (TmfExperiment
<ITmfEvent
>) signal
.getExperiment();
336 private void loadExperiment() {
337 initializeHistograms();
342 public void experimentRangeUpdated(TmfExperimentRangeUpdatedSignal signal
) {
344 if (signal
.getExperiment() != fCurrentExperiment
) {
348 boolean drawTimeRangeHistogram
= fExperimentStartTime
== 0;
349 TmfTimeRange fullRange
= signal
.getRange();
351 fExperimentStartTime
= fullRange
.getStartTime().getValue();
352 fExperimentEndTime
= fullRange
.getEndTime().getValue();
354 fFullTraceHistogram
.setFullRange(fExperimentStartTime
, fExperimentEndTime
);
355 fTimeRangeHistogram
.setFullRange(fExperimentStartTime
, fExperimentEndTime
);
357 if (drawTimeRangeHistogram
) {
358 fCurrentTimestamp
= fExperimentStartTime
;
359 fCurrentEventTimeControl
.setValue(fCurrentTimestamp
);
360 fFullTraceHistogram
.setTimeRange(fExperimentStartTime
, INITIAL_WINDOW_SPAN
);
361 fTimeRangeHistogram
.setTimeRange(fExperimentStartTime
, INITIAL_WINDOW_SPAN
);
362 sendTimeRangeRequest(fExperimentStartTime
, fExperimentStartTime
+ INITIAL_WINDOW_SPAN
);
365 sendFullRangeRequest(fullRange
);
369 public void experimentUpdated(TmfExperimentUpdatedSignal signal
) {
370 if (signal
.getExperiment() != fCurrentExperiment
) {
373 TmfTimeRange fullRange
= signal
.getExperiment().getTimeRange();
374 fExperimentStartTime
= fullRange
.getStartTime().getValue();
375 fExperimentEndTime
= fullRange
.getEndTime().getValue();
377 fFullTraceHistogram
.setFullRange(fExperimentStartTime
, fExperimentEndTime
);
378 fTimeRangeHistogram
.setFullRange(fExperimentStartTime
, fExperimentEndTime
);
382 public void currentTimeUpdated(TmfTimeSynchSignal signal
) {
383 // Because this can't happen :-)
384 assert (signal
!= null);
386 // Update the selected event time
387 ITmfTimestamp currentTime
= signal
.getCurrentTime();
388 fCurrentTimestamp
= currentTime
.getValue();
390 // Notify the relevant widgets
391 fFullTraceHistogram
.setCurrentEvent(fCurrentTimestamp
);
392 fTimeRangeHistogram
.setCurrentEvent(fCurrentTimestamp
);
393 fCurrentEventTimeControl
.setValue(fCurrentTimestamp
);
397 public void timeRangeUpdated(TmfRangeSynchSignal signal
) {
398 // Because this can't happen :-)
399 assert (signal
!= null);
401 if (fCurrentExperiment
!= null) {
402 // Update the time range
403 fWindowStartTime
= signal
.getCurrentRange().getStartTime().getValue();
404 fWindowEndTime
= signal
.getCurrentRange().getEndTime().getValue();
405 fWindowSpan
= fWindowEndTime
- fWindowStartTime
;
407 // Notify the relevant widgets
408 sendTimeRangeRequest(fWindowStartTime
, fWindowEndTime
);
409 fFullTraceHistogram
.setTimeRange(fWindowStartTime
, fWindowSpan
);
410 fTimeSpanControl
.setValue(fWindowSpan
);
414 // ------------------------------------------------------------------------
416 // ------------------------------------------------------------------------
418 private void initializeHistograms() {
419 TmfTimeRange fullRange
= updateExperimentTimeRange(fCurrentExperiment
);
421 fTimeRangeHistogram
.clear();
422 fTimeRangeHistogram
.setFullRange(fExperimentStartTime
, fExperimentEndTime
);
423 fTimeRangeHistogram
.setTimeRange(fExperimentStartTime
, INITIAL_WINDOW_SPAN
);
424 fTimeRangeHistogram
.setCurrentEvent(fExperimentStartTime
);
426 fFullTraceHistogram
.clear();
427 fFullTraceHistogram
.setFullRange(fExperimentStartTime
, fExperimentEndTime
);
428 fFullTraceHistogram
.setTimeRange(fExperimentStartTime
, INITIAL_WINDOW_SPAN
);
429 fFullTraceHistogram
.setCurrentEvent(fExperimentStartTime
);
431 fWindowStartTime
= fExperimentStartTime
;
432 fWindowSpan
= INITIAL_WINDOW_SPAN
;
433 fWindowEndTime
= fWindowStartTime
+ fWindowSpan
;
435 fCurrentEventTimeControl
.setValue(fExperimentStartTime
);
436 fTimeSpanControl
.setValue(fWindowSpan
);
438 sendTimeRangeRequest(fExperimentStartTime
, fExperimentStartTime
+ fWindowSpan
);
439 sendFullRangeRequest(fullRange
);
442 private TmfTimeRange
updateExperimentTimeRange(TmfExperiment
<ITmfEvent
> experiment
) {
443 fExperimentStartTime
= 0;
444 fExperimentEndTime
= 0;
445 fCurrentTimestamp
= 0;
447 TmfTimeRange timeRange
= fCurrentExperiment
.getTimeRange();
448 if (!timeRange
.equals(TmfTimeRange
.NULL_RANGE
)) {
449 fExperimentStartTime
= timeRange
.getStartTime().getValue();
450 fExperimentEndTime
= timeRange
.getEndTime().getValue();
451 fCurrentTimestamp
= fExperimentStartTime
;
456 private void sendTimeRangeRequest(long startTime
, long endTime
) {
457 if (fTimeRangeRequest
!= null && !fTimeRangeRequest
.isCompleted()) {
458 fTimeRangeRequest
.cancel();
460 TmfTimestamp startTS
= new TmfTimestamp(startTime
, TIME_SCALE
);
461 TmfTimestamp endTS
= new TmfTimestamp(endTime
, TIME_SCALE
);
462 TmfTimeRange timeRange
= new TmfTimeRange(startTS
, endTS
);
464 fTimeRangeHistogram
.clear();
465 fTimeRangeHistogram
.setTimeRange(startTime
, endTime
- startTime
);
467 int cacheSize
= fCurrentExperiment
.getCacheSize();
468 fTimeRangeRequest
= new HistogramRequest(fTimeRangeHistogram
.getDataModel(), timeRange
, 0, TmfDataRequest
.ALL_DATA
, cacheSize
, ExecutionType
.FOREGROUND
);
469 fCurrentExperiment
.sendRequest(fTimeRangeRequest
);
472 private void sendFullRangeRequest(TmfTimeRange fullRange
) {
473 if (fFullTraceRequest
!= null && !fFullTraceRequest
.isCompleted()) {
474 fFullTraceRequest
.cancel();
476 if (fullRange
.equals(TmfTimeRange
.NULL_RANGE
)) {
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
);