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

[mono] Extend mono AOT compiler to ingest .mibc profiles #70194

Merged
merged 6 commits into from
Jun 6, 2022

Conversation

mdh1418
Copy link
Member

@mdh1418 mdh1418 commented Jun 3, 2022

Part of #69268 and #69512.

In effort to bring back Profiled Ahead-Of-Time compilation on Mono through leveraging EventPipe diagnostics-tracing and CoreCLR's dotnet-pgo tool, this PR enables Mono's AOT Compiler to directly consume a .mibc (Managed Instrumented Block Counts) Portable Executable file generated through dotnet-pgo for the purpose of AOT compiling methods traced during an app run.

This follows the work to emit MethodDetails and BulkType events on the mono runtime, which was imperative to know exactly which methods were encountered during an app run.


Prior Profiled AOT .aotprofile processing

Mono's AOT Compiler (mono-sgen) prior Profiled AOT story involved a .aotprofile file which recorded identifying components of methods, embedded types, generic instantiations of methods/types, and the overarching modules https://github.com/mono/mono/tree/main/mcs/class/Mono.Profiler.Log/Mono.Profiler.Aot. The compiler, when compiling particular assemblies, would leverage .aotprofile data to determine which methods to AOT compile by:

  1. Loading the data into ProfileData structs
  2. Resolving the ProfileData structs into the corresponding images, classes, generic instantiations, and methods within the assemblies loaded through the compiler
  3. Adding the .aotprofile methods with some filtering to a particular assembly's (X.dll) AOT image (X.dll.so/X.dll.dylib/other native extensions) if they are inherently from that assembly, or related to that assembly. (e.g. method List<Q>.ToArray() where List is in System.Private.CoreLib.dll, but Q is in Q.dll, the method is related to assembly Q.dll)

.aotprofile example

Proposed Profiled AOT .mibc processing

