Пример #1
0
        private static void PerformEdgeHeatRanking(ProtoGraph graph)
        {
            if (graph.EdgeCount < 10)
            {
                return;
            }

            var edgeList = graph.GetEdgeObjListCopy();

            var allEdgeExecutions = edgeList.Select(e => e.ExecutionCount).Distinct().ToList();

            allEdgeExecutions.Sort();

            float decile  = allEdgeExecutions.Count / 10f;
            float current = decile;


            ulong[] EdgeHeatThresholds = new ulong[9];
            for (var i = 0; i < 9; i++)
            {
                EdgeHeatThresholds[i] = allEdgeExecutions.ElementAt((int)current);
                current += decile;
            }

            foreach (EdgeData e in edgeList)
            {
                ulong execCount = e.ExecutionCount;
                int   threshold = 0;
                while (threshold < EdgeHeatThresholds.Length && execCount > EdgeHeatThresholds[threshold])
                {
                    threshold++;
                }
                e.heatRank = threshold;
            }
        }
Пример #2
0
            /// <summary>
            /// Create a timeline event
            /// </summary>
            /// <param name="timelineEventType">The base category</param>
            /// <param name="item">The event data</param>
            public TIMELINE_EVENT(eTimelineEvent timelineEventType, object item) : base(eLogFilterBaseType.TimeLine)
            {
                _eventType = timelineEventType;
                _item      = item;
                switch (timelineEventType)
                {
                case eTimelineEvent.ProcessStart:
                case eTimelineEvent.ProcessEnd:
                {
                    TraceRecord process = (TraceRecord)item;
                    SetIDs(ID: process.PID);
                    break;
                }

                case eTimelineEvent.ThreadStart:
                case eTimelineEvent.ThreadEnd:
                {
                    ProtoGraph thread = (ProtoGraph)item;
                    SetIDs(ID: thread.ThreadID);
                    break;
                }

                case eTimelineEvent.APICall:
                {
                    TraceRecord process = ((APICALL)item).Graph !.TraceData;
                    SetIDs(process.PID);
                    break;
                }

                default:
                    Debug.Assert(false, "Bad timeline event");
                    break;
                }
                Inited = true;
            }
Пример #3
0
        private static void PerformNodeHeatRanking(ProtoGraph graph)
        {
            if (graph.NodeList.Count < 10)
            {
                return;
            }

            var nodeSpan = graph.GetNodeObjlistSpan();

            var allNodeExecutions = nodeSpan.ToArray().Select(n => n.ExecutionCount).ToList();

            allNodeExecutions.Sort();


            System.Collections.Generic.List <ulong> NodeHeatThresholds = Enumerable.Repeat((ulong)0, 9).ToList();
            int decile  = allNodeExecutions.Count / 10;
            int current = decile;

            for (var i = 0; i < 9; i++)
            {
                NodeHeatThresholds[i] = allNodeExecutions.ElementAt(current);
                current += decile;
            }

            foreach (NodeData n in nodeSpan)
            {
                ulong execCount = n.ExecutionCount;
                int   threshold = 0;
                while (threshold < NodeHeatThresholds.Count && execCount > NodeHeatThresholds[threshold])
                {
                    threshold++;
                }
                n.HeatRank = threshold;
            }
        }
