Fix compile with disabled FEATURE_READYTORUN option (#11875)
[platform/upstream/coreclr.git] / src / vm / eventpipeconfiguration.cpp
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 #include "common.h"
6 #include "eventpipe.h"
7 #include "eventpipeconfiguration.h"
8 #include "eventpipeeventinstance.h"
9 #include "eventpipeprovider.h"
10
11 #ifdef FEATURE_PERFTRACING
12
13 // {5291C09C-2660-4D6A-83A3-C383FD020DEC}
14 const GUID EventPipeConfiguration::s_configurationProviderID =
15     { 0x5291c09c, 0x2660, 0x4d6a, { 0x83, 0xa3, 0xc3, 0x83, 0xfd, 0x2, 0xd, 0xec } };
16
17 EventPipeConfiguration::EventPipeConfiguration()
18 {
19     STANDARD_VM_CONTRACT;
20
21     m_enabled = false;
22     m_rundownEnabled = false;
23     m_circularBufferSizeInBytes = 1024 * 1024 * 1000; // Default to 1000MB.
24     m_pEnabledProviderList = NULL;
25     m_pProviderList = new SList<SListElem<EventPipeProvider*>>();
26 }
27
28 EventPipeConfiguration::~EventPipeConfiguration()
29 {
30     CONTRACTL
31     {
32         THROWS;
33         GC_TRIGGERS;
34         MODE_ANY;
35     }
36     CONTRACTL_END;
37
38     if(m_pEnabledProviderList != NULL)
39     {
40         delete(m_pEnabledProviderList);
41         m_pEnabledProviderList = NULL;
42     }
43
44     if(m_pProviderList != NULL)
45     {
46         delete(m_pProviderList);
47         m_pProviderList = NULL;
48     }
49 }
50
51 void EventPipeConfiguration::Initialize()
52 {
53     CONTRACTL
54     {
55         THROWS;
56         GC_NOTRIGGER;
57         MODE_ANY;
58     }
59     CONTRACTL_END;
60
61     // Create the configuration provider.
62     m_pConfigProvider = EventPipe::CreateProvider(s_configurationProviderID);
63
64     // Create the metadata event.
65     m_pMetadataEvent = m_pConfigProvider->AddEvent(
66         0,      /* eventID */
67         0,      /* keywords */
68         0,      /* eventVersion */
69         EventPipeEventLevel::LogAlways,
70         false); /* needStack */
71 }
72
73 bool EventPipeConfiguration::RegisterProvider(EventPipeProvider &provider)
74 {
75     CONTRACTL
76     {
77         THROWS;
78         GC_NOTRIGGER;
79         MODE_ANY;
80     }
81     CONTRACTL_END;
82
83     // Take the lock before manipulating the provider list.
84     CrstHolder _crst(EventPipe::GetLock());
85
86     // See if we've already registered this provider.
87     EventPipeProvider *pExistingProvider = GetProviderNoLock(provider.GetProviderID());
88     if(pExistingProvider != NULL)
89     {
90         return false;
91     }
92
93     // The provider has not been registered, so register it.
94     m_pProviderList->InsertTail(new SListElem<EventPipeProvider*>(&provider));
95
96     // Set the provider configuration and enable it if we know anything about the provider before it is registered.
97     if(m_pEnabledProviderList != NULL)
98     {
99         EventPipeEnabledProvider *pEnabledProvider = m_pEnabledProviderList->GetEnabledProvider(&provider);
100         if(pEnabledProvider != NULL)
101         {
102             provider.SetConfiguration(
103                 true /* providerEnabled */,
104                 pEnabledProvider->GetKeywords(),
105                 pEnabledProvider->GetLevel());
106         }
107     }
108
109     return true;
110 }
111
112 bool EventPipeConfiguration::UnregisterProvider(EventPipeProvider &provider)
113 {
114     CONTRACTL
115     {
116         THROWS;
117         GC_NOTRIGGER;
118         MODE_ANY;
119     }
120     CONTRACTL_END;
121
122     // Take the lock before manipulating the provider list.
123     CrstHolder _crst(EventPipe::GetLock());
124
125     // Find the provider.
126     SListElem<EventPipeProvider*> *pElem = m_pProviderList->GetHead();
127     while(pElem != NULL)
128     {
129         if(pElem->GetValue() == &provider)
130         {
131             break;
132         }
133
134         pElem = m_pProviderList->GetNext(pElem);
135     }
136
137     // If we found the provider, remove it.
138     if(pElem != NULL)
139     {
140         if(m_pProviderList->FindAndRemove(pElem) != NULL)
141         {
142             return true;
143         }
144     }
145
146     return false;
147 }
148
149 EventPipeProvider* EventPipeConfiguration::GetProvider(const GUID &providerID)
150 {
151     CONTRACTL
152     {
153         THROWS;
154         GC_NOTRIGGER;
155         MODE_ANY;
156     }
157     CONTRACTL_END;
158
159     // Take the lock before touching the provider list to ensure no one tries to
160     // modify the list.
161     CrstHolder _crst(EventPipe::GetLock());
162
163     return GetProviderNoLock(providerID);
164 }
165
166 EventPipeProvider* EventPipeConfiguration::GetProviderNoLock(const GUID &providerID)
167 {
168     CONTRACTL
169     {
170         THROWS;
171         GC_NOTRIGGER;
172         MODE_ANY;
173         PRECONDITION(EventPipe::GetLock()->OwnedByCurrentThread());
174     }
175     CONTRACTL_END;
176
177     SListElem<EventPipeProvider*> *pElem = m_pProviderList->GetHead();
178     while(pElem != NULL)
179     {
180         EventPipeProvider *pProvider = pElem->GetValue();
181         if(pProvider->GetProviderID() == providerID)
182         {
183             return pProvider;
184         }
185
186         pElem = m_pProviderList->GetNext(pElem);
187     }
188
189     return NULL;
190 }
191
192 size_t EventPipeConfiguration::GetCircularBufferSize() const
193 {
194     LIMITED_METHOD_CONTRACT;
195
196     return m_circularBufferSizeInBytes;
197 }
198
199 void EventPipeConfiguration::SetCircularBufferSize(size_t circularBufferSize)
200 {
201     LIMITED_METHOD_CONTRACT;
202     
203     if(!m_enabled)
204     {
205         m_circularBufferSizeInBytes = circularBufferSize;
206     }
207 }
208
209 void EventPipeConfiguration::Enable(
210     unsigned int circularBufferSizeInMB,
211     EventPipeProviderConfiguration *pProviders,
212     int numProviders)
213 {
214     CONTRACTL
215     {
216         THROWS;
217         GC_NOTRIGGER;
218         MODE_ANY;
219         // Lock must be held by EventPipe::Enable.
220         PRECONDITION(EventPipe::GetLock()->OwnedByCurrentThread());
221     }
222     CONTRACTL_END;
223
224     m_circularBufferSizeInBytes = circularBufferSizeInMB * 1024 * 1024;
225     m_pEnabledProviderList = new EventPipeEnabledProviderList(pProviders, static_cast<unsigned int>(numProviders));
226     m_enabled = true;
227
228     SListElem<EventPipeProvider*> *pElem = m_pProviderList->GetHead();
229     while(pElem != NULL)
230     {
231         EventPipeProvider *pProvider = pElem->GetValue();
232
233         // Enable the provider if it has been configured.
234         EventPipeEnabledProvider *pEnabledProvider = m_pEnabledProviderList->GetEnabledProvider(pProvider);
235         if(pEnabledProvider != NULL)
236         {
237             pProvider->SetConfiguration(
238                 true /* providerEnabled */,
239                 pEnabledProvider->GetKeywords(),
240                 pEnabledProvider->GetLevel());
241         }
242
243         pElem = m_pProviderList->GetNext(pElem);
244     }
245
246 }
247
248 void EventPipeConfiguration::Disable()
249 {
250     CONTRACTL
251     {
252         THROWS;
253         GC_NOTRIGGER;
254         MODE_ANY;
255         // Lock must be held by EventPipe::Disable.
256         PRECONDITION(EventPipe::GetLock()->OwnedByCurrentThread());
257     }
258     CONTRACTL_END;
259
260     SListElem<EventPipeProvider*> *pElem = m_pProviderList->GetHead();
261     while(pElem != NULL)
262     {
263         EventPipeProvider *pProvider = pElem->GetValue();
264         pProvider->SetConfiguration(false /* providerEnabled */, 0 /* keywords */, EventPipeEventLevel::Critical /* level */);
265
266         pElem = m_pProviderList->GetNext(pElem);
267     }
268
269     m_enabled = false;
270     m_rundownEnabled = false;
271
272     // Free the enabled providers list.
273     if(m_pEnabledProviderList != NULL)
274     {
275         delete(m_pEnabledProviderList);
276         m_pEnabledProviderList = NULL;
277     }
278 }
279
280 bool EventPipeConfiguration::Enabled() const
281 {
282     LIMITED_METHOD_CONTRACT;
283     return m_enabled;
284 }
285
286 bool EventPipeConfiguration::RundownEnabled() const
287 {
288     LIMITED_METHOD_CONTRACT;
289     return m_rundownEnabled;
290 }
291
292 void EventPipeConfiguration::EnableRundown()
293 {
294     CONTRACTL
295     {
296         THROWS;
297         GC_NOTRIGGER;
298         MODE_ANY;
299         // Lock must be held by EventPipe::Disable.
300         PRECONDITION(EventPipe::GetLock()->OwnedByCurrentThread());
301     }
302     CONTRACTL_END;
303
304     // Build the rundown configuration.
305     _ASSERTE(m_pEnabledProviderList == NULL);
306     const unsigned int numRundownProviders = 2;
307     EventPipeProviderConfiguration rundownProviders[numRundownProviders];
308     rundownProviders[0] = EventPipeProviderConfiguration(W("e13c0d23-ccbc-4e12-931b-d9cc2eee27e4"), 0x80020138, static_cast<unsigned int>(EventPipeEventLevel::Verbose)); // Public provider.
309     rundownProviders[1] = EventPipeProviderConfiguration(W("a669021c-c450-4609-a035-5af59af4df18"), 0x80020138, static_cast<unsigned int>(EventPipeEventLevel::Verbose)); // Rundown provider.
310
311     // Enable rundown.
312     m_rundownEnabled = true;
313
314     // Enable tracing.  The circular buffer size doesn't matter because we're going to write all events synchronously during rundown.
315     Enable(1 /* circularBufferSizeInMB */, rundownProviders, numRundownProviders);
316 }
317
318 EventPipeEventInstance* EventPipeConfiguration::BuildEventMetadataEvent(EventPipeEventInstance &sourceInstance)
319 {
320     CONTRACTL
321     {
322         THROWS;
323         GC_NOTRIGGER;
324         MODE_ANY;
325     }
326     CONTRACTL_END;
327
328     // The payload of the event should contain:
329     // - GUID ProviderID.
330     // - unsigned int EventID.
331     // - unsigned int EventVersion.
332     // - Optional event description payload.
333
334     // Calculate the size of the event.
335     EventPipeEvent &sourceEvent = *sourceInstance.GetEvent();
336     const GUID &providerID = sourceEvent.GetProvider()->GetProviderID();
337     unsigned int eventID = sourceEvent.GetEventID();
338     unsigned int eventVersion = sourceEvent.GetEventVersion();
339     BYTE *pPayloadData = sourceEvent.GetMetadata();
340     unsigned int payloadLength = sourceEvent.GetMetadataLength();
341     unsigned int instancePayloadSize = sizeof(providerID) + sizeof(eventID) + sizeof(eventVersion) + sizeof(payloadLength) + payloadLength;
342
343     // Allocate the payload.
344     BYTE *pInstancePayload = new BYTE[instancePayloadSize];
345
346     // Fill the buffer with the payload.
347     BYTE *currentPtr = pInstancePayload;
348
349     // Write the provider ID.
350     memcpy(currentPtr, (BYTE*)&providerID, sizeof(providerID));
351     currentPtr += sizeof(providerID);
352
353     // Write the event ID.
354     memcpy(currentPtr, &eventID, sizeof(eventID));
355     currentPtr += sizeof(eventID);
356
357     // Write the event version.
358     memcpy(currentPtr, &eventVersion, sizeof(eventVersion));
359     currentPtr += sizeof(eventVersion);
360
361     // Write the size of the metadata.
362     memcpy(currentPtr, &payloadLength, sizeof(payloadLength));
363     currentPtr += sizeof(payloadLength);
364
365     // Write the incoming payload data.
366     memcpy(currentPtr, pPayloadData, payloadLength);
367
368     // Construct the event instance.
369     EventPipeEventInstance *pInstance = new EventPipeEventInstance(
370         *m_pMetadataEvent,
371         GetCurrentThreadId(),
372         pInstancePayload,
373         instancePayloadSize,
374         NULL /* pActivityId */,
375         NULL /* pRelatedActivityId */);
376
377     // Set the timestamp to match the source event, because the metadata event
378     // will be emitted right before the source event.
379     pInstance->SetTimeStamp(sourceInstance.GetTimeStamp());
380
381     return pInstance;
382 }
383
384 void EventPipeConfiguration::DeleteDeferredProviders()
385 {
386     CONTRACTL
387     {
388         THROWS;
389         GC_TRIGGERS;
390         MODE_ANY;
391         // Lock must be held by EventPipe::Disable.
392         PRECONDITION(EventPipe::GetLock()->OwnedByCurrentThread());
393
394     }
395     CONTRACTL_END;
396
397     SListElem<EventPipeProvider*> *pElem = m_pProviderList->GetHead();
398     while(pElem != NULL)
399     {
400         EventPipeProvider *pProvider = pElem->GetValue();
401         if(pProvider->GetDeleteDeferred())
402         {
403             // The act of deleting the provider unregisters it and removes it from the list.
404             delete(pProvider);
405         }
406
407         pElem = m_pProviderList->GetNext(pElem);
408     }
409 }
410
411 EventPipeEnabledProviderList::EventPipeEnabledProviderList(
412     EventPipeProviderConfiguration *pConfigs,
413     unsigned int numConfigs)
414 {
415     CONTRACTL
416     {
417         THROWS;
418         GC_NOTRIGGER;
419         MODE_ANY;
420     }
421     CONTRACTL_END;
422
423     m_pProviders = NULL;
424     m_pCatchAllProvider = NULL;
425     m_numProviders = 0;
426
427     // Test COMPLUS variable to enable tracing at start-up.
428     // If tracing is enabled at start-up create the catch-all provider and always return it.
429     if((CLRConfig::GetConfigValue(CLRConfig::INTERNAL_PerformanceTracing) & 1) == 1)
430     {
431         m_pCatchAllProvider = new EventPipeEnabledProvider();
432         m_pCatchAllProvider->Set(NULL, 0xFFFFFFFFFFFFFFFF, EventPipeEventLevel::Verbose);
433         return;
434     }
435
436     m_pCatchAllProvider = NULL;
437     m_numProviders = numConfigs;
438     if(m_numProviders == 0)
439     {
440         return;
441     }
442
443     m_pProviders = new EventPipeEnabledProvider[m_numProviders];
444     for(int i=0; i<m_numProviders; i++)
445     {
446         m_pProviders[i].Set(
447             pConfigs[i].GetProviderName(),
448             pConfigs[i].GetKeywords(),
449             (EventPipeEventLevel)pConfigs[i].GetLevel());
450     }
451 }
452
453 EventPipeEnabledProviderList::~EventPipeEnabledProviderList()
454 {
455     CONTRACTL
456     {
457         THROWS;
458         GC_NOTRIGGER;
459         MODE_ANY;
460     }
461     CONTRACTL_END;
462
463     if(m_pProviders != NULL)
464     {
465         delete[] m_pProviders;
466         m_pProviders = NULL;
467     }
468     if(m_pCatchAllProvider != NULL)
469     {
470         delete(m_pCatchAllProvider);
471         m_pCatchAllProvider = NULL;
472     }
473 }
474
475 EventPipeEnabledProvider* EventPipeEnabledProviderList::GetEnabledProvider(
476     EventPipeProvider *pProvider)
477 {
478     CONTRACTL
479     {
480         THROWS;
481         GC_NOTRIGGER;
482         MODE_ANY;
483     }
484     CONTRACTL_END;
485
486     // If tracing was enabled on start-up, all events should be on (this is a diagnostic config).
487     if(m_pCatchAllProvider != NULL)
488     {
489         return m_pCatchAllProvider;
490     }
491
492     if(m_pProviders == NULL)
493     {
494         return NULL;
495     }
496
497     // TEMPORARY: Convert the provider GUID to a string.
498     const unsigned int guidSize = 39;
499     WCHAR wszProviderID[guidSize];
500     if(!StringFromGUID2(pProvider->GetProviderID(), wszProviderID, guidSize))
501     {
502         wszProviderID[0] = '\0';
503     }
504
505     // Strip off the {}.
506     SString providerNameStr(&wszProviderID[1], guidSize-3);
507     LPCWSTR providerName = providerNameStr.GetUnicode();
508
509     EventPipeEnabledProvider *pEnabledProvider = NULL;
510     for(int i=0; i<m_numProviders; i++)
511     {
512         EventPipeEnabledProvider *pCandidate = &m_pProviders[i];
513         if(pCandidate != NULL)
514         {
515             if(wcscmp(providerName, pCandidate->GetProviderName()) == 0)
516             {
517                 pEnabledProvider = pCandidate;
518                 break;
519             }
520         }
521     }
522
523     return pEnabledProvider;
524 }
525
526 EventPipeEnabledProvider::EventPipeEnabledProvider()
527 {
528     LIMITED_METHOD_CONTRACT;
529     m_pProviderName = NULL;
530     m_keywords = 0;
531 }
532
533 EventPipeEnabledProvider::~EventPipeEnabledProvider()
534 {
535     CONTRACTL
536     {
537         THROWS;
538         GC_NOTRIGGER;
539         MODE_ANY;
540     }
541     CONTRACTL_END;
542
543     if(m_pProviderName != NULL)
544     {
545         delete[] m_pProviderName;
546         m_pProviderName = NULL;
547     }
548 }
549
550 void EventPipeEnabledProvider::Set(LPCWSTR providerName, UINT64 keywords, EventPipeEventLevel loggingLevel)
551 {
552     CONTRACTL
553     {
554         THROWS;
555         GC_NOTRIGGER;
556         MODE_ANY;
557     }
558     CONTRACTL_END;
559
560     if(m_pProviderName != NULL)
561     {
562         delete(m_pProviderName);
563         m_pProviderName = NULL;
564     }
565
566     if(providerName != NULL)
567     {
568         unsigned int bufSize = wcslen(providerName) + 1;
569         m_pProviderName = new WCHAR[bufSize];
570         wcscpy_s(m_pProviderName, bufSize, providerName);
571     }
572     m_keywords = keywords;
573     m_loggingLevel = loggingLevel;
574 }
575
576 LPCWSTR EventPipeEnabledProvider::GetProviderName() const
577 {
578     LIMITED_METHOD_CONTRACT;
579     return m_pProviderName;
580 }
581
582 UINT64 EventPipeEnabledProvider::GetKeywords() const
583 {
584     LIMITED_METHOD_CONTRACT;
585     return m_keywords;
586 }
587
588 EventPipeEventLevel EventPipeEnabledProvider::GetLevel() const
589 {
590     LIMITED_METHOD_CONTRACT;
591     return m_loggingLevel;
592 }
593
594 #endif // FEATURE_PERFTRACING