Skip to content

Commit

Permalink
Tmf: Add API to auto-detect experiment type and instantiate experiment
Browse files Browse the repository at this point in the history
Provided trace resources for an experiment, an experiment type is
detected. Given a type id, a custom TmfExperiment is instantiated.
This API will be used by trace server to support custom experiments.

Signed-off-by: Neel Gondalia <ngondalia@blackberry.com>
Change-Id: I1b75b4c83ca7e4edd31eb9f6163de775328c1e25
Reviewed-on: https://git.eclipse.org/r/c/tracecompass/org.eclipse.tracecompass/+/200945
Reviewed-by: Marco Miller <marco.miller@ericsson.com>
Reviewed-by: Bernd Hufmann <bernd.hufmann@ericsson.com>
Tested-by: Trace Compass Bot <tracecompass-bot@eclipse.org>
Tested-by: Bernd Hufmann <bernd.hufmann@ericsson.com>
  • Loading branch information
ngondalia authored and bhufmann committed Apr 10, 2023
1 parent 620ef55 commit 6002ffd
Show file tree
Hide file tree
Showing 3 changed files with 152 additions and 2 deletions.
Expand Up @@ -46,6 +46,7 @@
import org.eclipse.tracecompass.tmf.core.parsers.custom.CustomXmlTraceDefinition;
import org.eclipse.tracecompass.tmf.core.signal.TmfSignalManager;
import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
import org.eclipse.tracecompass.tmf.core.trace.experiment.TmfExperiment;
import org.eclipse.tracecompass.tmf.core.util.Pair;

/**
Expand Down Expand Up @@ -610,4 +611,100 @@ private static boolean isUnique(TraceTypeHelper trace, Collection<Pair<Integer,
}
return count == 0;
}

/**
* Auto-detect an experiment type based on the List of ITmfTrace and an
* experiment type hint.
*
* @param traces
* the list of traces for which an experiment type is to be
* determined
* @param experimentTypeHint
* the ID of an experiment (like "o.e.l.specificexperiment" )
* @return a list of {@link TraceTypeHelper} sorted by confidence (highest
* first)
* @since 8.4
*/
public static List<TraceTypeHelper> selectExperimentType(List<ITmfTrace> traces, String experimentTypeHint) {
Comparator<Pair<Integer, TraceTypeHelper>> comparator = (o1, o2) -> {
int res = o2.getFirst().compareTo(o1.getFirst()); // invert so that highest confidence is first
if (res == 0) {
res = o1.getSecond().getName().compareTo(o2.getSecond().getName());
}
return res;
};

TreeSet<Pair<Integer, TraceTypeHelper>> validCandidates = new TreeSet<>(comparator);
final Iterable<TraceTypeHelper> traceTypeHelpers = TmfTraceType.getTraceTypeHelpers();
for (TraceTypeHelper traceTypeHelper : traceTypeHelpers) {
// Skip if it is not enabled or it is not an experiment
if (!traceTypeHelper.isEnabled() || !traceTypeHelper.isExperimentType()) {
continue;
}
int confidence = traceTypeHelper.validateExperimentWithTraces(traces);
if (confidence >= 0) {
if (traceTypeHelper.getTraceTypeId().equals(experimentTypeHint)) {
// if the trace type hint is valid, return it immediately
return Collections.singletonList(traceTypeHelper);
}
// insert in the tree map, ordered by confidence (highest
// confidence first) then name
Pair<Integer, TraceTypeHelper> element = new Pair<>(confidence, traceTypeHelper);
validCandidates.add(element);
}
}
List<TraceTypeHelper> returned = new ArrayList<>();
// If no valid candidates are found, then add generic experiment type
if (validCandidates.isEmpty()) {
Activator.logInfo("No valid candidates were found, selecting generic TMF experiment type"); //$NON-NLS-1$
returned.add(getTraceType(DEFAULT_EXPERIMENT_TYPE));
return returned;
}

if (validCandidates.size() != 1) {
List<Pair<Integer, TraceTypeHelper>> reducedCandidates = reduce(validCandidates);
if (reducedCandidates.isEmpty()) {
Activator.logInfo("Error reducing experiment type candidates, selecting generic TMF experiment type"); //$NON-NLS-1$
returned.add(getTraceType(DEFAULT_EXPERIMENT_TYPE));
return returned;
} else if (reducedCandidates.size() == 1) {
// Don't select the exp type if it has the lowest confidence
if (reducedCandidates.get(0).getFirst() > 0) {
returned.add(reducedCandidates.get(0).getSecond());
}
} else {
for (Pair<Integer, TraceTypeHelper> candidatePair : reducedCandidates) {
// Don't select the exp type if it has the lowest confidence
if (candidatePair.getFirst() > 0) {
returned.add(candidatePair.getSecond());
}
}
}
} else {
// Don't select the exp type if it has the lowest confidence
if (validCandidates.first().getFirst() > 0) {
returned.add(validCandidates.first().getSecond());
}
}
return returned;
}

