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 void EventPipeFile::WriteEvent(EventPipeEventInstance &instance)
79 // Check to see if we've seen this event type before.
80 // If not, then write the event metadata to the event stream first.
81 unsigned int metadataId = GetMetadataId(*instance.GetEvent());
84 metadataId = GenerateMetadataId();
86 EventPipeEventInstance* pMetadataInstance = EventPipe::GetConfiguration()->BuildEventMetadataEvent(instance, metadataId);
88 WriteToBlock(*pMetadataInstance, 0); // 0 breaks recursion and represents the metadata event.
90 SaveMetadataId(*instance.GetEvent(), metadataId);
92 delete[] pMetadataInstance->GetData();
93 delete pMetadataInstance;
96 WriteToBlock(instance, metadataId);
99 void EventPipeFile::Flush()
101 // Write existing buffer to the stream/file regardless of whether it is full or not.
109 m_pSerializer->WriteObject(m_pBlock); // we write current block to the disk, whether it's full or not
113 void EventPipeFile::WriteEnd()
123 m_pSerializer->WriteObject(m_pBlock); // we write current block to the disk, whether it's full or not
127 // "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."
128 // see https://github.com/Microsoft/perfview/blob/master/src/TraceEvent/EventPipe/EventPipeFormat.md for more
129 m_pSerializer->WriteTag(FastSerializerTags::NullReference);
132 void EventPipeFile::WriteToBlock(EventPipeEventInstance &instance, unsigned int metadataId)
142 instance.SetMetadataId(metadataId);
144 if (m_pBlock->WriteEvent(instance))
145 return; // the block is not full, we added the event and continue
147 // we can't write this event to the current block (it's full)
148 // so we write what we have in the block to the serializer
149 m_pSerializer->WriteObject(m_pBlock);
153 bool result = m_pBlock->WriteEvent(instance);
155 _ASSERTE(result == true); // we should never fail to add event to a clear block (if we do the max size is too small)
158 unsigned int EventPipeFile::GenerateMetadataId()
168 // PAL does not support 32 bit InterlockedIncrement, so we are using the LONG version and cast to int
169 // https://github.com/dotnet/coreclr/blob/master/src/pal/inc/pal.h#L4159
170 // it's ok because the metadataId will never be bigger than 32 bit
171 return (unsigned int)InterlockedIncrement(&m_metadataIdCounter);
174 unsigned int EventPipeFile::GetMetadataId(EventPipeEvent &event)
184 unsigned int metadataId;
185 if(m_pMetadataIds->Lookup(&event, &metadataId))
187 _ASSERTE(metadataId != 0);
194 void EventPipeFile::SaveMetadataId(EventPipeEvent &event, unsigned int metadataId)
201 PRECONDITION(metadataId > 0);
205 // If a pre-existing metadata label exists, remove it.
207 if(m_pMetadataIds->Lookup(&event, &oldId))
208 m_pMetadataIds->Remove(&event);
210 // Add the metadata label.
211 m_pMetadataIds->Add(&event, metadataId);
214 #endif // FEATURE_PERFTRACING