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);
                }
            }
Example #2
0
        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;
        }
Example #3
0
        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();
            }
        }
Example #4
0
        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));
            }
Example #6
0
        //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);
        }