blob: 7b0998be23395cf19a9145fe432d4bcb7c46f09a [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2020 École Polytechnique de Montréal
*
* 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.examples.core.data.provider;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.atomic.AtomicLong;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.tracecompass.examples.core.analysis.ExampleStateSystemAnalysisModule;
import org.eclipse.tracecompass.internal.tmf.core.model.filters.FetchParametersUtils;
import org.eclipse.tracecompass.internal.tmf.core.model.tree.AbstractTreeDataProvider;
import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem;
import org.eclipse.tracecompass.statesystem.core.exceptions.StateSystemDisposedException;
import org.eclipse.tracecompass.statesystem.core.exceptions.TimeRangeException;
import org.eclipse.tracecompass.statesystem.core.interval.ITmfStateInterval;
import org.eclipse.tracecompass.tmf.core.dataprovider.DataProviderParameterUtils;
import org.eclipse.tracecompass.tmf.core.model.CommonStatusMessage;
import org.eclipse.tracecompass.tmf.core.model.TmfCommonXAxisModel;
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.ITmfTreeDataModel;
import org.eclipse.tracecompass.tmf.core.model.tree.ITmfTreeDataProvider;
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.ITmfResponse.Status;
import org.eclipse.tracecompass.tmf.core.response.TmfModelResponse;
import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
/**
* An example of an XY data provider.
*
* This class is also in the developer documentation of Trace Compass. If it is
* modified here, the doc should also be updated.
*
* @author Geneviève Bastien
*/
@SuppressWarnings("restriction")
@NonNullByDefault
public class ExampleXYDataProvider extends AbstractTreeDataProvider<ExampleStateSystemAnalysisModule, TmfTreeDataModel> implements ITmfTreeXYDataProvider<TmfTreeDataModel> {
/**
* Provider unique ID.
*/
public static final String ID = "org.eclipse.tracecompass.examples.xy.dataprovider"; //$NON-NLS-1$
private static final AtomicLong sfAtomicId = new AtomicLong();
private final BiMap<Long, Integer> fIDToDisplayQuark = HashBiMap.create();
private final Map<Integer, String> fQuarkToString = new HashMap<>();
/**
* Constructor
*
* @param trace
* The trace this data provider is for
* @param analysisModule
* The analysis module
*/
public ExampleXYDataProvider(ITmfTrace trace, ExampleStateSystemAnalysisModule analysisModule) {
super(trace, analysisModule);
}
/**
* Create the time graph data provider
*
* @param trace
* The trace for which is the data provider
* @return The data provider
*/
public static @Nullable ITmfTreeDataProvider<? extends ITmfTreeDataModel> create(ITmfTrace trace) {
ExampleStateSystemAnalysisModule module = TmfTraceUtils.getAnalysisModuleOfClass(trace, ExampleStateSystemAnalysisModule.class, ExampleStateSystemAnalysisModule.ID);
return module != null ? new ExampleXYDataProvider(trace, module) : null;
}
@Override
public String getId() {
return ID;
}
@Override
protected boolean isCacheable() {
return true;
}
@Override
protected TmfTreeModel<TmfTreeDataModel> getTree(ITmfStateSystem ss, Map<String, Object> fetchParameters, @Nullable IProgressMonitor monitor) throws StateSystemDisposedException {
// Make an entry for each base quark
List<TmfTreeDataModel> entryList = new ArrayList<>();
for (Integer quark : ss.getQuarks("CPUs", "*")) { //$NON-NLS-1$ //$NON-NLS-2$
int statusQuark = ss.optQuarkRelative(quark, "Status"); //$NON-NLS-1$
if (statusQuark != ITmfStateSystem.INVALID_ATTRIBUTE) {
Long id = fIDToDisplayQuark.inverse().computeIfAbsent(statusQuark, q -> sfAtomicId.getAndIncrement());
entryList.add(new TmfTreeDataModel(id, -1, ss.getAttributeName(quark)));
fQuarkToString.put(statusQuark, ss.getAttributeName(quark));
}
}
return new TmfTreeModel<>(Collections.emptyList(), entryList);
}
@Override
public TmfModelResponse<ITmfXyModel> fetchXY(Map<String, Object> fetchParameters, @Nullable IProgressMonitor monitor) {
ITmfStateSystem ss = getAnalysisModule().getStateSystem();
if (ss == null) {
return new TmfModelResponse<>(null, ITmfResponse.Status.FAILED, CommonStatusMessage.ANALYSIS_INITIALIZATION_FAILED);
}
Map<Integer, double[]> quarkToValues = new HashMap<>();
// Prepare the quarks to display
Collection<Long> selectedItems = DataProviderParameterUtils.extractSelectedItems(fetchParameters);
if (selectedItems == null) {
// No selected items, take them all
selectedItems = fIDToDisplayQuark.keySet();
}
List<Long> times = getTimes(ss, DataProviderParameterUtils.extractTimeRequested(fetchParameters));
for (Long id : selectedItems) {
Integer quark = fIDToDisplayQuark.get(id);
if (quark != null) {
quarkToValues.put(quark, new double[times.size()]);
}
}
long[] nativeTimes = new long[times.size()];
for (int i = 0; i < times.size(); i++) {
nativeTimes[i] = times.get(i);
}
// Query the state system to fill the array of values
try {
for (ITmfStateInterval interval : ss.query2D(quarkToValues.keySet(), times)) {
if (monitor != null && monitor.isCanceled()) {
return new TmfModelResponse<>(null, Status.CANCELLED, CommonStatusMessage.TASK_CANCELLED);
}
double[] row = quarkToValues.get(interval.getAttribute());
Object value = interval.getValue();
if (row != null && (value instanceof Number)) {
Double dblValue = ((Number) value).doubleValue();
for (int i = 0; i < times.size(); i++) {
Long time = times.get(i);
if (interval.getStartTime() <= time && interval.getEndTime() >= time) {
row[i] = dblValue;
}
}
}
}
} catch (IndexOutOfBoundsException | TimeRangeException | StateSystemDisposedException e) {
return new TmfModelResponse<>(null, Status.FAILED, CommonStatusMessage.STATE_SYSTEM_FAILED);
}
Map<String, IYModel> models = new HashMap<>();
for (Entry<Integer, double[]> values : quarkToValues.entrySet()) {
models.put(String.valueOf(fQuarkToString.get(values.getKey())), new YModel(fIDToDisplayQuark.inverse().getOrDefault(values.getKey(), -1L), String.valueOf(fQuarkToString.get(values.getKey())), values.getValue()));
}
return new TmfModelResponse<>(new TmfCommonXAxisModel("Example XY data provider", nativeTimes, models), Status.COMPLETED, CommonStatusMessage.COMPLETED); //$NON-NLS-1$
}
private static List<Long> getTimes(ITmfStateSystem key, @Nullable List<Long> list) {
if (list == null) {
return Collections.emptyList();
}
List<@NonNull Long> times = new ArrayList<>();
for (long t : list) {
if (key.getStartTime() <= t && t <= key.getCurrentEndTime()) {
times.add(t);
}
}
Collections.sort(times);
return times;
}
@Deprecated
@Override
public TmfModelResponse<ITmfXyModel> fetchXY(TimeQueryFilter filter, @Nullable IProgressMonitor monitor) {
Map<String, Object> parameters = FetchParametersUtils.timeQueryToMap(filter);
return fetchXY(parameters, monitor);
}
}