Add CI tests for notification profilers, and fix a couple things to make life with multiple profilers easier
* Reduced default timeout for profiler detach - we used to try at 300ms, 600ms, 5s, 10s, and then 10 minutes. The check is just a read of an int, so there's no reason to wait 10 minutes
* Got rid of a couple asserts that were wrong since switching from the dedicated profiler attach thread to the diagnostics server implementation
* ProfControlBlock::GetProfilerInfo would only work for active profilers, not attaching profilers, which could cause subtle bugs
// Profiler messages for event log
STRINGTABLE DISCARDABLE
BEGIN
- IDS_E_PROF_BAD_PATH "Loading profiler failed. COR_ENABLE_PROFILING and COR_PROFILER were set properly, but COR_PROFILER_PATH was not. COR_PROFILER_PATH must be set to the full path of the profiler DLL to load with no more than 260 charaters including the null terminator."
- IDS_E_PROF_NO_CLSID "Loading profiler failed. COR_ENABLE_PROFILING was set properly, but COR_PROFILER was not. COR_PROFILER must be set to the CLSID of the profiler to load."
- IDS_E_PROF_INTERNAL_INIT "Loading profiler failed due to an internal profiling services initialization failure. Profiler CLSID: '%s'. HRESULT: 0x%x."
- IDS_E_PROF_BAD_CLSID "Loading profiler failed. COR_PROFILER is set to an invalid CLSID: '%s'. HRESULT: 0x%x."
- IDS_E_PROF_NO_CALLBACK_IFACE "Loading profiler failed. COR_PROFILER is set to a CLSID of a COM object that does not implement the interface GUID (IID) requested by the CLR. This often indicates that the profiler does not support this version of the CLR. Profiler CLSID: '%s'. Requested IID: '%s'."
- IDS_E_PROF_CCI_FAILED "Loading profiler failed during CoCreateInstance. Profiler CLSID: '%s'. HRESULT: 0x%x."
- IDS_E_PROF_INIT_CALLBACK_FAILED "Loading profiler failed. The profiler COM object was instantiated, but the profiler failed during its initialization callback. Profiler CLSID: '%s'. HRESULT: 0x%x."
- IDS_PROF_SUPPLEMENTARY_INFO "Process ID (decimal): %d. Message ID: [0x%x]."
- IDS_PROF_LOAD_COMPLETE "The profiler was loaded successfully. Profiler CLSID: '%s'."
- IDS_E_PROF_NOT_ATTACHABLE "Loading profiler failed. The profiler COM object was instantiated, but the profiler does not support attaching to a live process. The profiler must be loaded at application startup by using a launcher program included with the profiler (if any) or by setting the COR_ENABLE_PROFILING and COR_PROFILER environment variables before launching the application to be profiled. Profiler CLSID: '%s'"
- IDS_E_PROF_UNHANDLED_EXCEPTION_ON_LOAD "Loading profiler failed. There was an unhandled exception while trying to instantiate the profiler COM object. Please ensure the CLSID is associated with a valid profiler designed to work with this version of the runtime. Profiler CLSID: '%s'."
- IDS_PROF_ATTACH_REQUEST_RECEIVED "The CLR received a request to attach a profiler. Profiler CLSID: '%s'."
- IDS_PROF_DETACH_INITIATED "The profiler currently in use has requested to be detached from the process. The CLR has disabled communication with the profiler and will unload the profiler when it is safe to do so."
- IDS_PROF_DETACH_COMPLETE "The CLR has fully detached and unloaded the profiler."
- IDS_PROF_DETACH_THREAD_ERROR "There was an internal failure in the profiling API detach infrastructure. The profiler will not be able to be detached. Error code: %d."
- IDS_PROF_CANCEL_ACTIVATION "The profiler has requested that the CLR instance not load the profiler into this process. Profiler CLSID: '%s'."
- IDS_PROF_V2PROFILER_DISABLED "Loading profiler failed. The profiler that was configured to load was designed for an older version of the CLR. You can use the COMPlus_ProfAPI_ProfilerCompatibilitySetting environment variable to allow older profilers to be loaded by the current version of the CLR. Please consult the documentation for information on how to use this environment variable, and the risks associated with it. Profiler CLSID: '%s'."
- IDS_PROF_V2PROFILER_ENABLED "A profiler designed for an older version of the CLR was loaded because of the environment variable setting below. Older profilers will continue to work in many cases, but if you encounter problems, please consider upgrading the profiler or changing the setting of the environment variable. Please consult the documentation for information on how to use this environment variable, and the risks associated with it. Environment variable setting: %s=%s. Profiler CLSID: '%s'."
- IDS_PROF_PROFILER_DISABLED "Profilers will not be loaded by the current version of the CLR because of the environment variable setting below. Please consult the documentation for information on how to use this environment variable, and the risks associated with it. Environment variable setting: %s=%s. Profiler CLSID: '%s'."
- IDS_E_PROF_NOTIFICATION_DISABLED "Profiler was prevented from loading notification profiler due to app settings."
- IDS_E_PROF_NOTIFICATION_LIMIT_EXCEEDED "Notification profiler was prevented from loading because the limit of notification profilers was reached."
- IDS_E_PROF_TIMEOUT_WAITING_FOR_CONCURRENT_GC "Profiler timed out on waiting for concurrent GC to finish after '%d' milliseconds. Please configure your profiler to increase its attaching time out value or consult the documentation for the COMPlus_ProfAPI_AttachProfilerMinTimeoutInMs environment variable and try again. Profiler CLSID: '%s'."
- IDS_PROF_ALREADY_LOADED "A request was made to load a profiler when a profiler was already loaded."
+ IDS_E_PROF_BAD_PATH "Loading profiler failed. COR_ENABLE_PROFILING and COR_PROFILER were set properly, but COR_PROFILER_PATH was not. COR_PROFILER_PATH must be set to the full path of the profiler DLL to load with no more than 260 charaters including the null terminator.\n"
+ IDS_E_PROF_NO_CLSID "Loading profiler failed. COR_ENABLE_PROFILING was set properly, but COR_PROFILER was not. COR_PROFILER must be set to the CLSID of the profiler to load.\n"
+ IDS_E_PROF_INTERNAL_INIT "Loading profiler failed due to an internal profiling services initialization failure. Profiler CLSID: '%s'. HRESULT: 0x%x.\n"
+ IDS_E_PROF_BAD_CLSID "Loading profiler failed. COR_PROFILER is set to an invalid CLSID: '%s'. HRESULT: 0x%x.\n"
+ IDS_E_PROF_NO_CALLBACK_IFACE "Loading profiler failed. COR_PROFILER is set to a CLSID of a COM object that does not implement the interface GUID (IID) requested by the CLR. This often indicates that the profiler does not support this version of the CLR. Profiler CLSID: '%s'. Requested IID: '%s'.\n"
+ IDS_E_PROF_CCI_FAILED "Loading profiler failed during CoCreateInstance. Profiler CLSID: '%s'. HRESULT: 0x%x.\n"
+ IDS_E_PROF_INIT_CALLBACK_FAILED "Loading profiler failed. The profiler COM object was instantiated, but the profiler failed during its initialization callback. Profiler CLSID: '%s'. HRESULT: 0x%x.\n"
+ IDS_PROF_SUPPLEMENTARY_INFO "Process ID (decimal): %d. Message ID: [0x%x].\n"
+ IDS_PROF_LOAD_COMPLETE "The profiler was loaded successfully. Profiler CLSID: '%s'.\n"
+ IDS_E_PROF_NOT_ATTACHABLE "Loading profiler failed. The profiler COM object was instantiated, but the profiler does not support attaching to a live process. The profiler must be loaded at application startup by using a launcher program included with the profiler (if any) or by setting the COR_ENABLE_PROFILING and COR_PROFILER environment variables before launching the application to be profiled. Profiler CLSID: '%s'\n"
+ IDS_E_PROF_UNHANDLED_EXCEPTION_ON_LOAD "Loading profiler failed. There was an unhandled exception while trying to instantiate the profiler COM object. Please ensure the CLSID is associated with a valid profiler designed to work with this version of the runtime. Profiler CLSID: '%s'.\n"
+ IDS_PROF_ATTACH_REQUEST_RECEIVED "The CLR received a request to attach a profiler. Profiler CLSID: '%s'.\n"
+ IDS_PROF_DETACH_INITIATED "The profiler currently in use has requested to be detached from the process. The CLR has disabled communication with the profiler and will unload the profiler when it is safe to do so.\n"
+ IDS_PROF_DETACH_COMPLETE "The CLR has fully detached and unloaded the profiler.\n"
+ IDS_PROF_DETACH_THREAD_ERROR "There was an internal failure in the profiling API detach infrastructure. The profiler will not be able to be detached. Error code: %d.\n"
+ IDS_PROF_CANCEL_ACTIVATION "The profiler has requested that the CLR instance not load the profiler into this process. Profiler CLSID: '%s'.\n"
+ IDS_PROF_V2PROFILER_DISABLED "Loading profiler failed. The profiler that was configured to load was designed for an older version of the CLR. You can use the COMPlus_ProfAPI_ProfilerCompatibilitySetting environment variable to allow older profilers to be loaded by the current version of the CLR. Please consult the documentation for information on how to use this environment variable, and the risks associated with it. Profiler CLSID: '%s'.\n"
+ IDS_PROF_V2PROFILER_ENABLED "A profiler designed for an older version of the CLR was loaded because of the environment variable setting below. Older profilers will continue to work in many cases, but if you encounter problems, please consider upgrading the profiler or changing the setting of the environment variable. Please consult the documentation for information on how to use this environment variable, and the risks associated with it. Environment variable setting: %s=%s. Profiler CLSID: '%s'.\n"
+ IDS_PROF_PROFILER_DISABLED "Profilers will not be loaded by the current version of the CLR because of the environment variable setting below. Please consult the documentation for information on how to use this environment variable, and the risks associated with it. Environment variable setting: %s=%s. Profiler CLSID: '%s'.\n"
+ IDS_E_PROF_NOTIFICATION_DISABLED "Profiler was prevented from loading notification profiler due to app settings.\n"
+ IDS_E_PROF_NOTIFICATION_LIMIT_EXCEEDED "Notification profiler was prevented from loading because the limit of notification profilers was reached.\n"
+ IDS_E_PROF_TIMEOUT_WAITING_FOR_CONCURRENT_GC "Profiler timed out on waiting for concurrent GC to finish after '%d' milliseconds. Please configure your profiler to increase its attaching time out value or consult the documentation for the COMPlus_ProfAPI_AttachProfilerMinTimeoutInMs environment variable and try again. Profiler CLSID: '%s'.\n"
+ IDS_PROF_ALREADY_LOADED "A request was made to load a profiler when a profiler was already loaded.\n"
END
EventMask eventMask;
//---------------------------------------------------------------
- // m_dwProfilerEvacuationCounter keeps track of how many profiler
+ // dwProfilerEvacuationCounter keeps track of how many profiler
// callback calls remain on the stack
//---------------------------------------------------------------
// Why volatile?
inline ProfilerInfo *ProfControlBlock::GetProfilerInfo(ProfToEEInterfaceImpl *pProfToEE)
{
ProfilerInfo *pProfilerInfo = NULL;
- IterateProfilers(ProfilerCallbackType::Active,
+ IterateProfilers(ProfilerCallbackType::ActiveOrInitializing,
[](ProfilerInfo *pProfilerInfo, ProfToEEInterfaceImpl *pProfToEE, ProfilerInfo **ppFoundProfilerInfo)
{
if (pProfilerInfo->pProfInterface->m_pProfToEE == pProfToEE)
}
CONTRACTL_END;
- // Always called before Thread created.
- _ASSERTE(GetThreadNULLOk() == NULL);
-
// Try and CoCreate the registered profiler
ReleaseHolder<ICorProfilerCallback2> pCallback2;
HModuleHolder hmodProfilerDLL;
_ASSERTE(m_pProfToEE != NULL);
- // Attach initialization occurs on the AttachThread, which does not have an EEThread
- // object
- _ASSERTE(GetThreadNULLOk() == NULL);
-
// Should only be called on profilers that support ICorProfilerCallback3
_ASSERTE(m_pCallback3 != NULL);
LL_INFO10,
"**PROF: Calling profiler's ProfilerAttachComplete() method.\n"));
- // Attach initialization occurs on the AttachThread, which does not have an EEThread
- // object
- _ASSERTE(GetThreadNULLOk() == NULL);
-
// Should only be called on profilers that support ICorProfilerCallback3
_ASSERTE(m_pCallback3 != NULL);
if (dwExpectedCompletionMilliseconds == 0)
{
- // Pick suitable default if the profiler just leaves this at 0. 5 seconds is
+ // Pick suitable default if the profiler just leaves this at 0. 2.5 seconds is
// reasonable.
- dwExpectedCompletionMilliseconds = 5000;
+ dwExpectedCompletionMilliseconds = 2500;
}
{
const DWORD kdwDefaultMinSleepMs = 300;
// The default "steady state" max sleep is how long we'll wait if, after a couple
- // tries the profiler still hasn't evacuated. Default to every 10 minutes
- const DWORD kdwDefaultMaxSleepMs = 600000;
+ // tries the profiler still hasn't evacuated. Default to every 5 seconds
+ const DWORD kdwDefaultMaxSleepMs = 5000;
static DWORD s_dwMinSleepMs = 0;
static DWORD s_dwMaxSleepMs = 0;
}
CONTRACTL_END;
- PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
+ PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(
kP2EEAllowableAfterAttach | kP2EETriggers,
(LF_CORPROF,
LL_INFO1000,
"**PROF: RequestProfilerDetach.\n"));
#ifdef FEATURE_PROFAPI_ATTACH_DETACH
- return ProfilingAPIDetach::RequestProfilerDetach(g_profControlBlock.GetProfilerInfo(this), dwExpectedCompletionMilliseconds);
+ ProfilerInfo *pProfilerInfo = g_profControlBlock.GetProfilerInfo(this);
+ _ASSERTE(pProfilerInfo != NULL);
+ return ProfilingAPIDetach::RequestProfilerDetach(pProfilerInfo, dwExpectedCompletionMilliseconds);
#else // FEATURE_PROFAPI_ATTACH_DETACH
return E_NOTIMPL;
#endif // FEATURE_PROFAPI_ATTACH_DETACH
namespace Profiler.Tests
{
+ public delegate void ProfilerCallback();
+
[Flags]
public enum ProfileeOptions
{
string profileeArguments = "",
ProfileeOptions profileeOptions = ProfileeOptions.None,
Dictionary<string, string> envVars = null,
- string reverseServerName = null)
+ string reverseServerName = null,
+ bool loadAsNotification = false,
+ int notificationCopies = 1)
{
string arguments;
string program;
if (!profileeOptions.HasFlag(ProfileeOptions.NoStartupAttach))
{
envVars.Add("CORECLR_ENABLE_PROFILING", "1");
- envVars.Add("CORECLR_PROFILER_PATH", profilerPath);
- envVars.Add("CORECLR_PROFILER", "{" + profilerClsid + "}");
+
+ if (loadAsNotification)
+ {
+ StringBuilder builder = new StringBuilder();
+ for(int i = 0; i < notificationCopies; ++i)
+ {
+ builder.Append(profilerPath);
+ builder.Append("=");
+ builder.Append("{");
+ builder.Append(profilerClsid.ToString());
+ builder.Append("}");
+ builder.Append(";");
+ }
+
+ envVars.Add("CORECLR_ENABLE_NOTIFICATION_PROFILERS", "1");
+ envVars.Add("CORECLR_NOTIFICATION_PROFILERS", builder.ToString());
+
+ }
+ else
+ {
+ envVars.Add("CORECLR_PROFILER", "{" + profilerClsid + "}");
+ envVars.Add("CORECLR_PROFILER_PATH", profilerPath);
+ }
}
if (profileeOptions.HasFlag(ProfileeOptions.OptimizationSensitive))
return 100;
}
- private static string GetProfilerPath()
+ public static string GetProfilerPath()
{
string profilerName;
if (TestLibrary.Utilities.IsWindows)
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Threading;
+
+namespace Profiler.Tests
+{
+ class MultiplyLoaded
+ {
+ static readonly Guid MultipleProfilerGuid = new Guid("BFA8EF13-E144-49B9-B95C-FC1C150C7651");
+ static readonly string ProfilerPath = ProfilerTestRunner.GetProfilerPath();
+
+ [DllImport("Profiler")]
+ private static extern void PassCallbackToProfiler(ProfilerCallback callback);
+
+ public static int RunTest(String[] args)
+ {
+ ManualResetEvent _profilerDone = new ManualResetEvent(false);
+ PassCallbackToProfiler(() => _profilerDone.Set());
+
+ ProfilerControlHelpers.AttachProfilerToSelf(MultipleProfilerGuid, ProfilerPath);
+
+ try
+ {
+ Console.WriteLine("Throwing exception");
+ throw new Exception("Test exception!");
+ }
+ catch
+ {
+ // intentionally swallow the exception
+ Console.WriteLine("Exception caught");
+ }
+
+ Console.WriteLine("Waiting for profilers to all detach");
+ if (!_profilerDone.WaitOne(TimeSpan.FromMinutes(5)))
+ {
+ Console.WriteLine("Profiler did not set the callback, test will fail.");
+ }
+
+ return 100;
+ }
+
+ public static int Main(string[] args)
+ {
+ if (args.Length > 0 && args[0].Equals("RunTest", StringComparison.OrdinalIgnoreCase))
+ {
+ return RunTest(args);
+ }
+
+ return ProfilerTestRunner.Run(profileePath: System.Reflection.Assembly.GetExecutingAssembly().Location,
+ testName: "MultiplyLoaded",
+ profilerClsid: MultipleProfilerGuid,
+ loadAsNotification: true,
+ notificationCopies: 2);
+ }
+ }
+}
--- /dev/null
+<Project Sdk="Microsoft.NET.Sdk">
+ <PropertyGroup>
+ <TargetFrameworkIdentifier>.NETCoreApp</TargetFrameworkIdentifier>
+ <OutputType>exe</OutputType>
+ <CLRTestKind>BuildAndRun</CLRTestKind>
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+ <CLRTestPriority>0</CLRTestPriority>
+ </PropertyGroup>
+ <ItemGroup>
+ <Compile Include="$(MSBuildProjectName).cs" />
+ <ProjectReference Include="$(TestSourceDir)Common/CoreCLRTestLibrary/CoreCLRTestLibrary.csproj" />
+ <ProjectReference Include="../common/profiler_common.csproj" />
+ <ProjectReference Include="$(MSBuildThisFileDirectory)/../native/CMakeLists.txt" />
+ </ItemGroup>
+</Project>
gcprofiler/gcprofiler.cpp
getappdomainstaticaddress/getappdomainstaticaddress.cpp
metadatagetdispenser/metadatagetdispenser.cpp
+ multiple/multiple.cpp
nullprofiler/nullprofiler.cpp
rejitprofiler/rejitprofiler.cpp
rejitprofiler/ilrewriter.cpp
#include "rejitprofiler/rejitprofiler.h"
#include "releaseondetach/releaseondetach.h"
#include "transitions/transitions.h"
+#include "multiple/multiple.h"
ClassFactory::ClassFactory(REFCLSID clsid) : refCount(0), clsid(clsid)
{
return CLASS_E_NOAGGREGATION;
}
- //A little simplistic, we create an instance of every profiler, then return the one whose CLSID matches
- Profiler* profilers[] = {
- new GCAllocateProfiler(),
- new GCBasicProfiler(),
- new ReJITProfiler(),
- new EventPipeReadingProfiler(),
- new EventPipeWritingProfiler(),
- new MetaDataGetDispenser(),
- new GetAppDomainStaticAddress(),
- new SlowPathELTProfiler(),
- new GCProfiler(),
- new ReleaseOnDetach(),
- new Transitions(),
- new NullProfiler()
- // add new profilers here
- };
-
Profiler* profiler = nullptr;
- for (unsigned int i = 0; i < sizeof(profilers)/sizeof(Profiler*); i++)
- {
- if (clsid == profilers[i]->GetClsid())
- {
- profiler = profilers[i];
- break;
- }
- }
-
- if (profiler == nullptr)
+ if (clsid == GCAllocateProfiler::GetClsid())
+ {
+ profiler = new GCAllocateProfiler();
+ }
+ else if (clsid == GCBasicProfiler::GetClsid())
+ {
+ profiler = new GCBasicProfiler();
+ }
+ else if (clsid == ReJITProfiler::GetClsid())
+ {
+ profiler = new ReJITProfiler();
+ }
+ else if (clsid == EventPipeReadingProfiler::GetClsid())
+ {
+ profiler = new EventPipeReadingProfiler();
+ }
+ else if (clsid == EventPipeWritingProfiler::GetClsid())
+ {
+ profiler = new EventPipeWritingProfiler();
+ }
+ else if (clsid == MetaDataGetDispenser::GetClsid())
+ {
+ profiler = new MetaDataGetDispenser();
+ }
+ else if (clsid == GetAppDomainStaticAddress::GetClsid())
+ {
+ profiler = new GetAppDomainStaticAddress();
+ }
+ else if (clsid == SlowPathELTProfiler::GetClsid())
+ {
+ profiler = new SlowPathELTProfiler();
+ }
+ else if (clsid == GCProfiler::GetClsid())
+ {
+ profiler = new GCProfiler();
+ }
+ else if (clsid == ReleaseOnDetach::GetClsid())
+ {
+ profiler = new ReleaseOnDetach();
+ }
+ else if (clsid == Transitions::GetClsid())
+ {
+ profiler = new Transitions();
+ }
+ else if (clsid == NullProfiler::GetClsid())
+ {
+ profiler = new NullProfiler();
+ }
+ else if (clsid == MultiplyLoaded::GetClsid())
+ {
+ profiler = new MultiplyLoaded();
+ }
+ else
{
printf("No profiler found in ClassFactory::CreateInstance. Did you add your profiler to the list?\n");
return E_FAIL;
_testType(TestType::Unknown)
{}
- virtual GUID GetClsid();
+ static GUID GetClsid();
virtual HRESULT STDMETHODCALLTYPE Initialize(IUnknown* pICorProfilerInfoUnk);
virtual HRESULT STDMETHODCALLTYPE Shutdown();
_metadataCache()
{}
- virtual GUID GetClsid();
+ static GUID GetClsid();
virtual HRESULT STDMETHODCALLTYPE Initialize(IUnknown* pICorProfilerInfoUnk);
_simpleEvent(0)
{}
- virtual GUID GetClsid();
+ static GUID GetClsid();
virtual HRESULT STDMETHODCALLTYPE Initialize(IUnknown* pICorProfilerInfoUnk);
virtual HRESULT STDMETHODCALLTYPE Shutdown();
virtual HRESULT STDMETHODCALLTYPE JITCompilationStarted(FunctionID functionId, BOOL fIsSafeToBlock);
_failures(0)
{}
- virtual GUID GetClsid();
+ static GUID GetClsid();
virtual HRESULT STDMETHODCALLTYPE Initialize(IUnknown* pICorProfilerInfoUnk);
virtual HRESULT STDMETHODCALLTYPE ObjectAllocated(ObjectID objectId, ClassID classId);
virtual HRESULT STDMETHODCALLTYPE Shutdown();
_failures(0)
{}
- virtual GUID GetClsid();
+ static GUID GetClsid();
virtual HRESULT STDMETHODCALLTYPE Initialize(IUnknown* pICorProfilerInfoUnk);
virtual HRESULT STDMETHODCALLTYPE Shutdown();
virtual HRESULT STDMETHODCALLTYPE GarbageCollectionStarted(int cGenerations, BOOL generationCollected[], COR_PRF_GC_REASON reason);
_objectReferencesSeen()
{}
- virtual GUID GetClsid();
+ static GUID GetClsid();
virtual HRESULT STDMETHODCALLTYPE Initialize(IUnknown* pICorProfilerInfoUnk);
virtual HRESULT STDMETHODCALLTYPE Shutdown();
virtual HRESULT STDMETHODCALLTYPE GarbageCollectionStarted(int cGenerations, BOOL generationCollected[], COR_PRF_GC_REASON reason);
GetAppDomainStaticAddress();
virtual ~GetAppDomainStaticAddress();
- virtual GUID GetClsid() override;
+ static GUID GetClsid();
virtual HRESULT STDMETHODCALLTYPE Initialize(IUnknown* pICorProfilerInfoUnk) override;
virtual HRESULT STDMETHODCALLTYPE Shutdown() override;
DEFINE_GUID(IID_ICorProfilerCallback8, 0x5BED9B15,0xC079,0x4D47,0xBF,0xE2,0x21,0x5A,0x14,0x0C,0x07,0xE0);
DEFINE_GUID(IID_ICorProfilerCallback9, 0x27583EC3,0xC8F5,0x482F,0x80,0x52,0x19,0x4B,0x8C,0xE4,0x70,0x5A);
DEFINE_GUID(IID_ICorProfilerCallback10, 0xCEC5B60E,0xC69C,0x495F,0x87,0xF6,0x84,0xD2,0x8E,0xE1,0x6F,0xFB);
+DEFINE_GUID(IID_ICorProfilerCallback11, 0x42350846,0xAAED,0x47F7,0xB1,0x28,0xFD,0x0C,0x98,0x88,0x1C,0xDE);
DEFINE_GUID(IID_ICorProfilerInfo, 0x28B5557D,0x3F3F,0x48B4,0x90,0xB2,0x5F,0x9E,0xEA,0x2F,0x6C,0x48);
DEFINE_GUID(IID_ICorProfilerInfo2, 0xCC0935CD,0xA518,0x487D,0xB0,0xBB,0xA9,0x32,0x14,0xE6,0x54,0x78);
DEFINE_GUID(IID_ICorProfilerInfo3, 0xB555ED4F,0x452A,0x4E54,0x8B,0x39,0xB5,0x36,0x0B,0xAD,0x32,0xA0);
MetaDataGetDispenser();
virtual ~MetaDataGetDispenser();
- virtual GUID GetClsid();
+ static GUID GetClsid();
virtual HRESULT STDMETHODCALLTYPE Initialize(IUnknown* pICorProfilerInfoUnk);
virtual HRESULT STDMETHODCALLTYPE Shutdown();
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#include "multiple.h"
+#include <thread>
+
+#define MAX_PROFILERS 3
+
+using std::thread;
+
+std::atomic<int> MultiplyLoaded::_exceptionThrownSeenCount(0);
+std::atomic<int> MultiplyLoaded::_detachCount(0);
+std::atomic<int> MultiplyLoaded::_failures(0);
+
+GUID MultiplyLoaded::GetClsid()
+{
+ // {BFA8EF13-E144-49B9-B95C-FC1C150C7651}
+ GUID clsid = { 0xBFA8EF13, 0xE144, 0x49B9, { 0xB9, 0x5C, 0xFC, 0x1C, 0x15, 0x0C, 0x76, 0x51 } };
+ return clsid;
+}
+
+HRESULT MultiplyLoaded::InitializeCommon(IUnknown* pICorProfilerInfoUnk)
+{
+ Profiler::Initialize(pICorProfilerInfoUnk);
+
+ HRESULT hr = S_OK;
+ printf("Setting exception mask\n");
+ if (FAILED(hr = pCorProfilerInfo->SetEventMask2(COR_PRF_MONITOR_EXCEPTIONS, 0)))
+ {
+ _failures++;
+ printf("FAIL: ICorProfilerInfo::SetEventMask2() failed hr=0x%x", hr);
+ return hr;
+ }
+
+ return S_OK;
+}
+
+HRESULT MultiplyLoaded::Initialize(IUnknown* pICorProfilerInfoUnk)
+{
+ return InitializeCommon(pICorProfilerInfoUnk);
+}
+
+HRESULT MultiplyLoaded::InitializeForAttach(IUnknown* pICorProfilerInfoUnk, void* pvClientData, UINT cbClientData)
+{
+ return InitializeCommon(pICorProfilerInfoUnk);
+}
+
+HRESULT MultiplyLoaded::LoadAsNotficationOnly(BOOL *pbNotificationOnly)
+{
+ *pbNotificationOnly = TRUE;
+ return S_OK;
+}
+
+HRESULT MultiplyLoaded::ProfilerDetachSucceeded()
+{
+ ++_detachCount;
+
+ printf("ProfilerDetachSucceeded _detachCount=%d\n", _detachCount.load());
+ if (_detachCount == (MAX_PROFILERS - 1)
+ && _exceptionThrownSeenCount >= (MAX_PROFILERS - 1)
+ && _failures == 0)
+ {
+ printf("PROFILER TEST PASSES\n");
+ NotifyManagedCodeViaCallback(pCorProfilerInfo);
+ }
+
+ return S_OK;
+}
+
+HRESULT MultiplyLoaded::ExceptionThrown(ObjectID thrownObjectId)
+{
+ int seen = _exceptionThrownSeenCount++;
+
+ printf("MultiplyLoaded::ExceptionThrown, number seen = %d\n", seen);
+
+ thread detachThread([&]()
+ {
+ printf("Requesting detach!!\n");
+ HRESULT hr = pCorProfilerInfo->RequestProfilerDetach(0);
+ printf("RequestProfilerDetach hr=0x%x\n", hr);
+ });
+
+ detachThread.detach();
+
+ return S_OK;
+}
+
+HRESULT MultiplyLoaded::Shutdown()
+{
+ Profiler::Shutdown();
+
+ fflush(stdout);
+
+ return S_OK;
+}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#pragma once
+
+#include "../profiler.h"
+
+class MultiplyLoaded : public Profiler
+{
+public:
+ MultiplyLoaded() : Profiler()
+ {}
+
+ static GUID GetClsid();
+ virtual HRESULT STDMETHODCALLTYPE Initialize(IUnknown* pICorProfilerInfoUnk);
+ virtual HRESULT STDMETHODCALLTYPE InitializeForAttach(IUnknown* pICorProfilerInfoUnk, void* pvClientData, UINT cbClientData);
+ virtual HRESULT STDMETHODCALLTYPE Shutdown();
+ virtual HRESULT STDMETHODCALLTYPE LoadAsNotficationOnly(BOOL *pbNotificationOnly);
+
+ virtual HRESULT STDMETHODCALLTYPE ProfilerDetachSucceeded();
+ virtual HRESULT STDMETHODCALLTYPE ExceptionThrown(ObjectID thrownObjectId);
+
+private:
+ static std::atomic<int> _exceptionThrownSeenCount;
+ static std::atomic<int> _detachCount;
+ static std::atomic<int> _failures;
+
+ HRESULT InitializeCommon(IUnknown* pCorProfilerInfoUnk);
+};
}
- virtual GUID GetClsid();
+ static GUID GetClsid();
virtual HRESULT STDMETHODCALLTYPE Initialize(IUnknown* pICorProfilerInfoUnk);
virtual HRESULT STDMETHODCALLTYPE Shutdown();
};
std::atomic<bool> ShutdownGuard::s_preventHooks(false);
std::atomic<int> ShutdownGuard::s_hooksInProgress(0);
+ProfilerCallback Profiler::s_callback;
+ManualEvent Profiler::s_callbackSet;
+
Profiler::Profiler() : refCount(0), pCorProfilerInfo(nullptr)
{
Profiler::Instance = this;
return S_OK;
}
+HRESULT STDMETHODCALLTYPE Profiler::LoadAsNotficationOnly(BOOL *pbNotificationOnly)
+{
+ *pbNotificationOnly = FALSE;
+ return S_OK;
+}
+
HRESULT STDMETHODCALLTYPE Profiler::QueryInterface(REFIID riid, void **ppvObject)
{
- if (riid == __uuidof(ICorProfilerCallback10) ||
+ if (riid == __uuidof(ICorProfilerCallback11) ||
+ riid == __uuidof(ICorProfilerCallback10) ||
riid == __uuidof(ICorProfilerCallback9) ||
riid == __uuidof(ICorProfilerCallback8) ||
riid == __uuidof(ICorProfilerCallback7) ||
void Profiler::SetCallback(ProfilerCallback cb)
{
assert(cb != NULL);
- callback = cb;
- callbackSet.Signal();
+ s_callback = cb;
+ s_callbackSet.Signal();
}
-void Profiler::NotifyManagedCodeViaCallback()
+void Profiler::NotifyManagedCodeViaCallback(ICorProfilerInfo11 *pCorProfilerInfo)
{
- callbackSet.Wait();
+ s_callbackSet.Wait();
thread callbackThread([&]()
{
// some crst order asserts if we call back in to managed code. Spin up
// a new thread to avoid that.
pCorProfilerInfo->InitializeCurrentThread();
- callback();
+ s_callback();
});
callbackThread.join();
extern "C" EXPORT void STDMETHODCALLTYPE PassCallbackToProfiler(ProfilerCallback callback)
{
- Profiler::Instance->SetCallback(callback);
+ Profiler::SetCallback(callback);
}
#ifndef WIN32
return; \
}
-class Profiler : public ICorProfilerCallback10
+class Profiler : public ICorProfilerCallback11
{
private:
std::atomic<int> refCount;
- ProfilerCallback callback;
- ManualEvent callbackSet;
+ static ProfilerCallback s_callback;
+ static ManualEvent s_callbackSet;
protected:
+ static void NotifyManagedCodeViaCallback(ICorProfilerInfo11 *pCorProfilerInfo);
+
String GetClassIDName(ClassID classId);
String GetFunctionIDName(FunctionID funcId);
String GetModuleIDName(ModuleID modId);
- void NotifyManagedCodeViaCallback();
public:
static Profiler *Instance;
+ static void SetCallback(ProfilerCallback callback);
ICorProfilerInfo11* pCorProfilerInfo;
Profiler();
virtual ~Profiler();
- virtual GUID GetClsid() = 0;
HRESULT STDMETHODCALLTYPE Initialize(IUnknown* pICorProfilerInfoUnk) override;
HRESULT STDMETHODCALLTYPE Shutdown() override;
HRESULT STDMETHODCALLTYPE AppDomainCreationStarted(AppDomainID appDomainId) override;
ULONG numStackFrames,
UINT_PTR stackFrames[]) override;
HRESULT STDMETHODCALLTYPE EventPipeProviderCreated(EVENTPIPE_PROVIDER provider) override;
+ HRESULT STDMETHODCALLTYPE LoadAsNotficationOnly(BOOL *pbNotificationOnly) override;
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) override;
ULONG STDMETHODCALLTYPE AddRef(void) override;
ULONG STDMETHODCALLTYPE Release(void) override;
-
- void SetCallback(ProfilerCallback callback);
};
ReJITProfiler();
virtual ~ReJITProfiler() = default;
- virtual GUID GetClsid();
+ static GUID GetClsid();
virtual HRESULT STDMETHODCALLTYPE Initialize(IUnknown* pICorProfilerInfoUnk);
virtual HRESULT STDMETHODCALLTYPE Shutdown();
fflush(stdout);
- NotifyManagedCodeViaCallback();
+ NotifyManagedCodeViaCallback(pCorProfilerInfo);
}
GUID ReleaseOnDetach::GetClsid()
ReleaseOnDetach();
virtual ~ReleaseOnDetach();
- virtual GUID GetClsid();
+ static GUID GetClsid();
virtual HRESULT STDMETHODCALLTYPE InitializeForAttach(IUnknown* pCorProfilerInfoUnk, void* pvClientData, UINT cbClientData);
virtual HRESULT STDMETHODCALLTYPE Shutdown();
Transitions();
virtual ~Transitions() = default;
- virtual GUID GetClsid();
+ static GUID GetClsid();
virtual HRESULT STDMETHODCALLTYPE Initialize(IUnknown* pICorProfilerInfoUnk);
virtual HRESULT STDMETHODCALLTYPE Shutdown();
virtual HRESULT STDMETHODCALLTYPE UnmanagedToManagedTransition(FunctionID functionID, COR_PRF_TRANSITION_REASON reason);
namespace Profiler.Tests
{
- public delegate void ProfilerCallback();
-
class ReleaseOnShutdown
{
private static readonly Guid ReleaseOnShutdownGuid = new Guid("B8C47A29-9C1D-4EEA-ABA0-8E8B3E3B792E");
- private static ManualResetEvent _profilerDone;
-
[DllImport("Profiler")]
private static extern void PassCallbackToProfiler(ProfilerCallback callback);
string rootPath = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
string profilerPath = Path.Combine(rootPath, profilerName);
- _profilerDone = new ManualResetEvent(false);
+ ManualResetEvent _profilerDone = new ManualResetEvent(false);
Console.WriteLine($"Attaching profiler {profilerPath} to self.");
ProfilerControlHelpers.AttachProfilerToSelf(ReleaseOnShutdownGuid, profilerPath);