Пример #4
0
            /// <summary>
            /// Get the label of the timeline event
            /// </summary>
            /// <returns>The list of strings and colours which need to be joined to make a label</returns>
            public List <Tuple <string, WritableRgbaFloat> > Label()
            {
                Debug.Assert(_item is not null);
                if (_cachedLabel != null && _cachedLabelTheme == Themes.ThemeVariant)
                {
                    return(_cachedLabel);
                }

                _cachedLabel      = new List <Tuple <string, WritableRgbaFloat> >();
                _cachedLabelTheme = Themes.ThemeVariant;

                WritableRgbaFloat textColour = Themes.GetThemeColourWRF(Themes.eThemeColour.WindowText);

                switch (_eventType)
                {
                case eTimelineEvent.ProcessStart:
                {
                    TraceRecord trace = (TraceRecord)_item;
                    _cachedLabel.Add(new Tuple <string, WritableRgbaFloat>($"Process ({trace.PID}) Started", textColour));
                    break;
                }

                case eTimelineEvent.ProcessEnd:
                {
                    TraceRecord trace = (TraceRecord)_item;
                    _cachedLabel.Add(new Tuple <string, WritableRgbaFloat>($"Process ({trace.PID}) Ended", textColour));
                    break;
                }

                case eTimelineEvent.ThreadStart:
                {
                    ProtoGraph graph = (ProtoGraph)_item;
                    _cachedLabel.Add(new Tuple <string, WritableRgbaFloat>($"Thread ({graph.ThreadID}) Started", textColour));
                    break;
                }

                case eTimelineEvent.ThreadEnd:
                {
                    ProtoGraph graph = (ProtoGraph)_item;
                    _cachedLabel.Add(new Tuple <string, WritableRgbaFloat>($"Thread ({graph.ThreadID}) Ended", textColour));
                    break;
                }

                case eTimelineEvent.APICall:
                {
                    Logging.APICALL call       = (Logging.APICALL)_item;
                    NodeData        n          = call.Node !;
                    var             labelitems = n.CreateColourisedSymbolCall(call.Graph, call.Index, textColour, Themes.GetThemeColourWRF(Themes.eThemeColour.Emphasis1));
                    _cachedLabel.AddRange(labelitems);
                    break;
                }

                default:
                    _cachedLabel.Add(new Tuple <string, WritableRgbaFloat>($"Bad timeline event: ", textColour));
                    Debug.Assert(false, $"Bad timeline event: {_eventType}");
                    return(_cachedLabel);
                }
                return(_cachedLabel);
            }
Пример #5
0
        /// <summary>
        /// Worker for processing trace data
        /// </summary>
        /// <param name="newProtoGraph">Thread graph being processed</param>
        public ThreadTraceProcessingThread(ProtoGraph newProtoGraph)
        {
            protograph = newProtoGraph;

            if (rgatState.ConnectedToRemote && rgatState.NetworkBridge.HeadlessMode)
            {
                Logging.RecordLogEvent("Error: Trace processor created in headless mode", Logging.LogFilterType.Error);
                rgatState.NetworkBridge.Teardown("TraceProcessor created in wrong mode");
            }
        }
Пример #6
0
        private readonly object _lock           = new object(); //functionality first, performance later

        public SocketTraceIngestThread(ProtoGraph newProtoGraph)
        {
            protograph = newProtoGraph;

            /*
             * _updateRates = Enumerable.Repeat(0.0f, _StatCacheSize).ToList();
             *
             * StatsTimer = new System.Timers.Timer(1000.0 / GlobalConfig.IngestStatsPerSecond);
             * StatsTimer.Elapsed += StatsTimerFired;
             * StatsTimer.AutoReset = true;
             * StatsTimer.Start();
             */
        }
Пример #7
0
        private void update_rendering(PlottedGraph graph)
        {
            ProtoGraph protoGraph = graph.InternalProtoGraph;

            if (protoGraph == null || protoGraph.EdgeCount == 0)
            {
                return;
            }

            //if (graph.NodesDisplayData == null)// || !graph.setGraphBusy(true, 2))
            //	return;

            if (graph.ReplayState == PlottedGraph.REPLAY_STATE.Ended && protoGraph.Terminated)
            {
                graph.ResetAnimation();
            }

            //update the render if there are more verts/edges or graph is being resized

            graph.RenderGraph();

            if (!protoGraph.Terminated)
            {
                if (graph.IsAnimated)
                {
                    graph.ProcessLiveAnimationUpdates(out int doneCount);
                }
            }
            else
            {
                if (graph.InternalProtoGraph.TraceData.DiscardTraceData is false &&
                    (graph.ReplayState == PlottedGraph.REPLAY_STATE.Playing ||
                     graph._userSelectedAnimPosition != -1))
                {
                    if (--_nextReplayStep <= 0)
                    {
                        graph.ProcessReplayUpdates();
                        _nextReplayStep = _FramesBetweenAnimationUpdates;
                    }
                }
            }
        }
