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.
4
5#ifndef __EVENTPIPE_BUFFERMANAGER_H__
6#define __EVENTPIPE_BUFFERMANAGER_H__
7
8#ifdef FEATURE_PERFTRACING
9
10#include "eventpipe.h"
11#include "eventpipefile.h"
12#include "eventpipebuffer.h"
13#include "eventpipesession.h"
14#include "spinlock.h"
15
16class EventPipeBufferList;
17
18class EventPipeBufferManager
19{
20
21 // Declare friends.
22 friend class EventPipeBufferList;
23
24private:
25
26 // A list of linked-lists of buffer objects.
27 // Each entry in this list represents a set of buffers owned by a single thread.
28 // The actual Thread object has a pointer to the object contained in this list. This ensures that
29 // each thread can access its own list, while at the same time, ensuring that when
30 // a thread is destroyed, we keep the buffers around without having to perform any
31 // migration or book-keeping.
32 SList<SListElem<EventPipeBufferList*>> *m_pPerThreadBufferList;
33
34 // The total allocation size of buffers under management.
35 size_t m_sizeOfAllBuffers;
36
37 // Lock to protect access to the per-thread buffer list and total allocation size.
38 SpinLock m_lock;
39
40#ifdef _DEBUG
41 // For debugging purposes.
42 unsigned int m_numBuffersAllocated;
43 unsigned int m_numBuffersStolen;
44 unsigned int m_numBuffersLeaked;
45 Volatile<LONG> m_numEventsStored;
46 Volatile<LONG> m_numEventsDropped;
47 LONG m_numEventsWritten;
48#endif // _DEBUG
49
50 // Allocate a new buffer for the specified thread.
51 // This function will store the buffer in the thread's buffer list for future use and also return it here.
52 // A NULL return value means that a buffer could not be allocated.
53 EventPipeBuffer* AllocateBufferForThread(EventPipeSession &session, Thread *pThread, unsigned int requestSize);
54
55 // Add a buffer to the thread buffer list.
56 void AddBufferToThreadBufferList(EventPipeBufferList *pThreadBuffers, EventPipeBuffer *pBuffer);
57
58 // Find the thread that owns the oldest buffer that is eligible to be stolen.
59 EventPipeBufferList* FindThreadToStealFrom();
60
61 // De-allocates the input buffer.
62 void DeAllocateBuffer(EventPipeBuffer *pBuffer);
63
64public:
65
66 EventPipeBufferManager();
67 ~EventPipeBufferManager();
68
69 // Write an event to the input thread's current event buffer.
70 // An optional eventThread can be provided for sample profiler events.
71 // This is because the thread that writes the events is not the same as the "event thread".
72 // An optional stack trace can be provided for sample profiler events.
73 // Otherwise, if a stack trace is needed, one will be automatically collected.
74 bool WriteEvent(Thread *pThread, EventPipeSession &session, EventPipeEvent &event, EventPipeEventPayload &payload, LPCGUID pActivityId, LPCGUID pRelatedActivityId, Thread *pEventThread = NULL, StackContents *pStack = NULL);
75
76 // Write the contents of the managed buffers to the specified file.
77 // The stopTimeStamp is used to determine when tracing was stopped to ensure that we
78 // skip any events that might be partially written due to races when tracing is stopped.
79 void WriteAllBuffersToFile(EventPipeFile *pFile, LARGE_INTEGER stopTimeStamp);
80
81 // Attempt to de-allocate resources as best we can. It is possible for some buffers to leak because
82 // threads can be in the middle of a write operation and get blocked, and we may not get an opportunity
83 // to free their buffer for a very long time.
84 void DeAllocateBuffers();
85
86 // Get next event. This is used to dispatch events to EventListener.
87 EventPipeEventInstance* GetNextEvent();
88
89#ifdef _DEBUG
90 bool EnsureConsistency();
91#endif // _DEBUG
92};
93
94// Represents a list of buffers associated with a specific thread.
95class EventPipeBufferList
96{
97private:
98
99 // The buffer manager that owns this list.
100 EventPipeBufferManager *m_pManager;
101
102 // Buffers are stored in an intrusive linked-list from oldest to newest.
103 // Head is the oldest buffer. Tail is the newest (and currently used) buffer.
104 EventPipeBuffer *m_pHeadBuffer;
105 EventPipeBuffer *m_pTailBuffer;
106
107 // The number of buffers in the list.
108 unsigned int m_bufferCount;
109
110 // The current read buffer (used when processing events on tracing stop).
111 EventPipeBuffer *m_pReadBuffer;
112
113 // True if this thread is owned by a thread.
114 // If it is false, then this buffer can be de-allocated after it is drained.
115 Volatile<bool> m_ownedByThread;
116
117#ifdef _DEBUG
118 // For diagnostics, keep the thread pointer.
119 Thread *m_pCreatingThread;
120#endif // _DEBUG
121
122public:
123
124 EventPipeBufferList(EventPipeBufferManager *pManager);
125
126 // Get the head node of the list.
127 EventPipeBuffer* GetHead();
128
129 // Get the tail node of the list.
130 EventPipeBuffer* GetTail();
131
132 // Insert a new buffer at the tail of the list.
133 void InsertTail(EventPipeBuffer *pBuffer);
134
135 // Remove the head node of the list.
136 EventPipeBuffer* GetAndRemoveHead();
137
138 // Get the count of buffers in the list.
139 unsigned int GetCount() const;
140
141 // Get the next event as long as it is before the specified timestamp.
142 EventPipeEventInstance* PeekNextEvent(LARGE_INTEGER beforeTimeStamp, EventPipeBuffer **pContainingBuffer);
143
144 // Get the next event as long as it is before the specified timestamp, and also mark it as read.
145 EventPipeEventInstance* PopNextEvent(LARGE_INTEGER beforeTimeStamp);
146
147 // True if a thread owns this list.
148 bool OwnedByThread();
149
150 // Set whether or not this list is owned by a thread.
151 // If it is not owned by a thread, then it can be de-allocated
152 // after the buffer is drained.
153 // The default value is true.
154 void SetOwnedByThread(bool value);
155
156#ifdef _DEBUG
157 // Get the thread associated with this list.
158 Thread* GetThread();
159
160 // Validate the consistency of the list.
161 // This function will assert if the list is in an inconsistent state.
162 bool EnsureConsistency();
163#endif // _DEBUG
164};
165
166#endif // FEATURE_PERFTRACING
167
168#endif // __EVENTPIPE_BUFFERMANAGER_H__
169