-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Add JitEnregStats complus.
#58776
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
Add JitEnregStats complus.
#58776
Conversation
|
Tagging subscribers to this area: @JulieLeeMSFT Issue Detailsnull
|
|
/azp list |
|
Commenter does not have sufficient privileges for PR 58776 in repo dotnet/runtime |
|
/azp list |
|
@sandreenko what pipleline do you want to run? I will run it. |
thank you Julie, I was just testing how /azp will react. |
|
Hmm, I can't call @dotnet/jit-contrib even if I am inside it looks like. |
@eiriktsarpalis do you have access to the bot to not tag owners for draft PRs? |
There doesn't seem to be an option to exclude draft PRs in FabricBot. We could perhaps ask the FB team to implement this /cc @danmoseley |
kunalspathak
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.
Thanks for doing this. Added few comments.
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.
nit: Have this under #ifdef DEBUG near LSRA stats for easy discoverability.
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.
will do.
src/coreclr/jit/gschecks.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.
why we don't need to set this anymore?
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.
These were the debug fields to explain why we don't enregister, now they are replaced with
DoNotEnregisterReason m_doNotEnregReason;
AddressExposedReason m_addrExposedReason;
src/coreclr/jit/lclvars.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.
Is it reasonable to add assert(varDsc->m_doNotEnregReason == reason)?
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.
Or if varDsc was set to DoNotRegister by some other phase, then also set the reason here?
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 was thinking to do DoNotEnregisterReason enum to be a set like some other enums:
#define MAKE_DNRREASON(bit) (1ULL << (bit))
AddrExposed= = MAKE_DNRREASON( 0),
DontEnregStructs= = MAKE_DNRREASON( 1),
but because one reason is often causing others for the purpose of this dump it is clearer to keep only the first reason and not all of them for each var.
So we record only the first reason why something can't be put into a register and if different reasons come we ignore it.
src/coreclr/jit/morph.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.
Why we don't need to clone these 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.
answered above, they are deleted.
src/coreclr/jit/fgbasic.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.
Why don't we clear address exposed reason?
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 saw only 1 method that was using this logic in benchmark collection so I did not dig deep here.
In fgAdjustForAddressExposedOrWrittenThis we are creating a clone for this and replace other uses of the original this with the clone, so we assume that now the reason why this was marked as address exposed is no longer valid and there could be no other reasons why it could be address exposed.
So after this transformation, the clone is address exposed and the original - not.
However, it is questionable if we can clear lvDoNotEnregister here as well because we don't have information if AddrExposed was the only reason why we can't enregister. So we can imagine a situation where we clear this flag and enregister the original this when we should not, for example, because local enreg is disabled or something like that.
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.
It will be better readable if we have a macro something like this:
#define PRINT_STATS(stat, total) \
if (stat != 0) \
{ \
fprintf(fout, #stat "%d, ratio: %.2f\n", stat, (float)stat / total); \
} \
PRINT_STATS(m_addrExposed, notEnreg)
PRINT_STATS(m_notRegSizeStruct , notEnreg)
...
PRINT_STATS(m_copyFldByFld, m_addrExposed)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.
ok, done.
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.
Looks like a nice cleanup, with useful stats
src/coreclr/jit/compiler.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.
This isn't going to bitwise pack with anything, since there aren't adjacent bool bit ops. Is there a reason this can't stay as before? (unsigned char :1) I'm not sure if you can change public/private visibility within a packing set; something to check.
Also, which m_ is a "new standard", it seems like since nothing else in this class is defined with that naming convention, we should stick with what's already here and use the lv previx like everything else.
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.
Also, which m_ is a "new standard", it seems like since nothing else in this class is defined with that naming convention, we should stick with what's already here and use the lv previx like everything else.
the other fields in this struct are mostly public so for public lv prefix makes sense (if somebody is using grep to find them and not IDE tools) but for private fields I don't see any value in having them.
This isn't going to bitwise pack with anything, since there aren't adjacent bool bit ops. Is there a reason this can't stay as before? (unsigned char :1)
fixed, but with bool instead of char if you don't mind.
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.
fixed, but with bool instead of char if you don't mind.
I thought that unsigned char :1 doesn't pack with bool :1 due to the rules of C bitfield packing, or maybe MSVC++ behavior. Can you check? It might be safest to use unsigned char just to ensure the greatest likelihood of packing across different compilers.
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.
https://godbolt.org/ shows that both clang and MSVC don't have problems with usnigned int a:1; bool b:1 packing.
src/coreclr/jit/jit.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.
Set
#define TRACK_ENREG_STATS 0
in the #else clause, like the other cases?
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 was considering it but the contract here is that you then will be able to set #define TRACK_ENREG_STATS 1 and get data in the release. It is not the case here, in order to make TRACK_ENREG_STATS 1 work in the release I would need to replace many DEBUGARG with something like
#if defined(DEBUG) || (TRACK_ENREG_STATS == 1)
#define DEBUG_OR_TACK_ENREG_STATS(arg) , arg
#endif
and it looked to me as overkill, especially because for this mode we don't expect different results from the release and checked like for others.
src/coreclr/jit/lclvars.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.
How about adding something to JitDump if the new reason is not the same as the existing reason?
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.
not sure about it, for example, lets say a var is marked as DoNotEnreg 2 times because of addrExposed and 2 times because of lclFld, the first reason is addrExposed, what would you prefer to see it the dump:
1.
should not be enregistered because: addrExposed
should not be enregistered also because: lclFld// a new reason
should not be enregistered because: addrExposed // the first reason called again
should not be enregistered also because: lclFld// a new reason, don't have information that we already had lclFld before.
should not be enregistered because: addrExposed
should not be enregistered also because: lclFld
should not be enregistered also because: addrExposed
should not be enregistered also because: lclFld
should not be enregistered because: addrExposed
should not be enregistered also because: lclFld
should not be enregistered also because: lclFld
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 was thinking of (3). I think it's better for the lclFld lines (in this example) to be duplicated than for there to be no output at all. Unless you tell me the number of duplicated lines will be large (>20), at which point maybe there's some other issue (like, why do we call do-not-enreg so much?)
src/coreclr/jit/lower.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.
Shouldn't this always call lvaSetVarDoNotEnregister and it can early-return if already set (but also possibly JitDump if already set for a different reason)
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.
not in this case in my opinion, if everything goes well it would be replaced with assert(varDsc->lvDoNotEnregister) soon because this code is a patch for some locals that are slipping morph analysis nowadays.
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.
not in this case in my opinion, if everything goes well it would be replaced with assert(varDsc->lvDoNotEnregister) soon because this code is a patch for some locals that are slipping morph analysis nowadays.
|
@sandreenko - Do you mind rebasing your branch and fixing formatting issues and then it should be ready to go. |
ea5e954 to
cfa2d3a
Compare
done, also sorted switches and prints according to the enum order. |
|
Since |
I can change that if you think it will be better. I think sometimes the presence of |
|
Thank you @sandreenko ! |
This PR adds a
COMPlus/DOTNET_JitEnregStatsto show additional information about our local enregistration.Example output for aspnet.run.windows.x64.checked.mch:
I was surprised to see so many Tier0 (Min opts) methods in the collection but otherwise, it looks right (lvNoRegVars 186363, ratio: 0.81).
No diffs, but so some asserts in both base/diff spmi collection with
GT_PHIruntime/src/coreclr/jit/gentree.cpp
Lines 7808 to 7810 in 3fd30b0