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 "eventpipeeventinstance.h"
8 #include "fastserializableobject.h"
9 #include "fastserializer.h"
11 // my attempts to include limits.h were hitting missing headers on Linux
12 // This might be resolvable with more effort but I chose not to head
13 // down the rabbit hole when a perfectly decent 60 second fix was available:
15 #define LLONG_MIN 0x8000000000000000
18 #define LLONG_MAX 0x7FFFFFFFFFFFFFFF
21 #ifdef FEATURE_PERFTRACING
25 DWORD GetBlockVersion(EventPipeSerializationFormat format)
27 LIMITED_METHOD_CONTRACT;
30 case EventPipeSerializationFormat::NetPerfV3:
32 case EventPipeSerializationFormat::NetTraceV4:
35 _ASSERTE(!"Unrecognized EventPipeSerializationFormat");
40 DWORD GetBlockMinVersion(EventPipeSerializationFormat format)
42 LIMITED_METHOD_CONTRACT;
45 case EventPipeSerializationFormat::NetPerfV3:
47 case EventPipeSerializationFormat::NetTraceV4:
50 _ASSERTE(!"Unrecognized EventPipeSerializationFormat");
55 EventPipeBlock::EventPipeBlock(unsigned int maxBlockSize, EventPipeSerializationFormat format) :
56 FastSerializableObject(GetBlockVersion(format), GetBlockMinVersion(format), format >= EventPipeSerializationFormat::NetTraceV4)
66 m_pBlock = new (nothrow) BYTE[maxBlockSize];
72 memset(m_pBlock, 0, maxBlockSize);
73 m_pWritePointer = m_pBlock;
74 m_pEndOfTheBuffer = m_pBlock + maxBlockSize;
78 EventPipeBlock::~EventPipeBlock()
91 void EventPipeBlock::Clear()
101 if (m_pBlock == NULL)
106 _ASSERTE(m_pWritePointer <= m_pEndOfTheBuffer);
108 memset(m_pBlock, 0, GetSize());
109 m_pWritePointer = m_pBlock;
112 EventPipeEventBlockBase::EventPipeEventBlockBase(unsigned int maxBlockSize, EventPipeSerializationFormat format, bool fUseHeaderCompression) :
113 EventPipeBlock(maxBlockSize, format), m_fUseHeaderCompression(fUseHeaderCompression)
115 memset(m_compressedHeader, 0, 100);
119 void EventPipeEventBlockBase::Clear()
121 EventPipeBlock::Clear();
122 m_lastHeader.MetadataId = 0;
123 m_lastHeader.SequenceNumber = 0;
124 m_lastHeader.ThreadId = 0;
125 m_lastHeader.CaptureThreadId = 0;
126 m_lastHeader.StackId = 0;
127 m_lastHeader.TimeStamp.QuadPart = 0;
128 m_lastHeader.ActivityId = { 0 };
129 m_lastHeader.RelatedActivityId = { 0 };
130 m_lastHeader.DataLength = 0;
132 m_minTimeStamp.QuadPart = LLONG_MAX;
133 m_maxTimeStamp.QuadPart = LLONG_MIN;
136 void WriteVarUInt32(BYTE* & pWritePointer, unsigned int value)
138 while (value >= 0x80)
140 *pWritePointer = (BYTE)(value | 0x80);
144 *pWritePointer = (BYTE)value;
148 void WriteVarUInt64(BYTE* & pWritePointer, ULONGLONG value)
150 while (value >= 0x80)
152 *pWritePointer = (BYTE)(value | 0x80);
156 *pWritePointer = (BYTE)value;
160 bool EventPipeEventBlockBase::WriteEvent(EventPipeEventInstance &instance,
161 ULONGLONG captureThreadId,
162 unsigned int sequenceNumber,
171 PRECONDITION(isSortedEvent || m_format >= EventPipeSerializationFormat::NetTraceV4);
175 if (m_pBlock == NULL)
180 unsigned int dataLength = 0;
181 BYTE* alignedEnd = NULL;
182 unsigned int captureProcNumber = instance.GetProcNumber();
184 if (!m_fUseHeaderCompression)
186 unsigned int totalSize = instance.GetAlignedTotalSize(m_format);
187 if (m_pWritePointer + totalSize >= m_pEndOfTheBuffer)
192 alignedEnd = m_pWritePointer + totalSize + sizeof(totalSize);
194 memcpy(m_pWritePointer, &totalSize, sizeof(totalSize));
195 m_pWritePointer += sizeof(totalSize);
197 unsigned int metadataId = instance.GetMetadataId();
198 _ASSERTE((metadataId & (1 << 31)) == 0);
199 metadataId |= (!isSortedEvent ? 1 << 31 : 0);
200 memcpy(m_pWritePointer, &metadataId, sizeof(metadataId));
201 m_pWritePointer += sizeof(metadataId);
203 if (m_format == EventPipeSerializationFormat::NetPerfV3)
205 DWORD threadId = instance.GetThreadId32();
206 memcpy(m_pWritePointer, &threadId, sizeof(threadId));
207 m_pWritePointer += sizeof(threadId);
209 else if (m_format == EventPipeSerializationFormat::NetTraceV4)
211 memcpy(m_pWritePointer, &sequenceNumber, sizeof(sequenceNumber));
212 m_pWritePointer += sizeof(sequenceNumber);
214 ULONGLONG threadId = instance.GetThreadId64();
215 memcpy(m_pWritePointer, &threadId, sizeof(threadId));
216 m_pWritePointer += sizeof(threadId);
218 memcpy(m_pWritePointer, &captureThreadId, sizeof(captureThreadId));
219 m_pWritePointer += sizeof(captureThreadId);
221 memcpy(m_pWritePointer, &captureProcNumber, sizeof(captureProcNumber));
222 m_pWritePointer += sizeof(captureProcNumber);
224 memcpy(m_pWritePointer, &stackId, sizeof(stackId));
225 m_pWritePointer += sizeof(stackId);
228 const LARGE_INTEGER* timeStamp = instance.GetTimeStamp();
229 memcpy(m_pWritePointer, timeStamp, sizeof(*timeStamp));
230 m_pWritePointer += sizeof(*timeStamp);
232 const GUID* activityId = instance.GetActivityId();
233 memcpy(m_pWritePointer, activityId, sizeof(*activityId));
234 m_pWritePointer += sizeof(*activityId);
236 const GUID* relatedActivityId = instance.GetRelatedActivityId();
237 memcpy(m_pWritePointer, relatedActivityId, sizeof(*relatedActivityId));
238 m_pWritePointer += sizeof(*relatedActivityId);
240 dataLength = instance.GetDataLength();
241 memcpy(m_pWritePointer, &dataLength, sizeof(dataLength));
242 m_pWritePointer += sizeof(dataLength);
244 else // using header compression
247 BYTE* pWritePointer = m_compressedHeader;
249 if (instance.GetMetadataId() != m_lastHeader.MetadataId)
251 WriteVarUInt32(pWritePointer, instance.GetMetadataId());
259 if (m_lastHeader.SequenceNumber + (instance.GetMetadataId() != 0 ? 1 : 0) != sequenceNumber ||
260 m_lastHeader.CaptureThreadId != captureThreadId ||
261 m_lastHeader.CaptureProcNumber != captureProcNumber)
263 WriteVarUInt32(pWritePointer, sequenceNumber - m_lastHeader.SequenceNumber - 1);
264 WriteVarUInt64(pWritePointer, captureThreadId);
265 WriteVarUInt32(pWritePointer, captureProcNumber);
269 if (m_lastHeader.ThreadId != instance.GetThreadId64())
271 WriteVarUInt64(pWritePointer, instance.GetThreadId64());
275 if (m_lastHeader.StackId != stackId)
277 WriteVarUInt32(pWritePointer, stackId);
281 const LARGE_INTEGER* timeStamp = instance.GetTimeStamp();
282 WriteVarUInt64(pWritePointer, timeStamp->QuadPart - m_lastHeader.TimeStamp.QuadPart);
284 if (memcmp(&m_lastHeader.ActivityId, instance.GetActivityId(), sizeof(GUID)) != 0)
286 memcpy(pWritePointer, instance.GetActivityId(), sizeof(GUID));
287 pWritePointer += sizeof(GUID);
291 if (memcmp(&m_lastHeader.RelatedActivityId, instance.GetRelatedActivityId(), sizeof(GUID)) != 0)
293 memcpy(pWritePointer, instance.GetRelatedActivityId(), sizeof(GUID));
294 pWritePointer += sizeof(GUID);
298 dataLength = instance.GetDataLength();
299 if (m_lastHeader.DataLength != dataLength)
301 WriteVarUInt32(pWritePointer, dataLength);
305 unsigned int bytesWritten = (unsigned int)(pWritePointer - m_compressedHeader);
306 unsigned int totalSize = 1 + bytesWritten + dataLength;
307 if (m_pWritePointer + totalSize >= m_pEndOfTheBuffer)
312 m_lastHeader.MetadataId = instance.GetMetadataId();
313 m_lastHeader.SequenceNumber = sequenceNumber;
314 m_lastHeader.ThreadId = instance.GetThreadId64();
315 m_lastHeader.CaptureThreadId = captureThreadId;
316 m_lastHeader.CaptureProcNumber = captureProcNumber;
317 m_lastHeader.StackId = stackId;
318 m_lastHeader.TimeStamp.QuadPart = timeStamp->QuadPart;
319 memcpy(&m_lastHeader.ActivityId, instance.GetActivityId(), sizeof(GUID));
320 memcpy(&m_lastHeader.RelatedActivityId, instance.GetRelatedActivityId(), sizeof(GUID));
321 m_lastHeader.DataLength = dataLength;
323 alignedEnd = m_pWritePointer + totalSize;
324 *m_pWritePointer = flags;
326 memcpy(m_pWritePointer, m_compressedHeader, bytesWritten);
327 m_pWritePointer += bytesWritten;
332 memcpy(m_pWritePointer, instance.GetData(), dataLength);
333 m_pWritePointer += dataLength;
336 if (m_format == EventPipeSerializationFormat::NetPerfV3)
338 unsigned int stackSize = instance.GetStackSize();
339 memcpy(m_pWritePointer, &stackSize, sizeof(stackSize));
340 m_pWritePointer += sizeof(stackSize);
344 memcpy(m_pWritePointer, instance.GetStack(), stackSize);
345 m_pWritePointer += stackSize;
349 while (m_pWritePointer < alignedEnd)
351 *m_pWritePointer++ = (BYTE)0; // put padding at the end to get 4 bytes alignment of the payload
353 _ASSERTE(m_pWritePointer == alignedEnd);
355 if (m_minTimeStamp.QuadPart > instance.GetTimeStamp()->QuadPart)
357 m_minTimeStamp.QuadPart = instance.GetTimeStamp()->QuadPart;
359 if (m_maxTimeStamp.QuadPart < instance.GetTimeStamp()->QuadPart)
361 m_maxTimeStamp.QuadPart = instance.GetTimeStamp()->QuadPart;
367 EventPipeEventBlock::EventPipeEventBlock(unsigned int maxBlockSize, EventPipeSerializationFormat format) :
368 EventPipeEventBlockBase(maxBlockSize, format, format >= EventPipeSerializationFormat::NetTraceV4)
372 EventPipeMetadataBlock::EventPipeMetadataBlock(unsigned int maxBlockSize) :
373 EventPipeEventBlockBase(maxBlockSize, EventPipeSerializationFormat::NetTraceV4)
376 unsigned int GetSequencePointBlockSize(EventPipeSequencePoint* pSequencePoint)
378 const unsigned int sizeOfSequenceNumber =
379 sizeof(ULONGLONG) + // thread id
380 sizeof(unsigned int); // sequence number
381 return sizeof(pSequencePoint->TimeStamp) +
382 sizeof(unsigned int) + // thread count
383 pSequencePoint->ThreadSequenceNumbers.GetCount() * sizeOfSequenceNumber;
386 EventPipeSequencePointBlock::EventPipeSequencePointBlock(EventPipeSequencePoint* pSequencePoint) :
387 EventPipeBlock(GetSequencePointBlockSize(pSequencePoint))
389 const LARGE_INTEGER timeStamp = pSequencePoint->TimeStamp;
390 memcpy(m_pWritePointer, &timeStamp, sizeof(timeStamp));
391 m_pWritePointer += sizeof(timeStamp);
393 const unsigned int threadCount = pSequencePoint->ThreadSequenceNumbers.GetCount();
394 memcpy(m_pWritePointer, &threadCount, sizeof(threadCount));
395 m_pWritePointer += sizeof(threadCount);
397 for (ThreadSequenceNumberMap::Iterator pCur = pSequencePoint->ThreadSequenceNumbers.Begin();
398 pCur != pSequencePoint->ThreadSequenceNumbers.End();
401 const ULONGLONG threadId = pCur->Key()->GetThread()->GetOSThreadId();
402 memcpy(m_pWritePointer, &threadId, sizeof(threadId));
403 m_pWritePointer += sizeof(threadId);
405 const unsigned int sequenceNumber = pCur->Value();
406 memcpy(m_pWritePointer, &sequenceNumber, sizeof(sequenceNumber));
407 m_pWritePointer += sizeof(sequenceNumber);
411 EventPipeStackBlock::EventPipeStackBlock(unsigned int maxBlockSize) :
412 EventPipeBlock(maxBlockSize)
417 void EventPipeStackBlock::Clear()
419 m_hasInitialIndex = false;
422 EventPipeBlock::Clear();
425 bool EventPipeStackBlock::WriteStack(DWORD stackId, StackContents* pStack)
435 if (m_pBlock == NULL)
440 unsigned int stackSize = pStack->GetSize();
441 unsigned int totalSize = sizeof(stackSize) + stackSize;
442 if (m_pWritePointer + totalSize >= m_pEndOfTheBuffer)
447 if (!m_hasInitialIndex)
449 m_hasInitialIndex = true;
450 m_initialIndex = stackId;
454 memcpy(m_pWritePointer, &stackSize, sizeof(stackSize));
455 m_pWritePointer += sizeof(stackSize);
459 memcpy(m_pWritePointer, pStack->GetPointer(), stackSize);
460 #ifdef FEATURE_LARGEADDRESS_SUPPORT
461 for (int i = 0; i < stackSize / sizeof(UINT_PTR); i++)
463 ((UINT_PTR*)m_pWritePointer)[i] &= INT_MAX;
465 #endif // FEATURE_LARGEADDRESS_SUPPORT
466 m_pWritePointer += stackSize;
473 #endif // FEATURE_PERFTRACING