VTuneChakraProfile.cpp 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  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. size_t length = methodLength * 3 + 1;
  61. utf8char_t* utf8MethodName = HeapNewNoThrowArray(utf8char_t, length);
  62. if (utf8MethodName)
  63. {
  64. methodInfo.method_id = iJIT_GetNewMethodID();
  65. utf8::EncodeIntoAndNullTerminate(utf8MethodName, methodNameBuffer, (charcount_t)methodLength);
  66. methodInfo.method_name = (char*)utf8MethodName;
  67. methodInfo.method_load_address = (void*)entryPoint->GetNativeAddress();
  68. methodInfo.method_size = (uint)entryPoint->GetCodeSize(); // Size in memory - Must be exact
  69. LineNumberInfo numberInfo[1];
  70. uint lineCount = (entryPoint->GetNativeOffsetMapCount()) * 2 + 1; // may need to record both .begin and .end for all elements
  71. LineNumberInfo* pLineInfo = HeapNewNoThrowArray(LineNumberInfo, lineCount);
  72. if (pLineInfo == NULL || Js::Configuration::Global.flags.DisableVTuneSourceLineInfo)
  73. {
  74. // resort to original implementation, attribute all samples to first line
  75. numberInfo[0].LineNumber = lineNumber;
  76. numberInfo[0].Offset = 0;
  77. methodInfo.line_number_size = 1;
  78. methodInfo.line_number_table = numberInfo;
  79. }
  80. else
  81. {
  82. int size = entryPoint->PopulateLineInfo(pLineInfo, body);
  83. methodInfo.line_number_size = size;
  84. methodInfo.line_number_table = pLineInfo;
  85. }
  86. size_t urlLength = 0;
  87. utf8char_t* utf8Url = GetUrl(body, &urlLength);
  88. methodInfo.source_file_name = (char*)utf8Url;
  89. OUTPUT_TRACE(Js::ProfilerPhase, _u("Method load event: %s\n"), methodNameBuffer);
  90. iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, &methodInfo);
  91. HeapDeleteArray(lineCount, pLineInfo);
  92. if (urlLength > 0)
  93. {
  94. HeapDeleteArray(urlLength, utf8Url);
  95. }
  96. HeapDeleteArray(length, utf8MethodName);
  97. }
  98. }
  99. #endif
  100. }
  101. //
  102. // Log loop body load event to VTune
  103. //
  104. void VTuneChakraProfile::LogLoopBodyLoadEvent(Js::FunctionBody* body, Js::LoopEntryPointInfo* entryPoint, uint16 loopNumber)
  105. {
  106. #if ENABLE_NATIVE_CODEGEN
  107. if (isJitProfilingActive)
  108. {
  109. iJIT_Method_Load methodInfo;
  110. memset(&methodInfo, 0, sizeof(iJIT_Method_Load));
  111. const char16* methodName = body->GetExternalDisplayName();
  112. size_t methodLength = wcslen(methodName);
  113. methodLength = min(methodLength, (size_t)UINT_MAX); // Just truncate if it is too big
  114. size_t length = methodLength * 3 + /* spaces */ 2 + _countof(LoopStr) + /*size of loop number*/ 10 + /*NULL*/ 1;
  115. utf8char_t* utf8MethodName = HeapNewNoThrowArray(utf8char_t, length);
  116. if(utf8MethodName)
  117. {
  118. methodInfo.method_id = iJIT_GetNewMethodID();
  119. size_t len = utf8::EncodeInto(utf8MethodName, methodName, (charcount_t)methodLength);
  120. sprintf_s((char*)(utf8MethodName + len), length - len," %s %d", LoopStr, loopNumber + 1);
  121. methodInfo.method_name = (char*)utf8MethodName;
  122. methodInfo.method_load_address = (void*)entryPoint->GetNativeAddress();
  123. methodInfo.method_size = (uint)entryPoint->GetCodeSize(); // Size in memory - Must be exact
  124. size_t urlLength = 0;
  125. utf8char_t* utf8Url = GetUrl(body, &urlLength);
  126. methodInfo.source_file_name = (char*)utf8Url;
  127. iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, &methodInfo);
  128. OUTPUT_TRACE(Js::ProfilerPhase, _u("Loop body load event: %s Loop %d\n"), methodName, loopNumber + 1);
  129. if(urlLength > 0)
  130. {
  131. HeapDeleteArray(urlLength, utf8Url);
  132. }
  133. HeapDeleteArray(length, utf8MethodName);
  134. }
  135. }
  136. #endif
  137. }
  138. //
  139. // Get URL from source context, called by LogMethodNativeLoadEvent and LogLoopBodyLoadEvent
  140. //
  141. utf8char_t* VTuneChakraProfile::GetUrl(Js::FunctionBody* body, size_t* urlBufferLength )
  142. {
  143. utf8char_t* utf8Url = NULL;
  144. if (!body->GetSourceContextInfo()->IsDynamic())
  145. {
  146. const wchar* url = body->GetSourceContextInfo()->url;
  147. if (url)
  148. {
  149. size_t urlCharLength = wcslen(url);
  150. urlCharLength = min(urlCharLength, (size_t)UINT_MAX); // Just truncate if it is too big
  151. *urlBufferLength = urlCharLength * 3 + 1;
  152. utf8Url = HeapNewNoThrowArray(utf8char_t, *urlBufferLength);
  153. if (utf8Url)
  154. {
  155. utf8::EncodeIntoAndNullTerminate(utf8Url, url, (charcount_t)urlCharLength);
  156. }
  157. }
  158. }
  159. else
  160. {
  161. utf8Url = (utf8char_t*)VTuneChakraProfile::DynamicCode;
  162. }
  163. return utf8Url;
  164. }
  165. #endif /* VTUNE_PROFILING */