[Tizen] Unify dnetmemoryenumlib terms to match the codebase (#291)
[platform/upstream/coreclr.git] / src / vm / eventpipesession.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 "eventpipebuffermanager.h"
8 #include "eventpipefile.h"
9 #include "eventpipeprovider.h"
10 #include "eventpipesession.h"
11 #include "eventpipesessionprovider.h"
12
13 #ifdef FEATURE_PERFTRACING
14
15 EventPipeSession::EventPipeSession(
16     uint32_t index,
17     LPCWSTR strOutputPath,
18     IpcStream *const pStream,
19     EventPipeSessionType sessionType,
20     EventPipeSerializationFormat format,
21     bool rundownSwitch,
22     uint32_t circularBufferSizeInMB,
23     const EventPipeProviderConfiguration *pProviders,
24     uint32_t numProviders,
25     bool rundownEnabled) : m_index(index),
26                            m_pProviderList(new EventPipeSessionProviderList(pProviders, numProviders)),
27                            m_rundownEnabled(rundownEnabled),
28                            m_SessionType(sessionType),
29                            m_format(format),
30                            m_rundownRequested(rundownSwitch)
31 {
32     CONTRACTL
33     {
34         THROWS;
35         GC_TRIGGERS;
36         MODE_PREEMPTIVE;
37         PRECONDITION(index < EventPipe::MaxNumberOfSessions);
38         PRECONDITION(format < EventPipeSerializationFormat::Count);
39         PRECONDITION(circularBufferSizeInMB > 0);
40         PRECONDITION(numProviders > 0 && pProviders != nullptr);
41         PRECONDITION(EventPipe::IsLockOwnedByCurrentThread());
42     }
43     CONTRACTL_END;
44
45     size_t sequencePointAllocationBudget = 0;
46     // Hard coded 10MB for now, we'll probably want to make
47     // this configurable later.
48     if (GetSessionType() != EventPipeSessionType::Listener &&
49         GetSerializationFormat() >= EventPipeSerializationFormat::NetTraceV4)
50     {
51         sequencePointAllocationBudget = 10 * 1024 * 1024;
52     }
53
54     m_pBufferManager = new EventPipeBufferManager(this, static_cast<size_t>(circularBufferSizeInMB) << 20, sequencePointAllocationBudget);
55
56     // Create the event pipe file.
57     // A NULL output path means that we should not write the results to a file.
58     // This is used in the EventListener case.
59     m_pFile = nullptr;
60     switch (sessionType)
61     {
62     case EventPipeSessionType::File:
63         if (strOutputPath != nullptr)
64             m_pFile = new EventPipeFile(new FileStreamWriter(SString(strOutputPath)), format);
65         break;
66
67     case EventPipeSessionType::IpcStream:
68         m_pFile = new EventPipeFile(new IpcStreamWriter(reinterpret_cast<uint64_t>(this), pStream), format);
69         break;
70
71     default:
72         m_pFile = nullptr;
73         break;
74     }
75
76     GetSystemTimeAsFileTime(&m_sessionStartTime);
77     QueryPerformanceCounter(&m_sessionStartTimeStamp);
78 }
79
80 void EventPipeSession::Close()
81 {
82     CONTRACTL
83     {
84         NOTHROW;
85         GC_TRIGGERS;
86         MODE_PREEMPTIVE;
87     }
88     CONTRACTL_END;
89
90     // FIXME: **ONLY** closes the stream. This explicitly **LEAKS** the
91     // provider list and buffer manager.
92     delete m_pFile;
93 }
94
95 EventPipeSession::~EventPipeSession()
96 {
97     CONTRACTL
98     {
99         NOTHROW;
100         GC_TRIGGERS;
101         MODE_PREEMPTIVE;
102         PRECONDITION(!m_ipcStreamingEnabled);
103     }
104     CONTRACTL_END;
105
106     delete m_pProviderList;
107     delete m_pBufferManager;
108     delete m_pFile;
109 }
110
111 bool EventPipeSession::HasIpcStreamingStarted()
112 {
113     CONTRACTL
114     {
115         NOTHROW;
116         GC_TRIGGERS;
117         MODE_PREEMPTIVE;
118     }
119     CONTRACTL_END;
120
121     return m_pIpcStreamingThread != nullptr ? m_pIpcStreamingThread->HasStarted() : false;
122 }
123
124 void EventPipeSession::SetThreadShutdownEvent()
125 {
126     CONTRACTL
127     {
128         NOTHROW;
129         GC_TRIGGERS;
130         MODE_PREEMPTIVE;
131     }
132     CONTRACTL_END;
133
134     // Signal Disable() that the thread has been destroyed.
135     m_threadShutdownEvent.Set();
136 }
137
138 static void PlatformSleep()
139 {
140     CONTRACTL
141     {
142         NOTHROW;
143         GC_TRIGGERS;
144         MODE_PREEMPTIVE;
145     }
146     CONTRACTL_END;
147
148     // Wait until it's time to sample again.
149     const uint32_t PeriodInNanoSeconds = 100000000; // 100 msec.
150
151 #ifdef FEATURE_PAL
152     PAL_nanosleep(PeriodInNanoSeconds);
153 #else  //FEATURE_PAL
154     const uint32_t NUM_NANOSECONDS_IN_1_MS = 1000000;
155     ClrSleepEx(PeriodInNanoSeconds / NUM_NANOSECONDS_IN_1_MS, FALSE);
156 #endif //FEATURE_PAL
157 }
158
159 DWORD WINAPI EventPipeSession::ThreadProc(void *args)
160 {
161     CONTRACTL
162     {
163         NOTHROW;
164         GC_TRIGGERS;
165         MODE_PREEMPTIVE;
166         PRECONDITION(args != nullptr);
167     }
168     CONTRACTL_END;
169
170     if (args == nullptr)
171         return 1;
172
173     EventPipeSession *const pEventPipeSession = reinterpret_cast<EventPipeSession *>(args);
174     if (pEventPipeSession->GetSessionType() != EventPipeSessionType::IpcStream)
175         return 1;
176
177     if (!pEventPipeSession->HasIpcStreamingStarted())
178         return 1;
179
180     Thread *const pThisThread = pEventPipeSession->GetIpcStreamingThread();
181     bool fSuccess = true;
182     CLREvent *waitEvent = pEventPipeSession->GetWaitEvent();
183
184     {
185         GCX_PREEMP();
186         EX_TRY
187         {
188             while (pEventPipeSession->IsIpcStreamingEnabled())
189             {
190                 bool eventsWritten = false;
191                 if (!pEventPipeSession->WriteAllBuffersToFile(&eventsWritten))
192                 {
193                     fSuccess = false;
194                     break;
195                 }
196
197                 if (!eventsWritten)
198                 {
199                     // No events were available, sleep until more are available
200                     waitEvent->Wait(INFINITE, FALSE);
201                 }
202                 
203                 // Wait until it's time to sample again.
204                 PlatformSleep();
205             }
206
207             pEventPipeSession->SetThreadShutdownEvent();
208         }
209         EX_CATCH
210         {
211             pEventPipeSession->SetThreadShutdownEvent();
212             // TODO: STRESS_LOG ?
213             // TODO: Notify `EventPipe` itself to remove this session from the list.
214         }
215         EX_END_CATCH(SwallowAllExceptions);
216     }
217
218     EX_TRY
219     {
220         if (!fSuccess)
221             EventPipe::Disable(reinterpret_cast<EventPipeSessionID>(pEventPipeSession));
222     }
223     EX_CATCH
224     {
225         // TODO: STRESS_LOG ?
226     }
227     EX_END_CATCH(SwallowAllExceptions);
228
229     if (pThisThread != nullptr)
230         ::DestroyThread(pThisThread);
231
232     return 0;
233 }
234
235 void EventPipeSession::CreateIpcStreamingThread()
236 {
237     CONTRACTL
238     {
239         THROWS;
240         GC_TRIGGERS;
241         MODE_PREEMPTIVE;
242         PRECONDITION(EventPipe::IsLockOwnedByCurrentThread());
243     }
244     CONTRACTL_END;
245
246     m_ipcStreamingEnabled = true;
247     m_pIpcStreamingThread = SetupUnstartedThread();
248     if (m_pIpcStreamingThread->CreateNewThread(0, ThreadProc, this))
249     {
250         m_pIpcStreamingThread->SetBackground(TRUE);
251         m_pIpcStreamingThread->StartThread();
252     }
253     else
254     {
255         _ASSERT(!"Unable to create IPC stream flushing thread.");
256     }
257     m_threadShutdownEvent.CreateManualEvent(FALSE);
258 }
259
260 bool EventPipeSession::IsValid() const
261 {
262     CONTRACTL
263     {
264         THROWS;
265         GC_TRIGGERS;
266         MODE_PREEMPTIVE;
267         PRECONDITION(EventPipe::IsLockOwnedByCurrentThread());
268     }
269     CONTRACTL_END;
270
271     return !m_pProviderList->IsEmpty();
272 }
273
274 void EventPipeSession::AddSessionProvider(EventPipeSessionProvider *pProvider)
275 {
276     CONTRACTL
277     {
278         THROWS;
279         GC_TRIGGERS;
280         MODE_PREEMPTIVE;
281     }
282     CONTRACTL_END;
283
284     m_pProviderList->AddSessionProvider(pProvider);
285 }
286
287 EventPipeSessionProvider *EventPipeSession::GetSessionProvider(const EventPipeProvider *pProvider) const
288 {
289     CONTRACTL
290     {
291         THROWS;
292         GC_TRIGGERS;
293         MODE_PREEMPTIVE;
294     }
295     CONTRACTL_END;
296
297     return m_pProviderList->GetSessionProvider(pProvider);
298 }
299
300 bool EventPipeSession::WriteAllBuffersToFile(bool *pEventsWritten)
301 {
302     CONTRACTL
303     {
304         THROWS;
305         GC_TRIGGERS;
306         MODE_PREEMPTIVE;
307     }
308     CONTRACTL_END;
309
310     if (m_pFile == nullptr)
311         return true;
312
313     // Get the current time stamp.
314     // EventPipeBufferManager::WriteAllBuffersToFile will use this to ensure that no events after
315     // the current timestamp are written into the file.
316     LARGE_INTEGER stopTimeStamp;
317     QueryPerformanceCounter(&stopTimeStamp);
318     m_pBufferManager->WriteAllBuffersToFile(m_pFile, stopTimeStamp, pEventsWritten);
319     return !m_pFile->HasErrors();
320 }
321
322 bool EventPipeSession::WriteEventBuffered(
323     Thread *pThread,
324     EventPipeEvent &event,
325     EventPipeEventPayload &payload,
326     LPCGUID pActivityId,
327     LPCGUID pRelatedActivityId,
328     Thread *pEventThread,
329     StackContents *pStack)
330 {
331     CONTRACTL
332     {
333         NOTHROW;
334         GC_NOTRIGGER;
335         MODE_ANY;
336     }
337     CONTRACTL_END;
338
339     // Filter events specific to "this" session based on precomputed flag on provider/events.
340     return event.IsEnabled(GetMask()) ?
341         m_pBufferManager->WriteEvent(pThread, *this, event, payload, pActivityId, pRelatedActivityId, pEventThread, pStack) :
342         false;
343 }
344
345 void EventPipeSession::WriteSequencePointUnbuffered()
346 {
347     CONTRACTL
348     {
349         THROWS;
350         GC_NOTRIGGER;
351         MODE_ANY;
352     }
353     CONTRACTL_END;
354
355     if (m_pFile == nullptr)
356         return;
357     EventPipeSequencePoint sequencePoint;
358     m_pBufferManager->InitSequencePointThreadList(&sequencePoint);
359     m_pFile->WriteSequencePoint(&sequencePoint);
360 }
361
362 EventPipeEventInstance *EventPipeSession::GetNextEvent()
363 {
364     CONTRACTL
365     {
366         THROWS;
367         GC_TRIGGERS;
368         MODE_PREEMPTIVE;
369         PRECONDITION(!EventPipe::IsLockOwnedByCurrentThread());
370     }
371     CONTRACTL_END;
372
373     return m_pBufferManager->GetNextEvent();
374 }
375
376 CLREvent *EventPipeSession::GetWaitEvent()
377 {
378     LIMITED_METHOD_CONTRACT;
379
380     return m_pBufferManager->GetWaitEvent();
381 }
382
383 void EventPipeSession::Enable()
384 {
385     CONTRACTL
386     {
387         THROWS;
388         GC_TRIGGERS;
389         MODE_PREEMPTIVE;
390         // Lock must be held by EventPipe::Enable.
391         PRECONDITION(EventPipe::IsLockOwnedByCurrentThread());
392     }
393     CONTRACTL_END;
394
395     if (m_SessionType == EventPipeSessionType::IpcStream)
396         CreateIpcStreamingThread();
397 }
398
399 void EventPipeSession::EnableRundown()
400 {
401     CONTRACTL
402     {
403         THROWS;
404         GC_TRIGGERS;
405         MODE_PREEMPTIVE;
406         // Lock must be held by EventPipe::Enable.
407         PRECONDITION(EventPipe::IsLockOwnedByCurrentThread());
408     }
409     CONTRACTL_END;
410
411     //! The keywords below seems to correspond to:
412     //!  LoaderKeyword                      (0x00000008)
413     //!  JitKeyword                         (0x00000010)
414     //!  NgenKeyword                        (0x00000020)
415     //!  unused_keyword                     (0x00000100)
416     //!  JittedMethodILToNativeMapKeyword   (0x00020000)
417     //!  ThreadTransferKeyword              (0x80000000)
418     const UINT64 Keywords = 0x80020138;
419     const UINT32 VerboseLoggingLevel = static_cast<UINT32>(EventPipeEventLevel::Verbose);
420     const EventPipeProviderConfiguration RundownProviders[] = {
421         {W("Microsoft-Windows-DotNETRuntime"), Keywords, VerboseLoggingLevel, NULL},       // Public provider.
422         {W("Microsoft-Windows-DotNETRuntimeRundown"), Keywords, VerboseLoggingLevel, NULL} // Rundown provider.
423     };
424     const uint32_t RundownProvidersSize = sizeof(RundownProviders) / sizeof(EventPipeProviderConfiguration);
425
426     // update the provider context here since the callback doesn't happen till we actually try to do rundown.
427     MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_DOTNET_Context.EventPipeProvider.Level = VerboseLoggingLevel;
428     MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_DOTNET_Context.EventPipeProvider.EnabledKeywordsBitmask = Keywords;
429     MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_DOTNET_Context.EventPipeProvider.IsEnabled = true;
430
431     // Update provider list with rundown configuration.
432     for (uint32_t i = 0; i < RundownProvidersSize; ++i)
433     {
434         const EventPipeProviderConfiguration &Config = RundownProviders[i];
435         m_pProviderList->AddSessionProvider(new EventPipeSessionProvider(
436             Config.GetProviderName(),
437             Config.GetKeywords(),
438             (EventPipeEventLevel)Config.GetLevel(),
439             Config.GetFilterData()));
440     }
441
442     m_rundownEnabled = true;
443 }
444
445 void EventPipeSession::DisableIpcStreamingThread()
446 {
447     CONTRACTL
448     {
449         THROWS;
450         GC_TRIGGERS;
451         MODE_PREEMPTIVE;
452         PRECONDITION(m_SessionType == EventPipeSessionType::IpcStream);
453         PRECONDITION(m_ipcStreamingEnabled);
454     }
455     CONTRACTL_END;
456
457     _ASSERTE(!g_fProcessDetach);
458
459     // The IPC streaming thread will watch this value and exit
460     // when profiling is disabled.
461     m_ipcStreamingEnabled = false;
462
463     // Thread could be waiting on the event that there is new data to read.
464     m_pBufferManager->GetWaitEvent()->Set();
465
466     // Wait for the sampling thread to clean itself up.
467     m_threadShutdownEvent.Wait(INFINITE, FALSE /* bAlertable */);
468     m_threadShutdownEvent.CloseEvent();
469 }
470
471 void EventPipeSession::Disable()
472 {
473     CONTRACTL
474     {
475         THROWS;
476         GC_TRIGGERS;
477         MODE_PREEMPTIVE;
478     }
479     CONTRACTL_END;
480
481     if ((m_SessionType == EventPipeSessionType::IpcStream) && m_ipcStreamingEnabled)
482         DisableIpcStreamingThread();
483
484     bool ignored;
485     WriteAllBuffersToFile(&ignored);
486     m_pProviderList->Clear();
487 }
488
489 void EventPipeSession::SuspendWriteEvent()
490 {
491     CONTRACTL
492     {
493         THROWS;
494         GC_TRIGGERS;
495         MODE_PREEMPTIVE;
496     }
497     CONTRACTL_END;
498
499     // Force all in-progress writes to either finish or cancel
500     // This is required to ensure we can safely flush and delete the buffers
501     m_pBufferManager->SuspendWriteEvent(GetIndex());
502 }
503
504 void EventPipeSession::ExecuteRundown()
505 {
506     CONTRACTL
507     {
508         THROWS;
509         GC_TRIGGERS;
510         MODE_PREEMPTIVE;
511         // Lock must be held by EventPipe::Disable.
512         PRECONDITION(EventPipe::IsLockOwnedByCurrentThread());
513     }
514     CONTRACTL_END;
515
516     if (m_pFile == nullptr)
517         return;
518
519     if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_EventPipeRundown) > 0)
520     {
521         // Ask the runtime to emit rundown events.
522         if (g_fEEStarted && !g_fEEShutDown)
523             ETW::EnumerationLog::EndRundown();
524     }
525 }
526
527 #endif // FEATURE_PERFTRACING