Пример #8
0
        private static bool EvaluateProcessTestResults(TraceRequirements requirements, TRACE_TEST_RESULTS results, int depth)
        {
            //need to ensure each set of thread requirements can be satisfied by at least one unique thread

            Dictionary <REQUIREMENTS_LIST, List <ProtoGraph> > reqSatisfyGraphs = new Dictionary <REQUIREMENTS_LIST, List <ProtoGraph> >();

            foreach (REQUIREMENTS_LIST reqlist in requirements.ThreadRequirements)
            {
                reqSatisfyGraphs[reqlist] = new List <ProtoGraph>();
            }

            foreach (var threadReqList in requirements.ThreadRequirements)
            {
                Dictionary <ProtoGraph, REQUIREMENT_TEST_RESULTS> allThreadResults = results.ThreadResults[threadReqList];
                foreach (var graph_results in allThreadResults)
                {
                    ProtoGraph graph = graph_results.Key;
                    if (graph_results.Value.Failed.Count == 0)
                    {
                        reqSatisfyGraphs[threadReqList].Add(graph);
                    }
                }
            }
            bool threadsVerified   = VerifyAllThreadRequirements(reqSatisfyGraphs, out string?threadVerifyError);
            bool processesVerified = results.ProcessResults.Failed.Count == 0;

            //if(!threadsVerified) FailedTestRequirements.Add(null, $"Thread traces didn't satisfy conditions list: "+threadVerifyError);
            //if(!processesVerified) FailedTestRequirements.Add(null, $"{results.ProcessResults.Failed.Count} requirements failed");

            return(threadsVerified && processesVerified);

            //todo - multi process tests

            /*
             * foreach(var x in results.ChildResults)
             * {
             *  TRACE_TEST_RESULTS processThreadResults = childtrace.EvaluateProcessTestRequirement(processThreadReqs);
             *  EvaluateProcessTestResults(processThreadReqs, processThreadResults);
             * }
             */
        }