/**
* Instantiate an experiment based on the provided type ID
*
* @param typeID
* the ID of the experiment (like "o.e.l.specificexperiment" )
* @return {@link TmfExperiment} instance or null if experiment type Id
* doesn't exist
* @throws CoreException
* if trace cannot be instantiated
* @since 8.4
*/
public static TmfExperiment instantiateExperiment(String typeID) throws CoreException {
IConfigurationElement ce = TRACE_TYPE_ATTRIBUTES.get(typeID);
if (ce == null) {
return null;
}
return (TmfExperiment) ce.createExecutableExtension(TmfTraceType.EXPERIMENT_TYPE_ATTR);
}
}
Expand Up @@ -17,11 +17,14 @@

package org.eclipse.tracecompass.tmf.core.project.model;

import java.util.List;

import org.eclipse.core.runtime.IStatus;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.tracecompass.tmf.core.project.model.TmfTraceType.TraceElementType;
import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
import org.eclipse.tracecompass.tmf.core.trace.TraceValidationStatus;
import org.eclipse.tracecompass.tmf.core.trace.experiment.TmfExperiment;

/**
* TraceTypeHelper, a helper that can link a few names to a configuration element
Expand Down Expand Up @@ -127,8 +130,30 @@ public IStatus validate(String path) {
* @return the confidence level (0 is lowest) or -1 if validation fails
*/
public int validateWithConfidence(String path) {
int result = -1;
IStatus status = fTrace.validate(null, path);
return getConfidenceFromStatus(status);
}

/**
* Validate an experiment against this experiment type with confidence level
*
* @param traces
* list of traces belonging to the experiment
* @return the confidence level (0 is lowest), or -1 if validation fails or
* trace is not an experiment
* @since 8.4
*/
public int validateExperimentWithTraces(List<ITmfTrace> traces) {
if (!isExperimentType()) {
return -1;
}
TmfExperiment exp = (TmfExperiment) fTrace;
IStatus status = exp.validateWithTraces(traces);
return getConfidenceFromStatus(status);
}

private static int getConfidenceFromStatus(IStatus status) {
int result = -1;
if (status.getSeverity() != IStatus.ERROR) {
result = 0;
if (status instanceof TraceValidationStatus) {
Expand Down Expand Up @@ -198,5 +223,4 @@ public void setEnabled(boolean enable) {
public String toString() {
return fName;
}

}
Expand Up @@ -70,6 +70,7 @@
import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
import org.eclipse.tracecompass.tmf.core.trace.TmfTrace;
import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager;
import org.eclipse.tracecompass.tmf.core.trace.TraceValidationStatus;
import org.eclipse.tracecompass.tmf.core.trace.indexer.ITmfPersistentlyIndexable;
import org.eclipse.tracecompass.tmf.core.trace.indexer.ITmfTraceIndexer;
import org.eclipse.tracecompass.tmf.core.trace.indexer.TmfBTreeTraceIndexer;
Expand Down Expand Up @@ -120,6 +121,11 @@ public class TmfExperiment extends TmfTrace implements ITmfPersistentlyIndexable
*/
private static final long CLOCK_OFFSET_THRESHOLD_NS = 500000;

/**
* The default confidence for the generic Tmf experiment
*/
private static final int DEFAULT_GENERIC_EXPERIMENT_CONFIDENCE = 1;

// ------------------------------------------------------------------------
// Attributes
// ------------------------------------------------------------------------
Expand Down Expand Up @@ -369,6 +375,29 @@ public IStatus validate(final IProject project, final String path) {
return Status.OK_STATUS;
}

/**
* Validates the experiment based on the traces provided. All subclasses of
* TmfExperiment should override this method to compute its own validation.
* If the experiment type is valid based on the provided traces, the
* method should return TraceValidationStatus with confidence. If it is not
* valid, an ERROR status should be returned. Note that the generic Tmf
* experiment reserves the confidence value of 1, therefore all extending
* classes should return a confidence level accordingly.
*
* @param traces
* list of ITmfTraces that is used to validate this experiment
* @return status an IStatus object with validation result. Use ERROR status
* to indicate an error, otherwise use TraceValidationStatus with a
* confidence.
* @since 8.4
*/
public IStatus validateWithTraces(List<ITmfTrace> traces) {
if (getClass() == TmfExperiment.class) {
return new TraceValidationStatus(DEFAULT_GENERIC_EXPERIMENT_CONFIDENCE, Activator.PLUGIN_ID);
}
return new Status(IStatus.ERROR, Activator.PLUGIN_ID, "class extends TmfExperiment"); //$NON-NLS-1$
}

// ------------------------------------------------------------------------
// Accessors
// ------------------------------------------------------------------------
Expand Down

0 comments on commit 6002ffd

Please sign in to comment.