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

JIT: Avoid reporting call-sites in MinOpts on all targets #103950

Open
wants to merge 12 commits into
base: main
Choose a base branch
from

Conversation

jakobbotsch
Copy link
Member

When the call-sites have no interesting GC information we avoid reporting them, but this behavior was enabled only for x86/x64. Enable this on other platforms too.

Fix #103917

When the call-sites have no interesting GC information we avoid
reporting them, but this behavior was enabled only for x86/x64. Enable
this on other platforms too.

Fix dotnet#103917
@dotnet-issue-labeler dotnet-issue-labeler bot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Jun 25, 2024
@@ -4065,13 +4065,7 @@ void GCInfo::gcMakeRegPtrTable(
{
GCENCODER_WITH_LOGGING(gcInfoEncoderWithLog, gcInfoEncoder);

// TODO: Decide on whether we should enable this optimization for all
// targets: https://github.com/dotnet/runtime/issues/103917
#ifdef TARGET_XARCH
const bool noTrackedGCSlots = compiler->opts.MinOpts() && !compiler->opts.jitFlags->IsSet(JitFlags::JIT_FLAG_PREJIT);
Copy link
Member Author

Choose a reason for hiding this comment

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

@jkotas do you know if there is any dependency on the call site locations by crossgen2? I'm not sure if the PREJIT condition can also be removed here.

Copy link
Member

Choose a reason for hiding this comment

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

I do not think crossgen2 has any dependency on that. NativeAOT might have (unintentional) dependency on it - you may want to run NativeAOT outer loop.

The primary motivation for this feature was JIT throughput improvement. This condition is likely result of that thinking - spending the extra cycles for AOT is no big deal.

I do not see a problem with removing this condition.

Copy link
Member

Choose a reason for hiding this comment

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

The change in https://github.com/dotnet/runtime/pull/102680/files#r1653150895 may make us sensitive to missing safepoints.

Mostly just a matter of changing asserts though. We know the caller site is GC-safe. (since we are in a GC-capable callee)

Copy link
Member Author

Choose a reason for hiding this comment

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

Do you want me to revert the PREJIT change for now?

@jakobbotsch
Copy link
Member Author

/azp run runtime-nativeaot-outerloop, runtime-coreclr gcstress0x3-gcstress0xc

Copy link

Azure Pipelines successfully started running 2 pipeline(s).

@jakobbotsch
Copy link
Member Author

/azp run runtime-nativeaot-outerloop

Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@jakobbotsch
Copy link
Member Author

/azp run runtime-coreclr gcstress0x3-gcstress0xc

Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@jakobbotsch jakobbotsch added this to the 10.0.0 milestone Aug 5, 2024
@dotnet-policy-service dotnet-policy-service bot removed this from the 10.0.0 milestone Sep 4, 2024
@github-actions github-actions bot locked and limited conversation to collaborators Oct 6, 2024
@jakobbotsch jakobbotsch reopened this Oct 28, 2024
@dotnet dotnet unlocked this conversation Oct 28, 2024
@jakobbotsch jakobbotsch marked this pull request as ready for review October 31, 2024 15:07
@jakobbotsch jakobbotsch requested review from jkotas and VSadov October 31, 2024 15:07
@jakobbotsch
Copy link
Member Author

/azp run runtime-nativeaot-outerloop, runtime-coreclr gcstress0x3-gcstress0xc

@VSadov
Copy link
Member

VSadov commented Oct 31, 2024

I think NativeAOT at this point should be compatible with this change. This mostly affects decoder and that is shared.
I was waiting for gc stress tests to maybe find something.

It may be worth pushing a temporary change that unconditionally enables minopts for naot to see whether there are any real issues.

I think it would be interesting. Maybe we will find issues related to this change or even unrelated ones…

@jakobbotsch
Copy link
Member Author

@jakobbotsch It may be worth pushing a temporary change that unconditionally enables minopts for naot to see whether there are any real issues.

Do you know what the simplest way to do that would be? I imagine I can't just do it on the JIT side due to IL scanner mismatches?

@jkotas
Copy link
Member

jkotas commented Nov 4, 2024

You should be able to do it in the JIT. IL scanner is not aware of minopts vs. full opts differences. It has to assume the worst case. It has no control over when the JIT decides to degrade to minopts on its own.

@jakobbotsch
Copy link
Member Author

Hmm, that didn't seem to work. Any other ideas?

@jkotas
Copy link
Member

jkotas commented Nov 5, 2024

This shows that there are pre-existing issues with minopts and IL scanner. cc @MichalStrehovsky

@MichalStrehovsky
Copy link
Member

This shows that there are pre-existing issues with minopts and IL scanner. cc @MichalStrehovsky

The scanner makes an assumption that NI_System_Runtime_InteropService_MemoryMarshal_GetArrayDataReference gets expanded. Submitted #109576 to make this easier to diagnose.

if (IsMemoryMarshalGetArrayDataReference(method))
{
return;
}

If I mark this as betterToExpand in RyuJIT, smoke tests can build fine with this change. Any opinions on doing this unconditionally, or on native AOT only?

Smoke tests don't run with this change however, we're hitting assert(decoder.IsSafePoint()); in CoffNativeCodeManager.cpp so there's probably some problems.

@VSadov
Copy link
Member

VSadov commented Nov 6, 2024

Smoke tests don't run with this change however, we're hitting assert(decoder.IsSafePoint()); in CoffNativeCodeManager.cpp so there's probably some problems.

This is a bit strange. This is an assert in a leaf frame checking that we were interrupted on a safe point.

This change indeed removes safe points from the GC info, but then how could the execution be interrupted if the safe point is missing?

@VSadov
Copy link
Member

VSadov commented Nov 6, 2024

but then how could the execution be interrupted if the safe point is missing?

Ah, yes, it could be interrupted via hijacking.
The assert should be changed to assert(decoder.CouldBeInterruptibleSafePoint()

The helper was specifically introduced to be more permissive in asserts and allow cases where safepoints are possibly missing due to MinOpts.

@jkotas
Copy link
Member

jkotas commented Nov 6, 2024

If I mark this as betterToExpand in RyuJIT, smoke tests can build fine with this change. Any opinions on doing this unconditionally, or on native AOT only?

I think we should do it unconditionally. (It would be more correct to treat it as mustToExpand, but we seem to depend on betterToExpand to mean mustToExpand with IL scanner for other methods, so it is not introducing a new fundamental problem.)

@jakobbotsch Are you fine with doing this and the change that @VSadov suggested in this PR, or would you like those changes to be submitted separately?

@jakobbotsch
Copy link
Member Author

jakobbotsch commented Nov 7, 2024

@jakobbotsch Are you fine with doing this and the change that @VSadov suggested in this PR, or would you like those changes to be submitted separately?

I think we should fix the ILScanner/GetArrayDataReference issue separately since it's not really related to this change, but @VSadov's issue seems related so makes sense to fix it here.

If you think we should expand this unconditionally the intrinsic should just be made recursive in the C# sources, right? (Hmm, no.. we don't really have prior art to unconditionally expanded intrinsics in callers outside of NAOT. I would probably suggest we just add this one to the list of ones expanded for NAOT.)

@jakobbotsch
Copy link
Member Author

/azp run runtime-nativeaot-outerloop

Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@VSadov
Copy link
Member

VSadov commented Nov 28, 2024

There are bunch of failures on NativeAOT that complain about size increase:

BUG: File size is not in the expected range (1228800 to 1638400 bytes). Did a libraries change regress size of Hello World?
Expected: 100
Actual: 1
END EXECUTION - FAILED

Those are expected, I assume.

However there are failures that look more like real failures:

DeadCodeElimination+TestUnmodifiableInstanceFieldOptimization+WithInitOnlyPropertyWrite
System.Exception: Exception of type 'System.Exception' was thrown.
   at DeadCodeElimination.ThrowIfPresentWithUsableMethodTable(Type, String) + 0x6a
   at DeadCodeElimination.TestTypeOfCodegenBranchElimination.Run() + 0x109
   at DeadCodeElimination.Run() + 0x68
   at TrimmingBehaviors!<BaseAddress>+0x29bf43
   at Program.<<Main>$>g__RunTest|0_0(Func`1, String) + 0x64
===== Test DeadCodeElimination.Run failed =====
DeadCodeElimination+TestUnmodifiableInstanceFieldOptimization+WithInitOnlyPropertyWrite
System.Exception: Exception of type 'System.Exception' was thrown.
   at DeadCodeElimination.ThrowIfPresentWithUsableMethodTable(Type, String) + 0x6a
   at DeadCodeElimination.TestTypeOfCodegenBranchElimination.Run() + 0x109
   at DeadCodeElimination.Run() + 0x68
   at TrimmingBehaviors!<BaseAddress>+0x29bf43
   at Program.<<Main>$>g__RunTest|0_0(Func`1, String) + 0x64
===== Test DeadCodeElimination.Run failed =====

Is that another expectation from the JIT (deadcode elimination), that is not guaranteed by MinOpts?

@MichalStrehovsky
Copy link
Member

Those three failures are due to the forced minopts since they all expect optimizations to happen. Smoketests tend to have tests that test optimizations happen. I think we should run nativeaot outerloop with the forced minopts and ignore all failures in tests that are only failing because of the minopts. There shouldn't be many more tests like that.

Unfortunately outerloop is on the floor right now, trying to fix it in #110238.

@VSadov
Copy link
Member

VSadov commented Nov 28, 2024

Those three failures are due to the forced minopts since they all expect optimizations to happen

Just want to clarify - the failures are only because the tests explicitly check for optimizations (the first case that simply looks for size regressions looks like that). Or if optimizations do not happen the codegen is actually incorrect? I can't tell about ThrowIfPresentWithUsableMethodTable cases.

@MichalStrehovsky
Copy link
Member

Those three failures are due to the forced minopts since they all expect optimizations to happen

Just want to clarify - the failures are only because the tests explicitly check for optimizations (the first case that simply looks for size regressions looks like that). Or if optimizations do not happen the codegen is actually incorrect? I can't tell about ThrowIfPresentWithUsableMethodTable cases.

The DeadCodeElimination tests test that branch removal happened and looks for that using side effects (it's hard to test branch removal directly). The side effect in this case is whether we have a full MethodTable for something.

I believe the lines:

    if (IsTargetAbi(CORINFO_NATIVEAOT_ABI))
    {
        theMinOptsValue = true;
    }

in this PR currently set minopts for everything (for testing purposes) so branch removal doesn't happen.

@jakobbotsch
Copy link
Member Author

/azp run runtime-nativeaot-outerloop

Copy link

Azure Pipelines successfully started running 1 pipeline(s).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-CodeGen-coreclr CLR 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.

JIT differences in reporting call sites in GC info
4 participants