Skip to content

Improve JitDisasm for top-level statements, expose DumpJittedMethods in Release - #74090

Merged
EgorBo merged 17 commits into
dotnet:mainfrom
EgorBo:improve-jitdisasm
Aug 22, 2022
Merged

Improve JitDisasm for top-level statements, expose DumpJittedMethods in Release#74090
EgorBo merged 17 commits into
dotnet:mainfrom
EgorBo:improve-jitdisasm

Conversation

@EgorBo

@EgorBoEgorBo commented Aug 17, 2022

Copy link
Copy Markdown
Member

For top-level statements (which are used by default when one creates console app via dotnet new console) JitDisasm wasn't easy to use for e.g.:

usingSystem;Foo();voidFoo()=>Console.WriteLine("Foo");

Both of these:

DOTNET_JitDisasm=Main
DOTNET_JitDisasm=Foo

didn't work as they had to be <Main>$ and <<Main>$>g__Foo|0_1() but now they should work as is.

Also, expose DOTNET_DumpJittedMethods=1 in Release so users can ask JIT to list all methods it's jitting - closes#74084
Example of its output:

JIT compiling 310 [Tier0]System.IO.StreamWriter::Write, ILsize=14
JIT compiling 311 [Tier0]System.String::op_Implicit, ILsize=31
JIT compiling 312 [Tier0]System.String::GetRawStringData, ILsize=7
JIT compiling 313 [Tier0]System.ReadOnlySpan`1[Char]::.ctor, ILsize=27
JIT compiling 314 [Tier0]System.IO.StreamWriter::WriteSpan, ILsize=368
JIT compiling 315 [Tier0]System.ReadOnlySpan`1[Char]::get_Item, ILsize=28
JIT compiling 316 [Tier0]System.Span`1[Byte]::Slice, ILsize=39
JIT compiling 317 [Tier0]System.Span`1[Byte]::.ctor, ILsize=27
JIT compiling 318 [Tier0]System.Span`1[Byte]::op_Implicit, ILsize=19
JIT compiling 319 [Tier0]System.ReadOnlySpan`1[Byte]::.ctor, ILsize=27
JIT compiling 320 [Tier0]WindowsConsoleStream::Write, ILsize=35
JIT compiling 321 [Tier0]WindowsConsoleStream::WriteFileNative, ILsize=107
JIT compiling 322 [Tier0]System.ReadOnlySpan`1[Byte]::get_IsEmpty, ILsize=10
JIT compiling 323 [Tier0]System.Threading.Thread::Sleep, ILsize=33
JIT compiling 324 [Tier1]System.Collections.HashHelpers::FastMod, ILsize=47
JIT compiling 325 [Tier1]System.Runtime.CompilerServices.CastHelpers::IsInstanceOfClass, ILsize=111
JIT compiling 326 [Tier1]System.Object::.ctor, ILsize=1
JIT compiling 327 [Tier1]System.ReadOnlySpan`1[Byte]::get_Length, ILsize=7
JIT compiling 328 [Tier1]System.Runtime.CompilerServices.RuntimeHelpers::GetMethodTable, ILsize=11
JIT compiling 329 [Tier1]System.ReadOnlySpan`1[Byte]::.ctor, ILsize=51
JIT compiling 330 [Tier1]System.Runtime.CompilerServices.RuntimeHelpers::IsReferenceOrContainsRef

I didn't expose neither JitOrder nor JitFunctionTrace as they look more low-level for end users, but happy to change that if you think it's worth exposing.

@ghostghost added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Aug 17, 2022
@ghostghost assigned EgorBoAug 17, 2022
@ghost

Copy link
Copy Markdown

Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch
See info in area-owners.md if you want to be subscribed.

Issue Details

For top-level statements (which are used by default when one creates console app via dotnet new console) JitDisasm wasn't easy to use for e.g.:

usingSystem;Foo();voidFoo()=>Console.WriteLine("Foo");

Both of these:

DOTNET_JitDisasm=Main
DOTNET_JitDisasm=Foo

didn't work as they had to be <Main>$ and <<Main>$>g__Foo|0_1() but now should work.

Also, expose DOTNET_DumpJittedMethods=1 in Release so users can ask JIT to list all methods it's jitting - closes #74084
Example of its output:

JIT compiling 310 [Tier0]System.IO.StreamWriter::Write, ILsize=14
JIT compiling 311 [Tier0]System.String::op_Implicit, ILsize=31
JIT compiling 312 [Tier0]System.String::GetRawStringData, ILsize=7
JIT compiling 313 [Tier0]System.ReadOnlySpan`1[Char]::.ctor, ILsize=27
JIT compiling 314 [Tier0]System.IO.StreamWriter::WriteSpan, ILsize=368
JIT compiling 315 [Tier0]System.ReadOnlySpan`1[Char]::get_Item, ILsize=28
JIT compiling 316 [Tier0]System.Span`1[Byte]::Slice, ILsize=39
JIT compiling 317 [Tier0]System.Span`1[Byte]::.ctor, ILsize=27
JIT compiling 318 [Tier0]System.Span`1[Byte]::op_Implicit, ILsize=19
JIT compiling 319 [Tier0]System.ReadOnlySpan`1[Byte]::.ctor, ILsize=27
JIT compiling 320 [Tier0]WindowsConsoleStream::Write, ILsize=35
JIT compiling 321 [Tier0]WindowsConsoleStream::WriteFileNative, ILsize=107
JIT compiling 322 [Tier0]System.ReadOnlySpan`1[Byte]::get_IsEmpty, ILsize=10
JIT compiling 323 [Tier0]System.Threading.Thread::Sleep, ILsize=33
JIT compiling 324 [Tier1]System.Collections.HashHelpers::FastMod, ILsize=47
JIT compiling 325 [Tier1]System.Runtime.CompilerServices.CastHelpers::IsInstanceOfClass, ILsize=111
JIT compiling 326 [Tier1]System.Object::.ctor, ILsize=1
JIT compiling 327 [Tier1]System.ReadOnlySpan`1[Byte]::get_Length, ILsize=7
JIT compiling 328 [Tier1]System.Runtime.CompilerServices.RuntimeHelpers::GetMethodTable, ILsize=11
JIT compiling 329 [Tier1]System.ReadOnlySpan`1[Byte]::.ctor, ILsize=51
JIT compiling 330 [Tier1]System.Runtime.CompilerServices.RuntimeHelpers::IsReferenceOrContainsRef

