analysis : Rename getResults() to getSegmentStore()
[deliverable/tracecompass.git] / analysis / org.eclipse.tracecompass.analysis.timing.ui / src / org / eclipse / tracecompass / analysis / timing / ui / views / segmentstore / scatter / AbstractSegmentStoreScatterGraphViewer.java
CommitLineData
03c96217 1/******************************************************************************
edded5c1 2 * Copyright (c) 2015, 2016 Ericsson
03c96217
BH
3 *
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
8 *
9 * Contributors:
10 * France Lapointe Nguyen - Initial API and implementation
11 * Bernd Hufmann - Extracted abstract class from LatencyScatterGraphViewer
12 *******************************************************************************/
13
edded5c1 14package org.eclipse.tracecompass.analysis.timing.ui.views.segmentstore.scatter;
03c96217 15
21c917fe 16import java.text.Format;
03c96217
BH
17import java.util.ArrayList;
18import java.util.Collection;
19import java.util.Collections;
20import java.util.Iterator;
21import java.util.List;
22
23import org.eclipse.core.runtime.IProgressMonitor;
24import org.eclipse.core.runtime.IStatus;
25import org.eclipse.core.runtime.Status;
26import org.eclipse.core.runtime.jobs.Job;
27import org.eclipse.jdt.annotation.Nullable;
28import org.eclipse.swt.graphics.Point;
29import org.eclipse.swt.widgets.Composite;
30import org.eclipse.swt.widgets.Display;
31import org.eclipse.tracecompass.analysis.timing.core.segmentstore.AbstractSegmentStoreAnalysisModule;
32import org.eclipse.tracecompass.analysis.timing.core.segmentstore.IAnalysisProgressListener;
21c917fe 33import org.eclipse.tracecompass.analysis.timing.ui.views.segmentstore.SubSecondTimeWithUnitFormat;
03c96217
BH
34import org.eclipse.tracecompass.common.core.NonNullUtils;
35import org.eclipse.tracecompass.internal.analysis.timing.ui.Activator;
edded5c1 36import org.eclipse.tracecompass.internal.analysis.timing.ui.views.segmentstore.scatter.Messages;
21c917fe 37import org.eclipse.tracecompass.internal.analysis.timing.ui.views.segmentstore.scatter.SegmentStoreScatterGraphTooltipProvider;
03c96217
BH
38import org.eclipse.tracecompass.segmentstore.core.ISegment;
39import org.eclipse.tracecompass.segmentstore.core.ISegmentStore;
40import org.eclipse.tracecompass.segmentstore.core.SegmentComparators;
41import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler;
42import org.eclipse.tracecompass.tmf.core.signal.TmfSignalManager;
43import org.eclipse.tracecompass.tmf.core.signal.TmfTraceClosedSignal;
44import org.eclipse.tracecompass.tmf.core.signal.TmfTraceOpenedSignal;
45import org.eclipse.tracecompass.tmf.core.signal.TmfTraceSelectedSignal;
46import org.eclipse.tracecompass.tmf.core.signal.TmfWindowRangeUpdatedSignal;
03c96217
BH
47import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimeRange;
48import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
49import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager;
50import org.eclipse.tracecompass.tmf.ui.signal.TmfTimeViewAlignmentInfo;
51import org.eclipse.tracecompass.tmf.ui.signal.TmfTimeViewAlignmentSignal;
52import org.eclipse.tracecompass.tmf.ui.viewers.xycharts.TmfChartTimeStampFormat;
53import org.eclipse.tracecompass.tmf.ui.viewers.xycharts.linecharts.TmfCommonXLineChartViewer;
54import org.swtchart.Chart;
55import org.swtchart.IAxis;
56import org.swtchart.IAxisTick;
57import org.swtchart.ILineSeries;
58import org.swtchart.ILineSeries.PlotSymbolType;
59import org.swtchart.ISeries.SeriesType;
60import org.swtchart.ISeriesSet;
61import org.swtchart.LineStyle;
62import org.swtchart.Range;
63
64/**
65 * Displays the segment store analysis data in a scatter graph
66 *
67 * @author France Lapointe Nguyen
68 * @author Matthew Khouzam - reduced memory usage
69 * @since 2.0
70 */
71public abstract class AbstractSegmentStoreScatterGraphViewer extends TmfCommonXLineChartViewer {
03c96217 72
21c917fe
MK
73 private static final Format FORMAT = new SubSecondTimeWithUnitFormat();
74
03c96217
BH
75 private final class CompactingSegmentStoreQuery extends Job {
76 private static final long MAX_POINTS = 1000;
77 private final TmfTimeRange fCurrentRange;
78
79 private CompactingSegmentStoreQuery(TmfTimeRange currentRange) {
80 super(Messages.SegmentStoreScatterGraphViewer_compactTitle);
81 fCurrentRange = currentRange;
82 }
83
84 @Override
85 protected IStatus run(@Nullable IProgressMonitor monitor) {
86 final IProgressMonitor statusMonitor = monitor;
87 if (statusMonitor == null) {
88 return new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Monitor is null"); //$NON-NLS-1$
89 }
90
91 AbstractSegmentStoreAnalysisModule module = getAnalysisModule();
16801c72
MK
92 final long startTimeInNanos = fCurrentRange.getStartTime().toNanos();
93 final long endTimeInNanos = fCurrentRange.getEndTime().toNanos();
03c96217
BH
94 if (module == null) {
95 setWindowRange(startTimeInNanos, endTimeInNanos);
df2597e0 96 redraw(statusMonitor, startTimeInNanos, startTimeInNanos, Collections.EMPTY_LIST);
03c96217
BH
97 return new Status(IStatus.WARNING, Activator.PLUGIN_ID, "Analysis module not available"); //$NON-NLS-1$
98 }
99
73c74de7
JCK
100 final ISegmentStore<ISegment> segStore = module.getSegmentStore();
101 if (segStore == null) {
03c96217 102 setWindowRange(startTimeInNanos, endTimeInNanos);
df2597e0 103 redraw(statusMonitor, startTimeInNanos, startTimeInNanos, Collections.EMPTY_LIST);
03c96217
BH
104 return new Status(IStatus.INFO, Activator.PLUGIN_ID, "Analysis module does not have results"); //$NON-NLS-1$
105 }
106
107 final long startTime = fCurrentRange.getStartTime().getValue();
108 final long endTime = fCurrentRange.getEndTime().getValue();
109 fPixelStart = startTime;
110 fPixelSize = (endTime - startTime) / MAX_POINTS;
73c74de7 111 final Iterable<ISegment> intersectingElements = segStore.getIntersectingElements(startTime, endTime);
03c96217
BH
112
113 final List<ISegment> list = convertIterableToList(intersectingElements, statusMonitor);
114 final List<ISegment> displayData = (!list.isEmpty()) ? compactList(startTime, list, statusMonitor) : list;
115
116 setWindowRange(startTimeInNanos, endTimeInNanos);
117 redraw(statusMonitor, startTime, endTime, displayData);
118
119 if (statusMonitor.isCanceled()) {
120 return NonNullUtils.checkNotNull(Status.CANCEL_STATUS);
121 }
122 return NonNullUtils.checkNotNull(Status.OK_STATUS);
123
124 }
125
126 private void redraw(final IProgressMonitor statusMonitor, final long startTime, final long endTime, final List<ISegment> displayData) {
127 fDisplayData = displayData;
128 Display.getDefault().asyncExec(new Runnable() {
129
130 @Override
131 public void run() {
132 updateData(startTime, endTime, displayData.size(), statusMonitor);
133 }
134 });
135 }
136
137 private List<ISegment> compactList(final long startTime, final List<ISegment> listToCompact, final IProgressMonitor statusMonitor) {
138 List<ISegment> displayData = new ArrayList<>();
139 ISegment last = listToCompact.get(0);
140 if (last.getStart() >= startTime) {
141 displayData.add(last);
142 }
143 for (ISegment next : listToCompact) {
144 if (next.getStart() < startTime) {
145 continue;
146 }
147 if (statusMonitor.isCanceled()) {
df2597e0 148 return Collections.EMPTY_LIST;
03c96217
BH
149 }
150 if (!overlaps(last, next)) {
151 displayData.add(next);
152 last = next;
153 }
154 }
155 return displayData;
156 }
157
158 private List<ISegment> convertIterableToList(final Iterable<ISegment> iterable, final IProgressMonitor statusMonitor) {
159 final List<ISegment> list = new ArrayList<>();
160 for (ISegment seg : iterable) {
161 if (statusMonitor.isCanceled()) {
df2597e0 162 return Collections.EMPTY_LIST;
03c96217
BH
163 }
164 list.add(seg);
165 }
166 Collections.sort(list, SegmentComparators.INTERVAL_START_COMPARATOR);
167 return list;
168 }
169
170 private boolean overlaps(ISegment last, ISegment next) {
171 long timePerPix = fPixelSize;
172 final long start = last.getStart();
173 final long pixelStart = fPixelStart;
174 final long pixelDuration = start - pixelStart;
175 long startPixBoundL = pixelDuration / timePerPix * timePerPix + pixelStart;
176 long startPixBoundR = startPixBoundL + timePerPix;
177 final long currentStart = next.getStart();
178 if (currentStart >= startPixBoundL && currentStart <= startPixBoundR) {
179 long length = last.getLength();
180 long lengthNext = next.getLength();
181 long lengthLow = length / timePerPix * timePerPix;
182 long lengthHigh = lengthLow + timePerPix;
183 return (lengthNext >= lengthLow && lengthNext <= lengthHigh);
184 }
185 return false;
186 }
187 }
188
189 // ------------------------------------------------------------------------
190 // Attributes
191 // ------------------------------------------------------------------------
192
193 /**
194 * Listener to update the model with the semgent store analysis results
195 * once the analysis is fully completed
196 */
197 private final class AnalysisProgressListener implements IAnalysisProgressListener {
198
199 @Override
200 public void onComplete(AbstractSegmentStoreAnalysisModule activeAnalysis, ISegmentStore<ISegment> results) {
201 // Only update the model if trace that was analyzed is active trace
202 if (activeAnalysis.equals(getAnalysisModule())) {
203 updateModel(results);
204 updateRange(TmfTraceManager.getInstance().getCurrentTraceContext().getWindowRange());
205 }
206 }
207 }
208
209 private long fPixelSize = -1;
210
211 private long fPixelStart = 0;
212 /**
213 * Data to display
214 */
df2597e0 215 private Collection<ISegment> fDisplayData = Collections.EMPTY_LIST;
03c96217
BH
216
217 /**
218 * Analysis completion listener
219 */
220 private AnalysisProgressListener fListener;
221
222 /**
223 * Current analysis module
224 */
225 private @Nullable AbstractSegmentStoreAnalysisModule fAnalysisModule;
226
227 private @Nullable Job fCompactingJob;
228
229 // ------------------------------------------------------------------------
230 // Constructor
231 // ------------------------------------------------------------------------
232
233 /**
234 * Constructor
235 *
236 * @param parent
237 * parent composite
238 * @param title
239 * name of the graph
240 * @param xLabel
241 * name of the x axis
242 * @param yLabel
243 * name of the y axis
244 */
245 public AbstractSegmentStoreScatterGraphViewer(Composite parent, String title, String xLabel, String yLabel) {
246 super(parent, title, xLabel, yLabel);
a2de198a 247 setTooltipProvider(new SegmentStoreScatterGraphTooltipProvider(this));
03c96217
BH
248 fListener = new AnalysisProgressListener();
249 ITmfTrace trace = TmfTraceManager.getInstance().getActiveTrace();
250 initializeModule(trace);
251 getSwtChart().getLegend().setVisible(false);
21c917fe 252 getSwtChart().getAxisSet().getYAxis(0).getTick().setFormat(FORMAT);
03c96217
BH
253 }
254
255 private final void initializeModule(@Nullable ITmfTrace trace) {
256 if (trace != null) {
257 final AbstractSegmentStoreAnalysisModule analysisModuleOfClass = getSegmentStoreAnalysisModule(trace);
258 if (analysisModuleOfClass != null) {
259 analysisModuleOfClass.addListener(fListener);
260 setData(analysisModuleOfClass);
261 updateRange(TmfTraceManager.getInstance().getCurrentTraceContext().getWindowRange());
262 }
263 }
264 }
265
266 // ------------------------------------------------------------------------
267 // Operations
268 // ------------------------------------------------------------------------
269
270 /**
271 * Update the data in the graph
272 *
273 * @param dataInput
274 * new model
275 */
276 public void updateModel(@Nullable ISegmentStore<ISegment> dataInput) {
277 // Update new window range
278 TmfTimeRange currentRange = TmfTraceManager.getInstance().getCurrentTraceContext().getWindowRange();
16801c72
MK
279 long currentStart = currentRange.getStartTime().toNanos();
280 long currentEnd = currentRange.getEndTime().toNanos();
03c96217
BH
281 if (dataInput == null) {
282 if (!getDisplay().isDisposed()) {
283 Display.getDefault().syncExec(new Runnable() {
284 @Override
285 public void run() {
286 clearContent();
287 }
288 });
289 }
df2597e0 290 fDisplayData = Collections.EMPTY_LIST;
03c96217
BH
291 } else {
292 Collection<ISegment> elements = (Collection<ISegment>) dataInput.getIntersectingElements(currentStart, currentEnd);
293 // getIntersectingElements can return an unsorted iterable, make
294 // sure our collection is sorted
295 ArrayList<ISegment> list = new ArrayList<>(elements);
296 Collections.sort(list, SegmentComparators.INTERVAL_START_COMPARATOR);
297 fDisplayData = list;
298 }
299 setWindowRange(currentStart, currentEnd);
300 updateRange(currentRange);
301 }
302
303 @Override
304 protected void initializeDataSource() {
305 ITmfTrace trace = getTrace();
306 initializeModule(trace);
307 if (trace != null) {
308 setData(getSegmentStoreAnalysisModule(trace));
309 }
310 }
311
312 @Override
313 protected void updateData(final long start, final long end, int nb, @Nullable IProgressMonitor monitor) {
314 // Third parameter is not used by implementation
315 // Determine data that needs to be visible
316 Collection<ISegment> data = fDisplayData;
317
318 final int dataSize = (nb == 0) ? data.size() : nb;
319 if (dataSize == 0 || end == start) {
320 return;
321 }
322
323 final double[] xSeries = new double[dataSize];
324 final double[] ySeries = new double[dataSize];
325 // For each visible segments, add start time to x value and duration
326 // for y value
327 Iterator<ISegment> modelIter = data.iterator();
328 long maxTempY = 1;
329 for (int i = 0; i < dataSize; i++) {
330 if (modelIter.hasNext()) {
331 ISegment segment = modelIter.next();
332 xSeries[i] = segment.getStart() - start;
333 ySeries[i] = segment.getLength();
334 maxTempY = Math.max(maxTempY, segment.getLength());
335 }
336 }
337 final long maxY = maxTempY;
338 setXAxis(xSeries);
339 final Chart swtChart = getSwtChart();
340 if (swtChart.isDisposed() || xSeries.length < 1) {
341 return;
342 }
343 swtChart.updateLayout();
344 setSeries(Messages.SegmentStoreScatterGraphViewer_legend, ySeries); // $NON-NLS-1$
345 final TmfChartTimeStampFormat tmfChartTimeStampFormat = new TmfChartTimeStampFormat(getTimeOffset());
346 ILineSeries series = (ILineSeries) swtChart.getSeriesSet().getSeries(Messages.SegmentStoreScatterGraphViewer_legend);
347 if (series == null) {
348 series = addSeries(Messages.SegmentStoreScatterGraphViewer_legend);
349 }
350 series.setXSeries(xSeries);
351 /* Find the minimal and maximum values in this series */
352 series.setYSeries(ySeries);
353
354 final IAxis xAxis = swtChart.getAxisSet().getXAxis(0);
355 IAxisTick xTick = xAxis.getTick();
356 xTick.setFormat(tmfChartTimeStampFormat);
357 xAxis.setRange(new Range(0.0, end - start));
358 if (maxY > 0.0) {
359 swtChart.getAxisSet().getYAxis(0).setRange(new Range(0.0, maxY));
360 }
361 swtChart.redraw();
362
363 if (isSendTimeAlignSignals()) {
364 // The width of the chart might have changed and its
365 // time axis might be misaligned with the other views
366 Point viewPos = AbstractSegmentStoreScatterGraphViewer.this.getParent().getParent().toDisplay(0, 0);
367 int axisPos = swtChart.toDisplay(0, 0).x + getPointAreaOffset();
368 int timeAxisOffset = axisPos - viewPos.x;
369 TmfTimeViewAlignmentInfo timeAlignmentInfo = new TmfTimeViewAlignmentInfo(getControl().getShell(), viewPos, timeAxisOffset);
370 TmfSignalManager.dispatchSignal(new TmfTimeViewAlignmentSignal(AbstractSegmentStoreScatterGraphViewer.this, timeAlignmentInfo, true));
371 }
372 }
373
374 @Override
375 protected void setWindowRange(final long windowStartTime, final long windowEndTime) {
376 super.setWindowRange(windowStartTime, windowEndTime);
377 }
378
379 @Override
380 protected ILineSeries addSeries(@Nullable String seriesName) {
381 ISeriesSet seriesSet = getSwtChart().getSeriesSet();
382 ILineSeries series = (ILineSeries) seriesSet.createSeries(SeriesType.LINE, seriesName);
383 series.setVisible(true);
384 series.enableArea(false);
385 series.setLineStyle(LineStyle.NONE);
386 series.setSymbolType(PlotSymbolType.DIAMOND);
387 return series;
388 }
389
390 /**
391 * Set the data into the viewer. Will update model is analysis is completed
392 * or run analysis if not completed
393 *
394 * @param analysis
395 * Segment store analysis module
396 */
397 public void setData(@Nullable AbstractSegmentStoreAnalysisModule analysis) {
398 if (analysis == null) {
399 updateModel(null);
400 return;
401 }
73c74de7 402 ISegmentStore<ISegment> segStore = analysis.getSegmentStore();
03c96217
BH
403 // If results are not null, then analysis is completed and model can be
404 // updated
73c74de7
JCK
405 if (segStore != null) {
406 updateModel(segStore);
03c96217
BH
407 setAnalysisModule(analysis);
408 return;
409 }
410 updateModel(null);
411 analysis.addListener(fListener);
412 analysis.schedule();
413 setAnalysisModule(analysis);
414 }
415
416 /**
417 * Returns the segment store analysis module
df2597e0 418 *
03c96217
BH
419 * @param trace
420 * The trace to consider
421 * @return the analysis module
422 */
423 protected @Nullable abstract AbstractSegmentStoreAnalysisModule getSegmentStoreAnalysisModule(ITmfTrace trace);
424
03c96217
BH
425 // ------------------------------------------------------------------------
426 // Signal handlers
427 // ------------------------------------------------------------------------
428
429 /**
430 * @param signal
431 * Signal received when a different trace is selected
432 */
433 @Override
434 @TmfSignalHandler
435 public void traceSelected(@Nullable TmfTraceSelectedSignal signal) {
436 super.traceSelected(signal);
437 if (signal == null) {
438 return;
439 }
440 ITmfTrace trace = signal.getTrace();
441 setTrace(trace);
442 if (trace != null) {
443 final TmfTimeRange timeRange = TmfTraceManager.getInstance().getCurrentTraceContext().getWindowRange();
444 setWindowRange(
16801c72
MK
445 timeRange.getStartTime().toNanos(),
446 timeRange.getEndTime().toNanos());
03c96217
BH
447 setData(getSegmentStoreAnalysisModule(trace));
448 updateRange(timeRange);
449 }
450 }
451
452 /**
453 * @param signal
454 * Signal received when trace is opened
455 */
456 @Override
457 @TmfSignalHandler
458 public void traceOpened(@Nullable TmfTraceOpenedSignal signal) {
459 super.traceOpened(signal);
460 if (signal == null) {
461 return;
462 }
463 ITmfTrace trace = signal.getTrace();
464 setTrace(trace);
465 if (trace != null) {
466
467 final AbstractSegmentStoreAnalysisModule analysisModuleOfClass = getSegmentStoreAnalysisModule(trace);
468 final TmfTimeRange timeRange = TmfTraceManager.getInstance().getCurrentTraceContext().getWindowRange();
469 setWindowRange(
16801c72
MK
470 timeRange.getStartTime().toNanos(),
471 timeRange.getEndTime().toNanos());
03c96217
BH
472 setData(analysisModuleOfClass);
473 }
474
475 }
476
477 private void updateRange(final @Nullable TmfTimeRange timeRange) {
478 Job compactingJob = fCompactingJob;
479 if (compactingJob != null && compactingJob.getState() == Job.RUNNING) {
480 compactingJob.cancel();
481 }
482 compactingJob = new CompactingSegmentStoreQuery(NonNullUtils.checkNotNull(timeRange));
483 fCompactingJob = compactingJob;
484 compactingJob.schedule();
485 }
486
487 /**
488 * @param signal
489 * Signal received when last opened trace is closed
490 */
491 @Override
492 @TmfSignalHandler
493 public void traceClosed(@Nullable TmfTraceClosedSignal signal) {
494 super.traceClosed(signal);
495 if (signal != null) {
496 // Check if there is no more opened trace
497 if (TmfTraceManager.getInstance().getActiveTrace() == null) {
498 AbstractSegmentStoreAnalysisModule analysis = getAnalysisModule();
499 if (analysis != null) {
76be6c00 500 analysis.removeListener(fListener);
03c96217
BH
501 }
502 clearContent();
503 }
504 }
505 refresh();
506 }
507
508 /**
509 * @param signal
510 * Signal received when window range is updated
511 */
512 @Override
513 @TmfSignalHandler
514 public void windowRangeUpdated(@Nullable TmfWindowRangeUpdatedSignal signal) {
515 super.windowRangeUpdated(signal);
516 if (signal == null) {
517 return;
518 }
519 if (getTrace() != null) {
520 final TmfTimeRange currentRange = signal.getCurrentRange();
521 updateRange(currentRange);
522 } else {
523 Activator.getDefault().logInfo("No Trace to update"); //$NON-NLS-1$
524 }
525 }
526
527 private @Nullable AbstractSegmentStoreAnalysisModule getAnalysisModule() {
528 return fAnalysisModule;
529 }
530
531 private void setAnalysisModule(AbstractSegmentStoreAnalysisModule analysisModule) {
532 fAnalysisModule = analysisModule;
533 }
03c96217 534}
This page took 0.076063 seconds and 5 git commands to generate.