From b405ad64068a9ff24bf6e6947c3a7b477deb8a3b Mon Sep 17 00:00:00 2001 From: Jean-Christian Kouame Date: Tue, 6 Sep 2016 13:21:04 -0400 Subject: [PATCH] timing.core: Add local statistics to the latency statistics Add the local statistics in the statistics view and update the general item tree of the view. The SystemCallLatencyStatisticsTableAnalysisTest is updated in consequence. Change-Id: I5209f9c6430ee4658e3cf55ef50f4769b8e28772 Signed-off-by: Jean-Christian Kouame Reviewed-on: https://git.eclipse.org/r/80952 Reviewed-by: Genevieve Bastien Tested-by: Genevieve Bastien Reviewed-by: Hudson CI Reviewed-by: Matthew Khouzam --- ...allLatencyStatisticsTableAnalysisTest.java | 1 - .../statistics/AbstractStatsAnalysisTest.java | 178 ++++++++++++++++++ .../StubSegmentStatisticsAnalysis.java | 119 ++++++++++++ .../AbstractSegmentStatisticsAnalysis.java | 139 +++++++++++--- .../AbstractSegmentStoreStatisticsViewer.java | 64 +++++-- .../segmentstore/statistics/Messages.java | 2 + .../statistics/messages.properties | 1 + .../stubs/trace/xml/TmfXmlTraceStub.java | 30 ++- 8 files changed, 485 insertions(+), 49 deletions(-) create mode 100644 analysis/org.eclipse.tracecompass.analysis.timing.core.tests/src/org/eclipse/tracecompass/analysis/timing/core/tests/segmentstore/statistics/AbstractStatsAnalysisTest.java create mode 100644 analysis/org.eclipse.tracecompass.analysis.timing.core.tests/src/org/eclipse/tracecompass/analysis/timing/core/tests/segmentstore/statistics/StubSegmentStatisticsAnalysis.java diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.ui.swtbot.tests/src/org/eclipse/tracecompass/analysis/os/linux/ui/swtbot/tests/latency/SystemCallLatencyStatisticsTableAnalysisTest.java b/analysis/org.eclipse.tracecompass.analysis.os.linux.ui.swtbot.tests/src/org/eclipse/tracecompass/analysis/os/linux/ui/swtbot/tests/latency/SystemCallLatencyStatisticsTableAnalysisTest.java index 187b733f30..7143045c73 100644 --- a/analysis/org.eclipse.tracecompass.analysis.os.linux.ui.swtbot.tests/src/org/eclipse/tracecompass/analysis/os/linux/ui/swtbot/tests/latency/SystemCallLatencyStatisticsTableAnalysisTest.java +++ b/analysis/org.eclipse.tracecompass.analysis.os.linux.ui.swtbot.tests/src/org/eclipse/tracecompass/analysis/os/linux/ui/swtbot/tests/latency/SystemCallLatencyStatisticsTableAnalysisTest.java @@ -194,7 +194,6 @@ public class SystemCallLatencyStatisticsTableAnalysisTest { assertEquals("175.875 ms", fTreeBot.cell(0, STDEV_COL)); assertEquals("1801", fTreeBot.cell(0, COUNT_COL)); SWTBotTreeItem treeItem = fTreeBot.getTreeItem("Total"); - treeItem = treeItem.getNode(0); assertEquals(55, treeItem.getNodes().size()); validate(treeItem.getNode(2), "select", "13.600 µs", "1.509 s", "192.251 ms", "386.369 ms", "58"); validate(treeItem.getNode(3), "poll", "6.300 µs", "6.800 µs", "6.550 µs", "---", "2"); diff --git a/analysis/org.eclipse.tracecompass.analysis.timing.core.tests/src/org/eclipse/tracecompass/analysis/timing/core/tests/segmentstore/statistics/AbstractStatsAnalysisTest.java b/analysis/org.eclipse.tracecompass.analysis.timing.core.tests/src/org/eclipse/tracecompass/analysis/timing/core/tests/segmentstore/statistics/AbstractStatsAnalysisTest.java new file mode 100644 index 0000000000..235890284d --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.timing.core.tests/src/org/eclipse/tracecompass/analysis/timing/core/tests/segmentstore/statistics/AbstractStatsAnalysisTest.java @@ -0,0 +1,178 @@ +/******************************************************************************* + * Copyright (c) 2016 Ericsson + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ + +package org.eclipse.tracecompass.analysis.timing.core.tests.segmentstore.statistics; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.util.Collections; +import java.util.Map; + +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.tracecompass.analysis.timing.core.segmentstore.statistics.AbstractSegmentStatisticsAnalysis; +import org.eclipse.tracecompass.analysis.timing.core.segmentstore.statistics.SegmentStoreStatistics; +import org.eclipse.tracecompass.tmf.core.exceptions.TmfAnalysisException; +import org.eclipse.tracecompass.tmf.tests.stubs.trace.xml.TmfXmlTraceStub; +import org.junit.Test; + +import com.google.common.collect.ImmutableSet; + +/** + * Test class to test the {@link AbstractSegmentStatisticsAnalysis} class + * + * @author Matthew Khouzam + */ +public class AbstractStatsAnalysisTest { + + /** + * Test execution with no trace + * + * @throws TmfAnalysisException + * should not happen + */ + @Test + public void testExecuteNoTrace() throws TmfAnalysisException { + StubSegmentStatisticsAnalysis fixture = new StubSegmentStatisticsAnalysis(); + assertFalse(fixture.executeAnalysis(new NullProgressMonitor())); + } + + /** + * Test execution with no dependent analyses + * + * @throws TmfAnalysisException + * should not happen + */ + @Test + public void testExecuteNoDepend() throws TmfAnalysisException { + StubSegmentStatisticsAnalysis fixture = new StubSegmentStatisticsAnalysis(); + fixture.setTrace(new TmfXmlTraceStub()); + assertFalse(fixture.executeAnalysis(new NullProgressMonitor())); + } + + /** + * Test good execution + * + * @throws TmfAnalysisException + * should not happen + */ + @Test + public void testExecute() throws TmfAnalysisException { + StubSegmentStatisticsAnalysis fixture = new StubSegmentStatisticsAnalysis(); + TmfXmlTraceStub trace = new TmfXmlTraceStub(); + fixture.setTrace(trace); + fixture.getDependentAnalyses(); + assertTrue(fixture.executeAnalysis(new NullProgressMonitor())); + } + + /** + * Test total statistics + * + * @throws TmfAnalysisException + * should not happen + * + */ + @Test + public void testTotalStats() throws TmfAnalysisException { + StubSegmentStatisticsAnalysis fixture = getValidSegmentStats(); + SegmentStoreStatistics totalStats = fixture.getTotalStats(); + assertNotNull(totalStats); + // no need to test the content much as it is tested in the other test. + assertEquals(StubSegmentStatisticsAnalysis.SIZE, totalStats.getNbSegments()); + } + + /** + * Test per-type statistics + * + * @throws TmfAnalysisException + * should not happen + * + */ + @Test + public void testPerTypeStats() throws TmfAnalysisException { + StubSegmentStatisticsAnalysis fixture = getValidSegmentStats(); + Map<@NonNull String, @NonNull SegmentStoreStatistics> perTypeStats = fixture.getPerSegmentTypeStats(); + assertNotNull(perTypeStats); + // no need to test the content much as it is tested in the other test. + assertEquals(2, perTypeStats.size()); + assertEquals(ImmutableSet. of("odd", "even"), perTypeStats.keySet()); + SegmentStoreStatistics segmentStoreStatistics = perTypeStats.get("even"); + assertNotNull(segmentStoreStatistics); + // starts with 0 so size + 1 + assertEquals(StubSegmentStatisticsAnalysis.SIZE / 2 + 1, segmentStoreStatistics.getNbSegments()); + } + + /** + * Test the partial statistics + * + * @throws TmfAnalysisException + * should not happen + * + */ + @Test + public void testPartialStats() throws TmfAnalysisException { + StubSegmentStatisticsAnalysis fixture = getValidSegmentStats(); + SegmentStoreStatistics totalStats = fixture.getTotalStatsForRange(100, 1100, new NullProgressMonitor()); + assertNotNull(totalStats); + // no need to test the content much as it is tested in the other test. + + // 1051 = 1001 where start is between start and end + 50 overlapping + // start + assertEquals(1051, totalStats.getNbSegments()); + } + + /** + * Test the partial per type statistic + * + * @throws TmfAnalysisException + * should not happen + * + */ + @Test + public void testPartialPerTypeStats() throws TmfAnalysisException { + StubSegmentStatisticsAnalysis fixture = getValidSegmentStats(); + Map<@NonNull String, @NonNull SegmentStoreStatistics> perTypeStats = fixture.getPerSegmentTypeStatsForRange(100, 1100, new NullProgressMonitor()); + assertNotNull(perTypeStats); + // no need to test the content much as it is tested in the other test. + assertEquals(2, perTypeStats.size()); + assertEquals(ImmutableSet. of("odd", "even"), perTypeStats.keySet()); + SegmentStoreStatistics segmentStoreStatistics = perTypeStats.get("even"); + assertNotNull(segmentStoreStatistics); + // 526 = 1051/2+1 = see explanation of 1051 in #testPartialStats + assertEquals(526, segmentStoreStatistics.getNbSegments()); + } + + /** + * Test the cancel operation + * + * @throws TmfAnalysisException + * should not happen + */ + @Test + public void testPartialPerTypeStatsCancel() throws TmfAnalysisException { + StubSegmentStatisticsAnalysis fixture = getValidSegmentStats(); + NullProgressMonitor monitor = new NullProgressMonitor(); + monitor.setCanceled(true); + Map<@NonNull String, @NonNull SegmentStoreStatistics> perTypeStats = fixture.getPerSegmentTypeStatsForRange(100, 1100, monitor); + assertEquals(Collections.emptyMap(), perTypeStats); + } + + private static StubSegmentStatisticsAnalysis getValidSegmentStats() throws TmfAnalysisException { + StubSegmentStatisticsAnalysis fixture = new StubSegmentStatisticsAnalysis(); + TmfXmlTraceStub trace = new TmfXmlTraceStub(); + fixture.setTrace(trace); + fixture.getDependentAnalyses(); + fixture.executeAnalysis(new NullProgressMonitor()); + return fixture; + } + +} diff --git a/analysis/org.eclipse.tracecompass.analysis.timing.core.tests/src/org/eclipse/tracecompass/analysis/timing/core/tests/segmentstore/statistics/StubSegmentStatisticsAnalysis.java b/analysis/org.eclipse.tracecompass.analysis.timing.core.tests/src/org/eclipse/tracecompass/analysis/timing/core/tests/segmentstore/statistics/StubSegmentStatisticsAnalysis.java new file mode 100644 index 0000000000..c65e7e2032 --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.timing.core.tests/src/org/eclipse/tracecompass/analysis/timing/core/tests/segmentstore/statistics/StubSegmentStatisticsAnalysis.java @@ -0,0 +1,119 @@ +/******************************************************************************* + * Copyright (c) 2016 Ericsson + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ + +package org.eclipse.tracecompass.analysis.timing.core.tests.segmentstore.statistics; + +import java.util.Collections; +import java.util.List; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.tracecompass.analysis.timing.core.segmentstore.IAnalysisProgressListener; +import org.eclipse.tracecompass.analysis.timing.core.segmentstore.ISegmentStoreProvider; +import org.eclipse.tracecompass.analysis.timing.core.segmentstore.statistics.AbstractSegmentStatisticsAnalysis; +import org.eclipse.tracecompass.segmentstore.core.BasicSegment; +import org.eclipse.tracecompass.segmentstore.core.ISegment; +import org.eclipse.tracecompass.segmentstore.core.ISegmentStore; +import org.eclipse.tracecompass.segmentstore.core.SegmentStoreFactory; +import org.eclipse.tracecompass.tmf.core.analysis.IAnalysisModule; +import org.eclipse.tracecompass.tmf.core.exceptions.TmfAnalysisException; +import org.eclipse.tracecompass.tmf.core.segment.ISegmentAspect; +import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; +import org.eclipse.tracecompass.tmf.tests.stubs.analysis.TestAnalysis; +import org.eclipse.tracecompass.tmf.tests.stubs.trace.xml.TmfXmlTraceStub; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableList.Builder; + +/** + * Test stuf for statistics analysis + * + * @author Matthew Khouzam + * + */ +class StubSegmentStatisticsAnalysis extends AbstractSegmentStatisticsAnalysis { + + private final class StubProvider extends TestAnalysis implements ISegmentStoreProvider { + private final ISegmentStore<@NonNull ISegment> ifFixture; + + public StubProvider(ISegmentStore<@NonNull ISegment> fixture) { + ifFixture = fixture; + } + + @Override + public void removeListener(@NonNull IAnalysisProgressListener listener) { + // nothing + } + + @Override + public @Nullable ISegmentStore<@NonNull ISegment> getSegmentStore() { + return ifFixture; + } + + @Override + public @NonNull Iterable<@NonNull ISegmentAspect> getSegmentAspects() { + return Collections.emptyList(); + } + + @Override + public void addListener(@NonNull IAnalysisProgressListener listener) { + // nothing + } + } + + public static final int SIZE = 65535; + + private final List<@NonNull ISegment> fPreFixture; + private final ISegmentStore<@NonNull ISegment> fFixture = SegmentStoreFactory.createSegmentStore(); + private StubProvider fSegmentStoreProvider; + + public StubSegmentStatisticsAnalysis() { + ImmutableList.Builder<@NonNull ISegment> builder = new Builder<>(); + for (int i = 0; i < SIZE; i++) { + ISegment seg = new BasicSegment(i, i + i); + builder.add(seg); + } + fPreFixture = builder.build(); + fFixture.addAll(fPreFixture); + fSegmentStoreProvider = new StubProvider(fFixture); + } + + @Override + public boolean setTrace(@NonNull ITmfTrace trace) throws TmfAnalysisException { + if (trace instanceof TmfXmlTraceStub) { + TmfXmlTraceStub tmfXmlTraceStub = (TmfXmlTraceStub) trace; + tmfXmlTraceStub.addAnalysisModule(this); + tmfXmlTraceStub.addAnalysisModule(fSegmentStoreProvider); + + } + return super.setTrace(trace); + } + @Override + protected @Nullable String getSegmentType(@NonNull ISegment segment) { + return segment.getLength() % 2 == 0 ? "even" : "odd"; + } + + @Override + protected @Nullable ISegmentStoreProvider getSegmentProviderAnalysis(@NonNull ITmfTrace trace) { + return fSegmentStoreProvider; + } + + // visibility change + @Override + public boolean executeAnalysis(@NonNull IProgressMonitor monitor) throws TmfAnalysisException { + return super.executeAnalysis(monitor); + } + + // visibility change + @Override + public @NonNull Iterable<@NonNull IAnalysisModule> getDependentAnalyses() { + return super.getDependentAnalyses(); + } +} diff --git a/analysis/org.eclipse.tracecompass.analysis.timing.core/src/org/eclipse/tracecompass/analysis/timing/core/segmentstore/statistics/AbstractSegmentStatisticsAnalysis.java b/analysis/org.eclipse.tracecompass.analysis.timing.core/src/org/eclipse/tracecompass/analysis/timing/core/segmentstore/statistics/AbstractSegmentStatisticsAnalysis.java index efbd8b43ae..fcba4aeeeb 100644 --- a/analysis/org.eclipse.tracecompass.analysis.timing.core/src/org/eclipse/tracecompass/analysis/timing/core/segmentstore/statistics/AbstractSegmentStatisticsAnalysis.java +++ b/analysis/org.eclipse.tracecompass.analysis.timing.core/src/org/eclipse/tracecompass/analysis/timing/core/segmentstore/statistics/AbstractSegmentStatisticsAnalysis.java @@ -8,13 +8,14 @@ *******************************************************************************/ package org.eclipse.tracecompass.analysis.timing.core.segmentstore.statistics; -import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull; - +import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; import org.eclipse.tracecompass.analysis.timing.core.segmentstore.ISegmentStoreProvider; import org.eclipse.tracecompass.segmentstore.core.ISegment; @@ -22,6 +23,7 @@ import org.eclipse.tracecompass.segmentstore.core.ISegmentStore; import org.eclipse.tracecompass.tmf.core.analysis.IAnalysisModule; import org.eclipse.tracecompass.tmf.core.analysis.TmfAbstractAnalysisModule; import org.eclipse.tracecompass.tmf.core.exceptions.TmfAnalysisException; +import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimeRange; import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; import com.google.common.collect.ImmutableList; @@ -37,7 +39,7 @@ public abstract class AbstractSegmentStatisticsAnalysis extends TmfAbstractAnaly private @Nullable SegmentStoreStatistics fTotalStats; - private @Nullable Map fPerSegmentTypeStats; + private Map fPerSegmentTypeStats = new HashMap<>(); @Override protected Iterable getDependentAnalyses() { @@ -54,52 +56,130 @@ public abstract class AbstractSegmentStatisticsAnalysis extends TmfAbstractAnaly @Override protected boolean executeAnalysis(IProgressMonitor monitor) throws TmfAnalysisException { - IAnalysisModule segmentStoreProviderModule = fSegmentStoreProviderModule; - ITmfTrace trace = getTrace(); - if (!(segmentStoreProviderModule instanceof ISegmentStoreProvider) || (trace == null)) { + if (monitor.isCanceled()) { + return false; + } + @Nullable SegmentStoreStatistics totalStats = getTotalStats(TmfTimeRange.ETERNITY.getStartTime().toNanos(), TmfTimeRange.ETERNITY.getEndTime().toNanos(), monitor); + if (totalStats == null) { return false; } - segmentStoreProviderModule.waitForCompletion(); - ISegmentStore segStore = ((ISegmentStoreProvider) segmentStoreProviderModule).getSegmentStore(); + @Nullable Map<@NonNull String, @NonNull SegmentStoreStatistics> perTypeStats = getPerTypeStats(TmfTimeRange.ETERNITY.getStartTime().toNanos(), TmfTimeRange.ETERNITY.getEndTime().toNanos(), monitor); + if (perTypeStats == null) { + return false; + } + fTotalStats = totalStats; + fPerSegmentTypeStats = perTypeStats; + return true; + } - if (segStore != null) { + private @Nullable SegmentStoreStatistics getTotalStats(long start, long end , IProgressMonitor monitor) { + Collection<@NonNull ISegment> store = getSegmentStore(start, end); + if (store == null) { + return null; + } + if (monitor.isCanceled()) { + return null; + } + return calculateTotalManual(store, monitor); + } - boolean result = calculateTotalManual(segStore, monitor); + /** + * Get the total statistics for a specific range. If the range start is + * TmfTimeRange.ETERNITY.getStartTime().toNanos() and the range end is + * TmfTimeRange.ETERNITY.getEndTime().toNanos(), it will return the + * statistics for the whole trace. + * + * @param start + * The start time of the range + * @param end + * The end time of the range + * @param monitor + * The progress monitor + * @return The total statistics, or null if segment store is not valid or if + * the request is canceled + * @since 1.2 + */ + public @Nullable SegmentStoreStatistics getTotalStatsForRange(long start, long end, IProgressMonitor monitor) { + @Nullable ITmfTrace trace = getTrace(); + if (trace != null && (start == TmfTimeRange.ETERNITY.getStartTime().toNanos() && end == TmfTimeRange.ETERNITY.getEndTime().toNanos())) { + waitForCompletion(); + return getTotalStats(); + } + return getTotalStats(start, end, monitor); + } - if (!result) { - return false; - } + private @Nullable Map<@NonNull String, @NonNull SegmentStoreStatistics> getPerTypeStats(long start, long end , IProgressMonitor monitor) { + Collection<@NonNull ISegment> store = getSegmentStore(start, end); + if (monitor.isCanceled()) { + return Collections.EMPTY_MAP; + } + return calculateTotalPerType(store, monitor); + } - result = calculateTotalPerType(segStore, monitor); - if (!result) { - return false; - } + /** + * Get the per segment type statistics for a specific range. If the range + * start is TmfTimeRange.ETERNITY.getStartTime().toNanos() and the range end + * is TmfTimeRange.ETERNITY.getEndTime().toNanos(), it will return the + * statistics for the whole trace. + * + * @param start + * The start time of the range + * @param end + * The end time of the range + * @param monitor + * The progress monitor + * @return The per segment type statistics, or null if segment store is not + * valid or if the request is canceled + * @since 1.2 + */ + public @Nullable Map<@NonNull String, @NonNull SegmentStoreStatistics> getPerSegmentTypeStatsForRange(long start, long end, IProgressMonitor monitor) { + @Nullable ITmfTrace trace = getTrace(); + if (trace != null && (start == TmfTimeRange.ETERNITY.getStartTime().toNanos() && end == TmfTimeRange.ETERNITY.getEndTime().toNanos())) { + waitForCompletion(); + return getPerSegmentTypeStats(); } - return true; + return getPerTypeStats(start, end, monitor); } - private boolean calculateTotalManual(ISegmentStore store, IProgressMonitor monitor) { + /** + * Get the segment store from which we want the statistics + * + * @return The segment store + */ + private @Nullable Collection<@NonNull ISegment> getSegmentStore(long start, long end) { + IAnalysisModule segmentStoreProviderModule = fSegmentStoreProviderModule; + if (!(segmentStoreProviderModule instanceof ISegmentStoreProvider)) { + return null; + } + segmentStoreProviderModule.waitForCompletion(); + + @Nullable ISegmentStore<@NonNull ISegment> segmentStore = ((ISegmentStoreProvider) segmentStoreProviderModule).getSegmentStore(); + return segmentStore != null ? + start != TmfTimeRange.ETERNITY.getStartTime().toNanos() || end != TmfTimeRange.ETERNITY.getEndTime().toNanos() ? (Collection<@NonNull ISegment>) segmentStore.getIntersectingElements(start, end) : segmentStore + : Collections.EMPTY_LIST; + } + + private static @Nullable SegmentStoreStatistics calculateTotalManual(Collection<@NonNull ISegment> segments, IProgressMonitor monitor) { SegmentStoreStatistics total = new SegmentStoreStatistics(); - Iterator iter = store.iterator(); + Iterator<@NonNull ISegment> iter = segments.iterator(); while (iter.hasNext()) { if (monitor.isCanceled()) { - return false; + return null; } - ISegment segment = iter.next(); - total.update(checkNotNull(segment)); + @NonNull ISegment segment = iter.next(); + total.update(segment); } - fTotalStats = total; - return true; + return total; } - private boolean calculateTotalPerType(ISegmentStore store, IProgressMonitor monitor) { + private Map<@NonNull String, @NonNull SegmentStoreStatistics> calculateTotalPerType(Collection segments, IProgressMonitor monitor) { Map perSegmentTypeStats = new HashMap<>(); - Iterator iter = store.iterator(); + Iterator iter = segments.iterator(); while (iter.hasNext()) { if (monitor.isCanceled()) { - return false; + return Collections.EMPTY_MAP; } ISegment segment = iter.next(); String segmentType = getSegmentType(segment); @@ -112,8 +192,7 @@ public abstract class AbstractSegmentStatisticsAnalysis extends TmfAbstractAnaly perSegmentTypeStats.put(segmentType, values); } } - fPerSegmentTypeStats = perSegmentTypeStats; - return true; + return perSegmentTypeStats; } /** diff --git a/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/analysis/timing/ui/views/segmentstore/statistics/AbstractSegmentStoreStatisticsViewer.java b/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/analysis/timing/ui/views/segmentstore/statistics/AbstractSegmentStoreStatisticsViewer.java index 5bb0544cf0..4bf0f3a460 100644 --- a/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/analysis/timing/ui/views/segmentstore/statistics/AbstractSegmentStoreStatisticsViewer.java +++ b/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/analysis/timing/ui/views/segmentstore/statistics/AbstractSegmentStoreStatisticsViewer.java @@ -19,6 +19,9 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.IAction; @@ -40,6 +43,8 @@ import org.eclipse.tracecompass.internal.analysis.timing.ui.views.segmentstore.s import org.eclipse.tracecompass.tmf.core.analysis.TmfAbstractAnalysisModule; import org.eclipse.tracecompass.tmf.core.exceptions.TmfAnalysisException; import org.eclipse.tracecompass.tmf.core.signal.TmfSelectionRangeUpdatedSignal; +import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler; +import org.eclipse.tracecompass.tmf.core.signal.TmfWindowRangeUpdatedSignal; import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestamp; import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; import org.eclipse.tracecompass.tmf.ui.viewers.tree.AbstractTmfTreeViewer; @@ -59,8 +64,7 @@ public abstract class AbstractSegmentStoreStatisticsViewer extends AbstractTmfTr private static final Format FORMATTER = new SubSecondTimeWithUnitFormat(); - @Nullable - private TmfAbstractAnalysisModule fModule; + private @Nullable TmfAbstractAnalysisModule fModule; private MenuManager fTablePopupMenuManager; private static final String[] COLUMN_NAMES = new String[] { @@ -322,6 +326,7 @@ public abstract class AbstractSegmentStoreStatisticsViewer extends AbstractTmfTr long start = segment.getEntry().getMinSegment().getStart(); long end = segment.getEntry().getMinSegment().getEnd(); broadcast(new TmfSelectionRangeUpdatedSignal(AbstractSegmentStoreStatisticsViewer.this, TmfTimestamp.fromNanos(start), TmfTimestamp.fromNanos(end))); + updateContent(start, end, true); } }; @@ -331,6 +336,7 @@ public abstract class AbstractSegmentStoreStatisticsViewer extends AbstractTmfTr long start = segment.getEntry().getMaxSegment().getStart(); long end = segment.getEntry().getMaxSegment().getEnd(); broadcast(new TmfSelectionRangeUpdatedSignal(AbstractSegmentStoreStatisticsViewer.this, TmfTimestamp.fromNanos(start), TmfTimestamp.fromNanos(end))); + updateContent(start, end, true); } }; @@ -387,9 +393,6 @@ public abstract class AbstractSegmentStoreStatisticsViewer extends AbstractTmfTr @Override protected @Nullable ITmfTreeViewerEntry updateElements(long start, long end, boolean isSelection) { - if (isSelection || (start == end)) { - return null; - } TmfAbstractAnalysisModule analysisModule = getStatisticsAnalysisModule(); @@ -402,24 +405,41 @@ public abstract class AbstractSegmentStoreStatisticsViewer extends AbstractTmfTr module.waitForCompletion(); TmfTreeViewerEntry root = new TmfTreeViewerEntry(""); //$NON-NLS-1$ - final SegmentStoreStatistics entry = module.getTotalStats(); - if (entry != null) { + List entryList = root.getChildren(); - List entryList = root.getChildren(); + if (isSelection) { + setStats(start, end, entryList, module, true, new NullProgressMonitor()); + } + setStats(start, end, entryList, module, false, new NullProgressMonitor()); + return root; + } + + private void setStats(long start, long end, List entryList, AbstractSegmentStatisticsAnalysis module, boolean isSelection, IProgressMonitor monitor) { + String label = isSelection ? getSelectionLabel() : getTotalLabel(); + final SegmentStoreStatistics entry = isSelection ? module.getTotalStatsForRange(start, end, monitor) : module.getTotalStats(); + if (entry != null) { - TmfTreeViewerEntry aggregateEntry = new SegmentStoreStatisticsEntry(getTotalLabel(), entry); - entryList.add(aggregateEntry); - HiddenTreeViewerEntry category = new HiddenTreeViewerEntry(getTypeLabel()); - aggregateEntry.addChild(category); + if (entry.getNbSegments() == 0) { + return; + } + TmfTreeViewerEntry child = new SegmentStoreStatisticsEntry(checkNotNull(label), entry); + entryList.add(child); - Map perSegmentStats = module.getPerSegmentTypeStats(); - if (perSegmentStats != null) { - for (Entry statsEntry : perSegmentStats.entrySet()) { - category.addChild(new SegmentStoreStatisticsEntry(statsEntry.getKey(), statsEntry.getValue())); + final Map<@NonNull String, @NonNull SegmentStoreStatistics> perTypeStats = isSelection? module.getPerSegmentTypeStatsForRange(start, end, monitor) : module.getPerSegmentTypeStats(); + if (perTypeStats != null) { + for (Entry<@NonNull String, @NonNull SegmentStoreStatistics> statsEntry : perTypeStats.entrySet()) { + child.addChild(new SegmentStoreStatisticsEntry(statsEntry.getKey(), statsEntry.getValue())); } } } - return root; + } + + @Override + @TmfSignalHandler + public void windowRangeUpdated(@Nullable TmfWindowRangeUpdatedSignal signal) { + // Do nothing. We do not want to update the view and lose the selection + // if the window range is updated with current selection outside of this + // new range. } /** @@ -442,6 +462,16 @@ public abstract class AbstractSegmentStoreStatisticsViewer extends AbstractTmfTr return checkNotNull(Messages.AbstractSegmentStoreStatisticsViewer_total); } + /** + * Get the selection column label + * + * @return The selection column label + * @since 1.2 + */ + protected String getSelectionLabel() { + return checkNotNull(Messages.AbstractSegmentStoreStatisticsViewer_selection); + } + /** * Class to define a level in the tree that doesn't have any values. */ diff --git a/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/views/segmentstore/statistics/Messages.java b/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/views/segmentstore/statistics/Messages.java index 2e4579e7cf..0458bee907 100644 --- a/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/views/segmentstore/statistics/Messages.java +++ b/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/views/segmentstore/statistics/Messages.java @@ -22,6 +22,8 @@ public class Messages extends NLS { private static final String BUNDLE_NAME = "org.eclipse.tracecompass.internal.analysis.timing.ui.views.segmentstore.statistics.messages"; //$NON-NLS-1$ + /** Default "selection" label in statistics viewer */ + public static String AbstractSegmentStoreStatisticsViewer_selection; /** Default "total" label in statistics viewer */ public static String AbstractSegmentStoreStatisticsViewer_total; /** Default "category" label in statistics viewer */ diff --git a/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/views/segmentstore/statistics/messages.properties b/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/views/segmentstore/statistics/messages.properties index 73a47d34ca..e6924cbfbc 100644 --- a/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/views/segmentstore/statistics/messages.properties +++ b/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/views/segmentstore/statistics/messages.properties @@ -9,6 +9,7 @@ # Contributors: # Bernd Hufmann - Initial API and implementation ############################################################################### +AbstractSegmentStoreStatisticsViewer_selection=Selection AbstractSegmentStoreStatisticsViewer_total=Total AbstractSegmentStoreStatisticsViewer_types=Types SegmentStoreStatistics_LevelLabel=Level diff --git a/tmf/org.eclipse.tracecompass.tmf.core.tests/stubs/org/eclipse/tracecompass/tmf/tests/stubs/trace/xml/TmfXmlTraceStub.java b/tmf/org.eclipse.tracecompass.tmf.core.tests/stubs/org/eclipse/tracecompass/tmf/tests/stubs/trace/xml/TmfXmlTraceStub.java index e7f28ff4f4..af595419c8 100644 --- a/tmf/org.eclipse.tracecompass.tmf.core.tests/stubs/org/eclipse/tracecompass/tmf/tests/stubs/trace/xml/TmfXmlTraceStub.java +++ b/tmf/org.eclipse.tracecompass.tmf.core.tests/stubs/org/eclipse/tracecompass/tmf/tests/stubs/trace/xml/TmfXmlTraceStub.java @@ -22,6 +22,8 @@ import java.io.InputStream; import java.net.URL; import java.util.Collection; import java.util.HashSet; +import java.util.Optional; +import java.util.stream.StreamSupport; import javax.xml.XMLConstants; import javax.xml.transform.Source; @@ -36,18 +38,20 @@ import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.jdt.annotation.DefaultLocation; +import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; import org.eclipse.osgi.util.NLS; import org.eclipse.tracecompass.internal.tmf.core.Activator; +import org.eclipse.tracecompass.tmf.core.analysis.IAnalysisModule; import org.eclipse.tracecompass.tmf.core.event.ITmfEvent; import org.eclipse.tracecompass.tmf.core.event.ITmfEventField; import org.eclipse.tracecompass.tmf.core.event.ITmfEventType; import org.eclipse.tracecompass.tmf.core.event.TmfEvent; import org.eclipse.tracecompass.tmf.core.event.TmfEventField; import org.eclipse.tracecompass.tmf.core.event.TmfEventType; -import org.eclipse.tracecompass.tmf.core.event.aspect.TmfBaseAspects; import org.eclipse.tracecompass.tmf.core.event.aspect.ITmfEventAspect; +import org.eclipse.tracecompass.tmf.core.event.aspect.TmfBaseAspects; import org.eclipse.tracecompass.tmf.core.event.aspect.TmfContentFieldAspect; import org.eclipse.tracecompass.tmf.core.event.aspect.TmfCpuAspect; import org.eclipse.tracecompass.tmf.core.exceptions.TmfTraceException; @@ -67,6 +71,7 @@ import org.eclipse.tracecompass.tmf.core.trace.location.ITmfLocation; import org.xml.sax.SAXException; import com.google.common.collect.ImmutableList; +import com.google.common.collect.Iterables; /** * An XML development trace using a custom XML trace definition and schema. @@ -106,6 +111,7 @@ public class TmfXmlTraceStub extends TmfTrace { private Collection> fAspects = TmfTrace.BASE_ASPECTS; private final Collection> fAdditionalAspects = new HashSet<>(); + private final Collection fAdditionalModules = new HashSet<>(); /** * Validate and initialize a {@link TmfXmlTraceStub} object @@ -402,4 +408,26 @@ public class TmfXmlTraceStub extends TmfTrace { fAdditionalAspects.add(aspect); } + /** + * Add an additional new module + * + * @param module + * The new module + */ + public void addAnalysisModule(IAnalysisModule module) { + fAdditionalModules.add(module); + } + + @Override + public Iterable<@NonNull IAnalysisModule> getAnalysisModules() { + @NonNull Iterable modules = super.getAnalysisModules(); + return checkNotNull(Iterables.concat(modules, fAdditionalModules)); + } + + @Override + public @Nullable IAnalysisModule getAnalysisModule(@Nullable String analysisId) { + Iterable<@NonNull IAnalysisModule> modules = getAnalysisModules(); + Optional opt = StreamSupport.stream(modules.spliterator(), false).filter(analysis -> analysis.getId().equals(analysisId)).findFirst(); + return opt.isPresent() ? opt.get() : null; + } } -- 2.34.1