I didn't expose neither JitOrder nor JitFunctionTrace as they look more low-level for end users, but happy to change that if you think it's worth exposing.

Author:EgorBo
Assignees:-
Labels:

area-CodeGen-coreclr

Milestone:-

Comment threadsrc/coreclr/jit/jitconfig.cpp Outdated
Comment threadsrc/coreclr/jit/compiler.cpp Outdated
@jakobbotsch

Copy link
Copy Markdown
Member

JIT compiling 327 [Tier1]System.ReadOnlySpan`1[Byte]::get_Length, ILsize=7

Is this format compatible with JitDisasm? Shouldn't it be a single colon?

Comment threadsrc/coreclr/jit/compiler.cpp Outdated
Comment threadsrc/coreclr/jit/compiler.cpp Outdated
@stephentoub

stephentoub commented Aug 18, 2022

Copy link
Copy Markdown
Member

Can we backport this to rc1? From my perspective, it meets the bar of addressing significant gaps in a new feature. The support for DOTNET_JitDisasm is awesome (it's literally the first thing I talk about in the .NET 7 performance post I'm writing), but its usability is hard because there's no good way to discover what can be written as the value for the variable, and there's no good way to simply express names that get mangled by the C# compiler (e.g. async methods, iterators, local methods, top-level statements main, generated main for async mains, etc.). On top of that, being able to see (without separate tools) what methods the JIT is compiling at a high-level is a stellar pedagogical tool, but just specifying * leads to way too much spew for it to be useful; having the one-line-per-compilation is a great for understanding what's being generated when.

@jakobbotsch

Copy link
Copy Markdown
Member

Just curious, but does it work to simply copy paste the name from DumpJittedMethods into JitDisasm to get the output in all cases? E.g. with generic instantiations, overloads... I feel like I often find that I cannot just copy the name directly. If @stephentoub is going to call these out in the blog post we should probably make sure this is seamless, or at least be aware of the cases that are broken.

I think my preference would be to make the matching follow some very basic understandable rules, e.g. something like: the JitDisasm string is a space separated list of patterns. If any pattern matches the method has its disassembly printed. Patterns can contain wildcards and characters. The string matched against depends on the pattern, but starts out with just the method name:

  • If the pattern contains (, then the method string name additionally contains its signature at the end (in the same format JitDisasm/DumpJittedMethods shows)
  • If the pattern contains :, then the method name string starts with ClassName: (again, compatible with the strings displayed by JitDisasm/DumpJittedMethods)

I'm not sure how this matches the rules today.

@EgorBo

EgorBo commented Aug 18, 2022

Copy link
Copy Markdown
MemberAuthor

@jakobbotsch I've just checked - whatever DOTNET_DumpJittedMethods=1 prints can be used for JitDisasm just fine with two special cases:

  1. If you use powershell you might need to escape ` symbol (works in cmd)
  2. VM's eeGetMethodFullName behaves differently for Release and Debug, it doesn't print generic signature in Release and I don't want to change that now (especially if we plan to backport this) 🙂 - so e.g. instead of Foo'1[Cannon] it prints just Foo'1 - so you might see some problems if you use Checked's DOTNET_DumpJittedMethods in Release's DOTNET_JitDisasm

