blob: 40f0eb39e5b0d48a3f356b7c368e3b0275a35e77 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2016 É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.xaf.core.statemachine.variable;
import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.tracecompass.analysis.graph.core.base.IGraphWorker;
import org.eclipse.tracecompass.analysis.graph.core.base.TmfEdge;
import org.eclipse.tracecompass.analysis.graph.core.base.TmfGraph;
import org.eclipse.tracecompass.analysis.graph.core.base.TmfVertex;
import org.eclipse.tracecompass.analysis.graph.core.criticalpath.CriticalPathAlgorithmException;
import org.eclipse.tracecompass.analysis.os.linux.core.execution.graph.OsExecutionGraph;
import org.eclipse.tracecompass.analysis.os.linux.core.execution.graph.OsWorker;
import org.eclipse.tracecompass.analysis.os.linux.core.kernel.KernelAnalysisModule;
import org.eclipse.tracecompass.common.core.NonNullUtils;
import org.eclipse.tracecompass.incubator.internal.xaf.core.Activator;
import org.eclipse.tracecompass.incubator.internal.xaf.core.statemachine.backend.Attributes;
import org.eclipse.tracecompass.incubator.internal.xaf.core.statemachine.backend.BackendStateValue;
import org.eclipse.tracecompass.incubator.internal.xaf.core.statemachine.backend.StateMachineBackendAnalysis;
import org.eclipse.tracecompass.incubator.internal.xaf.core.statemachine.constraint.StateMachineConstraint;
import org.eclipse.tracecompass.incubator.internal.xaf.core.statemachine.exception.StateMachineNoInvalidCaseException;
import org.eclipse.tracecompass.incubator.internal.xaf.core.statemachine.exception.StateMachineNoValidCaseException;
import org.eclipse.tracecompass.incubator.internal.xaf.core.statemachine.exception.StateMachineStateSystemNotFoundException;
import org.eclipse.tracecompass.incubator.internal.xaf.core.statemachine.exception.StateMachineStateSystemTimeRangeException;
import org.eclipse.tracecompass.incubator.internal.xaf.core.statemachine.exception.StateMachineTIDNotFoundException;
import org.eclipse.tracecompass.incubator.internal.xaf.core.statemachine.exception.StateMachineUnexpectedEventException;
import org.eclipse.tracecompass.incubator.internal.xaf.core.statemachine.variable.utils.ActionOnMapKey;
import org.eclipse.tracecompass.incubator.internal.xaf.core.statemachine.variable.utils.CpuFrequency;
import org.eclipse.tracecompass.incubator.internal.xaf.core.statemachine.variable.utils.CriticalPathState;
import org.eclipse.tracecompass.incubator.internal.xaf.core.statemachine.variable.utils.ElementProbability;
import org.eclipse.tracecompass.incubator.internal.xaf.core.statemachine.variable.utils.InterruptionDuration;
import org.eclipse.tracecompass.incubator.internal.xaf.core.statemachine.variable.utils.InterruptionDurationSet;
import org.eclipse.tracecompass.incubator.internal.xaf.core.statemachine.variable.utils.InterruptionEventList;
import org.eclipse.tracecompass.incubator.internal.xaf.core.statemachine.variable.utils.InterruptionInterval;
import org.eclipse.tracecompass.incubator.internal.xaf.core.statemachine.variable.utils.InterruptionIntervalSet;
import org.eclipse.tracecompass.incubator.internal.xaf.core.statemachine.variable.utils.InterruptionIntervalSetDiff;
import org.eclipse.tracecompass.incubator.internal.xaf.core.statemachine.variable.utils.InterruptionReason;
import org.eclipse.tracecompass.incubator.internal.xaf.core.statemachine.variable.utils.IsiSampleIterator;
import org.eclipse.tracecompass.incubator.internal.xaf.core.statemachine.variable.utils.ResponsibilityMap;
import org.eclipse.tracecompass.incubator.internal.xaf.core.statemachine.variable.utils.State;
import org.eclipse.tracecompass.incubator.internal.xaf.ui.statemachine.StateMachineBenchmark;
import org.eclipse.tracecompass.incubator.internal.xaf.ui.statemachine.StateMachineInstance.InstanceStepInformation;
import org.eclipse.tracecompass.incubator.internal.xaf.ui.statemachine.StateMachineInstanceGroup;
import org.eclipse.tracecompass.incubator.internal.xaf.ui.statemachine.StateMachineReport;
import org.eclipse.tracecompass.incubator.internal.xaf.ui.statemachine.StateMachineSegment;
import org.eclipse.tracecompass.incubator.internal.xaf.ui.statemachine.StateMachineUtils.TimestampInterval;
import org.eclipse.tracecompass.internal.analysis.graph.core.base.TmfGraphVisitor;
import org.eclipse.tracecompass.internal.analysis.graph.core.criticalpath.CriticalPathAlgorithmBounded;
import org.eclipse.tracecompass.internal.segmentstore.core.treemap.TreeMapStore;
import org.eclipse.tracecompass.segmentstore.core.ISegment;
import org.eclipse.tracecompass.segmentstore.core.ISegmentStore;
import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem;
import org.eclipse.tracecompass.statesystem.core.exceptions.AttributeNotFoundException;
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.event.ITmfEvent;
import org.eclipse.tracecompass.tmf.core.timestamp.ITmfTimestamp;
import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestamp;
import org.eclipse.tracecompass.tmf.core.trace.ITmfContext;
import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import com.google.common.base.Joiner;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
/**
* Class that contains all the needed resources to perform an analysis for different variables
* @author Raphaël Beamonte
*/
@SuppressWarnings("restriction")
public class StateMachineVariableAnalysis {
private StateMachineVariable variable;
private StateMachineConstraint constraint;
private List<InstanceStepInformation> invalidIsiList;
private List<InstanceStepInformation> validIsiList;
private Multimap<Map<InterruptionReason, Integer>, InstanceStepInformation> invalidKeyToIsiMap;
private Map<Map<InterruptionReason, Integer>, Collection<InstanceStepInformation>> keyMapToclosestValidIsiListMap;
private ResponsibilityMap<InterruptionReason> analysisResponsibilityMap = null;
private int differentInvalidCases = -1;
private int differentValidCases = -1;
private static final int MAXIMUM_REORDERED_ISI = 10000;
static final double REALISTIC_FACTOR = 0.1; // 10%
/** Index of the number of instances dropped because no state system was found */
public static final int NO_STATE_SYSTEM_FOUND = 0;
/** Index of the number of instances dropped because no TID was found */
public static final int NO_TID_FOUND = 1;
/** Index of the number of instances dropped because they were out of time range */
public static final int OUT_OF_TIME_RANGE = 2;
private int[] droppedInstances = new int[3];
/**
* Constructor of the StateMachineVariableAnalysis
* @param variable The variable on which that StateMachineVariableAnalysis applies
* @param constraint The constraint on which that StateMachineVariableAnalysis applies
* @param invalidIsiList The list of invalid instance step information
* @param validIsiList The list of valid instance step information
*/
public StateMachineVariableAnalysis(StateMachineVariable variable, StateMachineConstraint constraint, List<InstanceStepInformation> invalidIsiList, List<InstanceStepInformation> validIsiList) {
this.variable = variable;
this.constraint = constraint;
this.invalidIsiList = invalidIsiList;
this.validIsiList = validIsiList;
this.invalidKeyToIsiMap = null;
this.keyMapToclosestValidIsiListMap = null;
}
/**
* Constructor of the StateMachineVariableAnalysis
* @param variable The variable on which that StateMachineVariableAnalysis applies
* @param constraint The constraint on which that StateMachineVariableAnalysis applies
* @param invalidIsiList The list of invalid instance step information
* @param validIsiList The list of valid instance step information
* @param invalidKeyToIsiMap A map from invalid instance step information keyMap to the corresponding instance step information
* @param closestValidKeyToIsiListMap A map from invalid instance step information keyMap to the list of the closest valid instance step information
*/
public StateMachineVariableAnalysis(StateMachineVariable variable, StateMachineConstraint constraint, List<InstanceStepInformation> invalidIsiList, List<InstanceStepInformation> validIsiList, Multimap<Map<InterruptionReason, Integer>, InstanceStepInformation> invalidKeyToIsiMap, Map<Map<InterruptionReason, Integer>, Collection<InstanceStepInformation>> closestValidKeyToIsiListMap) {
this.variable = variable;
this.constraint = constraint;
this.invalidIsiList = invalidIsiList;
this.validIsiList = validIsiList;
this.invalidKeyToIsiMap = invalidKeyToIsiMap;
this.keyMapToclosestValidIsiListMap = closestValidKeyToIsiListMap;
}
/**
* To get the number of different invalid cases
* @return The number of different invalid cases
*/
public int getDifferentInvalidCases() {
return differentInvalidCases;
}
/**
* To get the number of different valid cases
* @return The number of different valid cases
*/
public int getDifferentValidCases() {
return differentValidCases;
}
/**
* To get the global analysis responsibility map
* @return The analysis responsibility map
*/
public ResponsibilityMap<InterruptionReason> getAnalysisResponsibilityMap() {
return analysisResponsibilityMap;
}
/**
* An InterruptionEventRunner
* @author Raphaël Beamonte
*/
public static abstract class InterruptionEventRunner {
/**
* The ResponsibilityMapGetter that will be used for this runner
*/
protected ResponsibilityMapGetter<InterruptionReason> responsibilityMapGetter = new DefaultResponsibilityMapGetter();
/**
* Method to get the ResponsibilityMap of InterruptionReason for a given InterruptionIntervalSetDiff
* @param iisd The InterruptionIntervalSetDiff for which to get the ResponsibilityMap
* @return The ResponsibilityMap of InterruptionReason for the given InterruptionIntervalSetDiff
*/
public ResponsibilityMap<InterruptionReason> getResponsibilityMap(InterruptionIntervalSetDiff iisd) {
return responsibilityMapGetter.execute(iisd);
}
/**
* Method to get the list of InterruptionEventList that happened during a given instance step
* @param isi The instance step information
* @return The List of InterruptionEventList
* @throws StateMachineStateSystemNotFoundException When the state machine state system is not found
* @throws StateMachineTIDNotFoundException When the instance does not have any TID
* @throws StateMachineStateSystemTimeRangeException When the time requested is outside the state machine state system time range
*/
public abstract List<InterruptionEventList> execute(InstanceStepInformation isi) throws StateMachineStateSystemNotFoundException, StateMachineTIDNotFoundException, StateMachineStateSystemTimeRangeException;
}
/**
* An InterruptionEventGetter to get the interruption event list for a given timestamp interval, state interval, and event
* @author Raphaël Beamonte
*/
public static abstract class InterruptionEventGetter {
/**
* Method to get the InterruptionEventList
* @param ti The timestamp interval
* @param si The state interval
* @param e The event
* @return The corresponding interruption event list
* @throws StateMachineStateSystemNotFoundException When the state machine state system is not found
* @throws StateMachineTIDNotFoundException When the instance does not have any TID
* @throws StateMachineStateSystemTimeRangeException When the time requested is outside the state machine state system time range
* @throws StateMachineUnexpectedEventException When the event received is not of the type we expected (can happen when two events share the same timestamp)
*/
public abstract InterruptionEventList execute(TimestampInterval ti, ITmfStateInterval si, ITmfEvent e) throws StateMachineStateSystemNotFoundException, StateMachineTIDNotFoundException, StateMachineStateSystemTimeRangeException, StateMachineUnexpectedEventException;
}
/**
* A ResponsibilityMapGetter to get the responsibility map from an InterruptionIntervalSetDiff
* @param <K> The kind of ResponsibilityMap that getter returns
* @author Raphaël Beamonte
*/
public static abstract class ResponsibilityMapGetter<K extends Comparable<K>> {
/**
* Method to get the ResponsibilityMap from an InterruptionIntervalSetDiff
* @param iisd InterruptionIntervalSetDiff from which to compute the ResponsibilityMap
* @return The computed ResponsibilityMap
*/
public abstract ResponsibilityMap<K> execute(InterruptionIntervalSetDiff iisd);
}
/**
* The default responsibility map getter, to be used for most cases
* @author Raphaël Beamonte
*/
public static class DefaultResponsibilityMapGetter extends ResponsibilityMapGetter<InterruptionReason> {
@Override
public ResponsibilityMap<InterruptionReason> execute(InterruptionIntervalSetDiff iisd) {
return iisd.getMeanResponsibilityMap();
}
}
/**
* The default interruption event runner, to be used for most cases
* @author Raphaël Beamonte
*/
public static class DefaultInterruptionEventRunner extends InterruptionEventRunner {
private StateMachineVariable variable = null;
private String attribute = null;
private InterruptionEventGetter interruptionEventGetter = null;
private Map<ITmfTrace, ITmfContext> contextPerTrace = new HashMap<>();
/**
* Constructor for the default interruption event runner
* @param variable The state machine variable on which that runner is working
* @param attribute The state machine state system attribute on which that runner is working
* @param interruptionEventGetter The interruption event getter to use to get the events
*/
public DefaultInterruptionEventRunner(@NonNull StateMachineVariable variable, @NonNull String attribute, @NonNull InterruptionEventGetter interruptionEventGetter) {
this.variable = variable;
this.attribute = attribute;
this.interruptionEventGetter = interruptionEventGetter;
this.responsibilityMapGetter = new DefaultResponsibilityMapGetter();
}
/**
* Constructor for the default interruption event runner
* @param variable The state machine variable on which that runner is working
* @param attribute The state machine state system attribute on which that runner is working
* @param interruptionEventGetter The interruption event getter to use to get the events
* @param responsibilityMapGetter The responsibility map getter to use to get the responsibility map for an InterruptionIntervalSetDiff
*/
public DefaultInterruptionEventRunner(@NonNull StateMachineVariable variable, @NonNull String attribute, @NonNull InterruptionEventGetter interruptionEventGetter, @NonNull ResponsibilityMapGetter<InterruptionReason> responsibilityMapGetter) {
this.variable = variable;
this.attribute = attribute;
this.interruptionEventGetter = interruptionEventGetter;
this.responsibilityMapGetter = responsibilityMapGetter;
}
@Override
public List<InterruptionEventList> execute(InstanceStepInformation isi) throws StateMachineStateSystemNotFoundException, StateMachineTIDNotFoundException, StateMachineStateSystemTimeRangeException {
// Get the instance group
StateMachineInstanceGroup group = isi.instance.getStateMachineInstanceGroup();
/* If we don't have kernel analysis modules for that group, we can
* just drop that analysis as we won't have the needed information to
* analyze that constraint. We can thus return.
*/
if (group.getStateMachineBackendAnalysisModules().isEmpty()) {
throw new StateMachineStateSystemNotFoundException();
}
/* Thread ID of our instance. We currently only manage
* situations in which our model follows an unique TID
*/
Integer tid = isi.instance.getVTid();
if (tid == null) {
throw new StateMachineTIDNotFoundException();
}
/* Get the timestamp interval for this variable application
*/
TimestampInterval ti = isi.getVariableInterval(variable.getName());
/* List in which we will store the events corresponding to an
* increment of the counter on which that variable is based
*/
List<InterruptionEventList> interruptionEventList = new ArrayList<>();
/// USING THE NEW STATE ATTRIBUTE
boolean analysisDone = false;
// For each analysis module...
for (StateMachineBackendAnalysis stateMachineBackendAnalysis : group.getStateMachineBackendAnalysisModules()) {
ITmfStateSystem ss = stateMachineBackendAnalysis.getStateSystem();
if (ss == null || ss.getCurrentEndTime() < ti.getEndTime().getValue() || ss.getStartTime() > ti.getStartTime().getValue()) {
continue;
}
analysisDone = true;
// Kernel trace on which we're currently working
ITmfTrace trace = stateMachineBackendAnalysis.getKernelTrace();
// To store the events we'll read
ITmfEvent e = null;
// To store the context for this trace
ITmfContext ctx = null;
// Get all the intervals for the period of time
StateMachineBenchmark benchmarkObject = new StateMachineBenchmark("Analysis SS Get"); //$NON-NLS-1$
List<ITmfStateInterval> intervals = stateMachineBackendAnalysis.getAllStateIntervalInPeriod(tid, ti.getStartTime().getValue(), ti.getEndTime().getValue(), attribute);
benchmarkObject.stop();
//System.out.println(intervals.size() + " intervals for attribute " + attribute);
//StateMachineReport.debug("NUMBER OF INTERVALS: " + intervals.size());
for (ITmfStateInterval si : intervals) {
if (e == null) {
ctx = contextPerTrace.get(trace);
if (ctx != null) {
// Get the next event in the trace
e = trace.getNext(ctx);
// If our event is after our intervalStart... we'll need to seek :(
/* TODO: probably replace > by >= as it's possible that we're still
* at the right timestamp but me missed the right event if two (or
* more) events share the same timestamp
*/
if (e.getTimestamp().getValue() > si.getStartTime()) {
ctx.dispose();
ctx = null;
}
}
if (ctx == null) {
ctx = trace.seekEvent(TmfTimestamp.create(si.getStartTime(), ITmfTimestamp.NANOSECOND_SCALE));
contextPerTrace.put(trace, ctx);
// Get the initial event of the interval
e = trace.getNext(ctx);
}
}
// Can't happen
if (e == null) {
throw new RuntimeException("e is null and can't be null... what happened?!"); //$NON-NLS-1$
}
while (e.getTimestamp().getValue() < si.getStartTime()) {
e = trace.getNext(ctx);
}
InterruptionEventList events = null;
while (events == null && e.getTimestamp().getValue() == si.getStartTime()) {
try {
events = interruptionEventGetter.execute(ti, si, e);
} catch (StateMachineUnexpectedEventException ex) {
e = trace.getNext(ctx);
}
}
if (events != null) {
interruptionEventList.add(events);
} else {
Activator.getInstance().logWarning("events is null and shouldn't be null... what happened?!"); //$NON-NLS-1$
}
}
}
// If we couldn't do the analysis
if (!analysisDone) {
throw new StateMachineStateSystemTimeRangeException();
}
return interruptionEventList;
}
}
/**
* To perform a partial analysis using only invalid instances
* @param runner The runner to use to get the interruption event list and the responsibility map
* @throws StateMachineNoInvalidCaseException When no invalid case is found
*/
public void doPartialAnalysis(InterruptionEventRunner runner) throws StateMachineNoInvalidCaseException {
StateMachineBenchmark benchmarkObjectAnalysis = new StateMachineBenchmark("Initial analysis (PARTIAL)"); //$NON-NLS-1$
// Local variables
//List<InterruptionIntervalSet> invalidiisList = new ArrayList<>();
Map<Map<InterruptionReason, Integer>, InterruptionIntervalSet> keyMapToiisMap = new HashMap<>();
//Map<InterruptionReason, Integer> reasonToInvalidInstanceCounterMap = new HashMap<>();
// Reset object attributes
invalidKeyToIsiMap = HashMultimap.create();
analysisResponsibilityMap = new ResponsibilityMap<>(0);
keyMapToclosestValidIsiListMap = new HashMap<>();
// Reset all counters of dropped instances
resetDroppedInstances();
Comparator<InstanceStepInformation> isiComparator = new Comparator<InstanceStepInformation>() {
@Override
public int compare(InstanceStepInformation isi1, InstanceStepInformation isi2) {
TimestampInterval t1 = isi1.getVariableInterval(variable.getName());
TimestampInterval t2 = isi2.getVariableInterval(variable.getName());
return t1.compareTo(t2);
}
};
StateMachineBenchmark benchmarkObject = new StateMachineBenchmark("Analysis get data"); //$NON-NLS-1$
/////////////////////////////////////////////
// COMPUTE SETS FOR INVALID INSTANCE STEPS //
/////////////////////////////////////////////
// For invalid instances
IsiSampleIterator invalidIsiIterator = new IsiSampleIterator(invalidIsiList);
int i = 0;
StateMachineReport.debug("Invalid instances: " + invalidIsiList.size()); //$NON-NLS-1$
StateMachineReport.debug("Treating ? " + invalidIsiIterator.size()); //$NON-NLS-1$
while (invalidIsiIterator.hasNext()) {
Iterator<InstanceStepInformation> isiIterator;
if (invalidIsiIterator.useFullPopulation) {
isiIterator = invalidIsiIterator;
} else {
Set<InstanceStepInformation> isiSet = new TreeSet<>(isiComparator);
int limit = MAXIMUM_REORDERED_ISI;
while (invalidIsiIterator.hasNext() && --limit > 0) {
isiSet.add(invalidIsiIterator.next());
}
isiIterator = isiSet.iterator();
}
while (isiIterator.hasNext()) {
InstanceStepInformation isi = isiIterator.next();
List<InterruptionEventList> interruptionEventLists;
try {
interruptionEventLists = runner.execute(isi);
} catch (StateMachineStateSystemNotFoundException | StateMachineTIDNotFoundException | StateMachineStateSystemTimeRangeException e) {
addDroppedInstance(e);
invalidIsiIterator.inc();
continue;
}
// Then, create an InterruptionDurationSet that will represent this case, we will put in it all
// the events and it will represents globally what happened in here
InterruptionDurationSet ids = new InterruptionDurationSet();
for (InterruptionEventList taskList : interruptionEventLists) {
for (InterruptionDuration id : taskList.split()) {
ids.add(id);
}
}
Map<InterruptionReason, Integer> keyMap = ids.keyMap();
invalidKeyToIsiMap.put(keyMap, isi);
InterruptionIntervalSet invalidIis = keyMapToiisMap.get(keyMap);
if (invalidIis == null) {
invalidIis = new InterruptionIntervalSet(constraint.getDirection());
keyMapToiisMap.put(keyMap, invalidIis);
}
invalidIis.addDurationSet(ids);
/*for (InterruptionReason reason : ids.getReasonSet()) {
reasonToInvalidInstanceCounterMap.put(reason, reasonToInvalidInstanceCounterMap.getOrDefault(reason, 0) + 1);
}*/
// DEBUG
i++;
if (i%20 == 0) {
StateMachineReport.debug(Integer.toString(i));
}
}
}
if (invalidKeyToIsiMap.isEmpty()) {
throw new StateMachineNoInvalidCaseException();
}
benchmarkObject.stop();
benchmarkObject = new StateMachineBenchmark("Analysis weight data"); //$NON-NLS-1$
InterruptionIntervalSetDiff iisd = new InterruptionIntervalSetDiff();
for (InterruptionIntervalSet iis : keyMapToiisMap.values()) {
for (InterruptionInterval ii : iis.getMergedIntervals()) {
iisd.add(ii, ii.getCounter());
}
}
analysisResponsibilityMap.mergeAll(runner.getResponsibilityMap(iisd));
/*for (Entry<InterruptionReason, Integer> entry : reasonToInvalidInstanceCounterMap.entrySet()) {
analysisResponsibilityMap.put(entry.getKey(), entry.getValue().doubleValue() / invalidIsiIterator.size());
}*/
/*System.out.println("CASE 1 => " + runner.getResponsibilityMap(iisd));
System.out.println("CASE 2 => " + analysisResponsibilityMap);*/
benchmarkObject.stop();
// Update counters
differentValidCases = -1;
differentInvalidCases = invalidKeyToIsiMap.keySet().size();
benchmarkObjectAnalysis.stop();
}
/**
* To perform a full analysis comparing valid and invalid instances
* @param runner The runner to use to get the interruption event list and the responsibility map
* @throws StateMachineNoValidCaseException When no valid case is found for the comparison
* @throws StateMachineNoInvalidCaseException When no invalid case is found for the comparison
*/
public void doAnalysis(InterruptionEventRunner runner) throws StateMachineNoValidCaseException, StateMachineNoInvalidCaseException {
StateMachineBenchmark benchmarkObjectAnalysis = new StateMachineBenchmark("Initial analysis (FULL)"); //$NON-NLS-1$
// Local variables
// List of the InterruptionIntervalSet
Map<Map<InterruptionReason, Integer>, InterruptionIntervalSet> validiisMap = new HashMap<>();
// Map of keyMap to valid InstanceStepInformation
Multimap<Map<InterruptionReason, Integer>, InstanceStepInformation> validKeyToIsiMap = HashMultimap.create();
Map<Map<InterruptionReason, Integer>, Map<InterruptionIntervalSet, List<InterruptionDurationSet>>> keyMapToSolutionsMap = new HashMap<>();
Map<Map<InterruptionReason, Integer>, InterruptionIntervalSet> keyMapToiisMap = new HashMap<>();
// Reset object attributes
invalidKeyToIsiMap = HashMultimap.create();
analysisResponsibilityMap = new ResponsibilityMap<>(0);
keyMapToclosestValidIsiListMap = new HashMap<>();
// Reset all counters of dropped instances
resetDroppedInstances();
Comparator<InstanceStepInformation> isiComparator = new Comparator<InstanceStepInformation>() {
@Override
public int compare(InstanceStepInformation isi1, InstanceStepInformation isi2) {
TimestampInterval t1 = isi1.getVariableInterval(variable.getName());
TimestampInterval t2 = isi2.getVariableInterval(variable.getName());
return t1.compareTo(t2);
}
};
StateMachineBenchmark benchmarkObject = new StateMachineBenchmark("Analysis get data"); //$NON-NLS-1$
///////////////////////////////////////////
// COMPUTE SETS FOR VALID INSTANCE STEPS //
///////////////////////////////////////////
// For valid instances
IsiSampleIterator validIsiIterator = new IsiSampleIterator(validIsiList);
int i = 0;
StateMachineReport.debug("Valid instances: " + validIsiList.size()); //$NON-NLS-1$
StateMachineReport.debug("Treating ? " + validIsiIterator.size()); //$NON-NLS-1$
while (validIsiIterator.hasNext()) {
Iterator<InstanceStepInformation> isiIterator;
if (validIsiIterator.useFullPopulation) {
isiIterator = validIsiIterator;
} else {
Set<InstanceStepInformation> isiSet = new TreeSet<>(isiComparator);
int limit = MAXIMUM_REORDERED_ISI;
while (validIsiIterator.hasNext() && --limit > 0) {
isiSet.add(validIsiIterator.next());
}
isiIterator = isiSet.iterator();
}
while (isiIterator.hasNext()) {
InstanceStepInformation isi = isiIterator.next();
List<InterruptionEventList> interruptionEventLists;
try {
interruptionEventLists = runner.execute(isi);
} catch (StateMachineStateSystemNotFoundException | StateMachineTIDNotFoundException | StateMachineStateSystemTimeRangeException e) {
addDroppedInstance(e);
validIsiIterator.inc();
continue;
}
InterruptionDurationSet ids = new InterruptionDurationSet();
for (InterruptionEventList taskList : interruptionEventLists) {
for (InterruptionDuration id : taskList.split()) {
ids.add(id);
}
}
//interruptionEventLists.clear();
Map<InterruptionReason, Integer> keyMap = ids.keyMap();
validKeyToIsiMap.put(keyMap, isi);
InterruptionIntervalSet iis = validiisMap.get(keyMap);
if (iis == null) {
iis = new InterruptionIntervalSet(constraint.getDirection());
validiisMap.put(keyMap, iis);
}
iis.addDurationSet(ids);
// DEBUG
i++;
if (i%20 == 0) {
StateMachineReport.debug(Integer.toString(i));
}
}
}
if (validiisMap.isEmpty()) {
throw new StateMachineNoValidCaseException();
}
//////////////////////////
// WORK ON INVALID ONES //
//////////////////////////
// For invalid instances
IsiSampleIterator invalidIsiIterator = new IsiSampleIterator(invalidIsiList);
i = 0;
StateMachineReport.debug("Invalid instances: " + invalidIsiList.size()); //$NON-NLS-1$
StateMachineReport.debug("Treating ? " + invalidIsiIterator.size()); //$NON-NLS-1$
while (invalidIsiIterator.hasNext()) {
Iterator<InstanceStepInformation> isiIterator;
if (invalidIsiIterator.useFullPopulation) {
isiIterator = invalidIsiIterator;
} else {
Set<InstanceStepInformation> isiSet = new TreeSet<>(isiComparator);
int limit = MAXIMUM_REORDERED_ISI;
while (invalidIsiIterator.hasNext() && --limit > 0) {
isiSet.add(invalidIsiIterator.next());
}
isiIterator = isiSet.iterator();
}
while (isiIterator.hasNext()) {
InstanceStepInformation isi = isiIterator.next();
List<InterruptionEventList> interruptionEventLists;
try {
interruptionEventLists = runner.execute(isi);
} catch (StateMachineStateSystemNotFoundException | StateMachineTIDNotFoundException | StateMachineStateSystemTimeRangeException e) {
addDroppedInstance(e);
invalidIsiIterator.inc();
continue;
}
// Then, create an InterruptionDurationSet that will represent this case, we will put in it all
// the events and it will represents globally what happened in here
InterruptionDurationSet ids = new InterruptionDurationSet();
for (InterruptionEventList taskList : interruptionEventLists) {
for (InterruptionDuration id : taskList.split()) {
ids.add(id);
}
}
Map<InterruptionReason, Integer> keyMap = ids.keyMap();
invalidKeyToIsiMap.put(keyMap, isi);
InterruptionIntervalSet invalidIis = keyMapToiisMap.get(keyMap);
if (invalidIis == null) {
invalidIis = new InterruptionIntervalSet(constraint.getDirection());
keyMapToiisMap.put(keyMap, invalidIis);
}
invalidIis.addDurationSet(ids);
Map<InterruptionIntervalSet, List<InterruptionDurationSet>> dataMap = keyMapToSolutionsMap.get(keyMap);
if (dataMap == null) {
dataMap = new HashMap<>();
keyMapToSolutionsMap.put(keyMap, dataMap);
}
for (InterruptionIntervalSet iis : validiisMap.values()) {
List<InterruptionDurationSet> data = dataMap.get(iis);
if (data == null) {
data = new ArrayList<>();
dataMap.put(iis, data);
}
data.add(iis.distance(ids));
}
// DEBUG
i++;
if (i%20 == 0) {
StateMachineReport.debug(Integer.toString(i));
}
}
}
if (invalidKeyToIsiMap.isEmpty()) {
throw new StateMachineNoInvalidCaseException();
}
benchmarkObject.stop();
benchmarkObject = new StateMachineBenchmark("Analysis weight data"); //$NON-NLS-1$
// Compute distance and store it accordingly
for (Entry<Map<InterruptionReason, Integer>, Map<InterruptionIntervalSet, List<InterruptionDurationSet>>> entryReasonSolutions : keyMapToSolutionsMap.entrySet()) {
// Re-organize the solutions in order of distance to the current invalid situation
Map<Integer, List<InterruptionIntervalSet>> validIisPerDistance = new TreeMap<>();
for (Entry<InterruptionIntervalSet, List<InterruptionDurationSet>> entrySolutionDistances : entryReasonSolutions.getValue().entrySet()) {
// TODO: well, I had a good reason to use -1 instead of 0, but I don't remember it!
int distance = -1;
for (InterruptionDurationSet ids : entrySolutionDistances.getValue()) {
distance += ids.size();
}
distance = (int) Math.ceil((double) distance / (double) entrySolutionDistances.getValue().size());
List<InterruptionIntervalSet> iisList = validIisPerDistance.get(distance);
if (iisList == null) {
iisList = new ArrayList<>();
validIisPerDistance.put(distance, iisList);
}
iisList.add(entrySolutionDistances.getKey());
}
// Compute the size of the invalid set
double s = 0;
for (int value : entryReasonSolutions.getKey().values()) {
s += value;
}
double totalsize = Math.max(1.0, s);
// To count the total number of occurrences up to now
double totaloccurrences = 0;
// For the penalty calculation
double penalty = REALISTIC_FACTOR * (1.0 - 1.0 / entryReasonSolutions.getValue().keySet().size());
Set<ElementProbability<InterruptionIntervalSet>> iisPerProbability = new TreeSet<>();
for (Entry<Integer, List<InterruptionIntervalSet>> entryIisPerDistances : validIisPerDistance.entrySet()) {
double distance = entryIisPerDistances.getKey();
// We need to add to the totaloccurrences counter
for (InterruptionIntervalSet iis : entryIisPerDistances.getValue()) {
totaloccurrences += iis.getCounter();
}
// Then we treat each list, for which we'll add the probability
for (InterruptionIntervalSet iis : entryIisPerDistances.getValue()) {
double occurrences = iis.getCounter();
double probability = (occurrences / totaloccurrences) * (distance / totalsize) + (totalsize - distance) / totalsize - penalty;
// Only take that probability into account if it's more than 0%
if (probability > 0) {
iisPerProbability.add(new ElementProbability<>(iis, (int) occurrences, (int) distance, probability));
}
}
}
// TODO: remove debug start
/*
System.out.println("Invalid interruption list " + //$NON-NLS-1$
keyMapToiisMap.get(entryReasonSolutions.getKey()) +
" has been encountered " + //$NON-NLS-1$
checkNotNull(keyMapToiisMap.get(entryReasonSolutions.getKey())).getCounter() +
" times"); //$NON-NLS-1$
System.out.println("Interruption lists identified as potential expected list instead of this invalid one:"); //$NON-NLS-1$
String[] columnNames = {
"Valid interruption list ", //$NON-NLS-1$
"Distance ", //$NON-NLS-1$
"Occurrences ", //$NON-NLS-1$
"Weight (%) ", //$NON-NLS-1$
};
List<Object[]> tableLines = new ArrayList<>();
Iterator<ElementProbability<InterruptionIntervalSet>> it2 = iisPerProbability.iterator();
while (it2.hasNext()) {
ElementProbability<InterruptionIntervalSet> proba = it2.next();
tableLines.add(new Object[]{
proba.element.toStringOneLine(),
new Integer(proba.distance),
new Integer(proba.occurrences),
String.format(" %.4f", proba.probability * 100), //$NON-NLS-1$
});
}
Object[][] res = new Object[tableLines.size()][];
tableLines.toArray(res);
TextTable tt = new TextTable(columnNames, res);
tt.setAddRowNumbering(true);
tt.printTable();
System.out.println(""); //$NON-NLS-1$*/
// TODO: remove debug end
keyMapToclosestValidIsiListMap.put(entryReasonSolutions.getKey(), validKeyToIsiMap.get(iisPerProbability.iterator().next().element.keyMap()));
InterruptionIntervalSetDiff iisd = null;
InterruptionIntervalSet iisError = NonNullUtils.checkNotNull(keyMapToiisMap.get(entryReasonSolutions.getKey()));
Iterator<ElementProbability<InterruptionIntervalSet>> it = iisPerProbability.iterator();
while (it.hasNext()) {
ElementProbability<InterruptionIntervalSet> proba = it.next();
if (proba.probability > .5 || iisd == null) {
InterruptionIntervalSetDiff iisdlocal = iisError.substract(proba.element);
if (iisd == null) {
iisd = iisdlocal;
} else {
iisd = iisd.interUnion(iisdlocal);
}
} else {
break;
}
}
// TODO: REMOVE DEBUG START
/*String[] header = {"Valid list", "Distance", "Occurrences", "Weight"}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
String[][] strs = new String[iisPerProbability.size()][4];
int idx = 0;
int progressSize = 10;
it = iisPerProbability.iterator();
while (it.hasNext()) {
ElementProbability<InterruptionIntervalSet> proba = it.next();
double ratioValue = proba.probability * 100;
String symbol = StateMachineReport.progressBar(ratioValue, progressSize);
strs[idx][0] = String.format("%s", proba.element.toString() + "\n "); //$NON-NLS-1$
strs[idx][1] = String.format("%d", proba.distance); //$NON-NLS-1$
strs[idx][2] = String.format("%d", proba.occurrences); //$NON-NLS-1$
strs[idx][3] = String.format("%.2f%% %s", ratioValue, symbol); //$NON-NLS-1$
idx++;
}
StateMachineReport.R.println_table(header, strs, Arrays.asList(new Integer[]{1, 2, 3}));
StateMachineReport.R.println();
StateMachineReport.R.println(iisError);
StateMachineReport.R.println();
StateMachineReport.R.println(iisd);
StateMachineReport.R.println();*/
// TODO: REMOVE DEBUG END
if (iisd != null) {
ResponsibilityMap<InterruptionReason> rm = runner.getResponsibilityMap(iisd);
analysisResponsibilityMap.mergeAll(rm);
}
}
benchmarkObject.stop();
// Update counters
differentValidCases = validKeyToIsiMap.keySet().size();
differentInvalidCases = invalidKeyToIsiMap.keySet().size();
benchmarkObjectAnalysis.stop();
}
/**
* Run the CPU Top analysis
*/
public void runCpuTop() {
runCpuTop(null, null);
}
/**
* Run the CPU Top analysis
* @param cpus The CPUs on which to run the analysis
*/
public void runCpuTop(Collection<Integer> cpus) {
runCpuTop(cpus, null);
}
/**
* Run the CPU Top analysis
* @param cpus The CPUs on which to run the analysis
* @param receivedIntervals The intervals on which to run the analysis
*/
public void runCpuTop(Collection<Integer> cpus, Collection<TimestampInterval> receivedIntervals) {
StateMachineBenchmark benchmarkObjectAnalysis = new StateMachineBenchmark("CPUTop analysis"); //$NON-NLS-1$
StateMachineReport.R.println_subsubsubsection("CPUTop analysis:"); //$NON-NLS-1$
Set<Integer> sortedCpusSet = new TreeSet<>(cpus);
StateMachineReport.R.println("Analyzed CPUs: " + Joiner.on(", ").join(sortedCpusSet)); //$NON-NLS-1$ //$NON-NLS-2$
Collection<TimestampInterval> intervals = receivedIntervals;
if (intervals == null || intervals.isEmpty()) {
intervals = new LinkedList<>();
for (InstanceStepInformation isi : invalidIsiList) {
TimestampInterval ti = isi.getVariableInterval(variable.getName());
intervals.add(ti);
}
}
HashMultimap<String, TimestampInterval> intervalsPerTrace = HashMultimap.create();
StateMachineInstanceGroup group = invalidIsiList.get(0).instance.getStateMachineInstanceGroup();
for (TimestampInterval ti : intervals) {
for (StateMachineBackendAnalysis module : group.getStateMachineBackendAnalysisModules()) {
if (module.getKernelTrace().getTimeRange().contains(checkNotNull(ti.getStartTime()))
|| module.getKernelTrace().getTimeRange().contains(checkNotNull(ti.getEndTime()))) {
intervalsPerTrace.put(module.getKernelTrace().getPath(), ti);
}
}
}
List<String> command = new LinkedList<>();
command.add("/home/gbastien/Dorsal/sources/lttng-analyses/lttng-cputop-mi"); //$NON-NLS-1$
command.add("--accumulate"); //$NON-NLS-1$
//command.add("--no-progress"); //$NON-NLS-1$
command.add("--skip-validation"); //$NON-NLS-1$
command.add("--limit"); command.add("5"); //$NON-NLS-1$ //$NON-NLS-2$
if (cpus != null && !cpus.isEmpty()) {
command.add("--cpu"); command.add(Joiner.on(",").join(sortedCpusSet)); //$NON-NLS-1$ //$NON-NLS-2$
}
for (Entry<String, Collection<TimestampInterval>> entry : intervalsPerTrace.asMap().entrySet()) {
List<String> localCommand = new LinkedList<>(command);
for (TimestampInterval ti : entry.getValue()) {
String intvlStart = ti.getStartTime().toString().replaceAll("\\s",""); //$NON-NLS-1$ //$NON-NLS-2$
String intvlEnd = ti.getEndTime().toString().replaceAll("\\s",""); //$NON-NLS-1$ //$NON-NLS-2$
localCommand.add("--timerange"); localCommand.add("[" + intvlStart + "," + intvlEnd + "]"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
}
localCommand.add(entry.getKey());
ProcessBuilder pb = new ProcessBuilder(localCommand);
pb.redirectErrorStream(true);
try {
Process pr = pb.start();
BufferedReader in = new BufferedReader(new InputStreamReader(pr.getInputStream()));
String fullTxt = ""; //$NON-NLS-1$
String line = null;
while ((line = in.readLine()) != null) {
//System.out.println(line);
fullTxt += line;
}
JSONObject jsonPerProcess = null;
JSONObject fullJson = new JSONObject(fullTxt);
JSONArray jarray = fullJson.getJSONArray("results"); //$NON-NLS-1$
for (int i = 0; i < jarray.length(); i++) {
JSONObject jobject = jarray.getJSONObject(i);
if (jobject.has("class") && jobject.getString("class").equals("per-process")) { //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
jsonPerProcess = jobject;
break;
}
}
if (jsonPerProcess == null) {
StateMachineReport.debug("Information not found ?!"); //$NON-NLS-1$
continue;
}
JSONObject jsonPerProcessTimerange = jsonPerProcess.getJSONObject("time-range"); //$NON-NLS-1$
JSONArray jsonPerProcessData = jsonPerProcess.getJSONArray("data"); //$NON-NLS-1$
StateMachineReport.R.println(String.format(
"Analyzed timerange: [%s, %s]", //$NON-NLS-1$
TmfTimestamp.create(jsonPerProcessTimerange.getLong("begin"), ITmfTimestamp.NANOSECOND_SCALE), //$NON-NLS-1$
TmfTimestamp.create(jsonPerProcessTimerange.getLong("end"), ITmfTimestamp.NANOSECOND_SCALE) //$NON-NLS-1$
));
String[] header = {"Per-TID Usage", "Process", "Migrations", "Priorities"}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
String[][] strs = new String[jsonPerProcessData.length()][4];
int progressSize = 8;
for (int idx = 0; idx < jsonPerProcessData.length(); idx++) {
JSONArray jsonEntry = jsonPerProcessData.getJSONArray(idx);
JSONObject process = jsonEntry.getJSONObject(0);
int migrations = jsonEntry.getInt(1);
String priorities = jsonEntry.getString(2);
JSONObject ratio = jsonEntry.getJSONObject(3);
double ratioValue = ratio.getDouble("value") * 100; //$NON-NLS-1$
String symbol = StateMachineReport.progressBar(ratioValue, progressSize);
strs[idx][0] = String.format("%.2f%% %s", ratioValue, symbol); //$NON-NLS-1$
strs[idx][1] = String.format("%s (%d)", //$NON-NLS-1$
process.getString("name"), //$NON-NLS-1$
process.getLong("tid") //$NON-NLS-1$
);
strs[idx][2] = String.format("%d", migrations); //$NON-NLS-1$
strs[idx][3] = priorities;
}
StateMachineReport.R.println_table(header, strs, Arrays.asList(new Integer[]{0, 2, 3}));
pr.waitFor();
} catch (IOException | InterruptedException | JSONException e) {
Activator.getInstance().logWarning("Error running cpu top analysis: " + e.getMessage()); //$NON-NLS-1$
}
}
benchmarkObjectAnalysis.stop();
}
/**
* To run the priority inheritance analysis
* @return The percent of time spent in sched_pi_setprio for invalid instances compared to valid ones
*/
public double runPriorityInheritance() {
StateMachineBenchmark benchmarkObjectAnalysis = new StateMachineBenchmark("PI analysis"); //$NON-NLS-1$
double meanSchedPiInvalid = 0;
double meanSchedPiInvalidNb = invalidIsiList.size();
for (InstanceStepInformation isi : invalidIsiList) {
TimestampInterval ti = isi.getVariableInterval(variable.getName());
Integer tid = isi.instance.getVTid();
if (tid == null) {
//throw new StateMachineTIDNotFoundException();
meanSchedPiInvalidNb--;
continue;
}
for (StateMachineBackendAnalysis module : isi.instance.getStateMachineInstanceGroup().getStateMachineBackendAnalysisModules()) {
Long schedPiDuration = module.getSchedPiIntvl(tid, ti.getStartTime().getValue(), ti.getEndTime().getValue());
meanSchedPiInvalid += schedPiDuration;
//System.out.printf("INVALID schedPiDuration: %.3fms\n", ((double)schedPiDuration / 1.0e6));
}
}
meanSchedPiInvalid /= meanSchedPiInvalidNb;
if (meanSchedPiInvalid == 0) {
return 0;
}
Long maxSchedPiValid = -1L;
for (InstanceStepInformation isi : validIsiList) {
TimestampInterval ti = isi.getVariableInterval(variable.getName());
Integer tid = isi.instance.getVTid();
if (tid == null) {
//throw new StateMachineTIDNotFoundException();
continue;
}
for (StateMachineBackendAnalysis module : isi.instance.getStateMachineInstanceGroup().getStateMachineBackendAnalysisModules()) {
Long schedPiDuration = module.getSchedPiIntvl(tid, ti.getStartTime().getValue(), ti.getEndTime().getValue());
if (schedPiDuration > maxSchedPiValid) {
maxSchedPiValid = schedPiDuration;
}
//System.out.printf("VALID schedPiDuration: %.3fms\n", ((double)schedPiDuration / 1.0e6));
}
}
StateMachineReport.R.println_subsubsubsection("Priority inheritance analysis:"); //$NON-NLS-1$
StateMachineReport.R.println("Duration of active 'sched_pi_setprio'..."); //$NON-NLS-1$
StateMachineReport.R.println(String.format(
"... in valid instances (maximum): %.3fus", //$NON-NLS-1$
maxSchedPiValid / 1e6
));
StateMachineReport.R.println(String.format(
"... in invalid instances (average): %.3fus", //$NON-NLS-1$
meanSchedPiInvalid / 1e6
));
StateMachineReport.R.println();
String probaLvlTxt;
double piProba = 0;
if (meanSchedPiInvalid > maxSchedPiValid) {
piProba = (meanSchedPiInvalid - maxSchedPiValid) / maxSchedPiValid;
if (piProba > .75) {
probaLvlTxt = "Very high probability of"; //$NON-NLS-1$
} else if (piProba > .5) {
probaLvlTxt = "High probability of"; //$NON-NLS-1$
} else if (piProba > .25) {
probaLvlTxt = "Medium probability of"; //$NON-NLS-1$
} else if (piProba > .1) {
probaLvlTxt = "Probability of"; //$NON-NLS-1$
} else if (piProba > .05) {
probaLvlTxt = "Low probability of"; //$NON-NLS-1$
} else {
probaLvlTxt = "Very low probability of"; //$NON-NLS-1$
}
StateMachineReport.R.println(String.format(
"Active %.2f%% more time in invalid instances than in valid instances.", //$NON-NLS-1$
piProba * 100
));
StateMachineReport.R.println();
} else {
probaLvlTxt = "Probably not"; //$NON-NLS-1$
}
StateMachineReport.R.println(String.format(
"Verdict: %s a priority inversion", //$NON-NLS-1$
probaLvlTxt
));
StateMachineReport.R.println();
benchmarkObjectAnalysis.stop();
return piProba;
}
/**
* To run the critical path analysis
*/
public void runCriticalPath() {
StateMachineBenchmark benchmarkObjectAnalysis = new StateMachineBenchmark("Critical path analysis"); //$NON-NLS-1$
StateMachineReport.R.println_subsubsubsection("Critical path analysis:"); //$NON-NLS-1$
ResponsibilityMap<InterruptionInterval> responsibilityMap = new ResponsibilityMap<>(new InterruptionInterval.IntervalToReasonComparator());
responsibilityMap.setWeight(0);
ActionOnMapKey<InterruptionInterval> actionOnMapKey = new ActionOnMapKey<InterruptionInterval>() {
@Override
public InterruptionInterval execute(InterruptionInterval key1, InterruptionInterval key2) {
InterruptionInterval key = new InterruptionInterval(key1);
key.addInterval(key2);
//key.addTsInterval(key2.getTsIntervals());
return key;
}
};
for (Entry<Map<InterruptionReason, Integer>, Collection<InstanceStepInformation>> entry : invalidKeyToIsiMap.asMap().entrySet()) {
// Get the keyMap
Map<InterruptionReason, Integer> keyMap = entry.getKey();
InterruptionIntervalSet iis = new InterruptionIntervalSet(constraint.getDirection());
List<InterruptionDuration> criticalPathSteps;
// Compute an InterruptionIntervalSet for the critical paths of the invalid cases
IsiSampleIterator isiIterator = new IsiSampleIterator(entry.getValue());
while (isiIterator.hasNext()) {
InstanceStepInformation isi = isiIterator.next();
//for (InstanceStepInformation isi : entry.getValue()) {
try {
criticalPathSteps = getCriticalPathSteps(isi);
} catch (CriticalPathAlgorithmException | StateMachineTIDNotFoundException e) {
e.printStackTrace();
continue;
}
//criticalPathSteps = InterruptionDuration.accumulateList(criticalPathSteps);
InterruptionDurationSet ids = new InterruptionDurationSet(criticalPathSteps);
iis.addDurationSet(ids);
}
// Compute it for one of the valid cases
Iterator<InstanceStepInformation> it = checkNotNull(keyMapToclosestValidIsiListMap.get(keyMap)).iterator();
InterruptionDurationSet validIds = null;
while (validIds == null && it.hasNext()) {
InstanceStepInformation isi = it.next();
try {
criticalPathSteps = getCriticalPathSteps(isi);
} catch (CriticalPathAlgorithmException | StateMachineTIDNotFoundException e) {
e.printStackTrace();
continue;
}
validIds = new InterruptionDurationSet(criticalPathSteps);
}
if (validIds == null || iis.isEmpty()) {
System.out.println("Not enough information for a comparison"); //$NON-NLS-1$
continue;
}
InterruptionIntervalSetDiff iisdLocal = iis.substract(validIds, constraint.getDirection());
/*if (iisdLocal.getIntervalMeanResponsibilityMap().getSum() != 1) {
StateMachineReport.debug("!!!!!!!!!! SUM != 1 ==> " + iisdLocal.getIntervalMeanResponsibilityMap().getSum());
}
StateMachineReport.debug("IIS: " + iis);
StateMachineReport.debug("validIds: " + validIds);
StateMachineReport.debug("iisdLocal: " + iisdLocal);
StateMachineReport.debug("iisdLocal.getResponsibilityMap():");
for (Entry<InterruptionInterval, Double[]> entryLocal : iisdLocal.getResponsibilityMap().entrySet()) {
StateMachineReport.debug(" I: " + entryLocal.getKey() + " -- [" + entryLocal.getValue()[0] + ", " + entryLocal.getValue()[1] + "]");
}*/
responsibilityMap.mergeAll(iisdLocal.getIntervalMeanResponsibilityMap(), actionOnMapKey);
}
StateMachineReport.R.println("General computed difference between invalid and valid instances:"); //$NON-NLS-1$
String[] header = {"Critical path state", "Responsibility for added time"}; //$NON-NLS-1$ //$NON-NLS-2$
String[][] strs = new String[responsibilityMap.getCollection().size()][2];
int idx = 0;
int progressSize = 20;
for (Entry<InterruptionInterval, Double> entry : responsibilityMap.getCollection()) {
double ratioValue = entry.getValue() * 100;
String symbol = StateMachineReport.progressBar(ratioValue, progressSize);
strs[idx][0] = entry.getKey().getReason().getID();
strs[idx][1] = String.format("%.2f%% %s", ratioValue, symbol); //$NON-NLS-1$
idx++;
}
StateMachineReport.R.println_table(header, strs, Arrays.asList(new Integer[]{1}));
StateMachineReport.R.println(String.format(
"Minimum responsibility for a case to be considered: %.2f%%", //$NON-NLS-1$
responsibilityMap.getMinProba() * 100
));
StateMachineReport.R.println();
benchmarkObjectAnalysis.stop();
StateMachineReport.R.println_subsubsubsubsection("Analysis of the states to keep for consideration:"); //$NON-NLS-1$
for (Entry<InterruptionInterval, Double> entry : responsibilityMap.getTopStdDevCollection()) {
StateMachineReport.R.println(String.format(
"%s for %.2f%% of the time", //$NON-NLS-1$
entry.getKey().getReason().getID(),
(entry.getValue() * 100)
));
StateMachineReport.R.inc();
if (!(entry.getKey().getReason() instanceof CriticalPathState)) {
throw new RuntimeException("Well, shouldn't happen now!!"); //$NON-NLS-1$
}
CriticalPathState cps = (CriticalPathState)entry.getKey().getReason();
switch (cps.getType()) {
case PREEMPTED:
Set<Integer> setOfCpu = new TreeSet<>();
Set<Integer> setOfPrio = new TreeSet<>();
/* Search on which CPU we should run: these CPUs are the ones on which the preempted process
* was running at some point during the intervals we saved for the preempted state.
*
* We also take advantage of that loop to get the priority of our preempted process during
* those intervals. This part will probably be changed once the main state system is fixed
* to get the best priority information.
*/
int tid = cps.getWorker().getHostThread().getTid();
StateMachineInstanceGroup group = invalidIsiList.get(0).instance.getStateMachineInstanceGroup();
for (StateMachineBackendAnalysis smss : group.getStateMachineBackendAnalysisModules()) {
for (TimestampInterval ti : entry.getKey().getTsIntervals()) {
for (ITmfStateInterval itsi : smss.getAllStateIntervalInPeriod(tid, ti.getStartTime().getValue(), ti.getEndTime().getValue(), Attributes.CPU)) {
setOfCpu.add(itsi.getStateValue().unboxInt());
}
for (ITmfStateInterval itsi : smss.getAllStateIntervalInPeriod(tid, ti.getStartTime().getValue(), ti.getEndTime().getValue(), Attributes.PRIO)) {
setOfPrio.add(itsi.getStateValue().unboxInt());
}
}
}
runCpuTop(setOfCpu, entry.getKey().getTsIntervals());
StateMachineReport.R.println(String.format(
"Priorities of the PREEMPTED process during that interval: %s", //$NON-NLS-1$
Joiner.on(", ").join(setOfPrio) //$NON-NLS-1$
));
break;
case BLOCKED:
case BLOCK_DEVICE:
case DEFAULT:
case EPS:
case INTERRUPTED:
case IPI:
case NETWORK:
case RUNNING:
case TIMER:
case UNKNOWN:
case USER_INPUT:
StateMachineReport.R.println("We don't know what to do for that yet!"); //$NON-NLS-1$
break;
default:
throw new RuntimeException("We never should arrive there."); //$NON-NLS-1$
}
StateMachineReport.R.dec();
}
}
private List<InterruptionDuration> getCriticalPathSteps(InstanceStepInformation isi) throws CriticalPathAlgorithmException, StateMachineTIDNotFoundException {
TimestampInterval ti = isi.getVariableInterval(variable.getName());
Integer tid = isi.instance.getVTid();
if (tid == null) {
throw new StateMachineTIDNotFoundException();
}
List<InterruptionDuration> criticalPathSteps = new ArrayList<>();
// We search the execution graph that matches
boolean graphFound = false;
boolean workerFound = false;
for (OsExecutionGraph g : isi.instance.getStateMachineInstanceGroup().getLttngKernelExecutionGraphModules()) {
// Just in case it didn't finish its work for now, wait for it...
g.waitForCompletion();
// Get the general graph for the trace
TmfGraph graph = g.getGraph();
if (graph == null) {
System.out.println("graph == null"); //$NON-NLS-1$
continue;
}
graphFound = true;
// Get the worker for the process we're following
OsWorker lw = null;
for (IGraphWorker worker : graph.getWorkers()) {
if (worker instanceof OsWorker) {
OsWorker lworker = (OsWorker) worker;
if (lworker.getHostThread().getTid().equals(tid)) {
lw = lworker;
break;
}
}
}
if (lw == null) {
System.out.println("lw == null"); //$NON-NLS-1$
continue;
}
workerFound = true;
// Compute the path for the period we're interested into
TmfVertex vstart = graph.getVertexAt(checkNotNull(ti.getStartTime()), lw);
TmfVertex vend = graph.getVertexAt(checkNotNull(ti.getEndTime()), lw);
TmfGraph path = new CriticalPathAlgorithmBounded(graph).compute(checkNotNull(vstart), checkNotNull(vend));
// Then traverse that path to get the data for what happened in there
path.scanLineTraverse(path.getHead(lw), new TmfGraphVisitor() {
@Override
public void visit(TmfEdge link, boolean horizontal) {
if (!horizontal) {
return;
}
IGraphWorker w = path.getParentOf(link.getVertexTo());
if (!(w instanceof OsWorker)) {
throw new RuntimeException("Should not have something that's not a OsWorker here..."); //$NON-NLS-1$
}
OsWorker llw = (OsWorker)w;
ITmfTimestamp tsStart = TmfTimestamp.create(link.getVertexFrom().getTs(), ITmfTimestamp.NANOSECOND_SCALE);
ITmfTimestamp tsEnd = TmfTimestamp.create(link.getVertexTo().getTs(), ITmfTimestamp.NANOSECOND_SCALE);
// Change the worker name to the actual process name if available
for (StateMachineBackendAnalysis smssa : isi.instance.getStateMachineInstanceGroup().getStateMachineBackendAnalysisModules()) {
ITmfTrace kernelTrace = smssa.getKernelTrace();
if (kernelTrace.getStartTime().compareTo(tsEnd) > 0 || kernelTrace.getEndTime().compareTo(tsEnd) < 0) {
//System.out.println("DEBUG: time does not fit");
continue;
}
KernelAnalysisModule kernelAnalysisModule = TmfTraceUtils.getAnalysisModuleOfClass(kernelTrace, KernelAnalysisModule.class, KernelAnalysisModule.ID);
if (kernelAnalysisModule == null) {
//System.out.println("DEBUG: kernelAnalysisModule is null");
continue;
}
// Just in case it wasn't finished yet
kernelAnalysisModule.waitForCompletion();
ITmfStateSystem ss = kernelAnalysisModule.getStateSystem();
if (ss == null) {
//System.out.println("DEBUG: ss is null");
continue;
}
try {
Integer execNameNode = ss.getQuarkAbsolute(org.eclipse.tracecompass.internal.analysis.os.linux.core.kernel.Attributes.THREADS, llw.getHostThread().getTid().toString(), org.eclipse.tracecompass.internal.analysis.os.linux.core.kernel.Attributes.EXEC_NAME);
ITmfStateInterval si = ss.querySingleState(tsEnd.getValue(), execNameNode);
while (si.getStateValue().isNull() && si.getStartTime() - 1 >= ss.getStartTime()) {
si = ss.querySingleState(si.getStartTime() - 1, execNameNode);
}
if (!si.getStateValue().isNull()) {
llw.setName(si.getStateValue().unboxStr());
}
} catch (AttributeNotFoundException | StateSystemDisposedException | TimeRangeException e) {
//e.printStackTrace(); // DEBUG
}
}
/*System.out.printf("%s (%d) was %s for %.04fms (between %s and %s)\n", //$NON-NLS-1$
llw.getName(),
llw.getHostThread().getTid(),
link.getType().name(),
link.getDuration() / 1.0e6,
new TmfTimestamp(link.getVertexFrom().getTs(), ITmfTimestamp.NANOSECOND_SCALE).toString(),
new TmfTimestamp(link.getVertexTo().getTs(), ITmfTimestamp.NANOSECOND_SCALE).toString());*/
InterruptionReason ir = new CriticalPathState(link.getType(), llw);
TimestampInterval tsInterval = new TimestampInterval(tsStart, tsEnd);
criticalPathSteps.add(new InterruptionDuration(ir, link.getDuration(), tsInterval));
}
});
//System.out.println("Interval Start: " + intervalStart + " (" + intervalStart.getValue() + ")");
//System.out.println("Interval End: " + intervalEnd + " (" + intervalEnd.getValue() + ")");
}
// If we didn't found the graph or the worker... we couldn't do that analysis
if (!graphFound) {
throw new CriticalPathAlgorithmException("No graph found"); //$NON-NLS-1$
} else if (!workerFound) {
throw new CriticalPathAlgorithmException("No worker found"); //$NON-NLS-1$
}
// Finally, return the steps of the critical path for the period of time we were interested into
return criticalPathSteps;
}
/**
* To run an analysis on the instances duration
*/
public void runInstancesDurationAnalysis() {
StateMachineBenchmark benchmarkObjectAnalysis = new StateMachineBenchmark("Instances duration analysis"); //$NON-NLS-1$
StateMachineReport.R.println_subsubsubsection("Instances duration analysis:"); //$NON-NLS-1$
double minValid = Double.MAX_VALUE, maxValid = Double.MIN_VALUE, sumValid = 0;
double avgValid = 0, varValid = 0, stdevValid = 0;
for (InstanceStepInformation isi : validIsiList) {
double duration = isi.getVariableInterval(variable.getName()).getDuration() / 1.e6;
if (duration > maxValid) {
maxValid = duration;
}
if (duration < minValid) {
minValid = duration;
}
sumValid += duration;
}
avgValid = sumValid / validIsiList.size();
for (InstanceStepInformation isi : validIsiList) {
double duration = isi.getVariableInterval(variable.getName()).getDuration() / 1.e6;
varValid += Math.pow(duration - avgValid, 2);
}
varValid /= validIsiList.size();
stdevValid = Math.sqrt(varValid);
double minInvalid = Double.MAX_VALUE, maxInvalid = Double.MIN_VALUE, sumInvalid = 0;
double avgInvalid = 0, varInvalid = 0, stdevInvalid = 0;
for (InstanceStepInformation isi : invalidIsiList) {
double duration = isi.getVariableInterval(variable.getName()).getDuration() / 1.e6;
if (duration > maxInvalid) {
maxInvalid = duration;
}
if (duration < minInvalid) {
minInvalid = duration;
}
sumInvalid += duration;
}
avgInvalid = sumInvalid / invalidIsiList.size();
for (InstanceStepInformation isi : invalidIsiList) {
double duration = isi.getVariableInterval(variable.getName()).getDuration() / 1.e6;
varInvalid += Math.pow(duration - avgInvalid, 2);
}
varInvalid /= invalidIsiList.size();
stdevInvalid = Math.sqrt(varInvalid);
//StateMachineReport.R.println("General computed difference between invalid and valid instances:"); //$NON-NLS-1$
String[] header = {"Instances", "Count", "Min (ms)", "Avg (ms)", "Max (ms)", "StDev (ms)"}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$
String[][] strs = new String[2][6];
strs[0][0] = "Valid"; //$NON-NLS-1$
strs[0][1] = String.format("%d", validIsiList.size()); //$NON-NLS-1$
strs[0][2] = String.format("%.3f", minValid); //$NON-NLS-1$
strs[0][3] = String.format("%.3f", avgValid); //$NON-NLS-1$
strs[0][4] = String.format("%.3f", maxValid); //$NON-NLS-1$
strs[0][5] = String.format("%.3f", stdevValid); //$NON-NLS-1$
strs[1][0] = "Invalid"; //$NON-NLS-1$
strs[1][1] = String.format("%d", invalidIsiList.size()); //$NON-NLS-1$
strs[1][2] = String.format("%.3f", minInvalid); //$NON-NLS-1$
strs[1][3] = String.format("%.3f", avgInvalid); //$NON-NLS-1$
strs[1][4] = String.format("%.3f", maxInvalid); //$NON-NLS-1$
strs[1][5] = String.format("%.3f", stdevInvalid); //$NON-NLS-1$
StateMachineReport.R.println_table(header, strs, Arrays.asList(new Integer[]{1, 2, 3, 4, 5}));
StateMachineReport.R.println();
benchmarkObjectAnalysis.stop();
}
private ResponsibilityMap<InterruptionReason> cpuFrequencyScalingAnalysisRunner(Collection<InstanceStepInformation> isiCollection) {
ResponsibilityMap<InterruptionReason> responsibilityMap = new ResponsibilityMap<>(0);
IsiSampleIterator isiIterator = new IsiSampleIterator(isiCollection);
while (isiIterator.hasNext()) {
InstanceStepInformation isi = isiIterator.next();
//for (InstanceStepInformation isi : isiCollection) {
TimestampInterval ti = isi.getVariableInterval(variable.getName());
StateMachineInstanceGroup group = isi.instance.getStateMachineInstanceGroup();
InterruptionDurationSet ids = new InterruptionDurationSet();
for (StateMachineBackendAnalysis smss : group.getStateMachineBackendAnalysisModules()) {
for (ITmfStateInterval cpuItsi : smss.getAllStateIntervalInPeriod(isi.instance.getVTid(), ti.getStartTime().getValue(), ti.getEndTime().getValue(), Attributes.CPU)) {
TimestampInterval cpuTi = new TimestampInterval(
Math.max(ti.getStartTime().getValue(), cpuItsi.getStartTime()),
Math.min(ti.getEndTime().getValue(), cpuItsi.getEndTime()));
if (cpuItsi.getStateValue().isNull()) {
InterruptionReason ir = new CpuFrequency(-1L);
InterruptionDuration id = new InterruptionDuration(ir, cpuTi.getDuration(), cpuTi);
ids.add(id);
continue;
}
Integer cpu = cpuItsi.getStateValue().unboxInt();
for (ITmfStateInterval freqItsi : smss.getAllStateIntervalInPeriod(cpuTi.getStartTime().getValue(), cpuTi.getEndTime().getValue(), Attributes.CPU_FREQ, cpu.toString())) {
Long freq = -1L;
if (!freqItsi.getStateValue().isNull()) {
freq = freqItsi.getStateValue().unboxLong();
}
TimestampInterval freqTi = new TimestampInterval(
Math.max(cpuTi.getStartTime().getValue(), freqItsi.getStartTime()),
Math.min(cpuTi.getEndTime().getValue(), freqItsi.getEndTime()));
InterruptionReason ir = new CpuFrequency(freq);
InterruptionDuration id = new InterruptionDuration(ir, freqTi.getDuration(), freqTi);
ids.add(id);
}
}
}
responsibilityMap.mergeAll(new InterruptionIntervalSetDiff(ids).getMeanResponsibilityMap());
}
return responsibilityMap;
}
private static double runCpuFrequencyScalingAnalysis(ResponsibilityMap<InterruptionReason> responsibilityMap) {
long sumFrequency = 0;
double sumPercent = 0;
String[] header = {"CPU Frequency", "Percent of time"}; //$NON-NLS-1$ //$NON-NLS-2$
String[][] strs = new String[responsibilityMap.getCollection().size()][2];
int idx = 0;
int progressSize = 20;
for (Entry<InterruptionReason, Double> entry : responsibilityMap.getCollection()) {
double ratioValue = entry.getValue() * 100;
String symbol = StateMachineReport.progressBar(ratioValue, progressSize);
if (entry.getKey().getID().equals("-1")) { //$NON-NLS-1$
strs[idx][0] = "Unknown"; //$NON-NLS-1$
} else {
long frequency = ((CpuFrequency)entry.getKey()).getFreq();
strs[idx][0] = String.format("%.2f MHz", frequency / 1000.0); //$NON-NLS-1$
sumFrequency += frequency * entry.getValue();
sumPercent += entry.getValue();
}
strs[idx][1] = String.format("%.2f%% %s", ratioValue, symbol); //$NON-NLS-1$
idx++;
}
StateMachineReport.R.println_table(header, strs, Arrays.asList(new Integer[]{1}));
double meanFreq = sumFrequency / sumPercent;
StateMachineReport.R.println(String.format("Average frequency: %.2f MHz", //$NON-NLS-1$
meanFreq / 1000));
StateMachineReport.R.println();
return meanFreq;
}
/**
* To run an analysis on the cpu frequency
*/
public void runCpuFrequencyScalingAnalysis() {
StateMachineBenchmark benchmarkObjectAnalysis = new StateMachineBenchmark("CPU Frequency scaling analysis"); //$NON-NLS-1$
ResponsibilityMap<InterruptionReason> responsibilityMapValid, responsibilityMapInvalid;
responsibilityMapInvalid = cpuFrequencyScalingAnalysisRunner(invalidIsiList);
// If we don't have enough information for the invalid instances
if (responsibilityMapInvalid.isEmpty() ||
responsibilityMapInvalid.size() == 1 && ((CpuFrequency)responsibilityMapInvalid.keySet().iterator().next()).getFreq() == -1) {
return;
}
responsibilityMapValid = cpuFrequencyScalingAnalysisRunner(validIsiList);
// If we don't have enough information for the valid instances
if (responsibilityMapValid.isEmpty() ||
responsibilityMapValid.size() == 1 && ((CpuFrequency)responsibilityMapValid.keySet().iterator().next()).getFreq() == -1) {
return;
}
// If we have exactly the same information for both the valid and invalid instances
if (responsibilityMapValid.size() == 1 && responsibilityMapInvalid.size() == 1 &&
((CpuFrequency)responsibilityMapValid.keySet().iterator().next()).getFreq() == ((CpuFrequency)responsibilityMapInvalid.keySet().iterator().next()).getFreq()) {
return;
}
StateMachineReport.R.println_subsubsubsection("CPU frequency analysis:"); //$NON-NLS-1$
StateMachineReport.R.println("CPU frequency for valid instances:"); //$NON-NLS-1$
double meanFreqValid = runCpuFrequencyScalingAnalysis(responsibilityMapValid);
StateMachineReport.R.println("CPU frequency for invalid instances:"); //$NON-NLS-1$
double meanFreqInvalid = runCpuFrequencyScalingAnalysis(responsibilityMapInvalid);
String higherOrLowerTxt = "higher"; //$NON-NLS-1$
String probaLvlTxt;
double freqProba;
switch (constraint.getDirection()) {
case VARIABLE_EQ_VALUE:
if (meanFreqValid < meanFreqInvalid) {
higherOrLowerTxt = "lower"; //$NON-NLS-1$
}
freqProba = Math.abs(meanFreqValid - meanFreqInvalid) / Math.min(meanFreqValid, meanFreqInvalid);
break;
case VARIABLE_OVER_VALUE:
higherOrLowerTxt = "lower"; //$NON-NLS-1$
freqProba = (meanFreqInvalid - meanFreqValid) / meanFreqValid;
break;
case VARIABLE_UNDER_VALUE:
freqProba = (meanFreqValid - meanFreqInvalid) / meanFreqInvalid;
break;
default:
freqProba = 0;
break;
}
if (freqProba > 0) {
if (freqProba > .75) {
probaLvlTxt = "Very high probability of"; //$NON-NLS-1$
} else if (freqProba > .5) {
probaLvlTxt = "High probability of"; //$NON-NLS-1$
} else if (freqProba > .25) {
probaLvlTxt = "Medium probability of"; //$NON-NLS-1$
} else if (freqProba > .1) {
probaLvlTxt = "Probability of"; //$NON-NLS-1$
} else if (freqProba > .05) {
probaLvlTxt = "Low probability of"; //$NON-NLS-1$
} else {
probaLvlTxt = "Very low probability of"; //$NON-NLS-1$
}
StateMachineReport.R.println(String.format(
"%.2f%% %s average frequency in valid instances than in invalid instances.", //$NON-NLS-1$
freqProba * 100,
higherOrLowerTxt
));
StateMachineReport.R.println();
} else {
probaLvlTxt = "No probability of"; //$NON-NLS-1$
}
StateMachineReport.R.println(String.format(
"Verdict: %s a frequency scaling problem", //$NON-NLS-1$
probaLvlTxt
));
StateMachineReport.R.println();
benchmarkObjectAnalysis.stop();
}
private InterruptionIntervalSet stateMachineStateAnalysisRunner(Collection<InstanceStepInformation> isiCollection) {
InterruptionIntervalSet iis = new InterruptionIntervalSet(constraint.getDirection());
IsiSampleIterator isiIterator = new IsiSampleIterator(isiCollection);
while (isiIterator.hasNext()) {
InstanceStepInformation isi = isiIterator.next();
TimestampInterval ti = isi.getVariableInterval(variable.getName());
List<InstanceStepInformation> isiList = isi.instance.getStepsInInterval(ti);
InterruptionDurationSet ids = new InterruptionDurationSet();
Iterator<InstanceStepInformation> it = isiList.iterator();
InstanceStepInformation current, next;
next = (it.hasNext()) ? it.next() : null;
while (next != null) {
current = next;
next = (it.hasNext()) ? it.next() : null;
if (next != null) {
InterruptionReason ir = new State(BackendStateValue.RUNNING.getValue(), current.node.getName());
TimestampInterval tInterval = new TimestampInterval(current.event.getTimestamp(), next.event.getTimestamp());
InterruptionDuration id = new InterruptionDuration(ir, tInterval.getDuration(), tInterval);
ids.add(id);
}
}
iis.addDurationSet(ids);
}
return iis;
}
/**
* To run an analysis on the state machine states
*/
public void runStateMachineStateAnalysis() {
StateMachineBenchmark benchmarkObjectAnalysis = new StateMachineBenchmark("State machine state analysis"); //$NON-NLS-1$
StateMachineReport.R.println_subsubsubsection("State machine state analysis:"); //$NON-NLS-1$
InterruptionIntervalSet validIis = stateMachineStateAnalysisRunner(validIsiList);
InterruptionIntervalSet invalidIis = stateMachineStateAnalysisRunner(invalidIsiList);
ResponsibilityMap<InterruptionReason> responsibilityMap = invalidIis.substract(validIis).getMeanResponsibilityMap();
StateMachineReport.R.println("General computed difference between invalid and valid instances:"); //$NON-NLS-1$
String[] header = {"Model state", "Responsibility for added time"}; //$NON-NLS-1$ //$NON-NLS-2$
String[][] strs = new String[responsibilityMap.getCollection().size()][2];
int idx = 0;
int progressSize = 20;
for (Entry<InterruptionReason, Double> entry : responsibilityMap.getCollection()) {
double ratioValue = entry.getValue() * 100;
String symbol = StateMachineReport.progressBar(ratioValue, progressSize);
strs[idx][0] = entry.getKey().getTaskId();
strs[idx][1] = String.format("%.2f%% %s", ratioValue, symbol); //$NON-NLS-1$
idx++;
}
StateMachineReport.R.println_table(header, strs, Arrays.asList(new Integer[]{1}));
StateMachineReport.R.println();
benchmarkObjectAnalysis.stop();
}
/**
* To get the number of dropped instances during the analysis for a given reason
* @param reason The reason for which instances were dropped
* @return The number of dropped instances during the analysis for that reason
*/
public int getDroppedInstances(int reason) {
return droppedInstances[reason];
}
/**
* To get the total number of dropped instances during the analysis
* @return The total number of dropped instances during the analysis
*/
public int getDroppedInstances() {
return droppedInstances[NO_STATE_SYSTEM_FOUND]
+ droppedInstances[NO_TID_FOUND]
+ droppedInstances[OUT_OF_TIME_RANGE];
}
/**
* To add to the dropped instances when an exception is happening
* @param e The exception that happened
*/
private void addDroppedInstance(Exception e) {
if (e instanceof StateMachineStateSystemNotFoundException) {
droppedInstances[NO_STATE_SYSTEM_FOUND]++;
} else if (e instanceof StateMachineTIDNotFoundException) {
droppedInstances[NO_TID_FOUND]++;
} else if (e instanceof StateMachineStateSystemTimeRangeException) {
droppedInstances[OUT_OF_TIME_RANGE]++;
}
}
/**
* To reset the number of dropped instances
*/
private void resetDroppedInstances() {
droppedInstances[NO_STATE_SYSTEM_FOUND] = 0;
droppedInstances[NO_TID_FOUND] = 0;
droppedInstances[OUT_OF_TIME_RANGE] = 0;
}
/**
* @return The list of invalid instance step information on which this
* state machine variable analysis applies
*/
public List<InstanceStepInformation> getInvalidIsiList() {
return invalidIsiList;
}
/**
* @return The variable on which this state machine variable analysis applies
*/
public StateMachineVariable getVariable() {
return variable;
}
/**
* @return The list of valid instance step information on which this
* state machine variable analysis applies
*/
public List<InstanceStepInformation> getValidIsiList() {
return validIsiList;
}
/**
* @return The segment store for constraint status for the instances steps,
* constraint and variable on which this state machine variable analysis applies
*/
public @NonNull ISegmentStore<@NonNull ISegment> getInstanceConstraintsSegmentStore() {
@NonNull ISegmentStore<@NonNull ISegment> segmentStore = new TreeMapStore<>();
for (InstanceStepInformation isi : invalidIsiList) {
TimestampInterval ti = isi.getVariableInterval(variable.getName());
segmentStore.add(new StateMachineSegment(isi.instance.getVTid(), ti.getStartTime().getValue(), ti.getEndTime().getValue(), constraint.toString()));
}
for (InstanceStepInformation isi : validIsiList) {
TimestampInterval ti = isi.getVariableInterval(variable.getName());
segmentStore.add(new StateMachineSegment(isi.instance.getVTid(), ti.getStartTime().getValue(), ti.getEndTime().getValue()));
}
return segmentStore;
}
}