-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Implement fake hot/cold splitting and corresponding stress mode #69763
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
Implement fake hot/cold splitting and corresponding stress mode #69763
Conversation
|
Tagging subscribers to this area: @JulieLeeMSFT Issue DetailsThe The
|
74705d6 to
dce5861
Compare
|
cc @dotnet/jit-contrib. |
dce5861 to
d748767
Compare
d748767 to
b5021de
Compare
BruceForstall
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few comments
src/coreclr/jit/compiler.cpp
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like there's no need for this assert, since we're not aligning this loop. In fact, we're specifically choosing to NOT align it, here.
src/coreclr/jit/ee_il_dll.cpp
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function should have the same signature as allocMem: no need to pass hotSizeRequest or coldSizeRequest since they can be found from args->hotCodeSize and args->coldCodeSize.
src/coreclr/jit/ee_il_dll.cpp
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: buffer is a pretty generic name. How about:
| const UNATIVE_OFFSET buffer = 4096; | |
| const UNATIVE_OFFSET fakeSplittingBuffer = 4096; |
src/coreclr/jit/ee_il_dll.cpp
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that changing args fields works out because the caller doesn't (I think) consult these values afterwards. To be perfectly clean, you might want to copy args to a local temp before modifying its fields.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Gotcha; for brevity, I simply copied and restored hotCodeSize and coldCodeSize, so args' input members behave like they're read-only.
src/coreclr/jit/ee_il_dll.cpp
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might be better to move this immediately before the call to reserveUnwindInfo, below, and add:
JITDUMP("reserveUnwindInfo for cold code with JitFakeProcedureSplitting enabled: ignoring cold unwind info\n");
which would add a line to the JitDump in this case, but also let the normal reserveUnwindInfo printf be executed first.
src/coreclr/jit/ee_il_dll.cpp
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment here as for reserveUnwindInfo: move to just before the allocUnwindInfo call, and add a JITDUMP printout.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that the earlier out is only for DEBUG, is that intentional?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, the JitFakeProcedureSplitting flag is defined only on Debug/Checked builds. For now, we skip unwind info for cold sections only when fake-splitting.
src/coreclr/jit/jitconfigvalues.h
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| // running the GC and breaking things. | |
| // running the GC which requires stack walking. |
src/coreclr/jit/compiler.cpp
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand why this is necessary. If someone sets COMPlus_JitFakeProcedureSplitting=1 and COMPlus_JitNoProcedureSplitting=Main, it seems like that should work: do fake splitting on all functions except Main.
It seems like the real issue is:
opts.compProcedureSplitting = !opts.compDbgCode;
maybe should be:
if (opts.compDbgCode && !JitConfig.JitFakeProcedureSplitting())
{
opts.compProcedureSplitting = false;
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see, looks like I misunderstood what precedence JitFakeProcedureSplitting should (not) take over other configurations. I've changed the logic so JitFakeProcedureSplitting can be partially overriden by other configs, but can still override opts.compDbgCode if enabled.
src/coreclr/jit/ee_il_dll.cpp
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that the earlier out is only for DEBUG, is that intentional?
b5021de to
0af0032
Compare
|
The 20 failing checks all seem to build/run correctly, but fail when sending the results to Helix -- an Azure DevOps API is returning a 401 error, citing a bad |
That was a general infrastructure problem, now fixed. You can request the testing to be rerun. (See the "Re-run" "button" on "runtime" here: https://github.com/dotnet/runtime/pull/69763/checks?check_run_id=6607345705 (rerunning the "parent" will cause rerunning all the failed "children")) |
BruceForstall
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Implementation splits after first basic block in method, assuming there is more than one block. Accompanying this implementation are the following fixes: - Loop alignment is disabled for cold blocks, as moving blocks into the cold section may invalidate the initial decision to align. - Long jumps are no longer reduced to short jumps if crossing hot/cold sections.
0af0032 to
5965366
Compare
|
Thank you! I couldn't find any re-run button in the Checks UI, but force-pushing an empty commit triggered the run. |
The
COMPlus_JitFakeProcedureSplittingconfiguration flag enables testing the JIT's hot/cold splitting functionality independent of the VM. This configuration "fakes" splitting by requesting only a hot section from the VM with the following layout:hot code + 4KB buffer + cold code. Hot/Cold code pointers are manually set to their respective sections of the buffer, and the JIT continues to operate as if the VM allocated separate sections. This implementation does not currently split unwind information, and only reserves/allocates it for the hot section -- this breaks stack walks and, thus, the GC. When using this configuration, suppress the GC with a large memory threshold (ex: setCOMPlus_GCgen0size=1000000).The
COMPlus_JitStressProcedureSplittingconfiguration flag runs a stress mode for hot/cold code splitting by always splitting a method after its first basic block. This mode exposed the following behaviors incompatible with splitting that have been corrected: