blob: a304bfcb030f56c95a57ac0f5695c86b1e71f1e0 [file] [log] [blame]
/**********************************************************************
* Copyright (c) 2019 É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.incubator.internal.ros.core.analysis.messageflow;
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.concurrent.atomic.AtomicLong;
import java.util.function.Predicate;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.tracecompass.incubator.internal.ros.core.analysis.model.messageflow.IRosMessageFlowModel;
import org.eclipse.tracecompass.incubator.internal.ros.core.analysis.model.messageflow.RosMessageFlowSegment;
import org.eclipse.tracecompass.incubator.internal.ros.core.analysis.model.messageflow.RosMessageFlowSegment.SegmentType;
import org.eclipse.tracecompass.internal.tmf.core.model.AbstractTmfTraceDataProvider;
import org.eclipse.tracecompass.internal.tmf.core.model.filters.FetchParametersUtils;
import org.eclipse.tracecompass.tmf.core.dataprovider.DataProviderParameterUtils;
import org.eclipse.tracecompass.tmf.core.model.CommonStatusMessage;
import org.eclipse.tracecompass.tmf.core.model.filters.SelectionTimeQueryFilter;
import org.eclipse.tracecompass.tmf.core.model.filters.TimeQueryFilter;
import org.eclipse.tracecompass.tmf.core.model.timegraph.ITimeGraphArrow;
import org.eclipse.tracecompass.tmf.core.model.timegraph.ITimeGraphDataProvider;
import org.eclipse.tracecompass.tmf.core.model.timegraph.ITimeGraphRowModel;
import org.eclipse.tracecompass.tmf.core.model.timegraph.ITimeGraphState;
import org.eclipse.tracecompass.tmf.core.model.timegraph.TimeGraphArrow;
import org.eclipse.tracecompass.tmf.core.model.timegraph.TimeGraphEntryModel;
import org.eclipse.tracecompass.tmf.core.model.timegraph.TimeGraphModel;
import org.eclipse.tracecompass.tmf.core.model.timegraph.TimeGraphRowModel;
import org.eclipse.tracecompass.tmf.core.model.timegraph.TimeGraphState;
import org.eclipse.tracecompass.tmf.core.model.tree.TmfTreeModel;
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 com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
/**
* Data provider for the ROS Message Flow view
*
* @author Christophe Bedard
*/
@SuppressWarnings("restriction")
public class RosMessageFlowDataProvider extends AbstractTmfTraceDataProvider implements ITimeGraphDataProvider<@NonNull TimeGraphEntryModel> {
/** Data provider suffix ID */
public static final @NonNull String SUFFIX = ".dataprovider"; //$NON-NLS-1$
/** Separator for info in entry model name */
public static final @NonNull String SEGMENT_NAME_SEP = ";"; //$NON-NLS-1$
private static final AtomicLong ATOMIC_LONG = new AtomicLong();
private @NonNull IRosMessageFlowModel fModel;
/**
* Map for message flow segment <-> id
* TODO eventually unflatten this tree
*/
private final BiMap<RosMessageFlowSegment, Long> fSegmentToId = HashBiMap.create();
/**
* Constructor
*
* @param trace
* the trace for this provider
* @param model
* the message flow model
*/
public RosMessageFlowDataProvider(@NonNull ITmfTrace trace, @NonNull IRosMessageFlowModel model) {
super(trace);
fModel = model;
}
private long getSegmentId(RosMessageFlowSegment segment) {
return fSegmentToId.computeIfAbsent(segment, i -> ATOMIC_LONG.getAndIncrement());
}
@Deprecated
@Override
public @NonNull TmfModelResponse<@NonNull List<@NonNull TimeGraphEntryModel>> fetchTree(@NonNull TimeQueryFilter filter, @Nullable IProgressMonitor monitor) {
TmfModelResponse<@NonNull TmfTreeModel<@NonNull TimeGraphEntryModel>> response = fetchTree(FetchParametersUtils.timeQueryToMap(filter), monitor);
TmfTreeModel<@NonNull TimeGraphEntryModel> model = response.getModel();
List<@NonNull TimeGraphEntryModel> treeModel = null;
if (model != null) {
treeModel = model.getEntries();
}
return new TmfModelResponse<>(treeModel, response.getStatus(), response.getStatusMessage());
}
@Override
public @NonNull TmfModelResponse<@NonNull TmfTreeModel<@NonNull TimeGraphEntryModel>> fetchTree(@NonNull Map<@NonNull String, @NonNull Object> fetchParameters, @Nullable IProgressMonitor monitor) {
TimeQueryFilter filter = FetchParametersUtils.createTimeQuery(fetchParameters);
if (filter == null) {
return new TmfModelResponse<>(null, Status.FAILED, CommonStatusMessage.INCORRECT_QUERY_PARAMETERS);
}
if (!fModel.isModelDone()) {
return new TmfModelResponse<>(null, Status.RUNNING, CommonStatusMessage.RUNNING);
}
List<@NonNull TimeGraphEntryModel> entries = new ArrayList<>();
long rootId = ATOMIC_LONG.getAndIncrement();
entries.add(new TimeGraphEntryModel(rootId, -1, String.valueOf(getTrace().getName()), filter.getStart(), filter.getEnd()));
RosMessageFlowSegment firstSegment = fModel.getFirstSegment();
addTreeChildren(entries, firstSegment, rootId);
return new TmfModelResponse<>(new TmfTreeModel<>(Collections.emptyList(), entries), Status.COMPLETED, CommonStatusMessage.COMPLETED);
}
private void addTreeChildren(List<@NonNull TimeGraphEntryModel> entries, RosMessageFlowSegment segment, long parentId) {
// TODO eventually find a better way to represent this (not flat/similar
// to queues view)
long entryId = getSegmentId(segment);
entries.add(new RosMessageFlowSegmentEntryModel(entryId, parentId, segment.getStartTime(), segment.getEndTime(), segment));
Collection<RosMessageFlowSegment> next = segment.getNext();
for (RosMessageFlowSegment n : next) {
addTreeChildren(entries, n, parentId);
}
}
@Deprecated
@Override
public @NonNull TmfModelResponse<@NonNull List<@NonNull ITimeGraphRowModel>> fetchRowModel(@NonNull SelectionTimeQueryFilter filter, @Nullable IProgressMonitor monitor) {
@NonNull Map<@NonNull String, @NonNull Object> parameters = FetchParametersUtils.selectionTimeQueryToMap(filter);
TmfModelResponse<@NonNull TimeGraphModel> response = fetchRowModel(parameters, monitor);
TimeGraphModel model = response.getModel();
List<@NonNull ITimeGraphRowModel> rows = null;
if (model != null) {
rows = model.getRows();
}
return new TmfModelResponse<>(rows, response.getStatus(), response.getStatusMessage());
}
@Override
public @NonNull TmfModelResponse<@NonNull TimeGraphModel> fetchRowModel(@NonNull Map<@NonNull String, @NonNull Object> fetchParameters, @Nullable IProgressMonitor monitor) {
SelectionTimeQueryFilter filter = FetchParametersUtils.createSelectionTimeQuery(fetchParameters);
if (filter == null) {
return new TmfModelResponse<>(null, Status.FAILED, CommonStatusMessage.INCORRECT_QUERY_PARAMETERS);
}
if (!fModel.isModelDone()) {
return new TmfModelResponse<>(null, Status.RUNNING, CommonStatusMessage.RUNNING);
}
@NonNull Map<@NonNull Integer, @NonNull Predicate<@NonNull Multimap<@NonNull String, @NonNull Object>>> predicates = new HashMap<>();
Multimap<@NonNull Integer, @NonNull String> regexesMap = DataProviderParameterUtils.extractRegexFilter(fetchParameters);
if (regexesMap != null) {
predicates.putAll(computeRegexPredicate(regexesMap));
}
List<@NonNull ITimeGraphRowModel> rows = new ArrayList<>();
RosMessageFlowSegment firstSegment = fModel.getFirstSegment();
addRowModels(rows, firstSegment, predicates, monitor);
return new TmfModelResponse<>(new TimeGraphModel(rows), Status.COMPLETED, CommonStatusMessage.COMPLETED);
}
private void addRowModels(
List<@NonNull ITimeGraphRowModel> rows,
RosMessageFlowSegment segment,
@NonNull Map<@NonNull Integer, @NonNull Predicate<@NonNull Multimap<@NonNull String, @NonNull Object>>> predicates,
@Nullable IProgressMonitor monitor) {
@NonNull List<@NonNull ITimeGraphState> eventList = new ArrayList<>();
// TODO eventually find a better way
long entryId = getSegmentId(segment);
long startTime = segment.getStartTime();
long duration = segment.getEndTime() - startTime + 1;
TimeGraphState state = new TimeGraphState(startTime, duration, getMatchingSegmentState(segment.getType()));
applyFilterAndAddState(eventList, state, entryId, predicates, monitor);
rows.add(new TimeGraphRowModel(entryId, eventList));
Collection<RosMessageFlowSegment> next = segment.getNext();
for (RosMessageFlowSegment n : next) {
addRowModels(rows, n, predicates, monitor);
}
}
private static int getMatchingSegmentState(SegmentType type) {
// See RosMessageFlowPresentationProvider.State
switch (type) {
case PUB_QUEUE:
return 0;
case SUB_QUEUE:
return 1;
case SUB_CALLBACK:
return 2;
case INVALID:
break;
default:
break;
}
return 4;
}
@Deprecated
@Override
public @NonNull TmfModelResponse<@NonNull List<@NonNull ITimeGraphArrow>> fetchArrows(@NonNull TimeQueryFilter filter, @Nullable IProgressMonitor monitor) {
return fetchArrows(FetchParametersUtils.timeQueryToMap(filter), monitor);
}
@Override
public @NonNull TmfModelResponse<@NonNull List<@NonNull ITimeGraphArrow>> fetchArrows(@NonNull Map<@NonNull String, @NonNull Object> fetchParameters, @Nullable IProgressMonitor monitor) {
TimeQueryFilter filter = FetchParametersUtils.createTimeQuery(fetchParameters);
if (filter == null) {
return new TmfModelResponse<>(null, Status.FAILED, CommonStatusMessage.INCORRECT_QUERY_PARAMETERS);
}
if (!fModel.isModelDone()) {
return new TmfModelResponse<>(null, Status.RUNNING, CommonStatusMessage.RUNNING);
}
return new TmfModelResponse<>(getArrows(filter.getStart(), filter.getEnd()), ITmfResponse.Status.COMPLETED, CommonStatusMessage.COMPLETED);
}
private @Nullable List<@NonNull ITimeGraphArrow> getArrows(long startTime, long endTime) {
List<@NonNull ITimeGraphArrow> arrows = Lists.newArrayList();
RosMessageFlowSegment firstSegment = fModel.getFirstSegment();
addArrows(firstSegment, arrows, startTime, endTime);
return arrows;
}
private void addArrows(RosMessageFlowSegment parent, List<@NonNull ITimeGraphArrow> arrows, long startTime, long endTime) {
Collection<RosMessageFlowSegment> next = parent.getNext();
for (RosMessageFlowSegment n : next) {
if (parent.getEndTime() <= endTime && n.getStartTime() >= startTime) {
addArrow(parent, n, arrows);
}
addArrows(n, arrows, startTime, endTime);
}
}
private void addArrow(RosMessageFlowSegment parent, RosMessageFlowSegment child, List<@NonNull ITimeGraphArrow> arrows) {
long sourceId = getSegmentId(parent);
long destinationId = getSegmentId(child);
long time = parent.getEndTime();
long duration = child.getStartTime() - parent.getEndTime();
arrows.add(new TimeGraphArrow(sourceId, destinationId, time, duration, getMatchingArrowState(parent.getType(), child.getType())));
}
private static int getMatchingArrowState(SegmentType source, SegmentType destination) {
// See RosMessageFlowPresentationProvider.State
if (source.equals(SegmentType.PUB_QUEUE) && destination.equals(SegmentType.SUB_QUEUE)) {
return 4;
} else if (source.equals(SegmentType.SUB_QUEUE) && destination.equals(SegmentType.SUB_CALLBACK)) {
return 5;
} else if (destination.equals(SegmentType.PUB_QUEUE)) {
return 6;
}
return 7;
}
@Deprecated
@Override
public @NonNull TmfModelResponse<@NonNull Map<@NonNull String, @NonNull String>> fetchTooltip(@NonNull SelectionTimeQueryFilter filter, @Nullable IProgressMonitor monitor) {
return fetchTooltip(FetchParametersUtils.selectionTimeQueryToMap(filter), monitor);
}
@Override
public @NonNull TmfModelResponse<@NonNull Map<@NonNull String, @NonNull String>> fetchTooltip(@NonNull Map<@NonNull String, @NonNull Object> fetchParameters, @Nullable IProgressMonitor monitor) {
// TODO
return new TmfModelResponse<>(null, ITmfResponse.Status.COMPLETED, CommonStatusMessage.COMPLETED);
}
@Override
public @NonNull String getId() {
return getFullDataProviderId();
}
/**
* @return the full dataprovider ID
*/
public static @NonNull String getFullDataProviderId() {
return RosMessageFlowAnalysis.ID + SUFFIX;
}
}