blob: 0f944df8b3fbc6d89a60ac206d7cb97610294c01 [file]
//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------
#include "RuntimeBasePch.h"
#ifdef VTUNE_PROFILING
#include "VTuneChakraProfile.h"
#include "jitprofiling.h"
static const char LoopStr[] = "Loop";
const utf8char_t VTuneChakraProfile::DynamicCode[] = "Dynamic code";
bool VTuneChakraProfile::isJitProfilingActive = false;
//
// Registers the VTune profiler, if VTune sampling is running, we will get
// true value for isJitProfilingActive variable.
//
void VTuneChakraProfile::Register()
{
#if ENABLE_NATIVE_CODEGEN
isJitProfilingActive = (iJIT_IsProfilingActive() == iJIT_SAMPLING_ON);
#endif
}
//
// Unregister and notify VTune that even sampling is done.
//
void VTuneChakraProfile::UnRegister()
{
#if ENABLE_NATIVE_CODEGEN
if(isJitProfilingActive)
{
iJIT_NotifyEvent(iJVM_EVENT_TYPE_SHUTDOWN, NULL);
}
#endif
}
//
// Log JIT method native load event to VTune
//
void VTuneChakraProfile::LogMethodNativeLoadEvent(Js::FunctionBody* body, Js::FunctionEntryPointInfo* entryPoint)
{
#if ENABLE_NATIVE_CODEGEN
if (isJitProfilingActive)
{
iJIT_Method_Load methodInfo;
memset(&methodInfo, 0, sizeof(iJIT_Method_Load));
const char16* methodName = body->GetExternalDisplayName();
// Append function line number info to method name so that VTune can distinguish between polymorphic methods
char16 methodNameBuffer[_MAX_PATH];
ULONG lineNumber = body->GetLineNumber();
char16 numberBuffer[20];
_ltow_s(lineNumber, numberBuffer, 10);
wcscpy_s(methodNameBuffer, methodName);
if (entryPoint->GetJitMode() == ExecutionMode::SimpleJit)
{
wcscat_s(methodNameBuffer, _u(" Simple"));
}
wcscat_s(methodNameBuffer, _u(" {line:"));
wcscat_s(methodNameBuffer, numberBuffer);
wcscat_s(methodNameBuffer, _u("}"));
size_t methodLength = wcslen(methodNameBuffer);
Assert(methodLength < _MAX_PATH);
size_t length = methodLength * 3 + 1;
utf8char_t* utf8MethodName = HeapNewNoThrowArray(utf8char_t, length);
if (utf8MethodName)
{
methodInfo.method_id = iJIT_GetNewMethodID();
utf8::EncodeIntoAndNullTerminate(utf8MethodName, methodNameBuffer, (charcount_t)methodLength);
methodInfo.method_name = (char*)utf8MethodName;
methodInfo.method_load_address = (void*)entryPoint->GetNativeAddress();
methodInfo.method_size = (uint)entryPoint->GetCodeSize(); // Size in memory - Must be exact
LineNumberInfo numberInfo[1];
uint lineCount = (entryPoint->GetNativeOffsetMapCount()) * 2 + 1; // may need to record both .begin and .end for all elements
LineNumberInfo* pLineInfo = HeapNewNoThrowArray(LineNumberInfo, lineCount);
if (pLineInfo == NULL || Js::Configuration::Global.flags.DisableVTuneSourceLineInfo)
{
// resort to original implementation, attribute all samples to first line
numberInfo[0].LineNumber = lineNumber;
numberInfo[0].Offset = 0;
methodInfo.line_number_size = 1;
methodInfo.line_number_table = numberInfo;
}
else
{
int size = entryPoint->PopulateLineInfo(pLineInfo, body);
methodInfo.line_number_size = size;
methodInfo.line_number_table = pLineInfo;
}
size_t urlLength = 0;
utf8char_t* utf8Url = GetUrl(body, &urlLength);
methodInfo.source_file_name = (char*)utf8Url;
OUTPUT_TRACE(Js::ProfilerPhase, _u("Method load event: %s\n"), methodNameBuffer);
iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, &methodInfo);
HeapDeleteArray(lineCount, pLineInfo);
if (urlLength > 0)
{
HeapDeleteArray(urlLength, utf8Url);
}
HeapDeleteArray(length, utf8MethodName);
}
}
#endif
}
//
// Log loop body load event to VTune
//
void VTuneChakraProfile::LogLoopBodyLoadEvent(Js::FunctionBody* body, Js::LoopHeader* loopHeader, Js::LoopEntryPointInfo* entryPoint, uint16 loopNumber)
{
#if ENABLE_NATIVE_CODEGEN
if (isJitProfilingActive)
{
iJIT_Method_Load methodInfo;
memset(&methodInfo, 0, sizeof(iJIT_Method_Load));
const char16* methodName = body->GetExternalDisplayName();
size_t methodLength = wcslen(methodName);
methodLength = min(methodLength, (size_t)UINT_MAX); // Just truncate if it is too big
size_t length = methodLength * 3 + /* spaces */ 2 + _countof(LoopStr) + /*size of loop number*/ 10 + /*NULL*/ 1;
utf8char_t* utf8MethodName = HeapNewNoThrowArray(utf8char_t, length);
if(utf8MethodName)
{
methodInfo.method_id = iJIT_GetNewMethodID();
size_t len = utf8::EncodeInto(utf8MethodName, methodName, (charcount_t)methodLength);
sprintf_s((char*)(utf8MethodName + len), length - len," %s %d", LoopStr, loopNumber + 1);
methodInfo.method_name = (char*)utf8MethodName;
methodInfo.method_load_address = (void*)entryPoint->GetNativeAddress();
methodInfo.method_size = (uint)entryPoint->GetCodeSize(); // Size in memory - Must be exact
size_t urlLength = 0;
utf8char_t* utf8Url = GetUrl(body, &urlLength);
methodInfo.source_file_name = (char*)utf8Url;
iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, &methodInfo);
OUTPUT_TRACE(Js::ProfilerPhase, _u("Loop body load event: %s Loop %d\n"), methodName, loopNumber + 1);
if(urlLength > 0)
{
HeapDeleteArray(urlLength, utf8Url);
}
HeapDeleteArray(length, utf8MethodName);
}
}
#endif
}
//
// Get URL from source context, called by LogMethodNativeLoadEvent and LogLoopBodyLoadEvent
//
utf8char_t* VTuneChakraProfile::GetUrl(Js::FunctionBody* body, size_t* urlBufferLength )
{
utf8char_t* utf8Url = NULL;
if (!body->GetSourceContextInfo()->IsDynamic())
{
const wchar* url = body->GetSourceContextInfo()->url;
if (url)
{
size_t urlCharLength = wcslen(url);
urlCharLength = min(urlCharLength, (size_t)UINT_MAX); // Just truncate if it is too big
*urlBufferLength = urlCharLength * 3 + 1;
utf8Url = HeapNewNoThrowArray(utf8char_t, *urlBufferLength);
if (utf8Url)
{
utf8::EncodeIntoAndNullTerminate(utf8Url, url, (charcount_t)urlCharLength);
}
}
}
else
{
utf8Url = (utf8char_t*)VTuneChakraProfile::DynamicCode;
}
return utf8Url;
}
#endif /* VTUNE_PROFILING */