timing.core: Refactor statistics analysis to add generic segment type This commit refactors the existing GenericSegmentStatisticsAnalysis and SegmentStoreStatisticsDataProviderFactory so that they can be extended to make new statistics analysis with different grouping logic: [1] The GenericSegmentStatisticsAnalysis is now a public class, and provides a default implementation for the getSegmentType method. By default, this method groups the data of a statistics analysis by segment name. The class can be extended to overwrite the default aggregating logic. [2] The SegmentStoreStatisticsDataProviderFactory is split into 2 classes: The AbstractSegmentStoreStatisticsDataProviderFactory and SegmentNameSegmentStoreStatisticsDataProviderFactory. The AbstractSegmentStoreStatisticsDataProviderFactory provides the common logic to generate a data provider for segment store statistics analysis. The SegmentNameSegmentStoreStatisticsDataProviderFactory extends the prior class, and binds the data provider to the GenericSegmentStatisticsAnalysis, which groups the data using the segment name. New data provider factories can extends the abstract class to use different grouping logic for statistics analysis by binding itself to different implementations of GenericSegmentStatisticsAnalysis. Change-Id: I895efe32384026ebfd8668bdb250e02900281c78 Signed-off-by: Hoang Thuan Pham <hoang.pham@calian.ca> Reviewed-on: https://git.eclipse.org/r/c/tracecompass/org.eclipse.tracecompass/+/204373 Tested-by: Trace Compass Bot <tracecompass-bot@eclipse.org> Tested-by: Matthew Khouzam <matthew.khouzam@ericsson.com> Reviewed-by: Patrick Tasse <patrick.tasse@gmail.com> Reviewed-by: Matthew Khouzam <matthew.khouzam@ericsson.com>
diff --git a/analysis/org.eclipse.tracecompass.analysis.timing.core/META-INF/MANIFEST.MF b/analysis/org.eclipse.tracecompass.analysis.timing.core/META-INF/MANIFEST.MF index 550b4bd..0a62d6d 100644 --- a/analysis/org.eclipse.tracecompass.analysis.timing.core/META-INF/MANIFEST.MF +++ b/analysis/org.eclipse.tracecompass.analysis.timing.core/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Bundle-Vendor: %Bundle-Vendor -Bundle-Version: 5.4.1.qualifier +Bundle-Version: 5.5.0.qualifier Bundle-Localization: plugin Bundle-SymbolicName: org.eclipse.tracecompass.analysis.timing.core;singleton:=true Bundle-Activator: org.eclipse.tracecompass.internal.analysis.timing.core.Activator
diff --git a/analysis/org.eclipse.tracecompass.analysis.timing.core/plugin.xml b/analysis/org.eclipse.tracecompass.analysis.timing.core/plugin.xml index 3fc1a71..a03eb60 100644 --- a/analysis/org.eclipse.tracecompass.analysis.timing.core/plugin.xml +++ b/analysis/org.eclipse.tracecompass.analysis.timing.core/plugin.xml
@@ -23,7 +23,7 @@ id="org.eclipse.tracecompass.internal.analysis.timing.core.segmentstore.scatter.dataprovider"> </dataProviderFactory> <dataProviderFactory - class="org.eclipse.tracecompass.internal.analysis.timing.core.segmentstore.SegmentStoreStatisticsDataProviderFactory" + class="org.eclipse.tracecompass.internal.analysis.timing.core.segmentstore.SegmentNameSegmentStoreStatisticsDataProviderFactory" id="org.eclipse.tracecompass.analysis.timing.core.segmentstore.SegmentStoreStatisticsDataProvider"> </dataProviderFactory> <dataProviderFactory
diff --git a/analysis/org.eclipse.tracecompass.analysis.timing.core/src/org/eclipse/tracecompass/analysis/timing/core/segmentstore/GenericSegmentStatisticsAnalysis.java b/analysis/org.eclipse.tracecompass.analysis.timing.core/src/org/eclipse/tracecompass/analysis/timing/core/segmentstore/GenericSegmentStatisticsAnalysis.java new file mode 100644 index 0000000..a91d517 --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.timing.core/src/org/eclipse/tracecompass/analysis/timing/core/segmentstore/GenericSegmentStatisticsAnalysis.java
@@ -0,0 +1,62 @@ +/******************************************************************************* + * Copyright (c) 2018, 2023 Ericsson + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License 2.0 which + * accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ + +package org.eclipse.tracecompass.analysis.timing.core.segmentstore; + +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.tracecompass.analysis.timing.core.segmentstore.statistics.AbstractSegmentStatisticsAnalysis; +import org.eclipse.tracecompass.segmentstore.core.ISegment; +import org.eclipse.tracecompass.segmentstore.core.segment.interfaces.INamedSegment; +import org.eclipse.tracecompass.tmf.core.analysis.IAnalysisModule; +import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; + +/** + * A generic abstraction of a {@link AbstractSegmentStatisticsAnalysis}. Entries + * in a trace that have the same key will be aggregated into one entry in the + * statistics table. The key is specified by the return value of the + * getSegmentType function. By default, the entries are grouped by the segment + * name, but the class can be extended to overwrite the default implementation. + * + * @author Loic Prieur-Drevon + * @since 5.5 + */ +public class GenericSegmentStatisticsAnalysis extends AbstractSegmentStatisticsAnalysis { + private final String fSecondaryId; + + /** + * Constructor + * + * @param secondaryId + * The secondary analysis id, which this statistics analysis will + * be based on. + */ + public GenericSegmentStatisticsAnalysis(String secondaryId) { + fSecondaryId = secondaryId; + } + + @Override + protected @Nullable String getSegmentType(ISegment segment) { + if (segment instanceof INamedSegment) { + return ((INamedSegment) segment).getName(); + } + return null; + } + + @Deprecated + @Override + protected @Nullable ISegmentStoreProvider getSegmentProviderAnalysis(ITmfTrace trace) { + IAnalysisModule segmentStoreModule = trace.getAnalysisModule(fSecondaryId); + if (segmentStoreModule instanceof ISegmentStoreProvider) { + return (ISegmentStoreProvider) segmentStoreModule; + } + return null; + } +} \ No newline at end of file
diff --git a/analysis/org.eclipse.tracecompass.analysis.timing.core/src/org/eclipse/tracecompass/internal/analysis/timing/core/segmentstore/AbstractSegmentStoreStatisticsDataProviderFactory.java b/analysis/org.eclipse.tracecompass.analysis.timing.core/src/org/eclipse/tracecompass/internal/analysis/timing/core/segmentstore/AbstractSegmentStoreStatisticsDataProviderFactory.java new file mode 100644 index 0000000..3077703 --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.timing.core/src/org/eclipse/tracecompass/internal/analysis/timing/core/segmentstore/AbstractSegmentStoreStatisticsDataProviderFactory.java
@@ -0,0 +1,137 @@ +/********************************************************************** + * Copyright (c) 2018, 2023 Ericsson + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License 2.0 which + * accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + **********************************************************************/ +package org.eclipse.tracecompass.internal.analysis.timing.core.segmentstore; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.tracecompass.analysis.timing.core.segmentstore.GenericSegmentStatisticsAnalysis; +import org.eclipse.tracecompass.analysis.timing.core.segmentstore.ISegmentStoreProvider; +import org.eclipse.tracecompass.analysis.timing.core.segmentstore.statistics.AbstractSegmentStatisticsAnalysis; +import org.eclipse.tracecompass.tmf.core.analysis.IAnalysisModule; +import org.eclipse.tracecompass.tmf.core.dataprovider.IDataProviderDescriptor; +import org.eclipse.tracecompass.tmf.core.dataprovider.IDataProviderFactory; +import org.eclipse.tracecompass.tmf.core.exceptions.TmfAnalysisException; +import org.eclipse.tracecompass.tmf.core.model.DataProviderDescriptor; +import org.eclipse.tracecompass.tmf.core.model.tree.ITmfTreeDataModel; +import org.eclipse.tracecompass.tmf.core.model.tree.ITmfTreeDataProvider; +import org.eclipse.tracecompass.tmf.core.model.tree.TmfTreeCompositeDataProvider; +import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; +import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager; +import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils; +import org.eclipse.tracecompass.tmf.core.trace.experiment.TmfExperiment; + +/** + * An abstract data provider factory for segment store statistics. To extend a + * new data provider factory, create an + * {@link GenericSegmentStatisticsAnalysis} and override the + * getSegmentType function to specify how entries should be grouped for the + * statistics. Then, bind the statistics analysis to the data provider by returning an + * instance of the analysis using the getAnalysis function. + * + * @author Loic Prieur-Drevon + */ +public abstract class AbstractSegmentStoreStatisticsDataProviderFactory implements IDataProviderFactory { + + @Override + public @Nullable ITmfTreeDataProvider<? extends ITmfTreeDataModel> createProvider(ITmfTrace trace) { + return null; + } + + @Override + public @Nullable ITmfTreeDataProvider<? extends ITmfTreeDataModel> createProvider(ITmfTrace trace, String secondaryId) { + + IAnalysisModule baseAnalysisModule = trace.getAnalysisModule(secondaryId); + String composedId = getDataProviderId() + ':' + secondaryId; + // check that this trace has the queried analysis. + if (!(baseAnalysisModule instanceof ISegmentStoreProvider)) { + if (!(trace instanceof TmfExperiment)) { + return null; + } + return TmfTreeCompositeDataProvider.create(TmfTraceManager.getTraceSet(trace), composedId); + } + baseAnalysisModule.schedule(); + + AbstractSegmentStatisticsAnalysis statisticsAnalysisModule = getAnalysis(secondaryId); + try { + setStatisticsAnalysisModuleName(statisticsAnalysisModule, baseAnalysisModule); + statisticsAnalysisModule.setTrace(trace); + } catch (TmfAnalysisException e) { + statisticsAnalysisModule.dispose(); + return null; + } + statisticsAnalysisModule.schedule(); + return new SegmentStoreStatisticsDataProvider(trace, statisticsAnalysisModule, composedId); + } + + @Override + public Collection<IDataProviderDescriptor> getDescriptors(ITmfTrace trace) { + Iterable<ISegmentStoreProvider> modules = TmfTraceUtils.getAnalysisModulesOfClass(trace, ISegmentStoreProvider.class); + List<IDataProviderDescriptor> descriptors = new ArrayList<>(); + Set<String> existingModules = new HashSet<>(); + for (ISegmentStoreProvider module : modules) { + IAnalysisModule analysis = (IAnalysisModule) module; + // Only add analysis once per trace (which could be an experiment) + if (!existingModules.contains(analysis.getId())) { + DataProviderDescriptor.Builder builder = getDataProviderDescriptor(analysis); + descriptors.add(builder.build()); + existingModules.add(analysis.getId()); + } + } + return descriptors; + } + + /** + * Get a {@link AbstractSegmentStatisticsAnalysis} that generates the + * statistics for another analysis which is identified by the secondaryId + * parameter. The statistics analysis should implement the getSegmentType method + * to specify how entries should be grouped for the statistics. + * + * @param secondaryId + * The ID of the analysis which the returned + * {@link AbstractSegmentStatisticsAnalysis} is based on. + * @return An {@link AbstractSegmentStatisticsAnalysis} that is based on the + * analysis that is identified by the secondary id. + */ + protected abstract AbstractSegmentStatisticsAnalysis getAnalysis(String secondaryId); + + /** + * Get the ID of the data provider to create. + * + * @return the ID of the data provider to create + */ + protected abstract String getDataProviderId(); + + /** + * Set the statistics analysis module name. + * + * @param statisticsAnalysisModule + * The statistics analysis module + * @param baseAnalysisModule + * The base module, which the statistics analysis is based on + */ + protected abstract void setStatisticsAnalysisModuleName(AbstractSegmentStatisticsAnalysis statisticsAnalysisModule, IAnalysisModule baseAnalysisModule); + + /** + * Get the data provider descriptor + * + * @param analysis + * The base analysis on which the statistics are based on. + * @return A + * {@link org.eclipse.tracecompass.tmf.core.model.DataProviderDescriptor.Builder} + * that contains the data provider information + */ + protected abstract DataProviderDescriptor.Builder getDataProviderDescriptor(IAnalysisModule analysis); +}
diff --git a/analysis/org.eclipse.tracecompass.analysis.timing.core/src/org/eclipse/tracecompass/internal/analysis/timing/core/segmentstore/SegmentNameSegmentStoreStatisticsDataProviderFactory.java b/analysis/org.eclipse.tracecompass.analysis.timing.core/src/org/eclipse/tracecompass/internal/analysis/timing/core/segmentstore/SegmentNameSegmentStoreStatisticsDataProviderFactory.java new file mode 100644 index 0000000..c496796 --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.timing.core/src/org/eclipse/tracecompass/internal/analysis/timing/core/segmentstore/SegmentNameSegmentStoreStatisticsDataProviderFactory.java
@@ -0,0 +1,60 @@ +/********************************************************************** + * Copyright (c) 2018, 2023 Ericsson + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License 2.0 which + * accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + **********************************************************************/ + +package org.eclipse.tracecompass.internal.analysis.timing.core.segmentstore; + +import java.util.Objects; + +import org.eclipse.osgi.util.NLS; +import org.eclipse.tracecompass.analysis.timing.core.segmentstore.GenericSegmentStatisticsAnalysis; +import org.eclipse.tracecompass.analysis.timing.core.segmentstore.statistics.AbstractSegmentStatisticsAnalysis; +import org.eclipse.tracecompass.tmf.core.analysis.IAnalysisModule; +import org.eclipse.tracecompass.tmf.core.component.DataProviderConstants; +import org.eclipse.tracecompass.tmf.core.dataprovider.IDataProviderDescriptor.ProviderType; +import org.eclipse.tracecompass.tmf.core.model.DataProviderDescriptor; +import org.eclipse.tracecompass.tmf.core.model.DataProviderDescriptor.Builder; + +/** + * Generalized {@link SegmentStoreStatisticsDataProvider} factory using + * secondary ID to identify which segment store provider to build it from. + * Entries in this data set are grouped by segment name. + * + * @author Loic Prieur-Drevon + * @author Hoang Thuan Pham + * @since 4.0 + */ +public class SegmentNameSegmentStoreStatisticsDataProviderFactory extends AbstractSegmentStoreStatisticsDataProviderFactory { + + @Override + protected AbstractSegmentStatisticsAnalysis getAnalysis(String secondaryId) { + return new GenericSegmentStatisticsAnalysis(secondaryId); + } + + @Override + protected String getDataProviderId() { + return SegmentStoreStatisticsDataProvider.ID; + } + + @Override + protected void setStatisticsAnalysisModuleName(AbstractSegmentStatisticsAnalysis statisticsAnalysisModule, IAnalysisModule baseAnalysisModule) { + statisticsAnalysisModule.setName(Objects.requireNonNull(NLS.bind(Messages.SegmentStoreStatisticsDataProviderFactory_AnalysisName, baseAnalysisModule.getName()))); + } + + @Override + protected Builder getDataProviderDescriptor(IAnalysisModule analysis) { + DataProviderDescriptor.Builder builder = new DataProviderDescriptor.Builder(); + builder.setId(SegmentStoreStatisticsDataProvider.ID + DataProviderConstants.ID_SEPARATOR + analysis.getId()) + .setName(Objects.requireNonNull(NLS.bind(Messages.SegmentStoreStatisticsDataProvider_title, analysis.getName()))) + .setDescription(Objects.requireNonNull(NLS.bind(Messages.SegmentStoreStatisticsDataProvider_description, analysis.getHelpText()))) + .setProviderType(ProviderType.DATA_TREE); + return builder; + } +}
diff --git a/analysis/org.eclipse.tracecompass.analysis.timing.core/src/org/eclipse/tracecompass/internal/analysis/timing/core/segmentstore/SegmentStoreStatisticsDataProviderFactory.java b/analysis/org.eclipse.tracecompass.analysis.timing.core/src/org/eclipse/tracecompass/internal/analysis/timing/core/segmentstore/SegmentStoreStatisticsDataProviderFactory.java deleted file mode 100644 index cec3695..0000000 --- a/analysis/org.eclipse.tracecompass.analysis.timing.core/src/org/eclipse/tracecompass/internal/analysis/timing/core/segmentstore/SegmentStoreStatisticsDataProviderFactory.java +++ /dev/null
@@ -1,130 +0,0 @@ -/********************************************************************** - * Copyright (c) 2018, 2021 Ericsson - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License 2.0 which - * accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - **********************************************************************/ - -package org.eclipse.tracecompass.internal.analysis.timing.core.segmentstore; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Objects; -import java.util.Set; - -import org.eclipse.jdt.annotation.NonNull; -import org.eclipse.jdt.annotation.Nullable; -import org.eclipse.osgi.util.NLS; -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.ISegment; -import org.eclipse.tracecompass.segmentstore.core.segment.interfaces.INamedSegment; -import org.eclipse.tracecompass.tmf.core.analysis.IAnalysisModule; -import org.eclipse.tracecompass.tmf.core.component.DataProviderConstants; -import org.eclipse.tracecompass.tmf.core.dataprovider.IDataProviderDescriptor; -import org.eclipse.tracecompass.tmf.core.dataprovider.IDataProviderDescriptor.ProviderType; -import org.eclipse.tracecompass.tmf.core.dataprovider.IDataProviderFactory; -import org.eclipse.tracecompass.tmf.core.exceptions.TmfAnalysisException; -import org.eclipse.tracecompass.tmf.core.model.DataProviderDescriptor; -import org.eclipse.tracecompass.tmf.core.model.tree.ITmfTreeDataModel; -import org.eclipse.tracecompass.tmf.core.model.tree.ITmfTreeDataProvider; -import org.eclipse.tracecompass.tmf.core.model.tree.TmfTreeCompositeDataProvider; -import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; -import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager; -import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils; -import org.eclipse.tracecompass.tmf.core.trace.experiment.TmfExperiment; - -/** - * Generalized {@link SegmentStoreStatisticsDataProvider} factory using - * secondary ID to identify which segment store provider to build it from. - * - * @author Loic Prieur-Drevon - * @since 4.0 - */ -public class SegmentStoreStatisticsDataProviderFactory implements IDataProviderFactory { - - private static final class GenericSegmentStatisticsAnalysis extends AbstractSegmentStatisticsAnalysis { - private final String fSecondaryId; - - private GenericSegmentStatisticsAnalysis(String secondaryId) { - fSecondaryId = secondaryId; - } - - @Override - protected @Nullable String getSegmentType(@NonNull ISegment segment) { - if (segment instanceof INamedSegment) { - return ((INamedSegment) segment).getName(); - } - return null; - } - - @Deprecated - @Override - protected @Nullable ISegmentStoreProvider getSegmentProviderAnalysis(@NonNull ITmfTrace trace) { - IAnalysisModule segmentStoreModule = trace.getAnalysisModule(fSecondaryId); - if (segmentStoreModule instanceof ISegmentStoreProvider) { - return (ISegmentStoreProvider) segmentStoreModule; - } - return null; - } - } - - @Override - public @Nullable ITmfTreeDataProvider<? extends ITmfTreeDataModel> createProvider(ITmfTrace trace) { - return null; - } - - @Override - public @Nullable ITmfTreeDataProvider<? extends ITmfTreeDataModel> createProvider(ITmfTrace trace, String secondaryId) { - - IAnalysisModule m = trace.getAnalysisModule(secondaryId); - String composedId = SegmentStoreStatisticsDataProvider.ID + ':' + secondaryId; - // check that this trace has the queried analysis. - if (!(m instanceof ISegmentStoreProvider)) { - if (!(trace instanceof TmfExperiment)) { - return null; - } - return TmfTreeCompositeDataProvider.create(TmfTraceManager.getTraceSet(trace), composedId); - } - m.schedule(); - - AbstractSegmentStatisticsAnalysis module = new GenericSegmentStatisticsAnalysis(secondaryId); - try { - module.setName(Objects.requireNonNull(NLS.bind(Messages.SegmentStoreStatisticsDataProviderFactory_AnalysisName, m.getName()))); - module.setTrace(trace); - } catch (TmfAnalysisException e) { - module.dispose(); - return null; - } - module.schedule(); - return new SegmentStoreStatisticsDataProvider(trace, module, composedId); - } - - @Override - public Collection<IDataProviderDescriptor> getDescriptors(ITmfTrace trace) { - Iterable<ISegmentStoreProvider> modules = TmfTraceUtils.getAnalysisModulesOfClass(trace, ISegmentStoreProvider.class); - List<IDataProviderDescriptor> descriptors = new ArrayList<>(); - Set<String> existingModules = new HashSet<>(); - for (ISegmentStoreProvider module : modules) { - IAnalysisModule analysis = (IAnalysisModule) module; - // Only add analysis once per trace (which could be an experiment) - if (!existingModules.contains(analysis.getId())) { - DataProviderDescriptor.Builder builder = new DataProviderDescriptor.Builder(); - builder.setId(SegmentStoreStatisticsDataProvider.ID + DataProviderConstants.ID_SEPARATOR + analysis.getId()) - .setName(Objects.requireNonNull(NLS.bind(Messages.SegmentStoreStatisticsDataProvider_title, analysis.getName()))) - .setDescription(Objects.requireNonNull(NLS.bind(Messages.SegmentStoreStatisticsDataProvider_description, analysis.getHelpText()))) - .setProviderType(ProviderType.DATA_TREE); - descriptors.add(builder.build()); - existingModules.add(analysis.getId()); - } - } - return descriptors; - } - -}