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. |
4 | |
5 | |
6 | #include "common.h" |
7 | #include "eventpipe.h" |
8 | #include "eventpipeeventinstance.h" |
9 | #include "eventpipebuffer.h" |
10 | |
11 | #ifdef FEATURE_PERFTRACING |
12 | |
13 | EventPipeBuffer::EventPipeBuffer(unsigned int bufferSize) |
14 | { |
15 | CONTRACTL |
16 | { |
17 | THROWS; |
18 | GC_NOTRIGGER; |
19 | MODE_ANY; |
20 | } |
21 | CONTRACTL_END; |
22 | |
23 | m_pBuffer = new BYTE[bufferSize]; |
24 | memset(m_pBuffer, 0, bufferSize); |
25 | m_pLimit = m_pBuffer + bufferSize; |
26 | m_pCurrent = GetNextAlignedAddress(m_pBuffer); |
27 | |
28 | m_mostRecentTimeStamp.QuadPart = 0; |
29 | m_pLastPoppedEvent = NULL; |
30 | m_pPrevBuffer = NULL; |
31 | m_pNextBuffer = NULL; |
32 | } |
33 | |
34 | EventPipeBuffer::~EventPipeBuffer() |
35 | { |
36 | CONTRACTL |
37 | { |
38 | NOTHROW; |
39 | GC_NOTRIGGER; |
40 | MODE_ANY; |
41 | } |
42 | CONTRACTL_END; |
43 | |
44 | if(m_pBuffer != NULL) |
45 | { |
46 | delete[] m_pBuffer; |
47 | } |
48 | } |
49 | |
50 | bool EventPipeBuffer::WriteEvent(Thread *pThread, EventPipeSession &session, EventPipeEvent &event, EventPipeEventPayload &payload, LPCGUID pActivityId, LPCGUID pRelatedActivityId, StackContents *pStack) |
51 | { |
52 | CONTRACTL |
53 | { |
54 | NOTHROW; |
55 | GC_NOTRIGGER; |
56 | MODE_ANY; |
57 | PRECONDITION(pThread != NULL); |
58 | PRECONDITION(((size_t)m_pCurrent % AlignmentSize) == 0); |
59 | } |
60 | CONTRACTL_END; |
61 | |
62 | // Calculate the size of the event. |
63 | unsigned int eventSize = sizeof(EventPipeEventInstance) + payload.GetSize(); |
64 | |
65 | // Make sure we have enough space to write the event. |
66 | if(m_pCurrent + eventSize >= m_pLimit) |
67 | { |
68 | return false; |
69 | } |
70 | |
71 | // Calculate the location of the data payload. |
72 | BYTE *pDataDest = m_pCurrent + sizeof(EventPipeEventInstance); |
73 | |
74 | bool success = true; |
75 | EX_TRY |
76 | { |
77 | // Placement-new the EventPipeEventInstance. |
78 | EventPipeEventInstance *pInstance = new (m_pCurrent) EventPipeEventInstance( |
79 | session, |
80 | event, |
81 | pThread->GetOSThreadId(), |
82 | pDataDest, |
83 | payload.GetSize(), |
84 | pActivityId, |
85 | pRelatedActivityId); |
86 | |
87 | // Copy the stack if a separate stack trace was provided. |
88 | if(pStack != NULL) |
89 | { |
90 | StackContents *pInstanceStack = pInstance->GetStack(); |
91 | pStack->CopyTo(pInstanceStack); |
92 | } |
93 | |
94 | // Write the event payload data to the buffer. |
95 | if(payload.GetSize() > 0) |
96 | { |
97 | payload.CopyData(pDataDest); |
98 | } |
99 | |
100 | // Save the most recent event timestamp. |
101 | m_mostRecentTimeStamp = *pInstance->GetTimeStamp(); |
102 | |
103 | } |
104 | EX_CATCH |
105 | { |
106 | // If a failure occurs, bail out and don't advance the pointer. |
107 | success = false; |
108 | } |
109 | EX_END_CATCH(SwallowAllExceptions); |
110 | |
111 | if(success) |
112 | { |
113 | // Advance the current pointer past the event. |
114 | m_pCurrent = GetNextAlignedAddress(m_pCurrent + eventSize); |
115 | } |
116 | |
117 | return success; |
118 | } |
119 | |
120 | LARGE_INTEGER EventPipeBuffer::GetMostRecentTimeStamp() const |
121 | { |
122 | LIMITED_METHOD_CONTRACT; |
123 | |
124 | return m_mostRecentTimeStamp; |
125 | } |
126 | |
127 | void EventPipeBuffer::Clear() |
128 | { |
129 | CONTRACTL |
130 | { |
131 | NOTHROW; |
132 | GC_TRIGGERS; |
133 | MODE_ANY; |
134 | } |
135 | CONTRACTL_END; |
136 | |
137 | memset(m_pBuffer, 0, (size_t)(m_pLimit - m_pBuffer)); |
138 | m_pCurrent = GetNextAlignedAddress(m_pBuffer); |
139 | m_mostRecentTimeStamp.QuadPart = 0; |
140 | m_pLastPoppedEvent = NULL; |
141 | } |
142 | |
143 | EventPipeEventInstance* EventPipeBuffer::GetNext(EventPipeEventInstance *pEvent, LARGE_INTEGER beforeTimeStamp) |
144 | { |
145 | CONTRACTL |
146 | { |
147 | NOTHROW; |
148 | GC_NOTRIGGER; |
149 | MODE_ANY; |
150 | } |
151 | CONTRACTL_END; |
152 | |
153 | EventPipeEventInstance *pNextInstance = NULL; |
154 | // If input is NULL, return the first event if there is one. |
155 | if(pEvent == NULL) |
156 | { |
157 | // If this buffer contains an event, select it. |
158 | BYTE *pFirstAlignedInstance = GetNextAlignedAddress(m_pBuffer); |
159 | if(m_pCurrent > pFirstAlignedInstance) |
160 | { |
161 | pNextInstance = (EventPipeEventInstance*)pFirstAlignedInstance; |
162 | } |
163 | else |
164 | { |
165 | return NULL; |
166 | } |
167 | } |
168 | else |
169 | { |
170 | // Confirm that pEvent is within the used range of the buffer. |
171 | if(((BYTE*)pEvent < m_pBuffer) || ((BYTE*)pEvent >= m_pCurrent)) |
172 | { |
173 | _ASSERT(!"Input pointer is out of range." ); |
174 | return NULL; |
175 | } |
176 | |
177 | // We have a pointer within the bounds of the buffer. |
178 | // Find the next event by skipping the current event with it's data payload immediately after the instance. |
179 | pNextInstance = (EventPipeEventInstance *)GetNextAlignedAddress(const_cast<BYTE *>(pEvent->GetData() + pEvent->GetDataLength())); |
180 | |
181 | // Check to see if we've reached the end of the written portion of the buffer. |
182 | if((BYTE*)pNextInstance >= m_pCurrent) |
183 | { |
184 | return NULL; |
185 | } |
186 | } |
187 | |
188 | // Ensure that the timestamp is valid. The buffer is zero'd before use, so a zero timestamp is invalid. |
189 | LARGE_INTEGER nextTimeStamp = *pNextInstance->GetTimeStamp(); |
190 | if(nextTimeStamp.QuadPart == 0) |
191 | { |
192 | return NULL; |
193 | } |
194 | |
195 | // Ensure that the timestamp is earlier than the beforeTimeStamp. |
196 | if(nextTimeStamp.QuadPart >= beforeTimeStamp.QuadPart) |
197 | { |
198 | return NULL; |
199 | } |
200 | |
201 | return pNextInstance; |
202 | } |
203 | |
204 | EventPipeEventInstance* EventPipeBuffer::PeekNext(LARGE_INTEGER beforeTimeStamp) |
205 | { |
206 | CONTRACTL |
207 | { |
208 | NOTHROW; |
209 | GC_NOTRIGGER; |
210 | MODE_ANY; |
211 | } |
212 | CONTRACTL_END; |
213 | |
214 | // Get the next event using the last popped event as a marker. |
215 | return GetNext(m_pLastPoppedEvent, beforeTimeStamp); |
216 | } |
217 | |
218 | EventPipeEventInstance* EventPipeBuffer::PopNext(LARGE_INTEGER beforeTimeStamp) |
219 | { |
220 | CONTRACTL |
221 | { |
222 | NOTHROW; |
223 | GC_NOTRIGGER; |
224 | MODE_ANY; |
225 | } |
226 | CONTRACTL_END; |
227 | |
228 | // Get the next event using the last popped event as a marker. |
229 | EventPipeEventInstance *pNext = PeekNext(beforeTimeStamp); |
230 | if(pNext != NULL) |
231 | { |
232 | m_pLastPoppedEvent = pNext; |
233 | } |
234 | |
235 | return pNext; |
236 | } |
237 | |
238 | #ifdef _DEBUG |
239 | bool EventPipeBuffer::EnsureConsistency() |
240 | { |
241 | CONTRACTL |
242 | { |
243 | NOTHROW; |
244 | GC_NOTRIGGER; |
245 | MODE_ANY; |
246 | } |
247 | CONTRACTL_END; |
248 | |
249 | // Check to see if the buffer is empty. |
250 | if(GetNextAlignedAddress(m_pBuffer) == m_pCurrent) |
251 | { |
252 | // Make sure that the buffer size is greater than zero. |
253 | _ASSERTE(m_pBuffer != m_pLimit); |
254 | } |
255 | |
256 | // Validate the contents of the filled portion of the buffer. |
257 | BYTE *ptr = GetNextAlignedAddress(m_pBuffer); |
258 | while(ptr < m_pCurrent) |
259 | { |
260 | // Validate the event. |
261 | EventPipeEventInstance *pInstance = (EventPipeEventInstance*)ptr; |
262 | _ASSERTE(pInstance->EnsureConsistency()); |
263 | |
264 | // Validate that payload and length match. |
265 | _ASSERTE((pInstance->GetData() != NULL && pInstance->GetDataLength() > 0) || (pInstance->GetData() == NULL && pInstance->GetDataLength() == 0)); |
266 | |
267 | // Skip the event. |
268 | ptr = GetNextAlignedAddress(ptr + sizeof(*pInstance) + pInstance->GetDataLength()); |
269 | } |
270 | |
271 | // When we're done walking the filled portion of the buffer, |
272 | // ptr should be the same as m_pCurrent. |
273 | _ASSERTE(ptr == m_pCurrent); |
274 | |
275 | // Walk the rest of the buffer, making sure it is properly zeroed. |
276 | while(ptr < m_pLimit) |
277 | { |
278 | _ASSERTE(*ptr++ == 0); |
279 | } |
280 | |
281 | return true; |
282 | } |
283 | #endif // _DEBUG |
284 | |
285 | #endif // FEATURE_PERFTRACING |
286 | |