From b48bf8e5b76e2c45d6b6fcc61f92b6da2514ddc1 Mon Sep 17 00:00:00 2001 From: yoann-heitz Date: Wed, 5 Jan 2022 17:19:50 +0100 Subject: [PATCH] OTF2: Add system architecture in callstack analysis Updated the OTF2 callstack analysis so it displays the system architecture. Now the different processes can be grouped/expanded by node and nodes can be grouped/expanded by cluster. Test traces can be found here: https://github.com/dorsal-lab/OTF2_testcases Signed-off-by: yoann-heitz Change-Id: Ia621df1c7fdbe106cb67f79801670fc5c1d3d1ab Reviewed-on: https://git.eclipse.org/r/c/tracecompass.incubator/org.eclipse.tracecompass.incubator/+/189315 Tested-by: Trace Compass Bot Tested-by: Matthew Khouzam Reviewed-by: Matthew Khouzam Reviewed-by: Marco Miller --- .../analysis/AbstractOtf2StateProvider.java | 9 + .../otf2/core/analysis/IOtf2Fields.java | 17 +- .../callstack/Otf2CallStackStateProvider.java | 194 +++++++++++++++--- .../callstack/Otf2CallstackAnalysis.java | 27 +++ 4 files changed, 221 insertions(+), 26 deletions(-) diff --git a/tracetypes/org.eclipse.tracecompass.incubator.otf2.core/src/org/eclipse/tracecompass/incubator/internal/otf2/core/analysis/AbstractOtf2StateProvider.java b/tracetypes/org.eclipse.tracecompass.incubator.otf2.core/src/org/eclipse/tracecompass/incubator/internal/otf2/core/analysis/AbstractOtf2StateProvider.java index 21f2b58a8..245e804f0 100644 --- a/tracetypes/org.eclipse.tracecompass.incubator.otf2.core/src/org/eclipse/tracecompass/incubator/internal/otf2/core/analysis/AbstractOtf2StateProvider.java +++ b/tracetypes/org.eclipse.tracecompass.incubator.otf2.core/src/org/eclipse/tracecompass/incubator/internal/otf2/core/analysis/AbstractOtf2StateProvider.java @@ -354,4 +354,13 @@ protected ArrayList getMembersFromCommunicatorReference(int communicatorRe return members; } + /** + * Getter for the fStringId field + * + * @return the fStringId field + */ + protected Map getStringId() { + return fStringId; + } + } \ No newline at end of file diff --git a/tracetypes/org.eclipse.tracecompass.incubator.otf2.core/src/org/eclipse/tracecompass/incubator/internal/otf2/core/analysis/IOtf2Fields.java b/tracetypes/org.eclipse.tracecompass.incubator.otf2.core/src/org/eclipse/tracecompass/incubator/internal/otf2/core/analysis/IOtf2Fields.java index 65251461b..cd8c73054 100644 --- a/tracetypes/org.eclipse.tracecompass.incubator.otf2.core/src/org/eclipse/tracecompass/incubator/internal/otf2/core/analysis/IOtf2Fields.java +++ b/tracetypes/org.eclipse.tracecompass.incubator.otf2.core/src/org/eclipse/tracecompass/incubator/internal/otf2/core/analysis/IOtf2Fields.java @@ -38,6 +38,11 @@ public interface IOtf2Fields { */ String OTF2_NAME = "name"; //$NON-NLS-1$ + /** + * Class name field name + */ + String OTF2_CLASS_NAME = "className"; //$NON-NLS-1$ + /** * Communicator field name */ @@ -83,13 +88,23 @@ public interface IOtf2Fields { */ String OTF2_SELF = "self"; //$NON-NLS-1$ + /** + * System tree parent field name + */ + String OTF2_SYSTEM_TREE_PARENT = "systemTreeParent"; //$NON-NLS-1$ + /** * Location field name */ String OTF2_LOCATION = "location"; //$NON-NLS-1$ /** - * LocationType field name + * Location group type field name + */ + String OTF2_LOCATION_GROUP_TYPE = "locationGroupType"; //$NON-NLS-1$ + + /** + * Location type field name */ String OTF2_LOCATION_TYPE = "locationType"; //$NON-NLS-1$ diff --git a/tracetypes/org.eclipse.tracecompass.incubator.otf2.core/src/org/eclipse/tracecompass/incubator/internal/otf2/core/analysis/callstack/Otf2CallStackStateProvider.java b/tracetypes/org.eclipse.tracecompass.incubator.otf2.core/src/org/eclipse/tracecompass/incubator/internal/otf2/core/analysis/callstack/Otf2CallStackStateProvider.java index 528543c34..2daeca42f 100644 --- a/tracetypes/org.eclipse.tracecompass.incubator.otf2.core/src/org/eclipse/tracecompass/incubator/internal/otf2/core/analysis/callstack/Otf2CallStackStateProvider.java +++ b/tracetypes/org.eclipse.tracecompass.incubator.otf2.core/src/org/eclipse/tracecompass/incubator/internal/otf2/core/analysis/callstack/Otf2CallStackStateProvider.java @@ -12,6 +12,7 @@ package org.eclipse.tracecompass.incubator.internal.otf2.core.analysis.callstack; import java.util.Map; +import java.util.Queue; import java.util.HashMap; import java.util.List; import java.util.ArrayList; @@ -52,6 +53,132 @@ public class Otf2CallStackStateProvider extends AbstractOtf2StateProvider { */ public static final String PROCESSES = "Processes"; //$NON-NLS-1$ + /** + * Whitespace string + */ + public static final String WHITESPACE = " "; //$NON-NLS-1$ + + /** + * Long representing the maximum value for a 32-bits unsigned integer + */ + protected static final long MAX_UINT32 = (1L << 32) - 1; + + /** + * A class representing a node from the system tree. It is used to represent + * how the different machines are distributed into a MPI cluster and how the + * MPI ranks are distributed on each node. + * + * @author Yoann Heitz + * + */ + private class SystemTreeNode { + private final long fParentId; + private final int fNameId; + private final int fClassNameId; + private int fSystemTreeNodeQuark; + + public SystemTreeNode(long parentId, int nameId, int classNameId) { + fParentId = parentId; + fNameId = nameId; + fClassNameId = classNameId; + fSystemTreeNodeQuark = UNKNOWN_ID; + } + + public String getFullName() { + Map stringIds = getStringId(); + String name = stringIds.get(fNameId); + String className = stringIds.get(fClassNameId); + return className + WHITESPACE + name; + } + + /* + * The method used to initialize the quark associated to this node. If + * the node ID of the parent of this node is the maximum value for + * unsigned integer, then this node is the root of a system tree. Else, + * the parent node is usually a machine node. Its quark must be + * retrieved and initialized if it was not done before. + */ + public void initializeQuarks(ITmfStateSystemBuilder ssb) { + if (fParentId == MAX_UINT32) { + fSystemTreeNodeQuark = ssb.getQuarkAbsoluteAndAdd(PROCESSES, getFullName()); + } else { + int machineQuark = getSystemTreeNodeQuark(fParentId); + if (machineQuark == UNKNOWN_ID) { + SystemTreeNode parentNode = fMapSystemTreeNode.get(fParentId); + if (parentNode == null) { + return; + } + parentNode.initializeQuarks(ssb); + machineQuark = getSystemTreeNodeQuark(fParentId); + } + if (machineQuark != UNKNOWN_ID) { + fSystemTreeNodeQuark = ssb.getQuarkRelativeAndAdd(machineQuark, getFullName()); + } + } + } + + public int getQuark() { + return fSystemTreeNodeQuark; + } + } + + private int getSystemTreeNodeQuark(long systemTreeNodeId) { + SystemTreeNode systemTreeNode = fMapSystemTreeNode.get(systemTreeNodeId); + if (systemTreeNode == null) { + return UNKNOWN_ID; + } + return systemTreeNode.getQuark(); + } + + /** + * A class representing a location group. It is used to represent a MPI + * rank. The group is associated to a system tree node which is the node on + * which is running this MPI rank. + * + * @author Yoann Heitz + * + */ + private class LocationGroup { + private final long fParentId; + private final int fNameId; + private final int fType; + private int fLocationGroupQuark; + + public LocationGroup(long parentId, int nameId, int type) { + fParentId = parentId; + fNameId = nameId; + fType = type; + fLocationGroupQuark = UNKNOWN_ID; + } + + public String getFullName() { + String name = getStringId().get(fNameId); + if (fType == 1 && name != null) { + return name; + } + return UNKNOWN; + } + + public void initializeQuarks(ITmfStateSystemBuilder ssb) { + int nodeQuark = getSystemTreeNodeQuark(fParentId); + if (nodeQuark != UNKNOWN_ID) { + fLocationGroupQuark = ssb.getQuarkRelativeAndAdd(nodeQuark, getFullName()); + } + } + + public int getQuark() { + return fLocationGroupQuark; + } + } + + private int getLocationGroupQuark(int locationGroupId) { + LocationGroup locationGroup = fMapLocationGroup.get(locationGroupId); + if (locationGroup == null) { + return UNKNOWN_ID; + } + return locationGroup.getQuark(); + } + /** * A class representing a location. When an OTF2 event is encountered, * methods from this class will be used to modify the state of the @@ -80,20 +207,15 @@ public Location(long id, int nameId, int processId) { /* * This method will be called by each location when all definitions have - * been read : the names of the location and of the parent process may - * be computed at this moment, and the corresponding quarks may be - * created. + * been read : the name of the location may be computed at this moment, + * and the corresponding quark may be created. */ public void initializeQuarks(ITmfStateSystemBuilder ssb) { - // Get the names of the location and its parent process + // Get the name of the location String locationName = getStringFromStringId(fLocationNameId); - Integer processStringId = fLocationGroupStringId.get(fProcessId); - if (processStringId == null) { - processStringId = UNKNOWN_ID; - } - String processName = getStringFromStringId(processStringId); - // Create the associated quarks - int processQuark = ssb.getQuarkAbsoluteAndAdd(PROCESSES, processName); + + // Create the associated quark + int processQuark = getLocationGroupQuark(fProcessId); fLocationQuark = ssb.getQuarkRelativeAndAdd(processQuark, locationName); fCallStackQuark = ssb.getQuarkRelativeAndAdd(fLocationQuark, InstrumentedCallStackAnalysis.CALL_STACK); } @@ -299,11 +421,12 @@ public void mpiAllToRoot(ITmfEvent srcEvent, ITmfStateSystemBuilder ssb) { /** * Mapping tables required for this analysis */ - private final Map fLocationGroupStringId; - private final Map fMapLocation; - private final Map fMsgDataEvent; - private final LinkedList fRootToAllQueue; - private final LinkedList fAllToRootQueue; + private final Map fMapSystemTreeNode = new HashMap<>(); + private final Map fMapLocationGroup = new HashMap<>(); + private final Map fMapLocation = new HashMap<>(); + private final Map fMsgDataEvent = new HashMap<>(); + private final Queue fRootToAllQueue = new LinkedList<>(); + private final Queue fAllToRootQueue = new LinkedList<>(); private boolean fAllDefinitionsRead; /** @@ -312,17 +435,12 @@ public void mpiAllToRoot(ITmfEvent srcEvent, ITmfStateSystemBuilder ssb) { */ public Otf2CallStackStateProvider(@Nullable ITmfTrace trace) { super(trace, ID); - fLocationGroupStringId = new HashMap<>(); - fMsgDataEvent = new HashMap<>(); - fMapLocation = new HashMap<>(); - fRootToAllQueue = new LinkedList<>(); - fAllToRootQueue = new LinkedList<>(); fAllDefinitionsRead = false; } @Override public int getVersion() { - return 1; + return 2; } @Override @@ -361,6 +479,10 @@ protected void processGlobalDefinition(ITmfEvent event, String name) { processGroupMemberDefinition(event); break; } + case IOtf2GlobalDefinitions.OTF2_SYSTEM_TREE_NODE: { + processSystemTreeNodeDefinition(event); + break; + } default: return; } @@ -380,11 +502,27 @@ private void processLocationDefinition(ITmfEvent event) { private void processLocationGroupDefinition(ITmfEvent event) { ITmfEventField content = event.getContent(); Integer locationGroupReference = content.getFieldValue(Integer.class, IOtf2Fields.OTF2_SELF); - Integer stringReference = content.getFieldValue(Integer.class, IOtf2Fields.OTF2_NAME); - if (locationGroupReference == null || stringReference == null) { + Integer nameReference = content.getFieldValue(Integer.class, IOtf2Fields.OTF2_NAME); + Integer locationGroupType = content.getFieldValue(Integer.class, IOtf2Fields.OTF2_LOCATION_GROUP_TYPE); + Long parentReference = content.getFieldValue(Long.class, IOtf2Fields.OTF2_SYSTEM_TREE_PARENT); + if (locationGroupReference == null || nameReference == null || locationGroupType == null || parentReference == null) { return; } - fLocationGroupStringId.put(locationGroupReference, stringReference); + LocationGroup locationGroup = new LocationGroup(parentReference, nameReference, locationGroupType); + fMapLocationGroup.put(locationGroupReference, locationGroup); + } + + private void processSystemTreeNodeDefinition(ITmfEvent event) { + ITmfEventField content = event.getContent(); + Long selfReference = content.getFieldValue(Long.class, IOtf2Fields.OTF2_SELF); + Integer nameReference = content.getFieldValue(Integer.class, IOtf2Fields.OTF2_NAME); + Integer classNameReference = content.getFieldValue(Integer.class, IOtf2Fields.OTF2_CLASS_NAME); + Long parentReference = content.getFieldValue(Long.class, IOtf2Fields.OTF2_SYSTEM_TREE_PARENT); + if (selfReference == null || nameReference == null || classNameReference == null || parentReference == null) { + return; + } + SystemTreeNode systemTreeNode = new SystemTreeNode(parentReference, nameReference, classNameReference); + fMapSystemTreeNode.put(selfReference, systemTreeNode); } @Override @@ -441,6 +579,12 @@ protected void processOtf2Event(ITmfEvent event, String name, ITmfStateSystemBui * Iterates over all the location and initializes the associated quarks */ private void initializeQuarks(ITmfStateSystemBuilder ssb) { + for (SystemTreeNode systemTreeNode : fMapSystemTreeNode.values()) { + systemTreeNode.initializeQuarks(ssb); + } + for (LocationGroup locationGroup : fMapLocationGroup.values()) { + locationGroup.initializeQuarks(ssb); + } for (Location location : fMapLocation.values()) { location.initializeQuarks(ssb); } diff --git a/tracetypes/org.eclipse.tracecompass.incubator.otf2.core/src/org/eclipse/tracecompass/incubator/internal/otf2/core/analysis/callstack/Otf2CallstackAnalysis.java b/tracetypes/org.eclipse.tracecompass.incubator.otf2.core/src/org/eclipse/tracecompass/incubator/internal/otf2/core/analysis/callstack/Otf2CallstackAnalysis.java index a53030ef6..3121f2404 100644 --- a/tracetypes/org.eclipse.tracecompass.incubator.otf2.core/src/org/eclipse/tracecompass/incubator/internal/otf2/core/analysis/callstack/Otf2CallstackAnalysis.java +++ b/tracetypes/org.eclipse.tracecompass.incubator.otf2.core/src/org/eclipse/tracecompass/incubator/internal/otf2/core/analysis/callstack/Otf2CallstackAnalysis.java @@ -13,8 +13,13 @@ import java.util.Collection; import java.util.Collections; +import java.util.List; import java.util.Objects; +import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.tracecompass.incubator.callstack.core.instrumented.statesystem.CallStackSeries; +import org.eclipse.tracecompass.incubator.callstack.core.instrumented.statesystem.CallStackSeries.IThreadIdResolver; +import org.eclipse.tracecompass.incubator.callstack.core.instrumented.statesystem.CallStackStateProvider; import org.eclipse.tracecompass.incubator.callstack.core.instrumented.statesystem.InstrumentedCallStackAnalysis; import org.eclipse.tracecompass.incubator.internal.otf2.core.analysis.AbstractOtf2Analysis; import org.eclipse.tracecompass.incubator.internal.otf2.core.analysis.IOtf2Constants; @@ -23,6 +28,8 @@ import org.eclipse.tracecompass.tmf.core.statesystem.ITmfStateProvider; import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; +import com.google.common.collect.ImmutableList; + /** * OTF2 callstack analysis * @@ -32,12 +39,18 @@ public class Otf2CallstackAnalysis extends InstrumentedCallStackAnalysis { private static final String ID_SUFFIX = ".callstack"; //$NON-NLS-1$ + private static final int THREAD_DEPTH = 3; @Override public String getId() { return AbstractOtf2Analysis.getAnalysisIdFromSuffix(ID_SUFFIX); } + @Override + protected @NonNull IThreadIdResolver getCallStackTidResolver() { + return new CallStackSeries.AttributeValueThreadResolver(THREAD_DEPTH); + } + @Override protected ITmfStateProvider createStateProvider() { ITmfTrace trace = Objects.requireNonNull(getTrace()); @@ -59,4 +72,18 @@ protected Collection getEdgeQuarks() { } return ss.getSubAttributes(edgeQuark, false); } + + /** + * Get the patterns for the clusters, nodes, processes and threads + * + * @return The patterns for the different levels in the state system + */ + @Override + protected List getPatterns() { + return ImmutableList.of( + new String[] { CallStackStateProvider.PROCESSES, "*" }, //$NON-NLS-1$ + new String[] { "*" }, //$NON-NLS-1$ + new String[] { "*" }, //$NON-NLS-1$ + new String[] { "*" }); //$NON-NLS-1$ + } } \ No newline at end of file