| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252 |
- //-------------------------------------------------------------------------------------------------------
- // Copyright (C) Microsoft. All rights reserved.
- // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
- //-------------------------------------------------------------------------------------------------------
- #pragma once
- #ifdef ENABLE_JS_ETW
- //
- // ETW (Event Tracing for Windows) is a high-performance, low overhead and highly scalable
- // tracing facility provided by the Windows Operating System. There are
- // four main types of components in ETW: event providers, controllers, consumers, and event trace sessions.
- // An event provider is a logical entity that writes events to ETW sessions. The event provider must register
- // a provider ID with ETW through the registration API. A provider first registers with ETW and writes events
- // from various points in the code by invoking the ETW logging API. When a provider is enabled dynamically by
- // the ETW controller application, calls to the logging API sends events to a specific trace session
- // designated by the controller. Javascript runtime is an event provider.
- //
- // When ETW's sample profile is enabled it logs the entry point of each function as part of
- // stackwalking on the platform. For javascript functions these entry points are not meaningful.
- // Therefore, we log events which map the entry point to the name of the function. There are two types of events
- // that we log for symbol decoding:
- // Rundown: Represents the state of the process and logged when tracing is enabled. Enables the 'attach' scenario.
- // Runtime: Represents the change of state of the process and logged as the state changes e.g. when a jitted function gets loaded.
- //
- // C-style callback
- extern "C" {
- void EtwCallback(
- ULONG controlCode,
- PVOID callbackContext);
- }
- #include "TestEtwEventSink.h"
- //
- // Represents type of method entry point.
- //
- enum MethodType : uint16
- {
- MethodType_Interpreted = 0x1,
- MethodType_Jit = 0x2,
- MethodType_LoopBody = 0x3,
- MethodType_HostMethod = 0x4,
- };
- #ifdef TEST_ETW_EVENTS
- #define WriteMethodEvent(EventName, ScriptContextID, MethodStartAddress, MethodSize, MethodID, MethodFlags, MethodAddressRangeID, SourceID, Line, Column, MethodName) \
- if(TestEtwEventSink::IsLoaded()) \
- { \
- TestEtwEventSink::Instance->WriteMethodEvent(EventName, ScriptContextID, MethodStartAddress, MethodSize, MethodID, MethodFlags, MethodAddressRangeID, SourceID, Line, Column, MethodName); \
- }
- #define WriteSourceEvent(EventName, SourceContext, ScriptContextID, SourceFlags, Url) \
- if(TestEtwEventSink::IsLoaded()) \
- { \
- TestEtwEventSink::Instance->WriteSourceEvent(EventName, SourceContext, ScriptContextID, SourceFlags, Url); \
- }
- #else
- #define WriteMethodEvent(Event, ...)
- #define WriteSourceEvent(Event, ...)
- #endif
- // Helper macro to log all the method level events
- #define LogSourceEvent(Function, SourceContext, ScriptContext, SourceFlags, Url) \
- JS_ETW(Function(SourceContext, \
- ScriptContext, \
- SourceFlags, \
- Url)); \
- \
- WriteSourceEvent(STRINGIZEW(Function), \
- SourceContext, \
- ScriptContext, \
- SourceFlags, \
- Url);
- #define LogMethodNativeEvent(Function, Body, entryPoint) \
- Assert(entryPoint->GetNativeAddress() != NULL); \
- Assert(entryPoint->GetCodeSize() > 0); \
- Assert(entryPoint->IsNativeCode()); \
- char16 functionNameArray[NameBufferLength]; \
- const char16 *functionName; \
- size_t requiredCharCapacity = 0; \
- bool deleteFunctionName = false; \
- const ExecutionMode jitMode = entryPoint->GetJitMode(); \
- if(jitMode == ExecutionMode::SimpleJit) \
- { \
- requiredCharCapacity = \
- GetSimpleJitFunctionName(Body, functionNameArray, _countof(functionNameArray)); \
- if(requiredCharCapacity == 0) \
- { \
- functionName = functionNameArray; \
- } \
- else \
- { \
- Assert(requiredCharCapacity > NameBufferLength); \
- char16 *const allocatedFunctionName = HeapNewNoThrowArray(char16, requiredCharCapacity);\
- if(allocatedFunctionName) \
- { \
- const size_t newRequiredCharCapacity = \
- GetSimpleJitFunctionName(Body, allocatedFunctionName, requiredCharCapacity); \
- Assert(newRequiredCharCapacity == 0); \
- functionName = allocatedFunctionName; \
- deleteFunctionName = true; \
- } \
- else \
- { \
- functionNameArray[0] = _u('\0'); \
- functionName = functionNameArray; \
- } \
- } \
- } \
- else \
- { \
- functionName = GetFunctionName(Body); \
- } \
- JS_ETW(Function( \
- Body->GetScriptContext(), \
- (void *)entryPoint->GetNativeAddress(), \
- entryPoint->GetCodeSize(), \
- GetFunctionId(Body), \
- 0 /* methodFlags - for future use*/, \
- MethodType_Jit, \
- GetSourceId(Body), \
- Body->GetLineNumber(), \
- Body->GetColumnNumber(), \
- functionName)); \
- WriteMethodEvent(STRINGIZEW(Function), \
- Body->GetScriptContext(), \
- (void *)entryPoint->GetNativeAddress(), \
- entryPoint->GetCodeSize(), \
- GetFunctionId(Body), \
- 0 /* methodFlags - for future use*/, \
- MethodType_Jit, \
- GetSourceId(Body), \
- Body->GetLineNumber(), \
- Body->GetColumnNumber(), \
- functionName); \
- if(deleteFunctionName) \
- { \
- HeapDeleteArray(requiredCharCapacity, functionName); \
- }
- #define LogMethodInterpretedThunkEvent(Function, Body) \
- Assert(Body->GetDynamicInterpreterEntryPoint() != NULL); \
- JS_ETW(Function(Body->GetScriptContext(), \
- Body->GetDynamicInterpreterEntryPoint(), \
- Body->GetDynamicInterpreterThunkSize(), \
- GetFunctionId(Body), \
- 0 /* methodFlags - for future use*/, \
- MethodType_Interpreted, \
- GetSourceId(Body), \
- Body->GetLineNumber(), \
- Body->GetColumnNumber(), \
- GetFunctionName(Body))); \
- \
- WriteMethodEvent(STRINGIZEW(Function), \
- Body->GetScriptContext(), \
- Body->GetDynamicInterpreterEntryPoint(), \
- Body->GetDynamicInterpreterThunkSize(), \
- GetFunctionId(Body), \
- 0 /* methodFlags - for future use*/, \
- MethodType_Interpreted, \
- GetSourceId(Body), \
- Body->GetLineNumber(), \
- Body->GetColumnNumber(), \
- GetFunctionName(Body))
- #define LogLoopBodyEvent(Function, Body, entryPoint, loopNumber) \
- Assert(entryPoint->GetNativeAddress() != NULL); \
- Assert(entryPoint->GetCodeSize() > 0); \
- WCHAR loopBodyNameArray[NameBufferLength]; \
- WCHAR* loopBodyName = loopBodyNameArray; \
- size_t bufferSize = Body->GetLoopBodyName(loopNumber, loopBodyName, NameBufferLength); \
- if(bufferSize > NameBufferLength) /* insufficient buffer space*/ \
- { \
- loopBodyName = HeapNewNoThrowArray(WCHAR, bufferSize); \
- if(loopBodyName) \
- { \
- Body->GetLoopBodyName(loopNumber, loopBodyName, NameBufferLength); \
- } \
- else \
- { \
- loopBodyNameArray[0] = _u('\0'); \
- loopBodyName = loopBodyNameArray; \
- } \
- } \
- JS_ETW(Function(Body->GetScriptContext(), \
- (void *)entryPoint->GetNativeAddress(), \
- entryPoint->GetCodeSize(), \
- GetFunctionId(Body), \
- 0 /* methodFlags - for future use*/, \
- MethodType_LoopBody + (uint16)loopNumber, \
- GetSourceId(Body), \
- /*line*/ 0, \
- /*column*/ 0, \
- loopBodyName)); \
- WriteMethodEvent(STRINGIZEW(Function), \
- Body->GetScriptContext(), \
- (void *)entryPoint->GetNativeAddress(), \
- entryPoint->GetCodeSize(), \
- GetFunctionId(Body), \
- 0 /* methodFlags - for future use*/, \
- MethodType_LoopBody + (uint16)loopNumber, \
- GetSourceId(Body), \
- /*line*/ 0, \
- /*column*/ 0, \
- loopBodyName); \
- if(loopBodyNameArray != loopBodyName) \
- { \
- HeapDeleteArray(bufferSize, loopBodyName); \
- }
- //
- // Encapsulates all ETW event logging and registration related to symbol decoding.
- //
- class EtwTrace
- {
- private:
- static const size_t NameBufferLength = 256;
- public:
- static void Register();
- static void UnRegister();
- static void PerformRundown(bool start);
- /* Unload events */
- static void LogSourceUnloadEvents(Js::ScriptContext* scriptContext);
- static void LogMethodNativeUnloadEvent(Js::FunctionBody* body, Js::FunctionEntryPointInfo* entryPoint);
- static void LogMethodInterpreterThunkUnloadEvent(Js::FunctionBody* body);
- static void LogLoopBodyUnloadEvent(Js::FunctionBody* body, Js::LoopEntryPointInfo* entryPoint, uint loopNumber);
- /* Load events */
- static void LogMethodInterpreterThunkLoadEvent(Js::FunctionBody* body);
- static void LogMethodNativeLoadEvent(Js::FunctionBody* body, Js::FunctionEntryPointInfo* entryPoint);
- static void LogLoopBodyLoadEvent(Js::FunctionBody* body, Js::LoopEntryPointInfo* entryPoint, uint16 loopNumber);
- static void LogScriptContextLoadEvent(Js::ScriptContext* scriptContext);
- static void LogSourceModuleLoadEvent(Js::ScriptContext* scriptContext, DWORD_PTR sourceContext, _In_z_ const char16* url);
- static const char16* GetFunctionName(Js::FunctionBody* body);
- static size_t GetLoopBodyName(_In_ Js::FunctionBody* body, _In_ Js::LoopHeader* loopHeader, _Out_writes_opt_z_(size) char16* nameBuffer, _In_ size_t size );
- _Success_(return == 0)
- static size_t GetSimpleJitFunctionName(Js::FunctionBody *const body, _Out_writes_opt_z_(nameCharCapacity) char16 *const name, const size_t nameCharCapacity);
- static DWORD_PTR GetSourceId(Js::FunctionBody* body);
- static uint GetFunctionId(Js::FunctionProxy* body);
- };
- #endif
|