Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add profiler startup command to the diagnostics command set #52175

Merged
merged 12 commits into from
May 7, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/coreclr/inc/profilepriv.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ struct ProfControlBlock
BOOL fGCInProgress;
BOOL fBaseSystemClassesLoaded;

BOOL fIsStoredProfilerRegistered;
CLSID clsStoredProfilerGuid;
SString sStoredProfilerPath;

#ifdef PROF_TEST_ONLY_FORCE_ELT_DATA
// #TestOnlyELT This implements a test-only (and debug-only) hook that allows a test
// profiler to ensure enter/leave/tailcall is enabled on startup even though no
Expand Down
5 changes: 5 additions & 0 deletions src/coreclr/vm/ceemain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -709,6 +709,11 @@ void EEStartupHelper()
}
#endif

#ifdef PROFILING_SUPPORTED
// The diagnostics server might register a profiler for delayed startup, indicate here that
// it is not currently set. This will be set to TRUE if a profiler is registered.
g_profControlBlock.fIsStoredProfilerRegistered = FALSE;
#endif // PROFILING_SUPPORTED
#ifdef FEATURE_PERFTRACING
DiagnosticServerAdapter::Initialize();
DiagnosticServerAdapter::PauseForDiagnosticsMonitor();
Expand Down
5 changes: 5 additions & 0 deletions src/coreclr/vm/diagnosticserveradapter.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ class DiagnosticServerAdapter final
{
return ds_server_resume_runtime_startup();
}

static bool IsPausedInRuntimeStartup()
{
return ds_server_is_paused_in_startup();
}
};

#endif // FEATURE_PERFTRACING && !CROSSGEN_COMPILE
Expand Down
24 changes: 21 additions & 3 deletions src/coreclr/vm/eventing/eventpipe/ds-rt-coreclr.h
Original file line number Diff line number Diff line change
Expand Up @@ -268,11 +268,11 @@ DS_RT_DEFINE_ARRAY_REVERSE_ITERATOR (port_config_array, ds_rt_port_config_array_
/*
* DiagnosticsProfiler.
*/

#ifdef FEATURE_PROFAPI_ATTACH_DETACH
#ifdef PROFILING_SUPPORTED
#include "profilinghelper.h"
#include "profilinghelper.inl"

#ifdef FEATURE_PROFAPI_ATTACH_DETACH
static
uint32_t
ds_rt_profiler_attach (DiagnosticsAttachProfilerCommandPayload *payload)
Expand All @@ -285,7 +285,7 @@ ds_rt_profiler_attach (DiagnosticsAttachProfilerCommandPayload *payload)
// Certain actions are only allowable during attach, and this flag is how we track it.
ClrFlsSetThreadType (ThreadType_ProfAPI_Attach);

HRESULT hr;
HRESULT hr = S_OK;
EX_TRY {
hr = ProfilingAPIUtility::LoadProfilerForAttach (reinterpret_cast<const CLSID *>(ds_attach_profiler_command_payload_get_profiler_guid_cref (payload)),
reinterpret_cast<LPCWSTR>(ds_attach_profiler_command_payload_get_profiler_path (payload)),
Expand All @@ -302,6 +302,24 @@ ds_rt_profiler_attach (DiagnosticsAttachProfilerCommandPayload *payload)
}
#endif // FEATURE_PROFAPI_ATTACH_DETACH

static
uint32_t
ds_rt_profiler_startup (DiagnosticsStartupProfilerCommandPayload *payload)
{
STATIC_CONTRACT_NOTHROW;

HRESULT hr = S_OK;
EX_TRY {
memcpy(&(g_profControlBlock.clsStoredProfilerGuid), reinterpret_cast<const CLSID *>(ds_startup_profiler_command_payload_get_profiler_guid_cref (payload)), sizeof(CLSID));
g_profControlBlock.sStoredProfilerPath.Set(reinterpret_cast<LPCWSTR>(ds_startup_profiler_command_payload_get_profiler_path (payload)));
g_profControlBlock.fIsStoredProfilerRegistered = TRUE;
}
EX_CATCH_HRESULT (hr);

return hr;
}
#endif // PROFILING_SUPPORTED

/*
* DiagnosticServer.
*/
Expand Down
136 changes: 80 additions & 56 deletions src/coreclr/vm/profilinghelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -686,85 +686,109 @@ HRESULT ProfilingAPIUtility::AttemptLoadProfilerForStartup()

fProfEnabled = CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_CORECLR_ENABLE_PROFILING);

// If profiling is not enabled, return.
if (fProfEnabled == 0)
{
LOG((LF_CORPROF, LL_INFO10, "**PROF: Profiling not enabled.\n"));
return S_FALSE;
}
NewArrayHolder<WCHAR> wszClsid(NULL);
NewArrayHolder<const WCHAR> cwszProfilerDLL(NULL);
CLSID *pClsid;
CLSID clsid;

LOG((LF_CORPROF, LL_INFO10, "**PROF: Initializing Profiling Services.\n"));
if (fProfEnabled != 0)
{
LOG((LF_CORPROF, LL_INFO10, "**PROF: Initializing Profiling Services.\n"));

// Get the CLSID of the profiler to CoCreate
NewArrayHolder<WCHAR> wszClsid(NULL);
NewArrayHolder<WCHAR> wszProfilerDLL(NULL);
NewArrayHolder<WCHAR> wszProfilerDLL(NULL);

IfFailRet(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_CORECLR_PROFILER, &wszClsid));
IfFailRet(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_CORECLR_PROFILER, &wszClsid));

#if defined(TARGET_ARM64)
IfFailRet(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_CORECLR_PROFILER_PATH_ARM64, &wszProfilerDLL));
#elif defined(TARGET_ARM)
IfFailRet(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_CORECLR_PROFILER_PATH_ARM32, &wszProfilerDLL));
#endif
if(wszProfilerDLL == NULL)
{
#ifdef TARGET_64BIT
IfFailRet(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_CORECLR_PROFILER_PATH_64, &wszProfilerDLL));
#else
IfFailRet(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_CORECLR_PROFILER_PATH_32, &wszProfilerDLL));
#endif
#if defined(TARGET_ARM64)
IfFailRet(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_CORECLR_PROFILER_PATH_ARM64, &wszProfilerDLL));
#elif defined(TARGET_ARM)
IfFailRet(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_CORECLR_PROFILER_PATH_ARM32, &wszProfilerDLL));
#endif
if(wszProfilerDLL == NULL)
{
IfFailRet(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_CORECLR_PROFILER_PATH, &wszProfilerDLL));
#ifdef TARGET_64BIT
IfFailRet(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_CORECLR_PROFILER_PATH_64, &wszProfilerDLL));
#else
IfFailRet(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_CORECLR_PROFILER_PATH_32, &wszProfilerDLL));
#endif
if(wszProfilerDLL == NULL)
{
IfFailRet(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_CORECLR_PROFILER_PATH, &wszProfilerDLL));
}
}
}

// If the environment variable doesn't exist, profiling is not enabled.
if (wszClsid == NULL)
{
LOG((LF_CORPROF, LL_INFO10, "**PROF: Profiling flag set, but required "
"environment variable does not exist.\n"));
// If the environment variable doesn't exist, profiling is not enabled.
if (wszClsid == NULL)
{
LOG((LF_CORPROF, LL_INFO10, "**PROF: Profiling flag set, but required "
"environment variable does not exist.\n"));

LogProfError(IDS_E_PROF_NO_CLSID);
LogProfError(IDS_E_PROF_NO_CLSID);

return S_FALSE;
}
return S_FALSE;
}

if ((wszProfilerDLL != NULL) && (wcslen(wszProfilerDLL) >= MAX_LONGPATH))
{
LOG((LF_CORPROF, LL_INFO10, "**PROF: Profiling flag set, but COR_PROFILER_PATH was not set properly.\n"));
if ((wszProfilerDLL != NULL) && (wcslen(wszProfilerDLL) >= MAX_LONGPATH))
{
LOG((LF_CORPROF, LL_INFO10, "**PROF: Profiling flag set, but COR_PROFILER_PATH was not set properly.\n"));

LogProfError(IDS_E_PROF_BAD_PATH);
LogProfError(IDS_E_PROF_BAD_PATH);

return S_FALSE;
}
return S_FALSE;
}

#ifdef TARGET_UNIX
// If the environment variable doesn't exist, profiling is not enabled.
if (wszProfilerDLL == NULL)
{
LOG((LF_CORPROF, LL_INFO10, "**PROF: Profiling flag set, but required "
"environment variable does not exist.\n"));
#ifdef TARGET_UNIX
// If the environment variable doesn't exist, profiling is not enabled.
if (wszProfilerDLL == NULL)
{
LOG((LF_CORPROF, LL_INFO10, "**PROF: Profiling flag set, but required "
"environment variable does not exist.\n"));

LogProfError(IDS_E_PROF_BAD_PATH);
LogProfError(IDS_E_PROF_BAD_PATH);

return S_FALSE;
}
#endif // TARGET_UNIX
return S_FALSE;
}
#endif // TARGET_UNIX

CLSID clsid;
hr = ProfilingAPIUtility::ProfilerCLSIDFromString(wszClsid, &clsid);
if (FAILED(hr))
hr = ProfilingAPIUtility::ProfilerCLSIDFromString(wszClsid, &clsid);
if (FAILED(hr))
{
// ProfilerCLSIDFromString already logged an event if there was a failure
return hr;
}

pClsid = &clsid;
cwszProfilerDLL.Assign(wszProfilerDLL.GetValue());
wszProfilerDLL.SuppressRelease();
}
else if (g_profControlBlock.fIsStoredProfilerRegistered)
{
// ProfilerCLSIDFromString already logged an event if there was a failure
return hr;
LOG((LF_CORPROF, LL_INFO10, "**PROF: Profiler loading from GUID/Path stored from the IPC channel."));
pClsid = &(g_profControlBlock.clsStoredProfilerGuid);

// Convert to string for logging
constexpr size_t guidStringSize = 128;
wszClsid.Assign(new (nothrow) WCHAR[guidStringSize]);
if (wszClsid != NULL)
{
StringFromGUID2(*pClsid, wszClsid, guidStringSize);
}

// Assign, but don't take ownership of, the stored profiler path. This relies on
// g_profControlBlock.sStoredProfilerPath not mutating, which would invalidate the pointer.
cwszProfilerDLL.Assign(g_profControlBlock.sStoredProfilerPath.GetUnicode(), FALSE);
}
else
{
LOG((LF_CORPROF, LL_INFO10, "**PROF: Profiling not enabled.\n"));
return S_FALSE;
}

hr = LoadProfiler(
kStartupLoad,
&clsid,
pClsid,
wszClsid,
wszProfilerDLL,
cwszProfilerDLL,
NULL, // No client data for startup load
0); // No client data for startup load
if (FAILED(hr))
Expand Down
9 changes: 9 additions & 0 deletions src/mono/mono/eventpipe/ds-rt-mono.h
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,15 @@ ds_rt_profiler_attach (DiagnosticsAttachProfilerCommandPayload *payload)
return DS_IPC_E_NOTSUPPORTED;
}

static
inline
uint32_t
ds_rt_profiler_startup (DiagnosticsStartupProfilerCommandPayload *payload)
{
// TODO: Implement.
return DS_IPC_E_NOTSUPPORTED;
}

/*
* DiagnosticServer.
*/
Expand Down
Loading