diff options
author | Adam Sitnik <adam.sitnik@gmail.com> | 2018-02-02 23:07:25 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-02-02 23:07:25 +0100 |
commit | f6ba335278bb966e8e5f9cd33f51818c6fac44fa (patch) | |
tree | 34f19451c962381c3d834fa8db5f334556390756 /src/vm | |
parent | 70bf6a4586b3cad9cf8cc26ca85ec6d552123202 (diff) | |
download | coreclr-f6ba335278bb966e8e5f9cd33f51818c6fac44fa.tar.gz coreclr-f6ba335278bb966e8e5f9cd33f51818c6fac44fa.tar.bz2 coreclr-f6ba335278bb966e8e5f9cd33f51818c6fac44fa.zip |
Event Pipe File V3 (#16107)
* write missing information to the event pipe file (pointer size to make it work fo x86)
* define where the events start, not only where they end
* include process Id in the event pipe file, bump the version so old consumers get clear error message
* write the missing EndObject tag to close the header
* include expected CPU sampling rate in the event pipe header file
* include keywords in V3 of EventPipe metadata, fixes #11934
* remove forward references
* entry object comes after the header and ends after it's data, before the event block objects
* introduce event block
* fix the GC contracts
* generate metadata ids
* end the file with null reference tag
* getting it work
* 4 byte alignment of serialized event data
* Revert "include keywords in V3 of EventPipe metadata, fixes #11934"
This reverts commit 98ef2f588e271f928fd051e96da526dc1e0f017c.
* remove event Id and event version from metadata buffer (it was duplicated with native code)
* increase the block size to be the same as buffer size
* Write the last event block to the file after disabling the event pipe, right after last events
* include the sife in itself
* the native part was supposed to not duplicate the event id and version, not manged
* ensure 4 byte alignment
* build metadata when it's not provided, so payload is never empty (no need to serialize length)
* this todo is no longer valid
* don't align everything, just the content of event block as suggested by @vancem
* improvements after code review
* update TraceEvent dependency, make the test verify new feature
* InterlockedIncrement(Int32) is not available for non-Windows OSes
* code improvements after Skype code review from @jorive
Diffstat (limited to 'src/vm')
-rw-r--r-- | src/vm/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/vm/eventpipeblock.cpp | 146 | ||||
-rw-r--r-- | src/vm/eventpipeblock.h | 92 | ||||
-rw-r--r-- | src/vm/eventpipebuffer.cpp | 10 | ||||
-rw-r--r-- | src/vm/eventpipebuffermanager.cpp | 2 | ||||
-rw-r--r-- | src/vm/eventpipeconfiguration.cpp | 27 | ||||
-rw-r--r-- | src/vm/eventpipeconfiguration.h | 2 | ||||
-rw-r--r-- | src/vm/eventpipeevent.cpp | 60 | ||||
-rw-r--r-- | src/vm/eventpipeevent.h | 8 | ||||
-rw-r--r-- | src/vm/eventpipeeventinstance.cpp | 87 | ||||
-rw-r--r-- | src/vm/eventpipeeventinstance.h | 87 | ||||
-rw-r--r-- | src/vm/eventpipefile.cpp | 159 | ||||
-rw-r--r-- | src/vm/eventpipefile.h | 60 | ||||
-rw-r--r-- | src/vm/fastserializer.cpp | 153 | ||||
-rw-r--r-- | src/vm/fastserializer.h | 44 | ||||
-rw-r--r-- | src/vm/sampleprofiler.h | 7 |
16 files changed, 599 insertions, 346 deletions
diff --git a/src/vm/CMakeLists.txt b/src/vm/CMakeLists.txt index cfa1b2ac43..f6396795b0 100644 --- a/src/vm/CMakeLists.txt +++ b/src/vm/CMakeLists.txt @@ -184,6 +184,7 @@ set(VM_SOURCES_WKS eventpipeconfiguration.cpp eventpipeevent.cpp eventpipeeventinstance.cpp + eventpipeblock.cpp eventpipefile.cpp eventpipejsonfile.cpp eventpipeprovider.cpp diff --git a/src/vm/eventpipeblock.cpp b/src/vm/eventpipeblock.cpp new file mode 100644 index 0000000000..5992b874de --- /dev/null +++ b/src/vm/eventpipeblock.cpp @@ -0,0 +1,146 @@ +// 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. + +#include "common.h" +#include "eventpipeblock.h" +#include "eventpipeeventinstance.h" +#include "fastserializableobject.h" +#include "fastserializer.h" + +#ifdef FEATURE_PERFTRACING + +EventPipeBlock::EventPipeBlock(unsigned int maxBlockSize) +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + m_pBlock = new (nothrow) BYTE[maxBlockSize]; + if (m_pBlock == NULL) + { + return; + } + + memset(m_pBlock, 0, maxBlockSize); + m_pWritePointer = m_pBlock; + m_pEndOfTheBuffer = m_pBlock + maxBlockSize; +} + +EventPipeBlock::~EventPipeBlock() +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + if(m_pBlock != NULL) + { + m_pEndOfTheBuffer = NULL; + m_pWritePointer = NULL; + delete[] m_pBlock; + m_pBlock = NULL; + } +} + +bool EventPipeBlock::WriteEvent(EventPipeEventInstance &instance) +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + if (m_pBlock == NULL) + { + return false; + } + + unsigned int totalSize = instance.GetAlignedTotalSize(); + if (m_pWritePointer + totalSize >= m_pEndOfTheBuffer) + { + return false; + } + + BYTE* alignedEnd = m_pWritePointer + totalSize + sizeof(totalSize); + + memcpy(m_pWritePointer, &totalSize, sizeof(totalSize)); + m_pWritePointer += sizeof(totalSize); + + unsigned int metadataId = instance.GetMetadataId(); + memcpy(m_pWritePointer, &metadataId, sizeof(metadataId)); + m_pWritePointer += sizeof(metadataId); + + DWORD threadId = instance.GetThreadId(); + memcpy(m_pWritePointer, &threadId, sizeof(threadId)); + m_pWritePointer += sizeof(threadId); + + const LARGE_INTEGER* timeStamp = instance.GetTimeStamp(); + memcpy(m_pWritePointer, timeStamp, sizeof(*timeStamp)); + m_pWritePointer += sizeof(*timeStamp); + + const GUID* activityId = instance.GetActivityId(); + memcpy(m_pWritePointer, activityId, sizeof(*activityId)); + m_pWritePointer += sizeof(*activityId); + + const GUID* relatedActivityId = instance.GetRelatedActivityId(); + memcpy(m_pWritePointer, relatedActivityId, sizeof(*relatedActivityId)); + m_pWritePointer += sizeof(*relatedActivityId); + + unsigned int dataLength = instance.GetDataLength(); + memcpy(m_pWritePointer, &dataLength, sizeof(dataLength)); + m_pWritePointer += sizeof(dataLength); + + if (dataLength > 0) + { + memcpy(m_pWritePointer, instance.GetData(), dataLength); + m_pWritePointer += dataLength; + } + + unsigned int stackSize = instance.GetStackSize(); + memcpy(m_pWritePointer, &stackSize, sizeof(stackSize)); + m_pWritePointer += sizeof(stackSize); + + if (stackSize > 0) + { + memcpy(m_pWritePointer, instance.GetStack(), stackSize); + m_pWritePointer += stackSize; + } + + while (m_pWritePointer < alignedEnd) + { + *m_pWritePointer++ = (BYTE)0; // put padding at the end to get 4 bytes alignment of the payload + } + + return true; +} + +void EventPipeBlock::Clear() +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + if (m_pBlock == NULL) + { + return; + } + + memset(m_pBlock, 0, GetSize()); + m_pWritePointer = m_pBlock; +} + +#endif // FEATURE_PERFTRACING diff --git a/src/vm/eventpipeblock.h b/src/vm/eventpipeblock.h new file mode 100644 index 0000000000..30bd458f38 --- /dev/null +++ b/src/vm/eventpipeblock.h @@ -0,0 +1,92 @@ +// 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_BLOCK_H__ +#define __EVENTPIPE_BLOCK_H__ + +#ifdef FEATURE_PERFTRACING + +#include "eventpipeeventinstance.h" +#include "fastserializableobject.h" +#include "fastserializer.h" + +class EventPipeBlock : public FastSerializableObject +{ + public: + EventPipeBlock(unsigned int maxBlockSize); + + ~EventPipeBlock(); + + // Write an event to the block. + // Returns: + // - true: The write succeeded. + // - false: The write failed. In this case, the block should be considered full. + bool WriteEvent(EventPipeEventInstance &instance); + + void Clear(); + + const char* GetTypeName() + { + LIMITED_METHOD_CONTRACT; + return "EventBlock"; + } + + void FastSerialize(FastSerializer *pSerializer) + { + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + MODE_PREEMPTIVE; + PRECONDITION(pSerializer != NULL); + } + CONTRACTL_END; + + if (m_pBlock == NULL) + { + return; + } + + unsigned int eventsSize = (unsigned int)(m_pWritePointer - m_pBlock); + pSerializer->WriteBuffer((BYTE*)&eventsSize, sizeof(eventsSize)); + + if (eventsSize == 0) + { + return; + } + + size_t currentPosition = pSerializer->GetCurrentPosition(); + if (currentPosition % ALIGNMENT_SIZE != 0) + { + BYTE maxPadding[ALIGNMENT_SIZE - 1] = {}; // it's longest possible padding, we are going to use only part of it + unsigned int paddingLength = ALIGNMENT_SIZE - (currentPosition % ALIGNMENT_SIZE); + pSerializer->WriteBuffer(maxPadding, paddingLength); // we write zeros here, the reader is going to always read from the first aligned address of the serialized content + + _ASSERTE(pSerializer->GetCurrentPosition() % ALIGNMENT_SIZE == 0); + } + + pSerializer->WriteBuffer(m_pBlock, eventsSize); + } + + private: + BYTE *m_pBlock; + BYTE *m_pWritePointer; + BYTE *m_pEndOfTheBuffer; + + unsigned int GetSize() const + { + LIMITED_METHOD_CONTRACT; + + if (m_pBlock == NULL) + { + return 0; + } + + return (unsigned int)(m_pEndOfTheBuffer - m_pBlock); + } +}; + +#endif // FEATURE_PERFTRACING + +#endif // __EVENTPIPE_BLOCK_H__ diff --git a/src/vm/eventpipebuffer.cpp b/src/vm/eventpipebuffer.cpp index 3ac2122233..d88dd165e0 100644 --- a/src/vm/eventpipebuffer.cpp +++ b/src/vm/eventpipebuffer.cpp @@ -97,7 +97,7 @@ bool EventPipeBuffer::WriteEvent(Thread *pThread, EventPipeSession &session, Eve } // Save the most recent event timestamp. - m_mostRecentTimeStamp = pInstance->GetTimeStamp(); + m_mostRecentTimeStamp = *pInstance->GetTimeStamp(); } EX_CATCH @@ -174,7 +174,7 @@ EventPipeEventInstance* EventPipeBuffer::GetNext(EventPipeEventInstance *pEvent, // We have a pointer within the bounds of the buffer. // Find the next event by skipping the current event with it's data payload immediately after the instance. - pNextInstance = (EventPipeEventInstance *)(pEvent->GetData() + pEvent->GetLength()); + pNextInstance = (EventPipeEventInstance *)(pEvent->GetData() + pEvent->GetDataLength()); // Check to see if we've reached the end of the written portion of the buffer. if((BYTE*)pNextInstance >= m_pCurrent) @@ -184,7 +184,7 @@ EventPipeEventInstance* EventPipeBuffer::GetNext(EventPipeEventInstance *pEvent, } // Ensure that the timestamp is valid. The buffer is zero'd before use, so a zero timestamp is invalid. - LARGE_INTEGER nextTimeStamp = pNextInstance->GetTimeStamp(); + LARGE_INTEGER nextTimeStamp = *pNextInstance->GetTimeStamp(); if(nextTimeStamp.QuadPart == 0) { return NULL; @@ -260,10 +260,10 @@ bool EventPipeBuffer::EnsureConsistency() _ASSERTE(pInstance->EnsureConsistency()); // Validate that payload and length match. - _ASSERTE((pInstance->GetData() != NULL && pInstance->GetLength() > 0) || (pInstance->GetData() != NULL && pInstance->GetLength() == 0)); + _ASSERTE((pInstance->GetData() != NULL && pInstance->GetDataLength() > 0) || (pInstance->GetData() != NULL && pInstance->GetDataLength() == 0)); // Skip the event. - ptr += sizeof(*pInstance) + pInstance->GetLength(); + ptr += sizeof(*pInstance) + pInstance->GetDataLength(); } // When we're done walking the filled portion of the buffer, diff --git a/src/vm/eventpipebuffermanager.cpp b/src/vm/eventpipebuffermanager.cpp index e93c439743..5f09295e95 100644 --- a/src/vm/eventpipebuffermanager.cpp +++ b/src/vm/eventpipebuffermanager.cpp @@ -430,7 +430,7 @@ void EventPipeBufferManager::WriteAllBuffersToFile(EventPipeFile *pFile, LARGE_I { // If it's the oldest event we've seen, then save it. if((pOldestInstance == NULL) || - (pOldestInstance->GetTimeStamp().QuadPart > pNext->GetTimeStamp().QuadPart)) + (pOldestInstance->GetTimeStamp()->QuadPart > pNext->GetTimeStamp()->QuadPart)) { pOldestInstance = pNext; pOldestContainingBuffer = pContainingBuffer; diff --git a/src/vm/eventpipeconfiguration.cpp b/src/vm/eventpipeconfiguration.cpp index c8833dcc11..6206bbc74f 100644 --- a/src/vm/eventpipeconfiguration.cpp +++ b/src/vm/eventpipeconfiguration.cpp @@ -448,7 +448,7 @@ void EventPipeConfiguration::EnableRundown(EventPipeSession *pSession) Enable(pSession); } -EventPipeEventInstance* EventPipeConfiguration::BuildEventMetadataEvent(EventPipeEventInstance &sourceInstance) +EventPipeEventInstance* EventPipeConfiguration::BuildEventMetadataEvent(EventPipeEventInstance &sourceInstance, unsigned int metadataId) { CONTRACTL { @@ -459,20 +459,17 @@ EventPipeEventInstance* EventPipeConfiguration::BuildEventMetadataEvent(EventPip CONTRACTL_END; // The payload of the event should contain: + // - Metadata ID // - GUID ProviderID. - // - unsigned int EventID. - // - unsigned int EventVersion. // - Optional event description payload. // Calculate the size of the event. EventPipeEvent &sourceEvent = *sourceInstance.GetEvent(); const SString &providerName = sourceEvent.GetProvider()->GetProviderName(); - unsigned int eventID = sourceEvent.GetEventID(); - unsigned int eventVersion = sourceEvent.GetEventVersion(); BYTE *pPayloadData = sourceEvent.GetMetadata(); unsigned int payloadLength = sourceEvent.GetMetadataLength(); unsigned int providerNameLength = (providerName.GetCount() + 1) * sizeof(WCHAR); - unsigned int instancePayloadSize = providerNameLength + sizeof(eventID) + sizeof(eventVersion) + sizeof(payloadLength) + payloadLength; + unsigned int instancePayloadSize = sizeof(metadataId) + providerNameLength + payloadLength; // Allocate the payload. BYTE *pInstancePayload = new BYTE[instancePayloadSize]; @@ -480,22 +477,12 @@ EventPipeEventInstance* EventPipeConfiguration::BuildEventMetadataEvent(EventPip // Fill the buffer with the payload. BYTE *currentPtr = pInstancePayload; - // Write the provider ID. + memcpy(currentPtr, &metadataId, sizeof(metadataId)); + currentPtr += sizeof(metadataId); + memcpy(currentPtr, (BYTE*)providerName.GetUnicode(), providerNameLength); currentPtr += providerNameLength; - // Write the event name as null-terminated unicode. - memcpy(currentPtr, &eventID, sizeof(eventID)); - currentPtr += sizeof(eventID); - - // Write the event version. - memcpy(currentPtr, &eventVersion, sizeof(eventVersion)); - currentPtr += sizeof(eventVersion); - - // Write the size of the metadata. - memcpy(currentPtr, &payloadLength, sizeof(payloadLength)); - currentPtr += sizeof(payloadLength); - // Write the incoming payload data. memcpy(currentPtr, pPayloadData, payloadLength); @@ -511,7 +498,7 @@ EventPipeEventInstance* EventPipeConfiguration::BuildEventMetadataEvent(EventPip // Set the timestamp to match the source event, because the metadata event // will be emitted right before the source event. - pInstance->SetTimeStamp(sourceInstance.GetTimeStamp()); + pInstance->SetTimeStamp(*sourceInstance.GetTimeStamp()); return pInstance; } diff --git a/src/vm/eventpipeconfiguration.h b/src/vm/eventpipeconfiguration.h index 7e587cdf0d..5ac68c277e 100644 --- a/src/vm/eventpipeconfiguration.h +++ b/src/vm/eventpipeconfiguration.h @@ -77,7 +77,7 @@ public: void EnableRundown(EventPipeSession *pSession); // Get the event used to write metadata to the event stream. - EventPipeEventInstance* BuildEventMetadataEvent(EventPipeEventInstance &sourceInstance); + EventPipeEventInstance* BuildEventMetadataEvent(EventPipeEventInstance &sourceInstance, unsigned int metdataId); // Delete deferred providers. void DeleteDeferredProviders(); diff --git a/src/vm/eventpipeevent.cpp b/src/vm/eventpipeevent.cpp index 1b2d4ebe40..3f7755149b 100644 --- a/src/vm/eventpipeevent.cpp +++ b/src/vm/eventpipeevent.cpp @@ -33,8 +33,9 @@ EventPipeEvent::EventPipeEvent(EventPipeProvider &provider, INT64 keywords, unsi } else { - m_pMetadata = NULL; - m_metadataLength = 0; + // if metadata is not provided, we have to build the minimum version. It's required by the serialization contract + m_pMetadata = BuildMinimumMetadata(); + m_metadataLength = GetMinimumMetadataLength(); } } @@ -55,6 +56,61 @@ EventPipeEvent::~EventPipeEvent() } } +unsigned int EventPipeEvent::GetMinimumMetadataLength() +{ + LIMITED_METHOD_CONTRACT; + + unsigned int minimumMetadataLength = + sizeof(m_eventID) + + (SString::Empty().GetCount() + 1) * sizeof(WCHAR) + // size of empty unicode string + sizeof(m_keywords) + + sizeof(m_eventVersion) + + sizeof(m_level) + + sizeof(unsigned int); // parameter count + + return minimumMetadataLength; +} + +BYTE *EventPipeEvent::BuildMinimumMetadata() +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + unsigned int minmumMetadataLength = GetMinimumMetadataLength(); + + BYTE *minmumMetadata = new BYTE[minmumMetadataLength]; + BYTE *currentPtr = minmumMetadata; + + // the order of fields is defined in coreclr\src\mscorlib\shared\System\Diagnostics\Tracing\EventSource.cs DefineEventPipeEvents method + memcpy(currentPtr, &m_eventID, sizeof(m_eventID)); + currentPtr += sizeof(m_eventID); + + SString eventName = SString::Empty(); + unsigned int eventNameSize = (eventName.GetCount() + 1) * sizeof(WCHAR); + memcpy(currentPtr, (BYTE*)eventName.GetUnicode(), eventNameSize); + currentPtr += eventNameSize; + + memcpy(currentPtr, &m_keywords, sizeof(m_keywords)); + currentPtr += sizeof(m_keywords); + + memcpy(currentPtr, &m_eventVersion, sizeof(m_eventVersion)); + currentPtr += sizeof(m_eventVersion); + + memcpy(currentPtr, &m_level, sizeof(m_level)); + currentPtr += sizeof(m_level); + + unsigned int noParameters = 0; + memcpy(currentPtr, &noParameters, sizeof(noParameters)); + currentPtr += sizeof(noParameters); + + return minmumMetadata; +} + EventPipeProvider* EventPipeEvent::GetProvider() const { LIMITED_METHOD_CONTRACT; diff --git a/src/vm/eventpipeevent.h b/src/vm/eventpipeevent.h index c91c4bac8e..1ae02900e1 100644 --- a/src/vm/eventpipeevent.h +++ b/src/vm/eventpipeevent.h @@ -75,11 +75,15 @@ private: // True if the event is currently enabled. bool IsEnabled() const; - // Get metadata BYTE *GetMetadata() const; - // Get metadata length unsigned int GetMetadataLength() const; + + private: + // used when Metadata is not provided + BYTE *BuildMinimumMetadata(); + + unsigned int GetMinimumMetadataLength(); }; #endif // FEATURE_PERFTRACING diff --git a/src/vm/eventpipeeventinstance.cpp b/src/vm/eventpipeeventinstance.cpp index 51bd4ce8a7..023b9b2aa9 100644 --- a/src/vm/eventpipeeventinstance.cpp +++ b/src/vm/eventpipeeventinstance.cpp @@ -65,60 +65,20 @@ EventPipeEventInstance::EventPipeEventInstance( #endif // _DEBUG } -StackContents* EventPipeEventInstance::GetStack() +unsigned int EventPipeEventInstance::GetAlignedTotalSize() const { - LIMITED_METHOD_CONTRACT; - - return &m_stackContents; -} - -EventPipeEvent* EventPipeEventInstance::GetEvent() const -{ - LIMITED_METHOD_CONTRACT; - - return m_pEvent; -} - -LARGE_INTEGER EventPipeEventInstance::GetTimeStamp() const -{ - LIMITED_METHOD_CONTRACT; - - return m_timeStamp; -} - -BYTE* EventPipeEventInstance::GetData() const -{ - LIMITED_METHOD_CONTRACT; - - return m_pData; -} - -unsigned int EventPipeEventInstance::GetLength() const -{ - LIMITED_METHOD_CONTRACT; - - return m_dataLength; -} - -void EventPipeEventInstance::FastSerialize(FastSerializer *pSerializer, StreamLabel metadataLabel) -{ - CONTRACTL + CONTRACT(unsigned int) { NOTHROW; GC_NOTRIGGER; MODE_ANY; + POSTCONDITION(RETVAL % ALIGNMENT_SIZE == 0); } - CONTRACTL_END; - -#ifdef EVENTPIPE_EVENT_MARKER - // Useful for diagnosing serialization bugs. - const unsigned int value = 0xDEADBEEF; - pSerializer->WriteBuffer((BYTE*)&value, sizeof(value)); -#endif + CONTRACT_END; // Calculate the size of the total payload so that it can be written to the file. unsigned int payloadLength = - sizeof(metadataLabel) + + sizeof(m_metadataId) + // Metadata ID sizeof(m_threadID) + // Thread ID sizeof(m_timeStamp) + // TimeStamp sizeof(m_activityId) + // Activity ID @@ -128,42 +88,13 @@ void EventPipeEventInstance::FastSerialize(FastSerializer *pSerializer, StreamLa sizeof(unsigned int) + // Prepended stack payload size in bytes m_stackContents.GetSize(); // Stack payload size - // Write the size of the event to the file. - pSerializer->WriteBuffer((BYTE*)&payloadLength, sizeof(payloadLength)); - - // Write the metadata label. - pSerializer->WriteBuffer((BYTE*)&metadataLabel, sizeof(metadataLabel)); - - // Write the thread ID. - pSerializer->WriteBuffer((BYTE*)&m_threadID, sizeof(m_threadID)); - - // Write the timestamp. - pSerializer->WriteBuffer((BYTE*)&m_timeStamp, sizeof(m_timeStamp)); - - // Write the activity id. - pSerializer->WriteBuffer((BYTE*)&m_activityId, sizeof(m_activityId)); - - // Write the related activity id. - pSerializer->WriteBuffer((BYTE*)&m_relatedActivityId, sizeof(m_relatedActivityId)); - - // Write the data payload size. - pSerializer->WriteBuffer((BYTE*)&m_dataLength, sizeof(m_dataLength)); - - // Write the event data payload. - if(m_dataLength > 0) + // round up to ALIGNMENT_SIZE bytes + if (payloadLength % ALIGNMENT_SIZE != 0) { - pSerializer->WriteBuffer(m_pData, m_dataLength); + payloadLength += ALIGNMENT_SIZE - (payloadLength % ALIGNMENT_SIZE); } - // Write the size of the stack in bytes. - unsigned int stackSize = m_stackContents.GetSize(); - pSerializer->WriteBuffer((BYTE*)&stackSize, sizeof(stackSize)); - - // Write the stack if present. - if(stackSize > 0) - { - pSerializer->WriteBuffer(m_stackContents.GetPointer(), stackSize); - } + RETURN payloadLength; } #ifdef _DEBUG diff --git a/src/vm/eventpipeeventinstance.h b/src/vm/eventpipeeventinstance.h index 5298122dbd..47f1b5c35b 100644 --- a/src/vm/eventpipeeventinstance.h +++ b/src/vm/eventpipeeventinstance.h @@ -10,6 +10,7 @@ #include "eventpipe.h" #include "eventpipeevent.h" #include "eventpipesession.h" +#include "eventpipeblock.h" #include "fastserializableobject.h" #include "fastserializer.h" @@ -22,23 +23,84 @@ public: EventPipeEventInstance(EventPipeSession &session, EventPipeEvent &event, DWORD threadID, BYTE *pData, unsigned int length, LPCGUID pActivityId, LPCGUID pRelatedActivityId); - // Get the event associated with this instance. - EventPipeEvent* GetEvent() const; + StackContents* GetStack() + { + LIMITED_METHOD_CONTRACT; - // Get the stack contents object to either read or write to it. - StackContents* GetStack(); + return &m_stackContents; + } - // Get the timestamp. - LARGE_INTEGER GetTimeStamp() const; + EventPipeEvent* GetEvent() const + { + LIMITED_METHOD_CONTRACT; - // Get a pointer to the data payload. - BYTE* GetData() const; + return m_pEvent; + } - // Get the length of the data. - unsigned int GetLength() const; + const LARGE_INTEGER* const GetTimeStamp() const + { + LIMITED_METHOD_CONTRACT; - // Serialize this object using FastSerialization. - void FastSerialize(FastSerializer *pSerializer, StreamLabel metadataLabel); + return &m_timeStamp; + } + + unsigned int GetMetadataId() const + { + LIMITED_METHOD_CONTRACT; + + return m_metadataId; + } + + void SetMetadataId(unsigned int metadataId) + { + LIMITED_METHOD_CONTRACT; + + m_metadataId = metadataId; + } + + DWORD GetThreadId() const + { + LIMITED_METHOD_CONTRACT; + + return m_threadID; + } + + const GUID* const GetActivityId() const + { + LIMITED_METHOD_CONTRACT; + + return &m_activityId; + } + + const GUID* const GetRelatedActivityId() const + { + LIMITED_METHOD_CONTRACT; + + return &m_relatedActivityId; + } + + const BYTE* const GetData() const + { + LIMITED_METHOD_CONTRACT; + + return m_pData; + } + + unsigned int GetDataLength() const + { + LIMITED_METHOD_CONTRACT; + + return m_dataLength; + } + + unsigned int GetStackSize() const + { + LIMITED_METHOD_CONTRACT; + + return m_stackContents.GetSize(); + } + + unsigned int GetAlignedTotalSize() const; #ifdef _DEBUG // Serialize this event to the JSON file. @@ -54,6 +116,7 @@ protected: #endif // _DEBUG EventPipeEvent *m_pEvent; + unsigned int m_metadataId; DWORD m_threadID; LARGE_INTEGER m_timeStamp; GUID m_activityId; diff --git a/src/vm/eventpipefile.cpp b/src/vm/eventpipefile.cpp index ba4eb39b29..3346ee54a5 100644 --- a/src/vm/eventpipefile.cpp +++ b/src/vm/eventpipefile.cpp @@ -4,8 +4,10 @@ #include "common.h" #include "eventpipebuffer.h" +#include "eventpipeblock.h" #include "eventpipeconfiguration.h" #include "eventpipefile.h" +#include "sampleprofiler.h" #ifdef FEATURE_PERFTRACING @@ -25,12 +27,10 @@ EventPipeFile::EventPipeFile( } CONTRACTL_END; - SetObjectVersion(2); + SetObjectVersion(3); SetMinReaderVersion(0); - m_pSerializer = new FastSerializer(outputFilePath, *this); - m_serializationLock.Init(LOCK_TYPE_DEFAULT); - m_pMetadataLabels = new MapSHashWithRemove<EventPipeEvent*, StreamLabel>(); + m_pBlock = new EventPipeBlock(100 * 1024); #ifdef _DEBUG m_lockOnWrite = lockOnWrite; @@ -41,21 +41,23 @@ EventPipeFile::EventPipeFile( QueryPerformanceCounter(&m_fileOpenTimeStamp); QueryPerformanceFrequency(&m_timeStampFrequency); - // Write a forward reference to the beginning of the event stream. - // This also allows readers to know where the event stream ends and skip it if needed. - m_beginEventsForwardReferenceIndex = m_pSerializer->AllocateForwardReference(); - m_pSerializer->WriteForwardReference(m_beginEventsForwardReferenceIndex); + m_pointerSize = TARGET_POINTER_SIZE; + + m_currentProcessId = GetCurrentProcessId(); - // Write the header information into the file. + SYSTEM_INFO sysinfo = {}; + GetSystemInfo(&sysinfo); + m_numberOfProcessors = sysinfo.dwNumberOfProcessors; - // Write the current date and time. - m_pSerializer->WriteBuffer((BYTE*)&m_fileOpenSystemTime, sizeof(m_fileOpenSystemTime)); + m_samplingRateInNs = SampleProfiler::GetSamplingRate(); + + m_pSerializer = new FastSerializer(outputFilePath); // it creates the file stream and writes the header + m_serializationLock.Init(LOCK_TYPE_DEFAULT); + m_pMetadataIds = new MapSHashWithRemove<EventPipeEvent*, unsigned int>(); - // Write FileOpenTimeStamp - m_pSerializer->WriteBuffer((BYTE*)&m_fileOpenTimeStamp, sizeof(m_fileOpenTimeStamp)); + m_metadataIdCounter = 0; // we start with 0, it's always gets incremented by generator so the first id will be 1, as specified in the docs - // Write ClockFrequency - m_pSerializer->WriteBuffer((BYTE*)&m_timeStampFrequency, sizeof(m_timeStampFrequency)); + m_pSerializer->WriteObject(this); // this is the first object in the file } EventPipeFile::~EventPipeFile() @@ -68,13 +70,17 @@ EventPipeFile::~EventPipeFile() } CONTRACTL_END; - // Mark the end of the event stream. - StreamLabel currentLabel = m_pSerializer->GetStreamLabel(); + if (m_pBlock != NULL && m_pSerializer != NULL) + { + WriteEnd(); + } - // Define the event start forward reference. - m_pSerializer->DefineForwardReference(m_beginEventsForwardReferenceIndex, currentLabel); + if (m_pBlock != NULL) + { + delete(m_pBlock); + m_pBlock = NULL; + } - // Close the serializer. if(m_pSerializer != NULL) { delete(m_pSerializer); @@ -92,8 +98,64 @@ void EventPipeFile::WriteEvent(EventPipeEventInstance &instance) } CONTRACTL_END; + // Check to see if we've seen this event type before. + // If not, then write the event metadata to the event stream first. + unsigned int metadataId = GetMetadataId(*instance.GetEvent()); + if(metadataId == 0) + { + metadataId = GenerateMetadataId(); + + EventPipeEventInstance* pMetadataInstance = EventPipe::GetConfiguration()->BuildEventMetadataEvent(instance, metadataId); + + WriteToBlock(*pMetadataInstance, 0); // 0 breaks recursion and represents the metadata event. + + SaveMetadataId(*instance.GetEvent(), metadataId); + + delete[] (pMetadataInstance->GetData()); + delete (pMetadataInstance); + } + + WriteToBlock(instance, metadataId); +} + +void EventPipeFile::WriteEnd() +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + m_pSerializer->WriteObject(m_pBlock); // we write current block to the disk, whether it's full or not + + m_pBlock->Clear(); + + // "After the last EventBlock is emitted, the stream is ended by emitting a NullReference Tag which indicates that there are no more objects in the stream to read." + // see https://github.com/Microsoft/perfview/blob/master/src/TraceEvent/EventPipe/EventPipeFormat.md for more + m_pSerializer->WriteTag(FastSerializerTags::NullReference); +} + +void EventPipeFile::WriteToBlock(EventPipeEventInstance &instance, unsigned int metadataId) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + instance.SetMetadataId(metadataId); + + if (m_pBlock->WriteEvent(instance)) + { + return; // the block is not full, we added the event and continue + } + #ifdef _DEBUG - if(m_lockOnWrite) + if (m_lockOnWrite) { // Take the serialization lock. // This is used for synchronous file writes. @@ -102,27 +164,34 @@ void EventPipeFile::WriteEvent(EventPipeEventInstance &instance) } #endif // _DEBUG - // Check to see if we've seen this event type before. - // If not, then write the event metadata to the event stream first. - StreamLabel metadataLabel = GetMetadataLabel(*instance.GetEvent()); - if(metadataLabel == 0) - { - EventPipeEventInstance* pMetadataInstance = EventPipe::GetConfiguration()->BuildEventMetadataEvent(instance); + // we can't write this event to the current block (it's full) + // so we write what we have in the block to the serializer + m_pSerializer->WriteObject(m_pBlock); - metadataLabel = m_pSerializer->GetStreamLabel(); - pMetadataInstance->FastSerialize(m_pSerializer, (StreamLabel)0); // 0 breaks recursion and represents the metadata event. + m_pBlock->Clear(); - SaveMetadataLabel(*instance.GetEvent(), metadataLabel); + bool result = m_pBlock->WriteEvent(instance); - delete[] (pMetadataInstance->GetData()); - delete (pMetadataInstance); + _ASSERTE(result == true); // we should never fail to add event to a clear block (if we do the max size is too small) +} + +unsigned int EventPipeFile::GenerateMetadataId() +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + MODE_ANY; } + CONTRACTL_END; - // Write the event to the stream. - instance.FastSerialize(m_pSerializer, metadataLabel); + // PAL does not support 32 bit InterlockedIncrement, so we are using the LONG version and cast to int + // https://github.com/dotnet/coreclr/blob/master/src/pal/inc/pal.h#L4159 + // it's ok because the metadataId will never be bigger than 32 bit + return (unsigned int)InterlockedIncrement(&m_metadataIdCounter); } -StreamLabel EventPipeFile::GetMetadataLabel(EventPipeEvent &event) +unsigned int EventPipeFile::GetMetadataId(EventPipeEvent &event) { CONTRACTL { @@ -132,36 +201,36 @@ StreamLabel EventPipeFile::GetMetadataLabel(EventPipeEvent &event) } CONTRACTL_END; - StreamLabel outLabel; - if(m_pMetadataLabels->Lookup(&event, &outLabel)) + unsigned int metadataId; + if(m_pMetadataIds->Lookup(&event, &metadataId)) { - _ASSERTE(outLabel != 0); - return outLabel; + _ASSERTE(metadataId != 0); + return metadataId; } return 0; } -void EventPipeFile::SaveMetadataLabel(EventPipeEvent &event, StreamLabel label) +void EventPipeFile::SaveMetadataId(EventPipeEvent &event, unsigned int metadataId) { CONTRACTL { THROWS; GC_NOTRIGGER; MODE_ANY; - PRECONDITION(label > 0); + PRECONDITION(metadataId > 0); } CONTRACTL_END; // If a pre-existing metadata label exists, remove it. - StreamLabel outLabel; - if(m_pMetadataLabels->Lookup(&event, &outLabel)) + unsigned int oldId; + if(m_pMetadataIds->Lookup(&event, &oldId)) { - m_pMetadataLabels->Remove(&event); + m_pMetadataIds->Remove(&event); } // Add the metadata label. - m_pMetadataLabels->Add(&event, label); + m_pMetadataIds->Add(&event, metadataId); } #endif // FEATURE_PERFTRACING diff --git a/src/vm/eventpipefile.h b/src/vm/eventpipefile.h index 2f6853545d..48f0bb0557 100644 --- a/src/vm/eventpipefile.h +++ b/src/vm/eventpipefile.h @@ -9,6 +9,7 @@ #ifdef FEATURE_PERFTRACING #include "eventpipe.h" +#include "eventpipeblock.h" #include "eventpipeeventinstance.h" #include "fastserializableobject.h" #include "fastserializer.h" @@ -25,37 +26,53 @@ class EventPipeFile : public FastSerializableObject ); ~EventPipeFile(); - // Write an event to the file. void WriteEvent(EventPipeEventInstance &instance); - // Serialize this object. - // Not supported - this is the entry object for the trace, - // which means that the contents hasn't yet been created. - void FastSerialize(FastSerializer *pSerializer) + void WriteEnd(); + + const char* GetTypeName() { LIMITED_METHOD_CONTRACT; - _ASSERTE(!"This function should never be called!"); + return "Trace"; } - // Get the type name of this object. - const char* GetTypeName() + void FastSerialize(FastSerializer *pSerializer) { - LIMITED_METHOD_CONTRACT; - return "Microsoft.DotNet.Runtime.EventPipeFile"; + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + MODE_PREEMPTIVE; + PRECONDITION(pSerializer != NULL); + } + CONTRACTL_END; + + pSerializer->WriteBuffer((BYTE*)&m_fileOpenSystemTime, sizeof(m_fileOpenSystemTime)); + pSerializer->WriteBuffer((BYTE*)&m_fileOpenTimeStamp, sizeof(m_fileOpenTimeStamp)); + pSerializer->WriteBuffer((BYTE*)&m_timeStampFrequency, sizeof(m_timeStampFrequency)); + + // the beginning of V3 + pSerializer->WriteBuffer((BYTE*)&m_pointerSize, sizeof(m_pointerSize)); + pSerializer->WriteBuffer((BYTE*)&m_currentProcessId, sizeof(m_currentProcessId)); + pSerializer->WriteBuffer((BYTE*)&m_numberOfProcessors, sizeof(m_numberOfProcessors)); + pSerializer->WriteBuffer((BYTE*)&m_samplingRateInNs, sizeof(m_samplingRateInNs)); } private: - // Get the metadata address in the file for an event. - // The return value can be written into the file as a back-pointer to the event metadata. - StreamLabel GetMetadataLabel(EventPipeEvent &event); + unsigned int GenerateMetadataId(); + + unsigned int GetMetadataId(EventPipeEvent &event); - // Save the metadata address in the file for an event. - void SaveMetadataLabel(EventPipeEvent &event, StreamLabel label); + void SaveMetadataId(EventPipeEvent &event, unsigned int metadataId); + + void WriteToBlock(EventPipeEventInstance &instance, unsigned int metadataId); // The object responsible for serialization. FastSerializer *m_pSerializer; + EventPipeBlock *m_pBlock; + // The system time when the file was opened. SYSTEMTIME m_fileOpenSystemTime; @@ -65,15 +82,22 @@ class EventPipeFile : public FastSerializableObject // The frequency of the timestamps used for this file. LARGE_INTEGER m_timeStampFrequency; - // The forward reference index that marks the beginning of the event stream. - unsigned int m_beginEventsForwardReferenceIndex; + unsigned int m_pointerSize; + + unsigned int m_currentProcessId; + + unsigned int m_numberOfProcessors; + + unsigned int m_samplingRateInNs; // The serialization which is responsible for making sure only a single event // or block of events gets written to the file at once. SpinLock m_serializationLock; // Hashtable of metadata labels. - MapSHashWithRemove<EventPipeEvent*, StreamLabel> *m_pMetadataLabels; + MapSHashWithRemove<EventPipeEvent*, unsigned int> *m_pMetadataIds; + + Volatile<LONG> m_metadataIdCounter; #ifdef _DEBUG bool m_lockOnWrite; diff --git a/src/vm/fastserializer.cpp b/src/vm/fastserializer.cpp index 2e2939a17f..7a79b2ff19 100644 --- a/src/vm/fastserializer.cpp +++ b/src/vm/fastserializer.cpp @@ -7,7 +7,11 @@ #ifdef FEATURE_PERFTRACING -FastSerializer::FastSerializer(SString &outputFilePath, FastSerializableObject &object) +// Event Pipe has previously implemented a feature called "forward references" +// As a result of work on V3 of Event Pipe (https://github.com/Microsoft/perfview/pull/532) it got removed +// if you need it, please use git to restore it + +FastSerializer::FastSerializer(SString &outputFilePath) { CONTRACTL { @@ -18,9 +22,7 @@ FastSerializer::FastSerializer(SString &outputFilePath, FastSerializableObject & CONTRACTL_END; m_writeErrorEncountered = false; - m_pEntryObject = &object; m_currentPos = 0; - m_nextForwardReference = 0; m_pFileStream = new CFileStream(); if(FAILED(m_pFileStream->OpenForWrite(outputFilePath))) { @@ -30,11 +32,7 @@ FastSerializer::FastSerializer(SString &outputFilePath, FastSerializableObject & return; } - // Write the file header. WriteFileHeader(); - - // Write the entry object. - WriteEntryObject(); } FastSerializer::~FastSerializer() @@ -47,15 +45,6 @@ FastSerializer::~FastSerializer() } CONTRACTL_END; - // Write the end of the entry object. - WriteTag(FastSerializerTags::EndObject); - - // Write forward reference table. - StreamLabel forwardReferenceLabel = WriteForwardReferenceTable(); - - // Write trailer. - WriteTrailer(forwardReferenceLabel); - if(m_pFileStream != NULL) { delete(m_pFileStream); @@ -74,23 +63,20 @@ void FastSerializer::WriteObject(FastSerializableObject *pObject) { CONTRACTL { - THROWS; - GC_TRIGGERS; + NOTHROW; + GC_NOTRIGGER; MODE_ANY; PRECONDITION(pObject != NULL); } CONTRACTL_END; - // Write a BeginObject tag. WriteTag(FastSerializerTags::BeginObject); - // Write object begin tag. WriteSerializationType(pObject); // Ask the object to serialize itself using the current serializer. pObject->FastSerialize(this); - // Write object end tag. WriteTag(FastSerializerTags::EndObject); } @@ -138,82 +124,12 @@ void FastSerializer::WriteBuffer(BYTE *pBuffer, unsigned int length) EX_END_CATCH(SwallowAllExceptions); } -void FastSerializer::WriteEntryObject() -{ - CONTRACTL - { - NOTHROW; - GC_TRIGGERS; - MODE_PREEMPTIVE; - } - CONTRACTL_END; - - // Write begin entry object tag. - WriteTag(FastSerializerTags::BeginObject); - - // Write the type information for the entry object. - WriteSerializationType(m_pEntryObject); - - // The object is now initialized. Fields or other objects can now be written. -} - -unsigned int FastSerializer::AllocateForwardReference() -{ - CONTRACTL - { - NOTHROW; - GC_TRIGGERS; - MODE_PREEMPTIVE; - PRECONDITION(m_nextForwardReference < MaxForwardReferences); - } - CONTRACTL_END; - - // TODO: Handle failure. - - // Save the index. - int index = m_nextForwardReference; - - // Allocate the forward reference and zero-fill it so that the reader - // will know if it was not properly defined. - m_forwardReferences[m_nextForwardReference++] = 0; - - return index; -} - -void FastSerializer::DefineForwardReference(unsigned int index, StreamLabel value) -{ - CONTRACTL - { - NOTHROW; - GC_TRIGGERS; - MODE_PREEMPTIVE; - PRECONDITION(index < MaxForwardReferences-1); - } - CONTRACTL_END; - - m_forwardReferences[index] = value; -} - -void FastSerializer::WriteForwardReference(unsigned int index) -{ - CONTRACTL - { - NOTHROW; - GC_TRIGGERS; - MODE_PREEMPTIVE; - PRECONDITION(index < MaxForwardReferences-1); - } - CONTRACTL_END; - - WriteBuffer((BYTE*)&index, sizeof(index)); -} - void FastSerializer::WriteSerializationType(FastSerializableObject *pObject) { CONTRACTL { NOTHROW; - GC_TRIGGERS; + GC_NOTRIGGER; MODE_PREEMPTIVE; PRECONDITION(pObject != NULL); } @@ -234,6 +150,7 @@ void FastSerializer::WriteSerializationType(FastSerializableObject *pObject) // Write the SerializationType TypeName field. const char *strTypeName = pObject->GetTypeName(); unsigned int length = (unsigned int)strlen(strTypeName); + WriteString(strTypeName, length); // Write the EndObject tag. @@ -246,7 +163,7 @@ void FastSerializer::WriteTag(FastSerializerTags tag, BYTE *payload, unsigned in CONTRACTL { NOTHROW; - GC_TRIGGERS; + GC_NOTRIGGER; MODE_PREEMPTIVE; } CONTRACTL_END; @@ -259,18 +176,17 @@ void FastSerializer::WriteTag(FastSerializerTags tag, BYTE *payload, unsigned in } } - void FastSerializer::WriteFileHeader() { CONTRACTL { NOTHROW; - GC_TRIGGERS; + GC_NOTRIGGER; MODE_ANY; } CONTRACTL_END; - const char *strSignature = "!FastSerialization.1"; + const char *strSignature = "!FastSerialization.1"; // the consumer lib expects exactly the same string, it must not be changed unsigned int length = (unsigned int)strlen(strSignature); WriteString(strSignature, length); } @@ -280,7 +196,7 @@ void FastSerializer::WriteString(const char *strContents, unsigned int length) CONTRACTL { NOTHROW; - GC_TRIGGERS; + GC_NOTRIGGER; MODE_PREEMPTIVE; } CONTRACTL_END; @@ -292,47 +208,4 @@ void FastSerializer::WriteString(const char *strContents, unsigned int length) WriteBuffer((BYTE*) strContents, length); } -StreamLabel FastSerializer::WriteForwardReferenceTable() -{ - CONTRACTL - { - NOTHROW; - GC_TRIGGERS; - MODE_PREEMPTIVE; - } - CONTRACTL_END; - - // Save the position of the start of the forward references table. - StreamLabel current = GetStreamLabel(); - - // Write the count of allocated references. - WriteBuffer((BYTE*) &m_nextForwardReference, sizeof(m_nextForwardReference)); - - // Write each of the allocated references. - WriteBuffer((BYTE*) m_forwardReferences, sizeof(StreamLabel) * m_nextForwardReference); - - return current; -} - -void FastSerializer::WriteTrailer(StreamLabel forwardReferencesTableStart) -{ - CONTRACTL - { - NOTHROW; - GC_TRIGGERS; - MODE_PREEMPTIVE; - } - CONTRACTL_END; - - // Get the current location to mark the beginning of the trailer. - StreamLabel current = GetStreamLabel(); - - // Write the trailer, which contains the start of the forward references table. - WriteBuffer((BYTE*) &forwardReferencesTableStart, sizeof(forwardReferencesTableStart)); - - // Write the location of the trailer. This is the final piece of data written to the file, - // so that it can be easily found by a reader that can seek to the end of the file. - WriteBuffer((BYTE*) ¤t, sizeof(current)); -} - #endif // FEATURE_PERFTRACING diff --git a/src/vm/fastserializer.h b/src/vm/fastserializer.h index 5fd2cfd4a5..fad04de48c 100644 --- a/src/vm/fastserializer.h +++ b/src/vm/fastserializer.h @@ -5,6 +5,8 @@ #ifndef __FASTSERIALIZER_H__ #define __FASTSERIALIZER_H__ +#define ALIGNMENT_SIZE 4 + #ifdef FEATURE_PERFTRACING #include "fastserializableobject.h" @@ -14,30 +16,33 @@ class FastSerializer; typedef unsigned int StreamLabel; +// the enumeration has a specific set of values to keep it compatible with consumer library +// it's sibling is defined in https://github.com/Microsoft/perfview/blob/10d1f92b242c98073b3817ac5ee6d98cd595d39b/src/FastSerialization/FastSerialization.cs#L2295 enum class FastSerializerTags : BYTE { - Error, // To improve debugabilty, 0 is an illegal tag. - NullReference, // Tag for a null object forwardReference. - ObjectReference, // Followed by StreamLabel - ForwardReference, // Followed by an index (32-bit integer) into the Forward forwardReference array and a Type object - BeginObject, // Followed by Type object, object data, tagged EndObject - BeginPrivateObject, // Like beginObject, but not placed in interning table on deserialiation - EndObject, // Placed after an object to mark its end. - ForwardDefinition, // Followed by a forward forwardReference index and an object definition (BeginObject) - Byte, + Error = 0, // To improve debugabilty, 0 is an illegal tag. + NullReference = 1, // Tag for a null object forwardReference. + ObjectReference = 2, // Followed by StreamLabel + // 3 used to belong to ForwardReference, which got removed in V3 + BeginObject = 4, // Followed by Type object, object data, tagged EndObject + BeginPrivateObject = 5, // Like beginObject, but not placed in interning table on deserialiation + EndObject = 6, // Placed after an object to mark its end. + // 7 used to belong to ForwardDefinition, which got removed in V3 + Byte = 8, Int16, Int32, Int64, SkipRegion, String, - Limit, // Just past the last valid tag, used for asserts. + Blob, + Limit // Just past the last valid tag, used for asserts. }; class FastSerializer { public: - FastSerializer(SString &outputFilePath, FastSerializableObject &object); + FastSerializer(SString &outputFilePath); ~FastSerializer(); StreamLabel GetStreamLabel() const; @@ -47,26 +52,21 @@ public: void WriteTag(FastSerializerTags tag, BYTE *payload = NULL, unsigned int payloadLength = 0); void WriteString(const char *strContents, unsigned int length); - unsigned int AllocateForwardReference(); - void DefineForwardReference(unsigned int index, StreamLabel value); - void WriteForwardReference(unsigned int index); + size_t GetCurrentPosition() const + { + LIMITED_METHOD_CONTRACT; + + return m_currentPos; + } private: - void WriteEntryObject(); void WriteSerializationType(FastSerializableObject *pObject); void WriteFileHeader(); - StreamLabel WriteForwardReferenceTable(); - void WriteTrailer(StreamLabel forwardReferencesTableStart); CFileStream *m_pFileStream; bool m_writeErrorEncountered; - FastSerializableObject *m_pEntryObject; size_t m_currentPos; - - static const unsigned int MaxForwardReferences = 100; - StreamLabel m_forwardReferences[MaxForwardReferences]; - unsigned int m_nextForwardReference; }; #endif // FEATURE_PERFTRACING diff --git a/src/vm/sampleprofiler.h b/src/vm/sampleprofiler.h index 1bee70e8f6..871b175604 100644 --- a/src/vm/sampleprofiler.h +++ b/src/vm/sampleprofiler.h @@ -35,6 +35,13 @@ class SampleProfiler // Set the sampling rate. static void SetSamplingRate(unsigned long nanoseconds); + static unsigned long GetSamplingRate() + { + LIMITED_METHOD_CONTRACT; + + return s_samplingRateInNs; + } + private: // Iterate through all managed threads and walk all stacks. |