Пример #9
0
        private void DrawEventListTable(TraceRecord trace, SandboxChart.ItemNode?selectedNode)
        {
            if (chart is null)
            {
                return;
            }

            ImGui.PushStyleColor(ImGuiCol.Header, Themes.GetThemeColourUINT(Themes.eThemeColour.Emphasis2, 40));
            TIMELINE_EVENT[] events = trace.GetTimeLineEntries();
            if (ImGui.BeginTable("#TaTTFullList", 4, ImGuiTableFlags.Borders | ImGuiTableFlags.ScrollY |
                                 ImGuiTableFlags.Resizable | ImGuiTableFlags.RowBg))
            {
                ImGui.TableSetupScrollFreeze(0, 1);
                ImGui.TableSetupColumn("#", ImGuiTableColumnFlags.WidthFixed, 50);
                ImGui.TableSetupColumn("Type", ImGuiTableColumnFlags.WidthFixed, 70);
                ImGui.TableSetupColumn("Module", ImGuiTableColumnFlags.WidthFixed, 70);
                ImGui.TableSetupColumn("Details", ImGuiTableColumnFlags.None);
                ImGui.TableHeadersRow();

                var SelectedEntity   = chart.SelectedEntity;
                var SelectedAPIEvent = chart.SelectedAPIEvent;

                bool ThreadNodeSelected  = selectedNode is not null && Equals(selectedNode.reference.GetType(), typeof(ProtoGraph));
                bool ProcessNodeSelected = selectedNode is not null && Equals(selectedNode.reference.GetType(), typeof(TraceRecord));


                int i = 0;
                foreach (TIMELINE_EVENT TLevent in events)
                {
                    i += 1;

                    ImGui.TableNextRow();
                    if (TLevent.MetaError != null)
                    {
                        ImGui.TableSetBgColor(ImGuiTableBgTarget.RowBg0, Themes.GetThemeColourUINT(Themes.eThemeColour.BadStateColour));
                        ImGui.TableSetBgColor(ImGuiTableBgTarget.RowBg1, Themes.GetThemeColourUINT(Themes.eThemeColour.BadStateColour));
                    }

                    bool   selected  = false;
                    string eventType = "";
                    string module    = "";
                    if (ImGui.TableNextColumn())
                    {
                        switch (TLevent.TimelineEventType)
                        {
                        case eTimelineEvent.ProcessStart:
                        case eTimelineEvent.ProcessEnd:
                            eventType = "Process";

                            if (selectedNode != null)
                            {
                                selected = (ProcessNodeSelected && TLevent.ID == ((TraceRecord)selectedNode.reference).PID);
                            }

                            break;

                        case eTimelineEvent.ThreadStart:
                        case eTimelineEvent.ThreadEnd:
                            eventType = "Thread";
                            if (selectedNode != null)
                            {
                                ProtoGraph currentEntryGraph = (ProtoGraph)TLevent.Item;
                                selected = (ThreadNodeSelected && currentEntryGraph.ThreadID == ((ProtoGraph)selectedNode.reference).ThreadID);
                                selected = selected || (ProcessNodeSelected && currentEntryGraph.TraceData.PID == ((TraceRecord)(selectedNode.reference)).PID);
                            }
                            break;

                        case eTimelineEvent.APICall:
                        {
                            Logging.APICALL call = (Logging.APICALL)(TLevent.Item);
                            selected = TLevent == SelectedAPIEvent;

                            if (call.Node !.IsExternal)
                            {
                                eventType = "API - " + call.APIType();
                                module    = Path.GetFileNameWithoutExtension(trace.DisassemblyData.GetModulePath(call.Node.GlobalModuleID));

                                //api call is selected if it is either directly activated, or interacts with a reference to the active entity
                                //eg: if the file.txt node is selected, writefile to the relevant handle will also be selected
                                selected = selected || (SelectedEntity != null && SelectedEntity == chart.GetInteractedEntity(TLevent));
                                if (!selected && selectedNode != null)
                                {
                                    //select all apis called by selected thread node
                                    selected = selected || (ThreadNodeSelected && call.Graph !.ThreadID == ((ProtoGraph)selectedNode.reference).ThreadID);
                                    //select all apis called by selected process node
                                    selected = selected || (ProcessNodeSelected && call.Graph !.TraceData.PID == ((TraceRecord)selectedNode.reference).PID);
                                }
                                //WinAPIDetails.API_ENTRY = call.APIEntry;
                            }
                            else
                            {
                                eventType = "Internal";
                            }
                        }
                        break;
                        }

                        if (ImGui.Selectable(i.ToString(), selected, ImGuiSelectableFlags.SpanAllColumns) && !selected)
                        {
                            chart.SelectAPIEvent(TLevent);
                        }
                    }
Пример #10
0
 /// <summary>
 /// Create an APi call
 /// </summary>
 /// <param name="graph">The graph of the thread that called it</param>
 public APICALL(ProtoGraph graph)
 {
     Graph = graph;
 }
Пример #11
0
 /// <summary>
 /// Set the graph (ie: thread) that generated this log
 /// </summary>
 /// <param name="graph">A ProtoGraph</param>
 public void SetAssociatedGraph(ProtoGraph graph)
 {
     Graph = graph;
     Trace = graph.TraceData;
 }
Пример #12
0
        /// <summary>
        /// Draw a chart node
        /// </summary>
        /// <param name="node">The node</param>
        /// <param name="position">Where on the chart to draw it</param>
        /// <param name="font">The font to use for text</param>
        /// <returns>If the node was clicked</returns>
        private bool DrawNode(ItemNode node, Vector2 position, ImFontPtr font)
        {
            Vector2 cursor = ImGui.GetCursorScreenPos();

            if (!InFrame(position - cursor))
            {
                return(false);
            }

            var DrawList = ImGui.GetWindowDrawList();

            bool isSelected = node == _selectedNode;

            switch (node.TLtype)
            {
            case Logging.eTimelineEvent.ProcessStart:
            case Logging.eTimelineEvent.ProcessEnd:
            {
                TraceRecord trace = (TraceRecord)node.reference;
                switch (trace.TraceState)
                {
                case TraceRecord.ProcessState.eTerminated:
                    DrawList.AddCircleFilled(position, 18, isSelected ? 0xffDDDDDD : 0xFFFFFFFF);
                    DrawList.AddText(font, 25, position - new Vector2(12.5f, 12.5f), 0xff0000ff, $"{ImGuiController.FA_ICON_COGS}");
                    DrawList.AddText(position + new Vector2(20, -14), 0xff000000, $"Process {trace.PID} (Exited)");
                    break;

                case TraceRecord.ProcessState.eRunning:
                    DrawList.AddCircleFilled(position, 18, isSelected ? 0xffDDDDDD : 0xFFFFFFFF);
                    DrawList.AddText(font, 25, position - new Vector2(12.5f, 12.5f), 0xff00ff00, $"{ImGuiController.FA_ICON_COGS}");
                    DrawList.AddText(position + new Vector2(20, -14), 0xff000000, $"Process {trace.PID} (Running)");
                    break;

                case TraceRecord.ProcessState.eSuspended:
                    DrawList.AddCircleFilled(position, 18, isSelected ? 0xffDDDDDD : 0xFFFFFFFF);
                    DrawList.AddText(font, 25, position - new Vector2(12.5f, 12.5f), 0xff00ffff, $"{ImGuiController.FA_ICON_COGS}");
                    DrawList.AddText(position + new Vector2(20, -14), 0xff000000, $"Process {trace.PID} (Suspended)");
                    break;

                default:
                    Debug.Assert(false, "Bad trace state");
                    break;
                }
            }
            break;

            case Logging.eTimelineEvent.ThreadStart:
            case Logging.eTimelineEvent.ThreadEnd:
            {
                ProtoGraph graph = (ProtoGraph)node.reference;
                if (graph.Terminated)
                {
                    DrawList.AddCircleFilled(position, 18, isSelected ? 0xffDDDDDD : 0xFFFFFFFF);
                    DrawList.AddText(font, 25, position - new Vector2(12.5f, 12.5f), 0xff0000ff, $"{ImGuiController.FA_ICON_COG}");
                    DrawList.AddText(position + new Vector2(20, -14), 0xff000000, $"Thread {graph.ThreadID} (Exited)");
                }
                else
                {
                    DrawList.AddCircleFilled(position, 18, isSelected ? 0xffDDDDDD : 0xFFFFFFFF);
                    DrawList.AddText(font, 25, position - new Vector2(12.5f, 12.5f), 0xff00ff00, $"{ImGuiController.FA_ICON_COG}");
                    DrawList.AddText(position + new Vector2(20, -14), 0xff000000, $"Thread {graph.ThreadID} (Active)");
                }
            }
            break;

            case Logging.eTimelineEvent.APICall:
                Logging.TIMELINE_EVENT apiEvent = (Logging.TIMELINE_EVENT)node.reference;
                Logging.APICALL        apicall  = (Logging.APICALL)apiEvent.Item;
                if (!apicall.APIDetails.HasValue)
                {
                    return(false);
                }
                APIDetailsWin.API_ENTRY details = apicall.APIDetails.Value;

                DrawList.AddCircleFilled(position, 18, isSelected ? 0xffDDDDDD : 0xFFFFFFFF);
                switch (details.FilterType)
                {
                case "File":
                    DrawList.AddText(font, 20, position - new Vector2(10f, 10f), 0xff000000, $"{ImGuiController.FA_ICON_FILECODE}");
                    DrawList.AddText(position + new Vector2(20, -15), 0xff000000, "File Interaction");
                    DrawList.AddText(position + new Vector2(20, 5), 0xff000000, node.label);
                    break;

                case "Registry":
                    DrawList.AddText(font, 25, position - new Vector2(12.5f, 12.5f), 0xff000000, $"{ImGuiController.FA_ICON_SQUAREGRID}");
                    DrawList.AddText(position + new Vector2(20, -15), 0xff000000, "Registry Interaction");
                    DrawList.AddText(position + new Vector2(20, 5), 0xff000000, node.label);
                    break;

                case "Process":
                    DrawList.AddText(font, 25, position - new Vector2(12.5f, 12.5f), 0xff000000, $"{ImGuiController.FA_ICON_COGS}");
                    DrawList.AddText(position + new Vector2(20, -15), 0xff000000, "Process Interaction");
                    DrawList.AddText(position + new Vector2(20, 5), 0xff000000, node.label);
                    break;

                case "Network":
                    DrawList.AddText(font, 25, position - new Vector2(12.5f, 12.5f), 0xff000000, $"{ImGuiController.FA_ICON_NETWORK}");
                    DrawList.AddText(position + new Vector2(20, -15), 0xff000000, "Network Interaction");
                    DrawList.AddText(position + new Vector2(20, 5), 0xff000000, node.label);
                    break;

                default:
                    DrawList.AddText(font, 25, position - new Vector2(12.5f, 12.5f), 0xff000000, $"{ImGuiController.FA_ICON_UP}");
                    DrawList.AddText(position + new Vector2(20, -15), 0xff000000, details.FilterType);
                    DrawList.AddText(position + new Vector2(20, 5), 0xff000000, node.label);
                    break;
                }
                break;


            default:
                DrawList.AddCircleFilled(position, nodeSize, 0xff000000);
                break;
            }


            if (node == _selectedNode)
            {
                DrawList.AddCircle(position, 18, 0xff222222);
            }
            ImGui.SetCursorScreenPos(position - new Vector2(12, 12));
            ImGui.InvisibleButton($"##{position.X}-{position.Y}", new Vector2(25, 25));
            bool clicked = false;

            if (ImGui.IsItemClicked())
            {
                clicked       = true;
                _selectedNode = node;
                if (_selectedNode.TLtype == Logging.eTimelineEvent.APICall)
                {
                    SelectedEntity   = node;
                    SelectedAPIEvent = (Logging.TIMELINE_EVENT)node.reference;
                }
                else
                {
                    SelectedEntity   = null;
                    SelectedAPIEvent = null;
                }
            }

            //Vector2 labelSize = ImGui.CalcTextSize(node.label);
            //DrawList.AddRectFilled(position, position + labelSize, 0xddffffff);
            ImGui.SetCursorScreenPos(cursor);
            return(clicked);
        }
Пример #13
0
        private static bool VerifyAllThreadRequirements(Dictionary <REQUIREMENTS_LIST, List <ProtoGraph> > reqSatisfyGraphs, out string?error)
        {
            error = "";
            int reqListCount = reqSatisfyGraphs.Count;
            List <REQUIREMENTS_LIST> unsatisfied = new List <REQUIREMENTS_LIST>();

            List <Tuple <REQUIREMENTS_LIST, ProtoGraph> > candidates = new List <Tuple <REQUIREMENTS_LIST, ProtoGraph> >();
            List <ProtoGraph> uniqueGraphs = new List <ProtoGraph>();

            //now we have a list of graphs that satisfy each set of requirements
            //list any requirements that no graphs satisfy
            foreach (var req_graplist in reqSatisfyGraphs)
            {
                REQUIREMENTS_LIST reqs = req_graplist.Key;
                if (req_graplist.Value.Count == 0)
                {
                    unsatisfied.Add(reqs);
                }
                foreach (var validGraph in req_graplist.Value)
                {
                    candidates.Add(new Tuple <REQUIREMENTS_LIST, ProtoGraph>(reqs, validGraph));
                    if (!uniqueGraphs.Contains(validGraph))
                    {
                        uniqueGraphs.Add(validGraph);
                    }
                }
            }
            if (unsatisfied.Count > 0)
            {
                return(false);
            }


            //now pair each requirementlist up to a single graph
            //this might be better solved with a theorem prover, but for now just terribly brute force it
            //might stipulate that each set of requirements needs to be sufficiently specific it will only match 1 graph
            List <Tuple <REQUIREMENTS_LIST, ProtoGraph> > bestList = new List <Tuple <REQUIREMENTS_LIST, ProtoGraph> >();


            List <Tuple <REQUIREMENTS_LIST, ProtoGraph> > currentList = new List <Tuple <REQUIREMENTS_LIST, ProtoGraph> >();

            List <REQUIREMENTS_LIST> usedReqs   = new List <REQUIREMENTS_LIST>();
            List <ProtoGraph>        usedGraphs = new List <ProtoGraph>();

            foreach (var permutation in GetPermutationsWithRept <Tuple <REQUIREMENTS_LIST, ProtoGraph> >(candidates, candidates.Count))
            {
                usedGraphs.Clear();
                usedReqs.Clear();
                currentList.Clear();
                foreach (var req_graph in permutation)
                {
                    ProtoGraph        graph = req_graph.Item2;
                    REQUIREMENTS_LIST reqs  = req_graph.Item1;
                    if (usedReqs.Contains(reqs))
                    {
                        continue;
                    }

                    if (usedGraphs.Contains(graph))
                    {
                        continue;
                    }

                    currentList.Add(req_graph);
                    usedGraphs.Add(graph);
                    usedReqs.Add(reqs);
                    if (usedReqs.Count == reqListCount)
                    {
                        return(true);
                    }
                }
                if (currentList.Count > bestList.Count)
                {
                    bestList = currentList;
                }
            }

            error = $"Failed to satisfy all thread requirements, best attempt was {bestList.Count}/{reqListCount}";
            return(false);
        }
Пример #14
0
        /// <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);
        }