зеркало из https://github.com/mono/coreclr.git
Adds support for resolving JIT compiled managed call frames in perf_events.
This commit is contained in:
Родитель
1426853c33
Коммит
e406060ba1
|
@ -455,6 +455,9 @@ if(WIN32)
|
|||
add_definitions(-DFEATURE_STRONGNAME_TESTKEY_ALLOWED)
|
||||
endif(WIN32)
|
||||
add_definitions(-DFEATURE_SVR_GC)
|
||||
if(CLR_CMAKE_PLATFORM_LINUX)
|
||||
add_definitions(-DFEATURE_PERFMAP)
|
||||
endif(CLR_CMAKE_PLATFORM_LINUX)
|
||||
add_definitions(-DFEATURE_SYNTHETIC_CULTURES)
|
||||
add_definitions(-DFEATURE_VERSIONING)
|
||||
if(WIN32)
|
||||
|
|
|
@ -102,6 +102,7 @@
|
|||
<CDefines Condition="'$(FeatureStrongnameMigration)' == 'true'">$(CDefines);FEATURE_STRONGNAME_MIGRATION</CDefines>
|
||||
<CDefines Condition="'$(FeatureStrongnameTestkeyAllowed)' == 'true'">$(CDefines);FEATURE_STRONGNAME_TESTKEY_ALLOWED</CDefines>
|
||||
<CDefines Condition="'$(FeatureSvrGc)' == 'true'">$(CDefines);FEATURE_SVR_GC</CDefines>
|
||||
<CDefines Condition="'$(FeaturePerfMap)' == 'true'">$(CDefines);FEATURE_PERFMAP</CDefines>
|
||||
<CDefines Condition="'$(FeatureSynchronizationcontextWait)' == 'true'">$(CDefines);FEATURE_SYNCHRONIZATIONCONTEXT_WAIT</CDefines>
|
||||
<CDefines Condition="'$(FeatureSyntheticCultures)' == 'true'">$(CDefines);FEATURE_SYNTHETIC_CULTURES</CDefines>
|
||||
<CDefines Condition="'$(FeatureTypeEquivalence)' == 'true'">$(CDefines);FEATURE_TYPEEQUIVALENCE</CDefines>
|
||||
|
|
|
@ -843,6 +843,10 @@ RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_VistaAndAboveETWEnabled, W("ETWEnabled"), 1
|
|||
RETAIL_CONFIG_STRING_INFO_EX(UNSUPPORTED_ETW_ObjectAllocationEventsPerTypePerSec, W("ETW_ObjectAllocationEventsPerTypePerSec"), "Desired number of GCSampledObjectAllocation ETW events to be logged per type per second. If 0, then the default built in to the implementation for the enabled event (e.g., High, Low), will be used.", CLRConfig::REGUTIL_default)
|
||||
RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_ProfAPI_ValidateNGENInstrumentation, W("ProfAPI_ValidateNGENInstrumentation"), 0, "This flag enables additional validations when using the IMetaDataEmit APIs for NGEN'ed images to ensure only supported edits are made.")
|
||||
|
||||
#ifdef FEATURE_PERFMAP
|
||||
RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_PerfMapEnabled, W("PerfMapEnabled"), 0, "This flag is used on Linux to enable writing /tmp/perf-$pid.map. It is disabled by default", CLRConfig::REGUTIL_default)
|
||||
#endif
|
||||
|
||||
//
|
||||
// Shim
|
||||
//
|
||||
|
|
|
@ -94,6 +94,7 @@ set(VM_SOURCES_DAC_AND_WKS_COMMON
|
|||
pefile.cpp
|
||||
peimage.cpp
|
||||
peimagelayout.cpp
|
||||
perfmap.cpp
|
||||
precode.cpp
|
||||
prestub.cpp
|
||||
rejit.cpp
|
||||
|
|
|
@ -252,6 +252,10 @@
|
|||
#include <mscoruefwrapper.h>
|
||||
#endif // FEATURE_UEF_CHAINMANAGER
|
||||
|
||||
#ifdef FEATURE_PERFMAP
|
||||
#include "perfmap.h"
|
||||
#endif
|
||||
|
||||
#ifdef FEATURE_IPCMAN
|
||||
static HRESULT InitializeIPCManager(void);
|
||||
static void PublishIPCManager(void);
|
||||
|
@ -926,6 +930,10 @@ void EEStartupHelper(COINITIEE fFlags)
|
|||
PerfLog::PerfLogInitialize();
|
||||
#endif //ENABLE_PERF_LOG
|
||||
|
||||
#ifdef FEATURE_PERFMAP
|
||||
PerfMap::Initialize();
|
||||
#endif
|
||||
|
||||
STRESS_LOG0(LF_STARTUP, LL_ALWAYS, "===================EEStartup Starting===================");
|
||||
|
||||
#ifndef CROSSGEN_COMPILE
|
||||
|
@ -1907,6 +1915,11 @@ void STDMETHODCALLTYPE EEShutDownHelper(BOOL fIsDllUnloading)
|
|||
ETW::TypeSystemLog::FlushObjectAllocationEvents();
|
||||
#endif // FEATURE_EVENT_TRACE
|
||||
|
||||
#ifdef FEATURE_PERFMAP
|
||||
// Flush and close the perf map file.
|
||||
PerfMap::Destroy();
|
||||
#endif
|
||||
|
||||
#ifdef FEATURE_PREJIT
|
||||
// If we're doing basic block profiling, we need to write the log files to disk.
|
||||
|
||||
|
|
|
@ -12533,7 +12533,7 @@ BOOL g_fAllowRel32 = TRUE;
|
|||
// are OK since they discard the return value of this method.
|
||||
|
||||
PCODE UnsafeJitFunction(MethodDesc* ftn, COR_ILMETHOD_DECODER* ILHeader,
|
||||
DWORD flags, DWORD flags2)
|
||||
DWORD flags, DWORD flags2, ULONG * pSizeOfCode)
|
||||
{
|
||||
STANDARD_VM_CONTRACT;
|
||||
|
||||
|
@ -12785,6 +12785,14 @@ PCODE UnsafeJitFunction(MethodDesc* ftn, COR_ILMETHOD_DECODER* ILHeader,
|
|||
(MethodDesc*)ftn);
|
||||
LOG((LF_CORDB, LL_EVERYTHING, "Got through CallCompile MethodWithSEHWrapper\n"));
|
||||
|
||||
#if FEATURE_PERFMAP
|
||||
// Save the code size so that it can be reported to the perfmap.
|
||||
if (pSizeOfCode != NULL)
|
||||
{
|
||||
*pSizeOfCode = sizeOfCode;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(ENABLE_PERF_COUNTERS)
|
||||
LARGE_INTEGER CycleStop;
|
||||
QueryPerformanceCounter(&CycleStop);
|
||||
|
|
|
@ -46,7 +46,7 @@ void InitJITHelpers1();
|
|||
void InitJITHelpers2();
|
||||
|
||||
PCODE UnsafeJitFunction(MethodDesc* ftn, COR_ILMETHOD_DECODER* header,
|
||||
DWORD flags, DWORD flags2);
|
||||
DWORD flags, DWORD flags2, ULONG* sizeOfCode = NULL);
|
||||
|
||||
void getMethodInfoHelper(MethodDesc * ftn,
|
||||
CORINFO_METHOD_HANDLE ftnHnd,
|
||||
|
|
|
@ -0,0 +1,141 @@
|
|||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
// ===========================================================================
|
||||
// File: perfmap.cpp
|
||||
//
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#ifdef FEATURE_PERFMAP
|
||||
#include "perfmap.h"
|
||||
#include "pal.h"
|
||||
|
||||
PerfMap * PerfMap::s_Current = NULL;
|
||||
|
||||
// Initialize the map for the process - called from EEStartupHelper.
|
||||
void PerfMap::Initialize()
|
||||
{
|
||||
LIMITED_METHOD_CONTRACT;
|
||||
|
||||
// Only enable the map if requested.
|
||||
if (CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_PerfMapEnabled))
|
||||
{
|
||||
// Get the current process id.
|
||||
int currentPid = GetCurrentProcessId();
|
||||
|
||||
// Create the map.
|
||||
s_Current = new PerfMap(currentPid);
|
||||
}
|
||||
}
|
||||
|
||||
// Log a method to the map.
|
||||
void PerfMap::LogMethod(MethodDesc * pMethod, PCODE pCode, size_t codeSize)
|
||||
{
|
||||
LIMITED_METHOD_CONTRACT;
|
||||
|
||||
if (s_Current != NULL)
|
||||
{
|
||||
s_Current->Log(pMethod, pCode, codeSize);
|
||||
}
|
||||
}
|
||||
|
||||
// Destroy the map for the process - called from EEShutdownHelper.
|
||||
void PerfMap::Destroy()
|
||||
{
|
||||
if (s_Current != NULL)
|
||||
{
|
||||
delete s_Current;
|
||||
s_Current = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Construct a new map for the process.
|
||||
PerfMap::PerfMap(int pid)
|
||||
{
|
||||
LIMITED_METHOD_CONTRACT;
|
||||
|
||||
// Initialize with no failures.
|
||||
m_ErrorEncountered = false;
|
||||
|
||||
// Build the path to the map file on disk.
|
||||
WCHAR tempPath[MAX_PATH+1];
|
||||
if(!GetTempPathW(MAX_PATH, tempPath))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SString path;
|
||||
path.Printf("%Sperf-%d.map", &tempPath, pid);
|
||||
|
||||
// Open the file stream.
|
||||
m_FileStream = new (nothrow) CFileStream();
|
||||
if(m_FileStream != NULL)
|
||||
{
|
||||
HRESULT hr = m_FileStream->OpenForWrite(path.GetUnicode());
|
||||
if(FAILED(hr))
|
||||
{
|
||||
delete m_FileStream;
|
||||
m_FileStream = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clean-up resources.
|
||||
PerfMap::~PerfMap()
|
||||
{
|
||||
LIMITED_METHOD_CONTRACT;
|
||||
|
||||
delete m_FileStream;
|
||||
m_FileStream = NULL;
|
||||
}
|
||||
|
||||
// Log a method to the map.
|
||||
void PerfMap::Log(MethodDesc * pMethod, PCODE pCode, size_t codeSize)
|
||||
{
|
||||
CONTRACTL{
|
||||
THROWS;
|
||||
GC_NOTRIGGER;
|
||||
MODE_PREEMPTIVE;
|
||||
PRECONDITION(pMethod != NULL);
|
||||
PRECONDITION(pCode != NULL);
|
||||
PRECONDITION(codeSize > 0);
|
||||
} CONTRACTL_END;
|
||||
|
||||
if (m_FileStream == NULL || m_ErrorEncountered)
|
||||
{
|
||||
// A failure occurred, do not log.
|
||||
return;
|
||||
}
|
||||
|
||||
// Logging failures should not cause any exceptions to flow upstream.
|
||||
EX_TRY
|
||||
{
|
||||
// Get the full method signature.
|
||||
SString fullMethodSignature;
|
||||
pMethod->GetFullMethodInfo(fullMethodSignature);
|
||||
|
||||
// Build the map file line.
|
||||
StackScratchBuffer scratch;
|
||||
SString line;
|
||||
line.Printf("%p %x %s\n", pCode, codeSize, fullMethodSignature.GetANSI(scratch));
|
||||
|
||||
// Write the line.
|
||||
// The PAL already takes a lock when writing, so we don't need to do so here.
|
||||
const char * strLine = line.GetANSI(scratch);
|
||||
ULONG inCount = line.GetCount();
|
||||
ULONG outCount;
|
||||
m_FileStream->Write(strLine, inCount, &outCount);
|
||||
|
||||
if (inCount != outCount)
|
||||
{
|
||||
// This will cause us to stop writing to the file.
|
||||
// The file will still remain open until shutdown so that we don't have to take a lock at this levelwhen we touch the file stream.
|
||||
m_ErrorEncountered = true;
|
||||
}
|
||||
}
|
||||
EX_CATCH{} EX_END_CATCH(SwallowAllExceptions);
|
||||
}
|
||||
|
||||
#endif // FEATURE_PERFMAP
|
|
@ -0,0 +1,49 @@
|
|||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
// ===========================================================================
|
||||
// File: perfmap.h
|
||||
//
|
||||
#ifndef PERFPID_H
|
||||
#define PERFPID_H
|
||||
|
||||
#include "sstring.h"
|
||||
#include "fstream.h"
|
||||
|
||||
class PerfMap
|
||||
{
|
||||
private:
|
||||
// The one and only PerfMap for the process.
|
||||
static PerfMap * s_Current;
|
||||
|
||||
// The file stream to write the map to.
|
||||
CFileStream * m_FileStream;
|
||||
|
||||
// Set to true if an error is encountered when writing to the file.
|
||||
bool m_ErrorEncountered;
|
||||
|
||||
// Construct a new map.
|
||||
PerfMap(int pid);
|
||||
|
||||
// Clean-up resources.
|
||||
~PerfMap();
|
||||
|
||||
// Does the actual work to log to the map.
|
||||
void Log(MethodDesc * pMethod, PCODE pCode, size_t codeSize);
|
||||
|
||||
// Does the actual work to close and flush the map.
|
||||
void Close();
|
||||
|
||||
public:
|
||||
// Initialize the map for the current process.
|
||||
static void Initialize();
|
||||
|
||||
// Log a method to the map.
|
||||
static void LogMethod(MethodDesc * pMethod, PCODE pCode, size_t codeSize);
|
||||
|
||||
// Close the map and flush any remaining data.
|
||||
static void Destroy();
|
||||
};
|
||||
|
||||
#endif // PERFPID_H
|
|
@ -49,6 +49,10 @@
|
|||
#include "stacksampler.h"
|
||||
#endif
|
||||
|
||||
#ifdef FEATURE_PERFMAP
|
||||
#include "perfmap.h"
|
||||
#endif
|
||||
|
||||
#ifndef DACCESS_COMPILE
|
||||
|
||||
EXTERN_C void STDCALL ThePreStub();
|
||||
|
@ -262,6 +266,7 @@ PCODE MethodDesc::MakeJitWorker(COR_ILMETHOD_DECODER* ILHeader, DWORD flags, DWO
|
|||
m_pszDebugMethodName));
|
||||
|
||||
PCODE pCode = NULL;
|
||||
ULONG sizeOfCode = 0;
|
||||
#ifdef FEATURE_INTERPRETER
|
||||
PCODE pPreviousInterpStub = NULL;
|
||||
BOOL fInterpreted = FALSE;
|
||||
|
@ -454,7 +459,7 @@ PCODE MethodDesc::MakeJitWorker(COR_ILMETHOD_DECODER* ILHeader, DWORD flags, DWO
|
|||
|
||||
EX_TRY
|
||||
{
|
||||
pCode = UnsafeJitFunction(this, ILHeader, flags, flags2);
|
||||
pCode = UnsafeJitFunction(this, ILHeader, flags, flags2, &sizeOfCode);
|
||||
}
|
||||
EX_CATCH
|
||||
{
|
||||
|
@ -514,6 +519,11 @@ PCODE MethodDesc::MakeJitWorker(COR_ILMETHOD_DECODER* ILHeader, DWORD flags, DWO
|
|||
{
|
||||
// Fire an ETW event to mark the end of JIT'ing
|
||||
ETW::MethodLog::MethodJitted(this, &namespaceOrClassName, &methodName, &methodSignature, pCode, 0 /* ReJITID */);
|
||||
|
||||
#ifdef FEATURE_PERFMAP
|
||||
// Save the JIT'd method information so that perf can resolve JIT'd call frames.
|
||||
PerfMap::LogMethod(this, pCode, sizeOfCode);
|
||||
#endif
|
||||
|
||||
mcJitManager.GetMulticoreJitCodeStorage().StoreMethodCode(this, pCode);
|
||||
|
||||
|
@ -593,6 +603,11 @@ GotNewCode:
|
|||
{
|
||||
// Fire an ETW event to mark the end of JIT'ing
|
||||
ETW::MethodLog::MethodJitted(this, &namespaceOrClassName, &methodName, &methodSignature, pCode, 0 /* ReJITID */);
|
||||
|
||||
#ifdef FEATURE_PERFMAP
|
||||
// Save the JIT'd method information so that perf can resolve JIT'd call frames.
|
||||
PerfMap::LogMethod(this, pCode, sizeOfCode);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче