Skip to content

Commit

Permalink
timing.core: add Segment Store Density Provider
Browse files Browse the repository at this point in the history
Currently for the function density views there is no data provider for
it and the logic for data and UI are in the same file, to improve the
efficiency a data provider is created for function density views.

[Added] SegmentStoreDensityDataProvider{Factory} for density views.

Change-Id: I3b6521b5e9aab90669f61315e804f9e326807a5b
Signed-off-by: Puru Jaiswal <puru.jaiswal@ericsson.com>
Reviewed-on: https://git.eclipse.org/r/c/tracecompass/org.eclipse.tracecompass/+/194660
Tested-by: Marco Miller <marco.miller@ericsson.com>
Reviewed-by: Marco Miller <marco.miller@ericsson.com>
  • Loading branch information
Puru Jaiswal authored and marco-miller committed Dec 2, 2022
1 parent ae8f8cc commit 55905e7
Show file tree
Hide file tree
Showing 8 changed files with 450 additions and 0 deletions.
@@ -0,0 +1,174 @@
/**********************************************************************
* Copyright (c) 2022 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.tests.segmentstore;

import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;

import java.util.Arrays;

import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.tracecompass.internal.analysis.timing.core.segmentstore.SegmentStoreDensityDataProvider;
import org.eclipse.tracecompass.internal.analysis.timing.core.segmentstore.SegmentStoreDensityDataProviderFactory;
import org.eclipse.tracecompass.internal.tmf.core.model.filters.FetchParametersUtils;
import org.eclipse.tracecompass.tmf.core.dataprovider.IDataProviderFactory;
import org.eclipse.tracecompass.tmf.core.exceptions.TmfAnalysisException;
import org.eclipse.tracecompass.tmf.core.model.SeriesModel;
import org.eclipse.tracecompass.tmf.core.model.filters.TimeQueryFilter;
import org.eclipse.tracecompass.tmf.core.model.tree.TmfTreeDataModel;
import org.eclipse.tracecompass.tmf.core.model.tree.TmfTreeModel;
import org.eclipse.tracecompass.tmf.core.model.xy.ITmfTreeXYDataProvider;
import org.eclipse.tracecompass.tmf.core.model.xy.ITmfXyModel;
import org.eclipse.tracecompass.tmf.core.response.TmfModelResponse;
import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
import org.eclipse.tracecompass.tmf.tests.stubs.trace.xml.TmfXmlTraceStub;
import org.eclipse.tracecompass.tmf.tests.stubs.trace.xml.TmfXmlTraceStubNs;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;

/**
* Tests the {@Link SegmentStoreDensityDataProvider}
*
* @author Puru Jaiswal
*/
public class SegmentStoreDensityDataProviderTest {

private static ITmfTreeXYDataProvider<@NonNull TmfTreeDataModel> fDataProvider;
private static ITmfTreeXYDataProvider<@NonNull TmfTreeDataModel> fDataProviderNullSegments;

@NonNull
private static final TmfXmlTraceStub fTrace = new TmfXmlTraceStubNs();
private static final double[] yValues = new double[] { 15.0, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324,
4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 15.0, 4.9E-324, 4.9E-324, 4.9E-324,
4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 15.0,
4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324,
4.9E-324, 4.9E-324, 15.0, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324,
4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 15.0, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324,
4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 15.0, 4.9E-324,
4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324,
4.9E-324, 15.0, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324,
4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324 };
private static final long[] xValues = new long[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5 };
private static final long[] xValuesNull = new long[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0 };
private static final double[] yValuesNull = new double[] { 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324,
4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324,
4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324,
4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324,
4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324,
4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324,
4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324,
4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324,
4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324,
4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324, 4.9E-324 };
private static final String ID = "org.eclipse.tracecompass.analysis.timing.core.tests.segmentstore";

/**
* Set-up resources
*
* @throws TmfAnalysisException
* Trace exception should not happen
*/
@BeforeClass
public static void init() throws TmfAnalysisException {
StubSegmentStoreProvider fixture = getValidSegment(fTrace);
IDataProviderFactory fp = new SegmentStoreDensityDataProviderFactory();
assertNull(fp.createProvider(fTrace));
assertNotNull(fp.createProvider(fTrace, ID));
assertTrue(fp.getDescriptors(fTrace).isEmpty());
fDataProvider = new SegmentStoreDensityDataProvider(fTrace, fixture, ID);
StubSegmentStoreProvider fixtureNull = getValidNullSegment(fTrace);
IDataProviderFactory fpNullSegment = new SegmentStoreDensityDataProviderFactory();
assertNull(fpNullSegment.createProvider(fTrace));
assertNotNull(fpNullSegment.createProvider(fTrace, ID));
assertTrue(fpNullSegment.getDescriptors(fTrace).isEmpty());
fDataProviderNullSegments = new SegmentStoreDensityDataProvider(fTrace, fixtureNull, ID);
}

/**
* Disposing resources
*/
@AfterClass
public static void clean() {
fTrace.dispose();
}

private static @NonNull StubSegmentStoreProvider getValidSegment(@NonNull ITmfTrace trace) throws TmfAnalysisException {
StubSegmentStoreProvider fixture = new StubSegmentStoreProvider(false);
fixture.setTrace(trace);
fixture.schedule();
fixture.waitForCompletion();
return fixture;
}

private static @NonNull StubSegmentStoreProvider getValidNullSegment(@NonNull ITmfTrace trace) throws TmfAnalysisException {
StubSegmentStoreProvider fixture = new StubSegmentStoreProvider(true);
fixture.setTrace(trace);
fixture.schedule();
fixture.waitForCompletion();
return fixture;
}

/**
* Tests data model returned by the fetch XY
*/
@Test()
public void testDataProviderFetchXY() {
TimeQueryFilter timeQueryFilter = new TimeQueryFilter(0, 100, 100);
TmfModelResponse<@NonNull ITmfXyModel> response = fDataProvider.fetchXY(FetchParametersUtils.timeQueryToMap(timeQueryFilter), null);
assertNotNull(response);
ITmfXyModel responseModel = response.getModel();
assertNotNull(responseModel);
SeriesModel seriesResponse = (SeriesModel) responseModel.getSeriesData().toArray()[0];
assertTrue(Arrays.equals(yValues, seriesResponse.getData()));
assertTrue(Arrays.equals(xValues, seriesResponse.getXAxis()));
}

/**
* Tests data model returned by the fetch XY
*/
@Test()
public void testDataProviderNullFetchXY() {
TimeQueryFilter timeQueryFilter = new TimeQueryFilter(0, 100, 100);
TmfModelResponse<@NonNull ITmfXyModel> response = fDataProviderNullSegments.fetchXY(FetchParametersUtils.timeQueryToMap(timeQueryFilter), null);
assertNotNull(response);
ITmfXyModel responseModel = response.getModel();
assertNotNull(responseModel);
SeriesModel seriesResponse = (SeriesModel) responseModel.getSeriesData().toArray()[0];
assertTrue(Arrays.equals(yValuesNull, seriesResponse.getData()));
assertTrue(Arrays.equals(xValuesNull, seriesResponse.getXAxis()));
}

/**
* Tests fetch tree of the data provider
*/
@Test()
public void testFetchTree() {
TimeQueryFilter timeQueryFilter = new TimeQueryFilter(0, 100, 100);
TmfModelResponse<@NonNull TmfTreeModel<@NonNull TmfTreeDataModel>> response = fDataProvider.fetchTree(FetchParametersUtils.timeQueryToMap(timeQueryFilter), null);
assertNotNull(response);
}

/**
* Tests provider ID
*/
@Test
public void testID() {
assertTrue(fDataProvider.getId().equals(ID));
}
}
Expand Up @@ -88,6 +88,29 @@ public StubSegmentStoreProvider() {
fPreFixture = builder.build();
}

/**
* Constructor to initialize segments
*
* @param nullSegments
* : to decide on null or not null segments
*/
public StubSegmentStoreProvider(boolean nullSegments) {
ImmutableList.Builder<@NonNull ISegment> builder = new Builder<>();
if (nullSegments) {
fPreFixture = builder.build();
} else {
int previousStartTime = 0;
for (int i = 0; i < SIZE; i++) {
if (i % 7 == 0) {
previousStartTime = i;
}
ISegment segment = new BasicSegment(previousStartTime, i);
builder.add(segment);
}
fPreFixture = builder.build();
}
}

@Override
protected boolean buildAnalysisSegments(@NonNull ISegmentStore<@NonNull ISegment> segmentStore, @NonNull IProgressMonitor monitor) throws TmfAnalysisException {
return segmentStore.addAll(fPreFixture);
Expand Down
Expand Up @@ -30,5 +30,9 @@
class="org.eclipse.tracecompass.internal.analysis.timing.core.segmentstore.SegmentStoreTableDataProviderFactory"
id="org.eclipse.tracecompass.analysis.timing.core.segmentstore.SegmentStoreTableDataProvider">
</dataProviderFactory>
<dataProviderFactory
class="org.eclipse.tracecompass.internal.analysis.timing.core.segmentstore.SegmentStoreDensityDataProviderFactory"
id="org.eclipse.tracecompass.internal.analysis.timing.core.segmentstore.SegmentStoreDensityDataProvider">
</dataProviderFactory>
</extension>
</plugin>
Expand Up @@ -139,6 +139,16 @@ public class Messages extends NLS {
*/
public static @Nullable String SegmentStoreTableDataProvider_description;

/**
* Segment store density title
*/
public static @Nullable String SegmentStoreDensityDataProvider_title;

/**
* Segment store density total
*/
public static @Nullable String SegmentStoreDensity_TotalLabel;

static {
// initialize resource bundle
NLS.initializeMessages(BUNDLE_NAME, Messages.class);
Expand Down
@@ -0,0 +1,163 @@
/**********************************************************************
* Copyright (c) 2022 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.Arrays;
import java.util.Collections;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.StreamSupport;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.tracecompass.analysis.timing.core.segmentstore.ISegmentStoreProvider;
import org.eclipse.tracecompass.internal.tmf.core.model.TmfXyResponseFactory;
import org.eclipse.tracecompass.internal.tmf.core.model.filters.FetchParametersUtils;
import org.eclipse.tracecompass.segmentstore.core.ISegment;
import org.eclipse.tracecompass.segmentstore.core.ISegmentStore;
import org.eclipse.tracecompass.segmentstore.core.SegmentComparators;
import org.eclipse.tracecompass.tmf.core.analysis.IAnalysisModule;
import org.eclipse.tracecompass.tmf.core.model.AbstractTmfTraceDataProvider;
import org.eclipse.tracecompass.tmf.core.model.CommonStatusMessage;
import org.eclipse.tracecompass.tmf.core.model.YModel;
import org.eclipse.tracecompass.tmf.core.model.filters.TimeQueryFilter;
import org.eclipse.tracecompass.tmf.core.model.tree.TmfTreeDataModel;
import org.eclipse.tracecompass.tmf.core.model.tree.TmfTreeModel;
import org.eclipse.tracecompass.tmf.core.model.xy.ITmfTreeXYDataProvider;
import org.eclipse.tracecompass.tmf.core.model.xy.ITmfXyModel;
import org.eclipse.tracecompass.tmf.core.model.xy.IYModel;
import org.eclipse.tracecompass.tmf.core.response.ITmfResponse;
import org.eclipse.tracecompass.tmf.core.response.TmfModelResponse;
import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableList.Builder;

/**
* This data provider will return an XY model based on a query filter. The model
* can be used by any viewer to draw density view charts. Model returned is for
* analysis using SegmentStore.
*
* @author Puru Jaiswal
*/
public class SegmentStoreDensityDataProvider extends AbstractTmfTraceDataProvider implements ITmfTreeXYDataProvider<TmfTreeDataModel> {

/**
* Extension point ID.
*/
public static final String ID = "org.eclipse.tracecompass.internal.analysis.timing.core.segmentstore.SegmentStoreDensityDataProvider"; //$NON-NLS-1$
private static final AtomicLong TRACE_IDS = new AtomicLong();

private final String fID;
private final String title = Objects.requireNonNull(Messages.SegmentStoreDensityDataProvider_title);
private final ISegmentStoreProvider fProvider;
private final long fTotalId = TRACE_IDS.getAndIncrement();
private final long fTraceId = TRACE_IDS.getAndIncrement();

/**
* Constructor
*
* @param trace
* trace provider with other properties of trace.
* @param provider
* segment store provider
* @param id
* analysis identifier
*/
public SegmentStoreDensityDataProvider(ITmfTrace trace, ISegmentStoreProvider provider, String id) {
super(trace);
fProvider = provider;
fID = id;
if (provider instanceof IAnalysisModule) {
((IAnalysisModule) provider).waitForCompletion();
}
}

@Override
public TmfModelResponse<ITmfXyModel> fetchXY(Map<String, Object> fetchParameters, @Nullable IProgressMonitor monitor) {
ISegmentStore<ISegment> segmentStore = fProvider.getSegmentStore();
if (segmentStore == null) {
return TmfXyResponseFactory.createFailedResponse(Objects.requireNonNull(Messages.SegmentStoreDataProvider_SegmentNotAvailable));
}
TimeQueryFilter queryFilter = FetchParametersUtils.createSelectionTimeQuery(fetchParameters);
if (queryFilter == null) {
queryFilter = FetchParametersUtils.createTimeQuery(fetchParameters);
if (queryFilter == null) {
return TmfXyResponseFactory.createFailedResponse(CommonStatusMessage.INCORRECT_QUERY_PARAMETERS);
}
}
return getXyData(segmentStore, queryFilter);
}

private TmfModelResponse<ITmfXyModel> getXyData(ISegmentStore<ISegment> segmentStore, TimeQueryFilter queryFilter) {
long startTraceTime = queryFilter.getStart();
long endTraceTime = queryFilter.getEnd();
int width = queryFilter.getTimesRequested().length;
Iterable<ISegment> displayData = segmentStore.getIntersectingElements(startTraceTime, endTraceTime);

IAnalysisModule module = (fProvider instanceof IAnalysisModule) ? (IAnalysisModule) fProvider : null;
boolean complete = module != null && module.isQueryable(queryFilter.getEnd());

Optional<ISegment> maxSegment = StreamSupport.stream(displayData.spliterator(), false).max(SegmentComparators.INTERVAL_LENGTH_COMPARATOR);
long maxLength = 1;
if (maxSegment.isPresent()) {
maxLength = maxSegment.get().getLength();
}

double[] yValues = getYValues(displayData, width, maxLength);
long[] xValues = getXValues(width, maxLength);
ImmutableList.Builder<IYModel> builder = ImmutableList.builder();
String totalName = getTrace().getName() + '/' + Messages.SegmentStoreDensity_TotalLabel;
builder.add(new YModel(fTotalId, totalName, yValues));
return TmfXyResponseFactory.create(title, xValues, builder.build(), complete);
}

private static long[] getXValues(int width, long maxLength) {
double timeWidth = (double) maxLength / (double) width;
long[] xValues = new long[width];
for (int i = 0; i < width; i++) {
xValues[i] = (long) (i * timeWidth);
xValues[i] += timeWidth / 2;
}
return xValues;
}

private static double[] getYValues(Iterable<ISegment> displayData, int width, long maxLength) {
double maxFactor = 1.0 / (maxLength + 1.0);
double[] yValues = new double[width];
Arrays.fill(yValues, Double.MIN_VALUE);
for (ISegment segment : displayData) {
double xBox = segment.getLength() * maxFactor * width;
if (yValues[(int) xBox] < 1) {
yValues[(int) xBox] = 1;
} else {
yValues[(int) xBox]++;
}
}
return yValues;
}

@Override
public TmfModelResponse<TmfTreeModel<TmfTreeDataModel>> fetchTree(Map<String, Object> fetchParameters, @Nullable IProgressMonitor monitor) {
Builder<TmfTreeDataModel> builder = ImmutableList.builder();
builder.add(new TmfTreeDataModel(fTraceId, -1, Collections.singletonList(String.valueOf(getTrace().getName()))));
builder.add(new TmfTreeDataModel(fTotalId, fTraceId, Collections.singletonList(Objects.requireNonNull(Messages.SegmentStoreDensity_TotalLabel))));
return new TmfModelResponse<>(new TmfTreeModel<>(Collections.emptyList(), builder.build()), ITmfResponse.Status.COMPLETED, CommonStatusMessage.COMPLETED);
}

@Override
public String getId() {
return fID;
}
}

0 comments on commit 55905e7

Please sign in to comment.