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.
6 #include "eventpipeblock.h"
7 #include "eventpipefile.h"
8 #include "sampleprofiler.h"
10 #ifdef FEATURE_PERFTRACING
12 EventPipeFile::EventPipeFile(StreamWriter *pStreamWriter) : FastSerializableObject(3, 0)
22 m_pBlock = new EventPipeBlock(100 * 1024);
24 // File start time information.
25 GetSystemTime(&m_fileOpenSystemTime);
26 QueryPerformanceCounter(&m_fileOpenTimeStamp);
27 QueryPerformanceFrequency(&m_timeStampFrequency);
29 m_pointerSize = TARGET_POINTER_SIZE;
31 m_currentProcessId = GetCurrentProcessId();
33 SYSTEM_INFO sysinfo = {};
34 GetSystemInfo(&sysinfo);
35 m_numberOfProcessors = sysinfo.dwNumberOfProcessors;
37 m_samplingRateInNs = SampleProfiler::GetSamplingRate();
39 // Create the file stream and write the header.
40 m_pSerializer = new FastSerializer(pStreamWriter);
42 m_serializationLock.Init(LOCK_TYPE_DEFAULT);
43 m_pMetadataIds = new MapSHashWithRemove<EventPipeEvent*, unsigned int>();
45 // Start and 0 - The value is always incremented prior to use, so the first ID will be 1.
46 m_metadataIdCounter = 0;
48 // Write the first object to the file.
49 m_pSerializer->WriteObject(this);
52 EventPipeFile::~EventPipeFile()
62 if (m_pBlock != NULL && m_pSerializer != NULL)
69 bool EventPipeFile::HasErrors() const
71 LIMITED_METHOD_CONTRACT;
72 return (m_pSerializer == nullptr) || m_pSerializer->HasWriteErrors();
75 void EventPipeFile::WriteEvent(EventPipeEventInstance &instance)
85 // Check to see if we've seen this event type before.
86 // If not, then write the event metadata to the event stream first.
87 unsigned int metadataId = GetMetadataId(*instance.GetEvent());
90 metadataId = GenerateMetadataId();
92 EventPipeEventInstance* pMetadataInstance = EventPipe::GetConfiguration()->BuildEventMetadataEvent(instance, metadataId);
94 WriteToBlock(*pMetadataInstance, 0); // 0 breaks recursion and represents the metadata event.
96 SaveMetadataId(*instance.GetEvent(), metadataId);
98 delete[] pMetadataInstance->GetData();
99 delete pMetadataInstance;
102 WriteToBlock(instance, metadataId);
105 void EventPipeFile::Flush()
107 // Write existing buffer to the stream/file regardless of whether it is full or not.
115 m_pSerializer->WriteObject(m_pBlock); // we write current block to the disk, whether it's full or not
119 void EventPipeFile::WriteEnd()
129 m_pSerializer->WriteObject(m_pBlock); // we write current block to the disk, whether it's full or not
133 // "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."
134 // see https://github.com/Microsoft/perfview/blob/master/src/TraceEvent/EventPipe/EventPipeFormat.md for more
135 m_pSerializer->WriteTag(FastSerializerTags::NullReference);
138 void EventPipeFile::WriteToBlock(EventPipeEventInstance &instance, unsigned int metadataId)
148 instance.SetMetadataId(metadataId);
150 if (m_pBlock->WriteEvent(instance))
151 return; // the block is not full, we added the event and continue
153 // we can't write this event to the current block (it's full)
154 // so we write what we have in the block to the serializer
155 m_pSerializer->WriteObject(m_pBlock);
159 bool result = m_pBlock->WriteEvent(instance);
161 _ASSERTE(result == true); // we should never fail to add event to a clear block (if we do the max size is too small)
164 unsigned int EventPipeFile::GenerateMetadataId()
174 // PAL does not support 32 bit InterlockedIncrement, so we are using the LONG version and cast to int
175 // https://github.com/dotnet/coreclr/blob/master/src/pal/inc/pal.h#L4159
176 // it's ok because the metadataId will never be bigger than 32 bit
177 return (unsigned int)InterlockedIncrement(&m_metadataIdCounter);
180 unsigned int EventPipeFile::GetMetadataId(EventPipeEvent &event)
190 unsigned int metadataId;
191 if(m_pMetadataIds->Lookup(&event, &metadataId))
193 _ASSERTE(metadataId != 0);
200 void EventPipeFile::SaveMetadataId(EventPipeEvent &event, unsigned int metadataId)
207 PRECONDITION(metadataId > 0);
211 // If a pre-existing metadata label exists, remove it.
213 if(m_pMetadataIds->Lookup(&event, &oldId))
214 m_pMetadataIds->Remove(&event);
216 // Add the metadata label.
217 m_pMetadataIds->Add(&event, metadataId);
220 #endif // FEATURE_PERFTRACING