So, to match CastHelpers:StelemRef(Array,long,Object) we currently can use the following patterns (some of them will print other methods too):

DOTNET_JitDisasm=CastHelpers:StelemRef(Array,long,Object)
DOTNET_JitDisasm=CastHelpers:StelemRef
DOTNET_JitDisasm=StelemRef
DOTNET_JitDisasm=StelemRef*
DOTNET_JitDisasm=StelemR*
DOTNET_JitDisasm=*telemRe*
DOTNET_JitDisasm=*
DOTNET_JitDisasm=**
DOTNET_JitDisasm=CastHelpers:*
DOTNET_JitDisasm=CastHelpers:**
DOTNET_JitDisasm=CastHelpers:*telemRe*
DOTNET_JitDisasm=CastHelpers::*
DOTNET_JitDisasm=CastHelpers::**
DOTNET_JitDisasm=CastHelpers::*telemRe*

Wildcards only work for methodName, className can be omitted or exactly match.

@stephentoub do you have any preferences for better name instead of DOTNET_DumpJittedMethods=1 ? e.g. DOTNET_JitDisasmList=1 etc

@stephentoub

Copy link
Copy Markdown
Member

@stephentoub do you have any preferences for better name instead of DOTNET_DumpJittedMethods=1 ? e.g. DOTNET_JitDisasmList=1 etc

No strong preference. DOTNET_JitListMethods? DOTNET_JitListCompilations? DOTNET_JitDisasmSummary?

@JulieLeeMSFTJulieLeeMSFT added this to the 8.0.0 milestone Aug 18, 2022
@EgorBo

Copy link
Copy Markdown
MemberAuthor

@dotnet/jit-contrib PTAL, it's ready for review - also, any thoughts on a better name for end users? 🙂

Comment threadsrc/coreclr/jit/jitconfigvalues.h Outdated
CONFIG_METHODSET(JitDisasm, W("JitDisasm"))
#endif // !defined(DEBUG)

CONFIG_INTEGER(DumpJittedMethods, W("DumpJittedMethods"), 0) // Prints all jitted methods to the console

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This is going to be awesome

@BruceForstallBruceForstall left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

As to naming, I prefer Stephen's suggestion DOTNET_JitDisasmSummary

Comment threadsrc/coreclr/jit/compiler.cpp Outdated
@ghostghost added the needs-author-action An issue or pull request that requires more info or actions from the author. label Aug 19, 2022
@BruceForstall

Copy link
Copy Markdown
Contributor

Can you show some examples of the newest output format, especially including some OSR methods (e.g., from the ASP.NET collection)?

Comment threadsrc/coreclr/jit/compiler.cpp Outdated
Co-authored-by: Bruce Forstall <brucefo@microsoft.com>
@ghostghost removed the needs-author-action An issue or pull request that requires more info or actions from the author. label Aug 19, 2022
@BruceForstall

Copy link
Copy Markdown
Contributor

Can you show an example with OSR in a Checked JIT? With JitStress enabled (in Checked)?

Are you going to rename the option?

@AndyAyersMS

Copy link
Copy Markdown
Member

Would also be nice to know if we're generating instrumented code and (perhaps) if we have access to PGO data -- and if so, what kind (at least for the root).