The .mibc file format as a Portable Executable already contains comprehensive information of traced methods (as a result of MethodDetails and BulkType events from #68571). As such, there is no need to neither generate nor load ProfileData structs. Instead, we:

  1. Leverage .mibc's AssemblyDictionary global function to obtain each mibcGroupMethod - add_mibc_profile_methods
  2. Iterate through each method entry within a mibcGroupMethod - add_mibc_group_method_methods
  3. Add individual .mibc methods using the same filter and method addition used when processing .aotprofile - add_single_mibc_profile_method

.mibc from HelloWorld mono sample
Breakdown of HelloWorld Sample .mibc file


This PR makes the following changes:

  1. Introduces .mibc profile file into the mono AOT compilation pipeline
  2. Extends mono's image handling to allow for loading MemberRefs from non executable images and replace boolean image open/load options with MonoImage(Open/Load)Options structs for scalability
  3. Bootstrap the MonoAOTCompiler to use the introduced .mibc processing

Using the mono-sgen compiler to process .mibc

  1. ./build -s mono+libs -os <OS> -arch <arch> -c <config>
  2. MONO_LOG_MASK=asm MONO_LOG_LEVEL=debug MONO_PATH=./artifacts/bin/HelloWorld/arm64/Release/osx-arm64/publish/ artifacts/obj/mono/OSX.arm64.Release/out/bin/mono-sgen --aot=profile-only,mibc-profile=/Users/mihw/runtime_two/HelloWorld_arm64.mibc artifacts/bin/HelloWorld/arm64/Release/osx-arm64/publish/System.Console.dll artifacts/bin/HelloWorld/arm64/Release/osx-arm64/publish/System.Private.CoreLib.dll artifacts/bin/HelloWorld/arm64/Release/osx-arm64/publish/HelloWorld.dll
    Screen Shot 2022-06-03 at 12 08 04 PM

@dotnet-issue-labeler
Copy link

I couldn't figure out the best area label to add to this PR. If you have write-permissions please help me learn by adding exactly one area label.

@ghost ghost assigned mdh1418 Jun 3, 2022
@mdh1418 mdh1418 marked this pull request as draft June 3, 2022 05:44
@mdh1418 mdh1418 mentioned this pull request Jun 3, 2022
6 tasks
Copy link
Member

@lambdageek lambdageek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good.

Couple of things i'd like to see changed:

  1. let's do some cleanup in image.c
  2. let's make the code that iterates over the mibc group a bit more aware of the format
  3. instead of copy/pasting the AOT "related methods" logic, extract it into a function and share between the mibc and legacy aot profiler

src/mono/mono/metadata/assembly.c Outdated Show resolved Hide resolved
src/mono/mono/metadata/image.c Outdated Show resolved Hide resolved
src/mono/mono/metadata/metadata-internals.h Outdated Show resolved Hide resolved
src/mono/mono/mini/aot-compiler.c Show resolved Hide resolved
src/mono/mono/mini/aot-compiler.c Outdated Show resolved Hide resolved
@mdh1418 mdh1418 marked this pull request as ready for review June 3, 2022 19:08
@mdh1418 mdh1418 force-pushed the mono_aot_compiler_ingest_mibc branch from e636d86 to 15372c2 Compare June 3, 2022 21:12
@mdh1418 mdh1418 force-pushed the mono_aot_compiler_ingest_mibc branch from 15372c2 to b1fb61e Compare June 4, 2022 03:35
Copy link
Member

@lambdageek lambdageek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. A couple of nits, some portability improvements, and a bit more image_open refactoring suggestions

src/mono/mono/mini/aot-compiler.c Show resolved Hide resolved
src/mono/mono/mini/aot-compiler.c Outdated Show resolved Hide resolved
continue;

g_assert (opcodeIp + 4 < opcodeEnd);
guint32 token = *(guint32 *)(opcodeIp + 1);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
guint32 token = *(guint32 *)(opcodeIp + 1);
guint32 token = read32 (opcodeIp + 1);

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! I thought it would work, but convinced myself it didnt when xcode lldb complained about expr read32 (opcodeIp + 1). Is there a way to have the xcode lldb recognize methods such as read32?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think if you compile the runtime with "enough" debug information (maybe -g3) then debuggers ought to recognize macros like read32. not sure if that really works with clang+lldb

src/mono/mono/metadata/image-internals.h Outdated Show resolved Hide resolved
src/mono/mono/metadata/image-internals.h Outdated Show resolved Hide resolved
src/mono/mono/metadata/image-internals.h Outdated Show resolved Hide resolved
@mdh1418
Copy link
Member Author

mdh1418 commented Jun 6, 2022

The failures are unrelated to this PR and have issues created.

@mdh1418 mdh1418 merged commit 2b21dcd into dotnet:main Jun 6, 2022
@mdh1418 mdh1418 deleted the mono_aot_compiler_ingest_mibc branch June 6, 2022 21:20
@@ -9,6 +9,17 @@
#include <mono/metadata/image.h>
#include <mono/metadata/loader-internals.h>

typedef struct {
int dont_care_about_cli : 1;
Copy link
Member

@lateralusX lateralusX Jun 7, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any specific reason why these parameters where inverted compared to the arguments passed to functions below?

Copy link
Member

@lateralusX lateralusX Jun 7, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any particular win to use bit fields for this? I think it would be much clearer to use bool type instead, it would also make the init code more clear.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any specific reason why these parameters where inverted compared to the arguments passed to functions below?

Turns out most of the time we care about cli and pecoff, so the callers become a bit simpler: they can just initialize the options struct to zero.

Any particular win to use bit fields for this? I think it would be much clearer to use bool type instead, it would also make the init code more clear.

I think I suggested bitfields more out of habit than any rational reason. These could be booleans.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! I'll modify these to a boolean type in the upcoming PR

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(the MonoImage:not_executable we do want to keep in a bitfield - we try to keep the size of that structure down)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is now in PR #71657 @lateralusX @lambdageek

@ghost ghost locked as resolved and limited conversation to collaborators Aug 4, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants