-
Notifications
You must be signed in to change notification settings - Fork 4.7k
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 an option to not generate precise GC info #88811
Conversation
Revived dotnet#75817 with a small change. Follow up to dotnet#75803. If enabled, conservative GC stack scanning will be used and metadata related to GC stack reporting will not be generated. The generated executable file will be smaller, but the GC will be less efficient (garbage collection might take longer and keep objects alive for longer periods of time than usual). Saves 4.4% in size on a Hello World. Saves 6.7% on Stage 1. I'll take that. The main difference from the previous PR is that I'm no longer dropping GC info on `UnmanagedCallersOnly` methods and that seems to be enough to make Smoke tests pass.
Tagging subscribers to this area: @agocke, @MichalStrehovsky, @jkotas Issue DetailsRevived #75817 with a small change. Follow up to #75803. If enabled, conservative GC stack scanning will be used and metadata related to GC stack reporting will not be generated. The generated executable file will be smaller, but the GC will be less efficient (garbage collection might take longer and keep objects alive for longer periods of time than usual). Saves 4.4% in size on a Hello World. Saves 6.7% on Stage 1. I'll take that. The main difference from the previous PR is that I'm no longer dropping GC info on Cc @dotnet/ilc-contrib
|
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as abuse.
This comment was marked as abuse.
/azp run runtime-extra-platforms |
Azure Pipelines successfully started running 1 pipeline(s). |
Hmm, the GC is not happy. I was hoping that if this doesn't look problematic, I would propose enabling this when Pulled this from
|
The JIT depends on the GC not happening in no GC regions. It is free to produce code that has GC references in SIMD register or temporary byrefs pointing outside the object. We would need to introduce conservative GC reporting mode for codegen to make this work reliably. |
I think that the conservative GC mode is useful debugging and bring up aid. I do not think it is interesting to spend time on trying to make it work reliably. It is too unpredictable performance-wise to be taken seriously. |
I think this should be tolerated. GC must validate every input and treat as checked+pinned.
This could be a problem, in theory. If there are regions of code that must be GC-atomic, and rely on GC info for that, they may no longer be GC-atomic. Does the same scenario work if GC info is present? (I am just concerned that conservative mode has issues, It should work or we must know reasons as there could be bugs affecting precise mode as well) |
When I ran tests in conservative mode in the past I saw failures in tests that observe object life times (finalizers, weakrefs,…), but no crashes. I wonder if we have some unexpected changes in the logic/invariants or it is just GC info not present is the actual cause. |
Right, you can make it work. It is not obvious to me that it works today. Does the conservative reporting report everything in SIMD registers?
Yes, it works fine if GC info is present. GC info has "no GC regions" where the runtime is disallowed to suspend for GC. Look for |
I do not think so. See Also we might see regression from #86917, but I think that will not impact conservative reporting, since it in unwinding. Another thing that bothers me is that the crash appears to be in pointer updating. It means GC was ok when marking through the same reference, but unhappy when seeing it again in plan phase. (all refs that need updating should have been seen when marking, "updated" is a subset of "live"). |
Also, special modes like conservative tend to challenge assumed invariants and point to fragilities in the design or even lurking stress issues. It is useful to have it working or at least know conditions when it does not work. I'd not recommend it as a kind of optimization though. It is an observable change. We have tests that will reliably fail in this mode. |
Yes. I believe that I have seen the JIT using SIMD registers to copy GC references in no-GC regions.
The values in the managed portion of the stack can be updating while the GC is in progress. Consider |
Actually, I think the relocation stackwalk should be suppressed in conservative mode altogether. There is nothing to relocate. |
We report some stack pointers precisely in conservative mode. NativeAOT reports threadstatic roots precisely, for example, maybe a few more things. As long as we report some stuff precisely, that same stuff needs to be reported for relocation. The rest does not need to be reported, but can be - for simplicity or because noone bothered to sort that out (since GC would sort it out anyways). |
The reason why I think this is interesting is scenarios where Mono is used - Mono never needs to pay for the size of precise GC info because is doesn't do precise GC in codegen. People will already observe similar lifetime issues there. Having this option allows more apples to apples comparison in size. But if it's too problematic for coreclr, it's probably not worth the effort. |
I like the option. It also could be used by pause-sensitive apps like games. But tying it to |
The JIT is generally free to extend lifetimes of things however it sees fit - is this different from lifetimes becoming different because the JIT devirtualized and inlined something in one configuration and didn't do it in the other? It feels like in either case something can unpredictably change. One should ideally not rely on these things. We've been resolving issues where people were complaining about lifetime differences as By Design in the past (e.g. #37064 but there's many of those). |
It is different in that:
|
That is impossible to fix, thus it is a Feature, not a Bug. :-). Reachability in general is not decidable (whether a program will use a given object is a halting problem), so we instead rely on liveness. But the moment when JIT kills variables, while intuitive, is not well defined - it is affected by codegen strategy and optimizations. Many programs will work fine when switched to conservative reporting, but the chances of breakage is higher and fixes may be nontrivial. |
Once the method returns, it's locals would be considered dead by a conservative scan too, wouldn't they (my assumption is that we do take the stack pointer into account)?
This also feels like "it's a range". It does depend on when the GC happens but the same thing happens for the arbitrary lifetime extensions done by the JIT, multiplied by the number of times the code gets paused. I'll concede to the opinions of the two of you because both of you know a lot more about the GC than I do. But I'm puzzled how our bug tracker is not filled with people complaining about lifetimes on Mono if this is such a big problem (the issues about lifetimes I see are pretty much exclusively CoreCLR issues and I don't even remember a Mono issue about this). |
It is not the case. The "bad" pointer can be stuck in some random place on the stack that you have no idea about.
Here are some examples of issues:
IIRC, there are also places in Mono runtime where optimizations are suppressed or stack cleared explicitly to reduce severity of the problem. If we were to introduce codegen mode for conservative GC and see it actually used, we would probably end up doing things like that too. |
Makes sense, thanks! I'm going to close this. It's still good to know we have a 5+% opportunity if we need it, but we'll need to make a bigger investment for it. |
Revived #75817 with a small change.
Follow up to #75803.
If enabled, conservative GC stack scanning will be used and metadata related to GC stack reporting will not be generated. The generated executable file will be smaller, but the GC will be less efficient (garbage collection might take longer and keep objects alive for longer periods of time than usual).
Saves 4.4% in size on a Hello World. Saves 6.7% on Stage 1. I'll take that.
The main difference from the previous PR is that I'm no longer dropping GC info on
UnmanagedCallersOnly
methods and that seems to be enough to make Smoke tests pass. Let's see what the rest of the testing thinks.Cc @dotnet/ilc-contrib