{
// 's2' must start with 'nameLen' characters of 'name'
if (strncmp(name, s2, nameLen) != 0)
for (size_t srcPos = 0; srcPos <= srcSize - needleSize; srcPos++)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

assert(srcSize >= needleSize)?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

if needleSize is bigger it will just return "not found" because it actually can be bigger

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

But in that case won't the srcSize - needleSize way bigger? You might just fast return "not found" in such cases.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Guess this is still unaddressed.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

@kunalspathak sorry didn't notice your comment - I am not sure I understand, let's say
srcSize is 10 and needleSize is 20, then srcSize - needleSize is -10 so for-loop immediately exits and returns "not found" - am I wrong?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I haven't looked in depth here, but srcSize - needleSize can never be negative, since size_t is unsigned.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

ah oops, it supposed to be ssize_t

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I haven't looked in depth here, but srcSize - needleSize can never be negative, since size_t is unsigned.

^ That.

@AndyAyersMS

Copy link
Copy Markdown
Member

6: JIT compiled Proga:Main() [Tier1-OSR, IL size=27, code size=56]

We should make sure the patchpoint IL offset shows up here.

@BruceForstall

Copy link
Copy Markdown
Contributor

6: JIT compiled Proga:Main() [Tier1-OSR, IL size=27, code size=56]

We should make sure the patchpoint IL offset shows up here.

It looks like the code to do that is only under ifdef DEBUG but doesn't need to be.

In fact, the "DEBUG" version, including compGetStressMessage(), should be used for Release (for simplicity) since compGetStressMessage() already ifdefs for DEBUG.

@EgorBo

Copy link
Copy Markdown
MemberAuthor

Unified Debug and Release, initially I just didn't want to show users irrelevant data they won't ever need

New Release output:

 1: JIT compiled CastHelpers:StelemRef(Array,long,Object) [Tier1, IL size=88, code size=93, hash=0x00000000 ]
2: JIT compiled CastHelpers:LdelemaRef(Array,long,long):byref [Tier1, IL size=44, code size=44, hash=0x00000000 ]
3: JIT compiled SpanHelpers:IndexOfNullCharacter(byref):int [Tier1, IL size=792, code size=388, hash=0x00000000 ]
4: JIT compiled Proga:Main() [Tier0, IL size=42, code size=124, hash=0x00000000 ]
5: JIT compiled Proga:foo() [Tier0, IL size=1, code size=6, hash=0x00000000 ]
6: JIT compiled Proga:foo() [Tier1, IL size=1, code size=1, hash=0x00000000 ]
7: JIT compiled Proga:Main() [Tier1-OSR @0x21, IL size=42, code size=56, hash=0x00000000

OSR offset is here.

Also, renamed to DOTNET_JitDisasmSummary

@BruceForstall

@BruceForstallBruceForstall left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM with one small request.

Andy said:

Would also be nice to know if we're generating instrumented code and (perhaps) if we have access to PGO data -- and if so, what kind (at least for the root).

Don't know if you want to address that, and if so, in this change or as a follow-up.

Comment threadsrc/coreclr/jit/compiler.cpp Outdated
EgorBoand others added 2 commits August 22, 2022 14:31
Co-authored-by: Bruce Forstall <brucefo@microsoft.com>
@EgorBo

EgorBo commented Aug 22, 2022

Copy link
Copy Markdown
MemberAuthor

Added PGO on @AndyAyersMS's request, example:

 33: JIT compiled SubStringCountTest:Foo():int [Instrumented Tier0, IL size=29, code size=156, hash=0x00000000]
34: JIT compiled SubStringCountTest:Foo():int [Instrumented Tier1-OSR @0x13 with Dynamic PGO, IL size=29, code size=63, hash=0x00000000]
35: JIT compiled SubStringCountTest:Foo():int [Tier1 with Dynamic PGO, IL size=29, code size=22, hash=0x00000000]
36: JIT compiled Thread:Sleep(int) [Tier1 with Static PGO, IL size=33, code size=148, hash=0x00000000]

e.g. 35 is both instrumented and optimized with PGO due to OSR

@BruceForstall

Copy link
Copy Markdown
Contributor

Given that hash is always zero in Release, maybe we shouldn't display it in Release builds?

@EgorBo
EgorBo merged commit d80d71f into dotnet:mainAug 22, 2022
@EgorBo

Copy link
Copy Markdown
MemberAuthor

/backport to release/7.0-rc1

@github-actions

Copy link
Copy Markdown
Contributor

Started backporting to release/7.0-rc1: https://github.com/dotnet/runtime/actions/runs/2907852964

@github-actions

Copy link
Copy Markdown
Contributor

@EgorBo an error occurred while backporting to release/7.0-rc1, please check the run log for details!

Error: @EgorBo is not a repo collaborator, backporting is not allowed. If you're a collaborator please make sure your dotnet team membership visibility is set to Public on https://github.com/orgs/dotnet/people?query=EgorBo

@EgorBo

Copy link
Copy Markdown
MemberAuthor

/backport to release/7.0-rc1

@github-actions

Copy link
Copy Markdown
Contributor

Started backporting to release/7.0-rc1: https://github.com/dotnet/runtime/actions/runs/2907874603

@github-actions

Copy link
Copy Markdown
Contributor

@EgorBo backporting to release/7.0-rc1 failed, the patch most likely resulted in conflicts:

$ git am --3way --ignore-whitespace --keep-non-patch changes.patch
Patch format detection failed.
Error: The process '/usr/bin/git' failed with exit code 128

Please backport manually!

@EgorBoEgorBo removed their assignment Aug 23, 2022
@EgorBo
EgorBo deleted the improve-jitdisasm branch August 23, 2022 12:37
@ghostghost locked as resolved and limited conversation to collaborators Sep 22, 2022
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Environment variable for summary of JIT info output to console

10 participants

@EgorBo@jakobbotsch@stephentoub@BruceForstall@AndyAyersMS@TIHan@jkotas@kunalspathak@SingleAccretion@JulieLeeMSFT