Beispiel #1
0
        private ProfileThread AddThread(int start)
        {
            Debug.Assert(Calls[start].ppid == Owner.Threadppid);
            int entryPoint = start + 1;
            int ownerId, depth;

            /* Don't crash if were a thread with no children at the end of the calls array */
            if (entryPoint < Calls.Length && Calls[start].ppid == Owner.Threadppid)
            {
                ownerId    = Calls[entryPoint].ppid;
                depth      = Calls[entryPoint].Depth;
                entryPoint = -1;

                /* Try to find a better node to use for a thread name and entryPoint if we hit HeapAllocator::Free or HeapAllocator::Allocate as the first node */
                for (int j = start + 1; j < Calls.Length; j++)
                {
                    if (Calls[j].Depth < depth)
                    {
                        break;
                    }
                    else if (Calls[j].Depth != depth)
                    {
                        /* Skip nested nodes */
                        continue;
                    }
                    int id = Calls[j].ppid;

                    if ((id == Owner.ServerGameUpdateId || id == Owner.ClientGameUpdateId))
                    {
                        entryPoint = j;
                        ownerId    = id;
                        break;
                    }

                    // Set a default incase we don't find ClientGame or ServerGame update root node
                    if (entryPoint == -1 && id != Owner.HeapFreeId && id != Owner.HeapAllocateId)
                    {
                        entryPoint = j;
                        ownerId    = id;
                    }
                }
            }
            else
            {
                depth      = Calls[start].Depth + 1;
                ownerId    = Owner.Threadppid;
                entryPoint = start;
            }

            var thread = new ProfileThread(this, ownerId, Owner.ppMap[ownerId])
            {
                StartIndex      = start,
                Time            = Calls[start].Time,
                EntryPointIndex = entryPoint,
            };

            if (ownerId == Owner.ServerGameUpdateId || ownerId == Owner.ClientGameUpdateId)
            {
                thread.Flags |= ProfileThreadFlag.MainThread;
                MainThread    = thread;
            }

            Threads.Add(thread);
            return(thread);
        }
Beispiel #2
0
        public void ComputeTime()
        {
            Threads = new List <ProfileThread>();

            if (Calls == null)
            {
                Calls = Array.Empty <CallRecord>();
                return;
            }

            int threadNodeId = Owner.Threadppid;
            int gcNodeId     = Owner.ScriptGC_STEP;

            int           prevDepth = 0, parent = 0;
            ProfileThread thread = null;

            var depthToParent = new int[MaxDepth + 1];

            for (int i = 1; i < Calls.Length; i++)
            {
                int depth = Calls[i].Depth;
                var time  = Calls[i].Time;

                if (Calls[i].ppid == threadNodeId)
                {
                    // Set the node count for the previous thread
                    if (thread != null)
                    {
                        thread.NodeCount = i - thread.StartIndex;
                    }

                    thread = AddThread(i);
                }
                else if (thread == null)
                {
                    // Skip until we hit a thread because the profiler lost its current profile node context
                    continue;
                }

                Calls[i].ExclusiveTime = time;

                if (depth > prevDepth)
                {
                    // We've entered a child node record the previous node as the parent for this depth
                    parent = Math.Max(i - 1, 0);
                    Debug.Assert(Calls[parent].Depth == depth - 1);
                    depthToParent[depth] = parent;
                }
                else if (depth < prevDepth)
                {
                    parent = depthToParent[depth];

                    if (i > 0 && depth == 0)
                    {
                        parent = i;
                    }
                    Debug.Assert(depth == 0 || depthToParent[depth] < i && Calls[depthToParent[depth]].Depth < depth);
                }

                if (Owner.IdleNodes.Contains(Calls[i].ppid))
                {
                    if (thread != null)
                    {
                        thread.AddIdleTime(time, Calls[i].CallCount);
                    }
                    SubTime(i, depthToParent);
                }

                if (Calls[i].ppid == gcNodeId && thread.Name != "CollectGarbageJob::Run")
                {
                    if (thread != null)
                    {
                        // Lift out the GC nodes so they don't distort actual CPU costs when analysing
                        thread.AddGCTime(time, Calls[i].CallCount);
                    }

                    // Subtract time from all the parents of this Node
                    SubTime(i, depthToParent);
                }

                /* Round*/
                int newTime = (int)Calls[parent].ExclusiveTime - (int)time;
                if (newTime < 0)
                {
                    /*
                     * HeapAllocator::Free and HeapAllocator::Free
                     * seem to have weird times
                     */
                    //Debug.Assert(parent == 0 || newTime >= -1);
                    newTime = 0;
                }
                Calls[parent].ExclusiveTime = (uint)newTime;
                Debug.Assert(parent == 0 || parent == thread.StartIndex || (Calls[parent].ExclusiveTime >= 0));

                prevDepth = depth;
            }

            if (thread != null)
            {
                thread.NodeCount = Calls.Length - thread.StartIndex;
            }
            Debug.Assert(MainThread != null);
        }