summaryrefslogtreecommitdiff
path: root/src/vm/eventpipebuffermanager.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/vm/eventpipebuffermanager.h')
-rw-r--r--src/vm/eventpipebuffermanager.h161
1 files changed, 161 insertions, 0 deletions
diff --git a/src/vm/eventpipebuffermanager.h b/src/vm/eventpipebuffermanager.h
new file mode 100644
index 0000000000..a53721b7b8
--- /dev/null
+++ b/src/vm/eventpipebuffermanager.h
@@ -0,0 +1,161 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#ifndef __EVENTPIPE_BUFFERMANAGER_H__
+#define __EVENTPIPE_BUFFERMANAGER_H__
+
+#ifdef FEATURE_PERFTRACING
+
+#include "eventpipefile.h"
+#include "eventpipebuffer.h"
+#include "spinlock.h"
+
+class EventPipeBufferList;
+
+class EventPipeBufferManager
+{
+
+ // Declare friends.
+ friend class EventPipeBufferList;
+
+private:
+
+ // A list of linked-lists of buffer objects.
+ // Each entry in this list represents a set of buffers owned by a single thread.
+ // The actual Thread object has a pointer to the object contained in this list. This ensures that
+ // each thread can access its own list, while at the same time, ensuring that when
+ // a thread is destroyed, we keep the buffers around without having to perform any
+ // migration or book-keeping.
+ SList<SListElem<EventPipeBufferList*>> *m_pPerThreadBufferList;
+
+ // The total allocation size of buffers under management.
+ size_t m_sizeOfAllBuffers;
+
+ // Lock to protect access to the per-thread buffer list and total allocation size.
+ SpinLock m_lock;
+
+#ifdef _DEBUG
+ // For debugging purposes.
+ unsigned int m_numBuffersAllocated;
+ unsigned int m_numBuffersStolen;
+ unsigned int m_numBuffersLeaked;
+ Volatile<LONG> m_numEventsStored;
+ LONG m_numEventsWritten;
+#endif // _DEBUG
+
+ // Allocate a new buffer for the specified thread.
+ // This function will store the buffer in the thread's buffer list for future use and also return it here.
+ // A NULL return value means that a buffer could not be allocated.
+ EventPipeBuffer* AllocateBufferForThread(Thread *pThread, unsigned int requestSize);
+
+ // Add a buffer to the thread buffer list.
+ void AddBufferToThreadBufferList(EventPipeBufferList *pThreadBuffers, EventPipeBuffer *pBuffer);
+
+ // Find the thread that owns the oldest buffer that is eligible to be stolen.
+ EventPipeBufferList* FindThreadToStealFrom();
+
+ // De-allocates the input buffer.
+ void DeAllocateBuffer(EventPipeBuffer *pBuffer);
+
+public:
+
+ EventPipeBufferManager();
+
+ // Write an event to the input thread's current event buffer.
+ // An optional eventThread can be provided for sample profiler events.
+ // This is because the thread that writes the events is not the same as the "event thread".
+ // An optional stack trace can be provided for sample profiler events.
+ // Otherwise, if a stack trace is needed, one will be automatically collected.
+ bool WriteEvent(Thread *pThread, EventPipeEvent &event, BYTE *pData, unsigned int length, LPCGUID pActivityId, LPCGUID pRelatedActivityId, Thread *pEventThread = NULL, StackContents *pStack = NULL);
+
+ // Write the contents of the managed buffers to the specified file.
+ // The stopTimeStamp is used to determine when tracing was stopped to ensure that we
+ // skip any events that might be partially written due to races when tracing is stopped.
+ void WriteAllBuffersToFile(EventPipeFile *pFile, LARGE_INTEGER stopTimeStamp);
+
+ // Attempt to de-allocate resources as best we can. It is possible for some buffers to leak because
+ // threads can be in the middle of a write operation and get blocked, and we may not get an opportunity
+ // to free their buffer for a very long time.
+ void DeAllocateBuffers();
+
+#ifdef _DEBUG
+ bool EnsureConsistency();
+#endif // _DEBUG
+};
+
+// Represents a list of buffers associated with a specific thread.
+class EventPipeBufferList
+{
+private:
+
+ // The buffer manager that owns this list.
+ EventPipeBufferManager *m_pManager;
+
+ // Buffers are stored in an intrusive linked-list from oldest to newest.
+ // Head is the oldest buffer. Tail is the newest (and currently used) buffer.
+ EventPipeBuffer *m_pHeadBuffer;
+ EventPipeBuffer *m_pTailBuffer;
+
+ // The number of buffers in the list.
+ unsigned int m_bufferCount;
+
+ // The current read buffer (used when processing events on tracing stop).
+ EventPipeBuffer *m_pReadBuffer;
+
+ // True if this thread is owned by a thread.
+ // If it is false, then this buffer can be de-allocated after it is drained.
+ Volatile<bool> m_ownedByThread;
+
+#ifdef _DEBUG
+ // For diagnostics, keep the thread pointer.
+ Thread *m_pCreatingThread;
+#endif // _DEBUG
+
+public:
+
+ EventPipeBufferList(EventPipeBufferManager *pManager);
+
+ // Get the head node of the list.
+ EventPipeBuffer* GetHead();
+
+ // Get the tail node of the list.
+ EventPipeBuffer* GetTail();
+
+ // Insert a new buffer at the tail of the list.
+ void InsertTail(EventPipeBuffer *pBuffer);
+
+ // Remove the head node of the list.
+ EventPipeBuffer* GetAndRemoveHead();
+
+ // Get the count of buffers in the list.
+ unsigned int GetCount() const;
+
+ // Get the next event as long as it is before the specified timestamp.
+ EventPipeEventInstance* PeekNextEvent(LARGE_INTEGER beforeTimeStamp, EventPipeBuffer **pContainingBuffer);
+
+ // Get the next event as long as it is before the specified timestamp, and also mark it as read.
+ EventPipeEventInstance* PopNextEvent(LARGE_INTEGER beforeTimeStamp);
+
+ // True if a thread owns this list.
+ bool OwnedByThread();
+
+ // Set whether or not this list is owned by a thread.
+ // If it is not owned by a thread, then it can be de-allocated
+ // after the buffer is drained.
+ // The default value is true.
+ void SetOwnedByThread(bool value);
+
+#ifdef _DEBUG
+ // Get the thread associated with this list.
+ Thread* GetThread();
+
+ // Validate the consistency of the list.
+ // This function will assert if the list is in an inconsistent state.
+ bool EnsureConsistency();
+#endif // _DEBUG
+};
+
+#endif // FEATURE_PERFTRACING
+
+#endif // __EVENTPIPE_BUFFERMANAGER_H__