VTuneChakraProfile.cpp 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. #include "RuntimeBasePch.h"
  6. #ifdef VTUNE_PROFILING
  7. #include "VTuneChakraProfile.h"
  8. #include "jitprofiling.h"
  9. static const char LoopStr[] = "Loop";
  10. const utf8char_t VTuneChakraProfile::DynamicCode[] = "Dynamic code";
  11. bool VTuneChakraProfile::isJitProfilingActive = false;
  12. //
  13. // Registers the VTune profiler, if VTune sampling is running, we will get
  14. // true value for isJitProfilingActive variable.
  15. //
  16. void VTuneChakraProfile::Register()
  17. {
  18. #if ENABLE_NATIVE_CODEGEN
  19. isJitProfilingActive = (iJIT_IsProfilingActive() == iJIT_SAMPLING_ON);
  20. #endif
  21. }
  22. //
  23. // Unregister and notify VTune that even sampling is done.
  24. //
  25. void VTuneChakraProfile::UnRegister()
  26. {
  27. #if ENABLE_NATIVE_CODEGEN
  28. if(isJitProfilingActive)
  29. {
  30. iJIT_NotifyEvent(iJVM_EVENT_TYPE_SHUTDOWN, NULL);
  31. }
  32. #endif
  33. }
  34. //
  35. // Log JIT method native load event to VTune
  36. //
  37. void VTuneChakraProfile::LogMethodNativeLoadEvent(Js::FunctionBody* body, Js::FunctionEntryPointInfo* entryPoint)
  38. {
  39. #if ENABLE_NATIVE_CODEGEN
  40. if (isJitProfilingActive)
  41. {
  42. iJIT_Method_Load methodInfo;
  43. memset(&methodInfo, 0, sizeof(iJIT_Method_Load));
  44. const char16* methodName = body->GetExternalDisplayName();
  45. // Append function line number info to method name so that VTune can distinguish between polymorphic methods
  46. char16 methodNameBuffer[_MAX_PATH];
  47. ULONG lineNumber = body->GetLineNumber();
  48. char16 numberBuffer[20];
  49. _ltow_s(lineNumber, numberBuffer, 10);
  50. wcscpy_s(methodNameBuffer, methodName);
  51. if (entryPoint->GetJitMode() == ExecutionMode::SimpleJit)
  52. {
  53. wcscat_s(methodNameBuffer, _u(" Simple"));
  54. }
  55. wcscat_s(methodNameBuffer, _u(" {line:"));
  56. wcscat_s(methodNameBuffer, numberBuffer);
  57. wcscat_s(methodNameBuffer, _u("}"));
  58. size_t methodLength = wcslen(methodNameBuffer);
  59. Assert(methodLength < _MAX_PATH);
  60. charcount_t ccMethodLength = static_cast<charcount_t>(methodLength);
  61. size_t cbUtf8MethodName = UInt32Math::MulAdd<3, 1>(ccMethodLength);
  62. utf8char_t* utf8MethodName = HeapNewNoThrowArray(utf8char_t, cbUtf8MethodName);
  63. if (utf8MethodName)
  64. {
  65. methodInfo.method_id = iJIT_GetNewMethodID();
  66. utf8::EncodeIntoAndNullTerminate<utf8::Utf8EncodingKind::Cesu8>(utf8MethodName, cbUtf8MethodName, methodNameBuffer, ccMethodLength);
  67. methodInfo.method_name = (char*)utf8MethodName;
  68. methodInfo.method_load_address = (void*)entryPoint->GetNativeAddress();
  69. methodInfo.method_size = (uint)entryPoint->GetCodeSize(); // Size in memory - Must be exact
  70. LineNumberInfo numberInfo[1];
  71. uint lineCount = (entryPoint->GetNativeOffsetMapCount()) * 2 + 1; // may need to record both .begin and .end for all elements
  72. LineNumberInfo* pLineInfo = HeapNewNoThrowArray(LineNumberInfo, lineCount);
  73. if (pLineInfo == NULL || Js::Configuration::Global.flags.DisableVTuneSourceLineInfo)
  74. {
  75. // resort to original implementation, attribute all samples to first line
  76. numberInfo[0].LineNumber = lineNumber;
  77. numberInfo[0].Offset = 0;
  78. methodInfo.line_number_size = 1;
  79. methodInfo.line_number_table = numberInfo;
  80. }
  81. else
  82. {
  83. int size = entryPoint->PopulateLineInfo(pLineInfo, body);
  84. methodInfo.line_number_size = size;
  85. methodInfo.line_number_table = pLineInfo;
  86. }
  87. size_t urlLength = 0;
  88. utf8char_t* utf8Url = GetUrl(body, &urlLength);
  89. methodInfo.source_file_name = (char*)utf8Url;
  90. OUTPUT_TRACE(Js::ProfilerPhase, _u("Method load event: %s\n"), methodNameBuffer);
  91. iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, &methodInfo);
  92. HeapDeleteArray(lineCount, pLineInfo);
  93. if (urlLength > 0)
  94. {
  95. HeapDeleteArray(urlLength, utf8Url);
  96. }
  97. HeapDeleteArray(cbUtf8MethodName, utf8MethodName);
  98. }
  99. }
  100. #endif
  101. }
  102. //
  103. // Log loop body load event to VTune
  104. //
  105. void VTuneChakraProfile::LogLoopBodyLoadEvent(Js::FunctionBody* body, Js::LoopEntryPointInfo* entryPoint, uint16 loopNumber)
  106. {
  107. #if ENABLE_NATIVE_CODEGEN
  108. if (isJitProfilingActive)
  109. {
  110. iJIT_Method_Load methodInfo;
  111. memset(&methodInfo, 0, sizeof(iJIT_Method_Load));
  112. const char16* methodName = body->GetExternalDisplayName();
  113. size_t methodLength = wcslen(methodName);
  114. charcount_t ccMethodLength = static_cast<charcount_t>(methodLength);
  115. ccMethodLength = min(ccMethodLength, UINT_MAX); // Just truncate if it is too big
  116. constexpr size_t sizeToAdd = /* spaces */ 2 + _countof(LoopStr) + /* size of loop number */ 10 + /*NULL*/ 1;
  117. size_t cbUtf8MethodName = UInt32Math::MulAdd<3, sizeToAdd>(ccMethodLength);
  118. utf8char_t* utf8MethodName = HeapNewNoThrowArray(utf8char_t, cbUtf8MethodName);
  119. if(utf8MethodName)
  120. {
  121. methodInfo.method_id = iJIT_GetNewMethodID();
  122. size_t len = utf8::EncodeInto<utf8::Utf8EncodingKind::Cesu8>(utf8MethodName, cbUtf8MethodName, methodName, ccMethodLength);
  123. sprintf_s((char*)(utf8MethodName + len), cbUtf8MethodName - len," %s %d", LoopStr, loopNumber + 1);
  124. methodInfo.method_name = (char*)utf8MethodName;
  125. methodInfo.method_load_address = (void*)entryPoint->GetNativeAddress();
  126. methodInfo.method_size = (uint)entryPoint->GetCodeSize(); // Size in memory - Must be exact
  127. size_t urlLength = 0;
  128. utf8char_t* utf8Url = GetUrl(body, &urlLength);
  129. methodInfo.source_file_name = (char*)utf8Url;
  130. iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, &methodInfo);
  131. OUTPUT_TRACE(Js::ProfilerPhase, _u("Loop body load event: %s Loop %d\n"), methodName, loopNumber + 1);
  132. if(urlLength > 0)
  133. {
  134. HeapDeleteArray(urlLength, utf8Url);
  135. }
  136. HeapDeleteArray(cbUtf8MethodName, utf8MethodName);
  137. }
  138. }
  139. #endif
  140. }
  141. //
  142. // Get URL from source context, called by LogMethodNativeLoadEvent and LogLoopBodyLoadEvent
  143. //
  144. utf8char_t* VTuneChakraProfile::GetUrl(Js::FunctionBody* body, size_t* urlBufferLength )
  145. {
  146. utf8char_t* utf8Url = NULL;
  147. if (!body->GetSourceContextInfo()->IsDynamic())
  148. {
  149. const wchar* url = body->GetSourceContextInfo()->url;
  150. if (url)
  151. {
  152. size_t urlCharLength = wcslen(url);
  153. charcount_t ccUrlCharLength = static_cast<charcount_t>(urlCharLength);
  154. ccUrlCharLength = min(ccUrlCharLength, UINT_MAX); // Just truncate if it is too big
  155. *urlBufferLength = UInt32Math::MulAdd<3, 1>(ccUrlCharLength);
  156. utf8Url = HeapNewNoThrowArray(utf8char_t, *urlBufferLength);
  157. if (utf8Url)
  158. {
  159. utf8::EncodeIntoAndNullTerminate<utf8::Utf8EncodingKind::Cesu8>(utf8Url, *urlBufferLength, url, ccUrlCharLength);
  160. }
  161. }
  162. }
  163. else
  164. {
  165. utf8Url = (utf8char_t*)VTuneChakraProfile::DynamicCode;
  166. }
  167. return utf8Url;
  168. }
  169. #endif /* VTUNE_PROFILING */