1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
5 #ifndef __EVENTPIPE_BUFFER_H__
6 #define __EVENTPIPE_BUFFER_H__
8 #ifdef FEATURE_PERFTRACING
10 #include "eventpipe.h"
11 #include "eventpipeevent.h"
12 #include "eventpipeeventinstance.h"
13 #include "eventpipesession.h"
15 class EventPipeThread;
20 // EventPipeBuffer starts off writable and accumulates events in a buffer, then at some point converts to be readable and a second thread can
21 // read back the events which have accumulated. The transition occurs when calling ConvertToReadOnly(). Write methods will assert if the buffer
22 // isn't writable and read-related methods will assert if it isn't readable. Methods that have no asserts should have immutable results that
23 // can be used at any point during the buffer's lifetime. The buffer has no internal locks so it is the caller's responsibility to synchronize
25 // Writing into the buffer and calling ConvertToReadOnly() is always done with EventPipeThread::m_lock held. The eventual reader thread can do
26 // a few different things to ensure it sees a consistent state:
27 // 1) Take the writer's EventPipeThread::m_lock at least once after the last time the writer writes events
28 // 2) Use a memory barrier that prevents reader loads from being re-ordered earlier, such as the one that will occur implicitly by evaluating
29 // EventPipeBuffer::GetVolatileState()
32 enum EventPipeBufferState
34 // This buffer is currently assigned to a thread and pWriterThread may write events into it
38 // This buffer has been returned to the EventPipeBufferManager and pWriterThread is guaranteed
39 // to never access it again.
46 friend class EventPipeBufferList;
47 friend class EventPipeBufferManager;
51 // Instances of EventPipeEventInstance in the buffer must be 8-byte aligned.
52 // It is OK for the data payloads to be unaligned because they are opaque blobs that are copied via memcpy.
53 const size_t AlignmentSize = 8;
55 // State transition WRITABLE -> READ_ONLY only occurs while holding the m_pWriterThread->m_lock;
56 // It can be read at any time
57 Volatile<EventPipeBufferState> m_state;
59 // Thread that is/was allowed to write into this buffer when m_state == WRITABLE
60 EventPipeThread* m_pWriterThread;
62 // The sequence number corresponding to m_pCurrentReadEvent
63 // Prior to read iteration it is the sequence number of the first event in the buffer
64 unsigned int m_eventSequenceNumber;
66 // A pointer to the actual buffer.
69 // The current write pointer.
72 // The max write pointer (end of the buffer).
75 // The timestamp the buffer was created. If our clock source
76 // is monotonic then all events in the buffer should have
77 // timestamp >= this one. If not then all bets are off.
78 LARGE_INTEGER m_creationTimeStamp;
80 // Pointer to the current event being read
81 EventPipeEventInstance *m_pCurrentReadEvent;
83 // Each buffer will become part of a per-thread linked list of buffers.
84 // The linked list is invasive, thus we declare the pointers here.
85 EventPipeBuffer *m_pPrevBuffer;
86 EventPipeBuffer *m_pNextBuffer;
88 unsigned int GetSize() const
90 LIMITED_METHOD_CONTRACT;
91 return (unsigned int)(m_pLimit - m_pBuffer);
94 EventPipeBuffer* GetPrevious() const
96 LIMITED_METHOD_CONTRACT;
100 EventPipeBuffer* GetNext() const
102 LIMITED_METHOD_CONTRACT;
103 return m_pNextBuffer;
106 void SetPrevious(EventPipeBuffer *pBuffer)
108 LIMITED_METHOD_CONTRACT;
109 m_pPrevBuffer = pBuffer;
112 void SetNext(EventPipeBuffer *pBuffer)
114 LIMITED_METHOD_CONTRACT;
115 m_pNextBuffer = pBuffer;
118 FORCEINLINE BYTE* GetNextAlignedAddress(BYTE *pAddress)
120 LIMITED_METHOD_CONTRACT;
121 _ASSERTE(m_pBuffer <= pAddress && pAddress <= m_pLimit);
123 pAddress = (BYTE*)ALIGN_UP(pAddress, AlignmentSize);
125 _ASSERTE((size_t)pAddress % AlignmentSize == 0);
131 EventPipeBuffer(unsigned int bufferSize, EventPipeThread* pWriterThread, unsigned int eventSequenceNumber);
134 // Write an event to the buffer.
135 // An optional stack trace can be provided for sample profiler events.
136 // Otherwise, if a stack trace is needed, one will be automatically collected.
138 // - true: The write succeeded.
139 // - false: The write failed. In this case, the buffer should be considered full.
140 bool WriteEvent(Thread *pThread, EventPipeSession &session, EventPipeEvent &event, EventPipeEventPayload &payload, LPCGUID pActivityId, LPCGUID pRelatedActivityId, StackContents *pStack = NULL);
142 // Get the timestamp the buffer was created.
143 LARGE_INTEGER GetCreationTimeStamp() const;
145 // Advances read cursor to the next event or NULL if there aren't any more. When the
146 // buffer is first made readable the cursor is automatically positioned on the first
147 // event or NULL if there are no events in the buffer.
148 void MoveNextReadEvent();
150 // Returns the event at the current read cursor. The returned event pointer is valid
151 // until the buffer is deleted.
152 EventPipeEventInstance* GetCurrentReadEvent();
154 // Gets the sequence number of the event corresponding to GetCurrentReadEvent();
155 unsigned int GetCurrentSequenceNumber();
157 // Get the thread that is (or was) assigned to write to this buffer
158 EventPipeThread* GetWriterThread();
160 // Check the state of the buffer
161 EventPipeBufferState GetVolatileState();
163 // Convert the buffer writable to readable
164 void ConvertToReadOnly();
167 bool EnsureConsistency();
171 #endif // FEATURE_PERFTRACING
173 #endif // __EVENTPIPE_BUFFER_H__