コード例 #1
0
        private unsafe void SortAndDispatch(long stopTimestamp)
        {
            // This sort could be made faster by using a min-heap but this is a simple place to start
            List <Queue <EventMarker> > threadQueues = new List <Queue <EventMarker> >(_threads.Values.Select(t => t.Events));

            while (true)
            {
                long lowestTimestamp = stopTimestamp;
                Queue <EventMarker> oldestEventQueue = null;
                foreach (Queue <EventMarker> threadQueue in threadQueues)
                {
                    if (threadQueue.Count == 0)
                    {
                        continue;
                    }
                    long eventTimestamp = threadQueue.Peek().Header.TimeStamp;
                    if (eventTimestamp < lowestTimestamp)
                    {
                        oldestEventQueue = threadQueue;
                        lowestTimestamp  = eventTimestamp;
                    }
                }
                if (oldestEventQueue == null)
                {
                    break;
                }
                else
                {
                    EventMarker eventMarker = oldestEventQueue.Dequeue();
                    OnEvent?.Invoke(ref eventMarker.Header);
                }
            }

            // If the app creates and destroys threads over time we need to flush old threads
            // from the cache or memory usage will grow unbounded. AddThread handles the
            // the thread objects but the storage for the queue elements also does not shrink
            // below the high water mark unless we free it explicitly. Although not unbounded
            // growth our current runtime policy reads ahead up to 10,000 events ahead per-thread
            // * 5000 threads * 24 bytes = ~1GB. It would be nice not to leave that much memory
            // laying around probably mostly unused.
            foreach (Queue <EventMarker> q in threadQueues)
            {
                if (q.Count == 0)
                {
                    q.TrimExcess();
                }
            }
        }
コード例 #2
0
        public unsafe void ProcessEventBlock(byte[] eventBlockData)
        {
            // parse the header
            if (eventBlockData.Length < 20)
            {
                Debug.Assert(false, "Expected EventBlock of at least 20 bytes");
                return;
            }
            ushort headerSize = BitConverter.ToUInt16(eventBlockData, 0);

            if (headerSize < 20 || headerSize > eventBlockData.Length)
            {
                Debug.Assert(false, "Invalid EventBlock header size");
                return;
            }
            ushort flags = BitConverter.ToUInt16(eventBlockData, 2);
            bool   useHeaderCompression = (flags & (ushort)EventBlockFlags.HeaderCompression) != 0;

            // parse the events
            PinnedBuffer buffer = new PinnedBuffer(eventBlockData);
            byte *       cursor = (byte *)buffer.PinningHandle.AddrOfPinnedObject();
            byte *       end    = cursor + eventBlockData.Length;

            cursor += headerSize;
            EventMarker eventMarker = new EventMarker(buffer);
            long        timestamp   = 0;

            EventPipeEventHeader.ReadFromFormatV4(cursor, useHeaderCompression, ref eventMarker.Header);
            if (!_threads.TryGetValue(eventMarker.Header.CaptureThreadId, out EventCacheThread thread))
            {
                thread = new EventCacheThread();
                thread.SequenceNumber = eventMarker.Header.SequenceNumber - 1;
                AddThread(eventMarker.Header.CaptureThreadId, thread);
            }
            eventMarker = new EventMarker(buffer);
            while (cursor < end)
            {
                EventPipeEventHeader.ReadFromFormatV4(cursor, useHeaderCompression, ref eventMarker.Header);
                bool isSortedEvent = eventMarker.Header.IsSorted;
                timestamp = eventMarker.Header.TimeStamp;
                int sequenceNumber = eventMarker.Header.SequenceNumber;
                if (isSortedEvent)
                {
                    thread.LastCachedEventTimestamp = timestamp;

                    // sorted events are the only time the captureThreadId should change
                    long captureThreadId = eventMarker.Header.CaptureThreadId;
                    if (!_threads.TryGetValue(captureThreadId, out thread))
                    {
                        thread = new EventCacheThread();
                        thread.SequenceNumber = sequenceNumber - 1;
                        AddThread(captureThreadId, thread);
                    }
                }

                int droppedEvents = (int)Math.Min(int.MaxValue, sequenceNumber - thread.SequenceNumber - 1);
                if (droppedEvents > 0)
                {
                    OnEventsDropped?.Invoke(droppedEvents);
                }
                else
                {
                    // When a thread id is recycled the sequenceNumber can abruptly reset to 1 which
                    // makes droppedEvents go negative
                    Debug.Assert(droppedEvents == 0 || sequenceNumber == 1);
                }
                thread.SequenceNumber = sequenceNumber;

                if (isSortedEvent)
                {
                    SortAndDispatch(timestamp);
                    OnEvent?.Invoke(ref eventMarker.Header);
                }
                else
                {
                    thread.Events.Enqueue(eventMarker);
                }

                cursor += eventMarker.Header.TotalNonHeaderSize + eventMarker.Header.HeaderSize;
                EventMarker lastEvent = eventMarker;
                eventMarker        = new EventMarker(buffer);
                eventMarker.Header = lastEvent.Header;
            }
            thread.LastCachedEventTimestamp = timestamp;
        }