int IComparable.CompareTo(object?obj) { NodeData?other = obj as NodeData; if (other != null) { if (Ref.Equal(localName, other.localName)) { if (Ref.Equal(ns, other.ns)) { return(0); } else { return(string.CompareOrdinal(ns, other.ns)); } } else { return(string.CompareOrdinal(localName, other.localName)); } } else { Debug.Fail("We should never get to this point."); // 'other' is null, 'this' is not null. Always return 1, like "".CompareTo(null). return(1); } }
private void RefreshExternHighlightData(System.ReadOnlySpan <uint> externNodes) { ProtoGraph? graph = _ActiveGraph?.InternalProtoGraph; ProcessRecord?processrec = graph?.ProcessData; if (processrec == null || graph is null) { return; } foreach (uint nodeIdx in externNodes) { NodeData?n = graph.GetNode(nodeIdx); System.Diagnostics.Debug.Assert(n is not null); if (!_activeHighlights.displayedModules.TryGetValue(n.GlobalModuleID, out moduleEntry modentry)) { modentry = new moduleEntry(); modentry.symbols = new Dictionary <ulong, symbolInfo>(); modentry.path = processrec.GetModulePath(n.GlobalModuleID); _activeHighlights.displayedModules.Add(n.GlobalModuleID, modentry); } if (!modentry.symbols.TryGetValue(n.Address, out symbolInfo symentry)) { symentry = new symbolInfo(); symentry.address = n.Address; symentry.selected = false; symentry.moduleID = n.GlobalModuleID; string?foundName; if (processrec.GetSymbol(n.GlobalModuleID, n.Address, out foundName) && foundName is not null) { symentry.name = foundName; } else { symentry.name = "[No Symbol Name]"; } symentry.threadNodes = new List <uint>() { n.Index }; modentry.symbols.Add(n.Address, symentry); } else { if (!symentry.threadNodes.Contains(n.Index)) { symentry.threadNodes.Add(n.Index); } } } _activeHighlights.LastExternNodeCount = externNodes.Length; }
private void DrawExceptionSelectBox(PlottedGraph plot) { uint[]? exceptionNodes = plot.InternalProtoGraph.GetExceptionNodes(); if (exceptionNodes is null || exceptionNodes.Length == 0) { string caption = $"No exceptions recorded in thread ID {_ActiveGraph?.TID}"; ImGuiUtils.DrawRegionCenteredText(caption); return; } string[] labels = exceptionNodes.Select(x => x.ToString()).ToArray(); if (ImGui.BeginTable("##ExceptionsTable", 2, ImGuiTableFlags.ScrollY | ImGuiTableFlags.RowBg, ImGui.GetContentRegionAvail() - new Vector2(10, _activeHighlights.SelectedExceptionNodes.Any() ? 30 : 0))) { ImGui.TableSetupColumn("Address", ImGuiTableColumnFlags.WidthFixed, 160); ImGui.TableSetupColumn("Module"); ImGui.TableSetupScrollFreeze(0, 1); ImGui.TableHeadersRow(); foreach (uint nodeidx in exceptionNodes) { NodeData?n = plot.InternalProtoGraph.GetNode(nodeidx); if (n is not null) { ImGui.TableNextRow(); if (ImGui.TableNextColumn()) { if (ImGui.Selectable($"0x{n.Address:X}", _activeHighlights.SelectedExceptionNodes.Contains(nodeidx), ImGuiSelectableFlags.SpanAllColumns)) { if (_activeHighlights.SelectedExceptionNodes.Contains(nodeidx)) { _activeHighlights.SelectedExceptionNodes.Remove(nodeidx); plot.RemoveHighlightedNodes(new List <uint> { nodeidx }, CONSTANTS.HighlightType.Exceptions); } else { _activeHighlights.SelectedExceptionNodes.Add(nodeidx); plot.AddHighlightedNodes(new List <uint> { nodeidx }, CONSTANTS.HighlightType.Exceptions); } } } if (ImGui.TableNextColumn()) { ImGui.Text(System.IO.Path.GetFileName(plot.InternalProtoGraph.ProcessData.GetModulePath(n.GlobalModuleID))); } } } ImGui.EndTable(); } }
private static void DrawThreadSelectorCombo(TraceRecord?trace, out PlottedGraph?selectedGraph, bool abbreviate) { selectedGraph = null; ProtoGraph?graph = rgatState.ActiveGraph?.InternalProtoGraph; if (trace is not null && graph is not null) { string selString = $"{(abbreviate ? "TID" : "Thread")} {graph.ThreadID}: {graph.FirstInstrumentedModuleName}"; if (graph.NodeCount == 0) { selString += " [Uninstrumented]"; } List <PlottedGraph> graphs = trace.GetPlottedGraphs(); if (ImGui.TableNextColumn()) { ImGui.AlignTextToFramePadding(); ImGuiUtils.DrawHorizCenteredText($"{graphs.Count}x"); SmallWidgets.MouseoverText($"This trace has {graphs.Count} thread{(graphs.Count != 1 ? 's' : "")}"); } if (ImGui.TableNextColumn()) { ImGui.SetNextItemWidth(ImGui.GetContentRegionAvail().X - 35); if (ImGui.BeginCombo("##SelectorThreadCombo", selString)) { foreach (PlottedGraph selectablegraph in graphs) { string caption = $"{selectablegraph.TID}: {selectablegraph.InternalProtoGraph.FirstInstrumentedModuleName}"; int nodeCount = selectablegraph.GraphNodeCount(); if (nodeCount == 0) { ImGui.PushStyleColor(ImGuiCol.Text, Themes.GetThemeColourUINT(Themes.eThemeColour.Dull1)); caption += " [Uninstrumented]"; } else { ImGui.PushStyleColor(ImGuiCol.Text, Themes.GetThemeColourUINT(Themes.eThemeColour.WindowText)); caption += $" [{nodeCount} nodes]"; } if (ImGui.Selectable(caption, graph.ThreadID == selectablegraph.TID) && nodeCount > 0) { selectedGraph = selectablegraph; } if (ImGui.IsItemHovered()) { ImGui.BeginTooltip(); ImGui.Text($"Thread Start: 0x{selectablegraph.InternalProtoGraph.StartAddress:X} [{selectablegraph.InternalProtoGraph.StartModuleName}]"); if (selectablegraph.InternalProtoGraph.NodeList.Count > 0) { NodeData?n = selectablegraph.InternalProtoGraph.GetNode(0); if (n is not null) { string insBase = System.IO.Path.GetFileName(graph.ProcessData.GetModulePath(n.GlobalModuleID)); ImGui.Text($"First Instrumented: 0x{n.Address:X} [{insBase}]"); } } ImGui.EndTooltip(); } ImGui.PopStyleColor(); } ImGui.EndCombo(); } ImGui.SameLine(); ImGui.Text($"{ImGuiController.FA_ICON_COG}"); } } }
public int Compare(object?x, object?y) { Debug.Assert(x == null || x is NodeData || x is IDtdDefaultAttributeInfo); Debug.Assert(y == null || y is NodeData || y is IDtdDefaultAttributeInfo); string localName, localName2; string prefix, prefix2; if (x == null) { return(y == null ? 0 : -1); } else if (y == null) { return(1); } NodeData?nodeData = x as NodeData; if (nodeData != null) { localName = nodeData.localName; prefix = nodeData.prefix; } else { if (x is IDtdDefaultAttributeInfo attrDef) { localName = attrDef.LocalName; prefix = attrDef.Prefix; } else { throw new XmlException(SR.Xml_DefaultException, string.Empty); } } nodeData = y as NodeData; if (nodeData != null) { localName2 = nodeData.localName; prefix2 = nodeData.prefix; } else { if (y is IDtdDefaultAttributeInfo attrDef) { localName2 = attrDef.LocalName; prefix2 = attrDef.Prefix; } else { throw new XmlException(SR.Xml_DefaultException, string.Empty); } } // string.Compare does reference euqality first for us, so we don't have to do it here int result = string.Compare(localName, localName2, StringComparison.Ordinal); if (result != 0) { return(result); } return(string.Compare(prefix, prefix2, StringComparison.Ordinal)); }
//peforms non-sequence-critical graph updates //update nodes with cached execution counts and new edges from unchained runs //also updates graph with delayed edge notifications private void AssignBlockRepeats() { Stopwatch ABRtime = new System.Diagnostics.Stopwatch(); ABRtime.Start(); int RecordedBlocksQty = protograph.BlocksFirstLastNodeList.Count; for (var i = blockRepeatQueue.Count - 1; i >= 0; i--) { BLOCKREPEAT brep = blockRepeatQueue[i]; NodeData? n = null; if (brep.blockInslist == null) { if (brep.blockID >= protograph.ProcessData.BasicBlocksList.Count) { continue; } var block = protograph.ProcessData.BasicBlocksList[(int)brep.blockID]; if (block is null) { continue; } brep.blockInslist = block.Item2; } //we have to validate that all the data is available before making any changes bool needWait = false; foreach (var targblockID_Count in brep.targEdges) { int edgeblock = (int)targblockID_Count.Item1; if (edgeblock >= protograph.ProcessData.BasicBlocksList.Count) { //block has not been processed yet needWait = true; break; } if (edgeblock >= protograph.BlocksFirstLastNodeList.Count || (protograph.BlocksFirstLastNodeList[edgeblock] == null && !ApiThunks.ContainsKey(edgeblock))) { var block = protograph.ProcessData.BasicBlocksList[edgeblock]; if (block is null) { continue; } if (block.Item2[0].PossibleidataThunk) { //block has not been processed (and its probably (...) not a thunk) needWait = true; break; } } var blockB = protograph.ProcessData.BasicBlocksList[edgeblock]; if (blockB is null || !blockB.Item2[0].InThread(protograph.ThreadID)) { //block has not been placed on graph needWait = true; break; } } if (needWait) { continue; } //store pending changes, only apply them if all the data is available List <Tuple <NodeData, ulong> > increaseNodes = new List <Tuple <NodeData, ulong> >(); List <Tuple <EdgeData, ulong> > increaseEdges = new List <Tuple <EdgeData, ulong> >(); InstructionData lastIns = brep.blockInslist[^ 1];
/// <summary> /// Creates an array of metadata for basic blocks used for basic-block-centric graph layout /// item[0] = blockID /// item[1] = offsetFromCenter; number of nodes ahead the center node is /// item[2] = centerPseudoBlockTopID; top of the block this node is in /// item[3] = centerPseudoBlockBaseID; base of the block this node is in /// </summary> /// <param name="plot">The graph being plotted</param> /// <param name="blockData">Output description of basic block information for each node</param> /// <param name="blockMiddles">Output List of basic block middle nodes</param> private static bool CreateBlockMetadataBuf(PlottedGraph plot, out NODE_BLOCK_METADATA_COMPUTEBUFFER[] blockData, out int[] blockMiddles) { ProtoGraph graph = plot.InternalProtoGraph; List <int>[] nodeNeighboursArray = plot.GetNodeNeighboursArray(); int nodeCount = nodeNeighboursArray.Length; NODE_BLOCK_METADATA_COMPUTEBUFFER[] blockDataInts = new NODE_BLOCK_METADATA_COMPUTEBUFFER[nodeCount]; Dictionary <int, int> blockMiddlesDict = new Dictionary <int, int>(); List <int> blockMiddleNodesList = new List <int>(); Dictionary <int, NodeData> exceptionBlocks = new(); /* * Step 1: Build a list of active blocks (ie: blocks which currently have instructions in, * as opposed to blocks which have been split into new ones by control flow */ List <int> activeBlockIDs = new(); Dictionary <int, int> NodeBlockToBlockMetaIndex = new(); Dictionary <int, int> BlockMetaToBlockFirstLastIndex = new(); for (var i = 0; i < nodeCount; i++) { NodeData n = graph.NodeList[i]; int nodeBlockID = (int)n.BlockID; if (NodeBlockToBlockMetaIndex.TryGetValue(nodeBlockID, out int metaBlockID) is false || activeBlockIDs.Contains(metaBlockID) is false) { metaBlockID = activeBlockIDs.Count; NodeBlockToBlockMetaIndex[nodeBlockID] = metaBlockID; BlockMetaToBlockFirstLastIndex[metaBlockID] = nodeBlockID; activeBlockIDs.Add(metaBlockID); if (n.CausedException) { exceptionBlocks[metaBlockID] = n; } } } //Step 2: Build the list of block center nodes that the block velocity shader will run over blockMiddleNodesList.Capacity = activeBlockIDs.Count; foreach (int blockIdx in activeBlockIDs) { if (blockIdx == -1) { blockMiddleNodesList.Add(-1); } int originalBlockIndex = BlockMetaToBlockFirstLastIndex[blockIdx]; if (originalBlockIndex < 0 || originalBlockIndex >= graph.BlocksFirstLastNodeList.Count) { blockMiddlesDict[blockIdx] = -1; //instructions sent and not executed? why? blockMiddleNodesList.Add((int)-1); continue; } var firstIdx_LastIdx = graph.BlocksFirstLastNodeList[originalBlockIndex]; if (firstIdx_LastIdx == null) { continue; } if (firstIdx_LastIdx.Item1 == firstIdx_LastIdx.Item2) { if (blockMiddleNodesList.Contains((int)firstIdx_LastIdx.Item1)) { continue; } blockMiddlesDict[blockIdx] = (int)firstIdx_LastIdx.Item1; //1 node block, top/mid/base is the same blockMiddleNodesList.Add((int)firstIdx_LastIdx.Item1); //Debug.Assert(blockIdx == (blockMiddleNodesList.Count-1)); } else { var block = graph.ProcessData.BasicBlocksList[originalBlockIndex]?.Item2; Debug.Assert(block is not null); int midIdx = (int)Math.Ceiling((block.Count - 1.0) / 2.0); var middleIns = block[midIdx]; if (!middleIns.GetThreadVert(graph.ThreadID, out uint centerNodeID)) { blockMiddlesDict[blockIdx] = -1; //instructions sent and not executed? why? //Debug.Assert(false, $"Instruction 0x{middleIns.address:X} not found in thread {tid}"); } else { //if (blockMiddleNodesList.Contains((int)centerNodeID)) //{ // continue; //} blockMiddlesDict[blockIdx] = (int)centerNodeID; blockMiddleNodesList.Add((int)centerNodeID); //Debug.Assert(blockIdx == (blockMiddleNodesList.Count - 1)); } } } /* * Step 3: Build the block metadata buffer which allows the position and velocity shaders to process each * node in the context of the block it is in */ int externals = 0; for (uint nodeIdx = 0; nodeIdx < nodeCount; nodeIdx++) { NodeData?n = graph.GetNode(nodeIdx); Debug.Assert(n is not null); int blockID; int offsetFromCenter; Tuple <uint, uint>?FirstLastIdx; if (!n.IsExternal) { if (n.BlockID >= graph.BlocksFirstLastNodeList.Count) { continue; } FirstLastIdx = graph.BlocksFirstLastNodeList[(int)n.BlockID]; //bug: this can happen before bflnl is filled if (FirstLastIdx == null) { continue; } blockID = NodeBlockToBlockMetaIndex[(int)n.BlockID]; if (!blockMiddlesDict.ContainsKey(blockID)) { continue; } var blockEntry = graph.ProcessData.BasicBlocksList[(int)n.BlockID]; Debug.Assert(blockEntry is not null); int blockNodeCount = blockEntry.Item2.Count; if (exceptionBlocks.TryGetValue(blockID, out NodeData? exceptionNode) && exceptionNode is not null) { for (int bIdx = 0; bIdx < blockNodeCount; bIdx++) { if (blockEntry.Item2[bIdx].Address == exceptionNode.Address) { blockNodeCount = bIdx + 1; break; } } } int midIdx = (int)Math.Ceiling((blockNodeCount - 1.0) / 2.0); offsetFromCenter = n.BlockIndex - midIdx; } else { externals += 1; FirstLastIdx = new Tuple <uint, uint>(n.Index, n.Index); offsetFromCenter = 0; blockMiddleNodesList.Add((int)n.Index); //external nodes dont have a block id so just give them a unique one //all that matters in the shader is it's unique blockID = blockMiddleNodesList.Count; blockMiddlesDict[blockID] = (int)n.Index; } int blockTopNodeIndex = -1; int blockBaseNodeIndex = -1; if (offsetFromCenter is 0) { if (graph.GetNode(FirstLastIdx.Item1)?.IncomingNeighboursSet.Count > 0) { blockTopNodeIndex = (int)FirstLastIdx.Item1; } else { //these are all back edges, which have 0 force /* * //the top of the block wasnt connected to anything * //there might be a connection below though * List<InstructionData>? blockInslist = graph.ProcessData.BasicBlocksList[(int)n.BlockID]?.Item2; * if (blockInslist is not null) * { * for (var i = 1; i < blockInslist.Count; i++) * { * uint n2Idx = (uint)(FirstLastIdx.Item1 + i); * NodeData? n2 = graph.GetNode(n2Idx); * if (n2 is not null && n2.IncomingNeighboursSet.Count > 0) * { * blockTopNodeIndex = (int)n2Idx; * break; * } * } * } */ } if (graph.GetNode(FirstLastIdx.Item2)?.OutgoingNeighboursSet.Count > 0) { blockBaseNodeIndex = (int)FirstLastIdx.Item2; } } blockDataInts[nodeIdx].MetaBlockIndex = blockID; blockDataInts[nodeIdx].OffsetFromCenter = offsetFromCenter; blockDataInts[nodeIdx].BlockTopEdgeList = blockTopNodeIndex; blockDataInts[nodeIdx].BlockBaseEdgeList = blockBaseNodeIndex != blockTopNodeIndex ? blockBaseNodeIndex : -1; //Debug.Assert(offsetFromCenter is not 0 || n.IsExternal || (blockMiddleNodesList[blockID] == (int)nodeIdx)); } blockMiddles = blockMiddleNodesList.ToArray(); blockData = blockDataInts; return(true); }