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

Emit ICorProfiler ModuleLoadFinished for dynamic modules #77068

Merged
merged 3 commits into from
Oct 17, 2022
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
8 changes: 8 additions & 0 deletions src/coreclr/vm/domainassembly.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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())
Expand Down
1 change: 1 addition & 0 deletions src/tests/profiler/native/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 5 additions & 0 deletions src/tests/profiler/native/classfactory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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");
Expand Down
95 changes: 95 additions & 0 deletions src/tests/profiler/native/moduleload/moduleload.cpp
Original file line number Diff line number Diff line change
@@ -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;
}
42 changes: 42 additions & 0 deletions src/tests/profiler/native/moduleload/moduleload.h
Original file line number Diff line number Diff line change
@@ -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<int> _assemblyLoadStartedCount;
std::atomic<int> _assemblyLoadFinishedCount;
std::atomic<int> _moduleLoadStartedCount;
std::atomic<int> _moduleLoadFinishedCount;
std::atomic<int> _failures;

HRESULT InitializeCommon(IUnknown* pCorProfilerInfoUnk);
};
46 changes: 46 additions & 0 deletions src/tests/profiler/unittest/moduleload.cs
Original file line number Diff line number Diff line change
@@ -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);
}
}
}
20 changes: 20 additions & 0 deletions src/tests/profiler/unittest/moduleload.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworkIdentifier>.NETCoreApp</TargetFrameworkIdentifier>
<OutputType>exe</OutputType>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<!-- This test provides no interesting scenarios for GCStress -->
<GCStressIncompatible>true</GCStressIncompatible>
<!-- The test launches a secondary process and process launch creates
an infinite event loop in the SocketAsyncEngine on Linux. Since
runincontext loads even framework assemblies into the unloadable
context, locals in this loop prevent unloading -->
<UnloadabilityIncompatible>true</UnloadabilityIncompatible>
</PropertyGroup>
<ItemGroup>
<Compile Include="$(MSBuildProjectName).cs" />
<ProjectReference Include="$(TestSourceDir)Common/CoreCLRTestLibrary/CoreCLRTestLibrary.csproj" />
<ProjectReference Include="../common/profiler_common.csproj" />
<CMakeProjectReference Include="$(MSBuildThisFileDirectory)/../native/CMakeLists.txt" />
</ItemGroup>
</Project>