diff --git a/src/coreclr/vm/domainassembly.cpp b/src/coreclr/vm/domainassembly.cpp index 2ae508ca073c5..fc9821780b4a6 100644 --- a/src/coreclr/vm/domainassembly.cpp +++ b/src/coreclr/vm/domainassembly.cpp @@ -810,6 +810,14 @@ void DomainAssembly::DeliverSyncEvents() GetModule()->NotifyEtwLoadFinished(S_OK); +#ifdef PROFILING_SUPPORTED + if (!IsProfilerNotified()) + { + SetProfilerNotified(); + GetModule()->NotifyProfilerLoadFinished(S_OK); + } +#endif + #ifdef DEBUGGING_SUPPORTED GCX_COOP(); if (!IsDebuggerNotified()) diff --git a/src/tests/profiler/native/CMakeLists.txt b/src/tests/profiler/native/CMakeLists.txt index f72f359af3ceb..a3d2d77902f38 100644 --- a/src/tests/profiler/native/CMakeLists.txt +++ b/src/tests/profiler/native/CMakeLists.txt @@ -14,6 +14,7 @@ set(SOURCES handlesprofiler/handlesprofiler.cpp inlining/inlining.cpp metadatagetdispenser/metadatagetdispenser.cpp + moduleload/moduleload.cpp multiple/multiple.cpp nullprofiler/nullprofiler.cpp rejitprofiler/rejitprofiler.cpp diff --git a/src/tests/profiler/native/classfactory.cpp b/src/tests/profiler/native/classfactory.cpp index 6bc76c21f8ac2..418b0b680830b 100644 --- a/src/tests/profiler/native/classfactory.cpp +++ b/src/tests/profiler/native/classfactory.cpp @@ -17,6 +17,7 @@ #include "transitions/transitions.h" #include "multiple/multiple.h" #include "inlining/inlining.h" +#include "moduleload/moduleload.h" ClassFactory::ClassFactory(REFCLSID clsid) : refCount(0), clsid(clsid) { @@ -124,6 +125,10 @@ HRESULT STDMETHODCALLTYPE ClassFactory::CreateInstance(IUnknown *pUnkOuter, REFI { profiler = new HandlesProfiler(); } + else if (clsid == ModuleLoad::GetClsid()) + { + profiler = new ModuleLoad(); + } else { printf("No profiler found in ClassFactory::CreateInstance. Did you add your profiler to the list?\n"); diff --git a/src/tests/profiler/native/moduleload/moduleload.cpp b/src/tests/profiler/native/moduleload/moduleload.cpp new file mode 100644 index 0000000000000..008ecdfd8d271 --- /dev/null +++ b/src/tests/profiler/native/moduleload/moduleload.cpp @@ -0,0 +1,95 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#include "moduleload.h" + +GUID ModuleLoad::GetClsid() +{ + // {1774B2E5-028B-4FA8-9DE5-26218CBCBBAC } + GUID clsid = {0x1774b2e5, 0x028b, 0x4fa8, {0x9d, 0xe5, 0x26, 0x21, 0x8c, 0xbc, 0xbb, 0xac}}; + return clsid; +} + +HRESULT ModuleLoad::InitializeCommon(IUnknown* pICorProfilerInfoUnk) +{ + Profiler::Initialize(pICorProfilerInfoUnk); + + HRESULT hr = S_OK; + printf("Setting exception mask\n"); + if (FAILED(hr = pCorProfilerInfo->SetEventMask2(COR_PRF_MONITOR_MODULE_LOADS | COR_PRF_MONITOR_ASSEMBLY_LOADS, 0))) + { + _failures++; + printf("FAIL: ICorProfilerInfo::SetEventMask2() failed hr=0x%x", hr); + return hr; + } + + return S_OK; +} + +HRESULT ModuleLoad::Initialize(IUnknown* pICorProfilerInfoUnk) +{ + return InitializeCommon(pICorProfilerInfoUnk); +} + +HRESULT ModuleLoad::InitializeForAttach(IUnknown* pICorProfilerInfoUnk, void* pvClientData, UINT cbClientData) +{ + return InitializeCommon(pICorProfilerInfoUnk); +} + +HRESULT ModuleLoad::LoadAsNotificationOnly(BOOL *pbNotificationOnly) +{ + *pbNotificationOnly = TRUE; + return S_OK; +} + +HRESULT ModuleLoad::AssemblyLoadStarted(AssemblyID assemblyId) +{ + _assemblyLoadStartedCount++; + return S_OK; +} + +HRESULT ModuleLoad::AssemblyLoadFinished(AssemblyID assemblyId, HRESULT hrStatus) +{ + _assemblyLoadFinishedCount++; + return S_OK; +} + +HRESULT ModuleLoad::ModuleLoadStarted(ModuleID moduleId) +{ + _moduleLoadStartedCount++; + return S_OK; +} + +HRESULT ModuleLoad::ModuleLoadFinished(ModuleID moduleId, HRESULT hrStatus) +{ + _moduleLoadFinishedCount++; + return S_OK; +} + + +HRESULT ModuleLoad::Shutdown() +{ + Profiler::Shutdown(); + + if(_failures == 0 + && (_moduleLoadStartedCount != 0) + && (_assemblyLoadStartedCount != 0) + && (_moduleLoadStartedCount == _moduleLoadFinishedCount) + && (_assemblyLoadStartedCount == _assemblyLoadFinishedCount)) + { + printf("PROFILER TEST PASSES\n"); + } + else + { + printf("PROFILER TEST FAILED, failures=%d moduleLoadStarted=%d moduleLoadFinished=%d assemblyLoadStarted=%d assemblyLoadFinished=%d\n", + _failures.load(), + _moduleLoadStartedCount.load(), + _moduleLoadFinishedCount.load(), + _assemblyLoadStartedCount.load(), + _assemblyLoadFinishedCount.load()); + } + + fflush(stdout); + + return S_OK; +} diff --git a/src/tests/profiler/native/moduleload/moduleload.h b/src/tests/profiler/native/moduleload/moduleload.h new file mode 100644 index 0000000000000..56ccc13125019 --- /dev/null +++ b/src/tests/profiler/native/moduleload/moduleload.h @@ -0,0 +1,42 @@ +// 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 ModuleLoad : public Profiler +{ +public: + + ModuleLoad() : + Profiler(), + _assemblyLoadStartedCount(0), + _assemblyLoadFinishedCount(0), + _moduleLoadStartedCount(0), + _moduleLoadFinishedCount(0), + _failures(0) + { + + } + + 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 LoadAsNotificationOnly(BOOL *pbNotificationOnly); + + virtual HRESULT STDMETHODCALLTYPE AssemblyLoadStarted(AssemblyID assemblyId); + virtual HRESULT STDMETHODCALLTYPE AssemblyLoadFinished(AssemblyID assemblyId, HRESULT hrStatus); + virtual HRESULT STDMETHODCALLTYPE ModuleLoadStarted(ModuleID moduleId); + virtual HRESULT STDMETHODCALLTYPE ModuleLoadFinished(ModuleID moduleId, HRESULT hrStatus); + +private: + std::atomic _assemblyLoadStartedCount; + std::atomic _assemblyLoadFinishedCount; + std::atomic _moduleLoadStartedCount; + std::atomic _moduleLoadFinishedCount; + std::atomic _failures; + + HRESULT InitializeCommon(IUnknown* pCorProfilerInfoUnk); +}; diff --git a/src/tests/profiler/unittest/moduleload.cs b/src/tests/profiler/unittest/moduleload.cs new file mode 100644 index 0000000000000..17e1312d8b096 --- /dev/null +++ b/src/tests/profiler/unittest/moduleload.cs @@ -0,0 +1,46 @@ +// 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.IO; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Threading; +using System.Reflection; +using System.Reflection.Emit; + +namespace Profiler.Tests +{ + class ModuleLoadTest + { + private static readonly Guid ModuleLoadGuid = new Guid("1774B2E5-028B-4FA8-9DE5-26218CBCBBAC"); + + public static int RunTest(string[] args) + { + var type = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("TestAssembly"), AssemblyBuilderAccess.Run) + .DefineDynamicModule("TestModule") + .DefineType("TestClass", TypeAttributes.Public) + .CreateType(); + + var obj = Activator.CreateInstance(type); + if (obj == null) + { + throw new NullReferenceException(); + } + + 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: "UnitTestModuleLoad", + profilerClsid: ModuleLoadGuid); + } + } +} diff --git a/src/tests/profiler/unittest/moduleload.csproj b/src/tests/profiler/unittest/moduleload.csproj new file mode 100644 index 0000000000000..e94b734bb5a97 --- /dev/null +++ b/src/tests/profiler/unittest/moduleload.csproj @@ -0,0 +1,20 @@ + + + .NETCoreApp + exe + true + + true + + true + + + + + + + +