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

Proposal: Add hard limit to MemoryInfo API #29998

Closed
ghost opened this issue Jun 24, 2019 · 34 comments · Fixed by dotnet/coreclr#25437
Closed

Proposal: Add hard limit to MemoryInfo API #29998

ghost opened this issue Jun 24, 2019 · 34 comments · Fixed by dotnet/coreclr#25437
Labels
api-approved API was approved in API review, it can be implemented area-System.Runtime
Milestone

Comments

@ghost
Copy link

ghost commented Jun 24, 2019

This is a proposal to add a new property to struct GCMemoryInfo from the coreclr repo (in src/System.Private.CoreLib/shared/System/GCMemoryInfo.cs).
The new property would be:

namespace System
{
    public readonly partial struct GCMemoryInfo
    {
        // Existing:

        public long FragmentedBytes { get; }
        public long HeapSizeBytes { get; }
        public long HighMemoryLoadThresholdBytes { get; }
        public long MemoryLoadBytes { get; }
        public long TotalAvailableMemoryBytes { get; }

        // Proposed:

        public long HardLimitBytes { get; }
    }
}

This would be the COMPLUS_GCHARDLIMIT value we got from configuration (environment variable or runtimeconfig.json);
or if a hard limit was not specified by COMPLUS_GCHARDLIMIT but the program is run in a container, this would be the hard limit calculated from the container size (currently that is 75% of the container size).
Else, this would be 0.

CC @stephentoub @janvorli @Maoni0

@ghost ghost self-assigned this Jun 24, 2019
@Maoni0
Copy link
Member

Maoni0 commented Jun 24, 2019

@davidfowl there you go

@ghost
Copy link
Author

ghost commented Jun 25, 2019

I noticed corefx has a file GCMemoryInfo.cs that looks identical to GCMemoryInfo.cs in coreclr -- is this the result of some automated process? I am working on a change in coreclr only right now, is it automatically copied to corefx or do I have to make the change again in corefx?

@stephentoub
Copy link
Member

I noticed corefx has a file GCMemoryInfo.cs that looks identical to GCMemoryInfo.cs in coreclr -- is this the result of some automated process?

The https://github.com/dotnet/corefx/tree/master/src/Common/src/CoreLib directory is a mirror of https://github.com/dotnet/coreclr/tree/master/src/System.Private.CoreLib/shared; any commits that change one result in an automated PR to the other to propagate those commits. You can just make the changes in coreclr.

@stephentoub
Copy link
Member

I am working on a change in coreclr only right now

Please work with @terrajobst to get the API reviewed before putting up a PR for it. Are you trying to get this into .NET Core 3.0? I believe with a few exceptions all new APIs for the release are supposed to be merged by tomorrow, though my information may be slightly out of date. You'll want to set the milestone on this issue appropriately, and if you believe the API is ready for review, label it as api-ready-for-review.

@davidfowl
Copy link
Member

Else, this would be 0.

Why not make it map to whatever hard limit the GC is using? It's never actually 0 right?

@Maoni0
Copy link
Member

Maoni0 commented Jun 25, 2019

@stephentoub I was the one who asked Andy to open a PR as this is changing an API that's added in 3.0 and we are merely adding a field. I was hoping we wouldn't need to go through an API review meeting for this and @terrajobst can let us know on this thread. but please let me know if I'm mistaken.

@stephentoub
Copy link
Member

and we are merely adding a field

It's a new public property; needs to be reviewed. Even if such a review is quick.

@Maoni0
Copy link
Member

Maoni0 commented Jun 25, 2019

but can it be done without us attending the API review meeting in person?

@stephentoub
Copy link
Member

but can it be done without us attending the API review meeting in person?

It can. Things usually go more smoothly when someone in the know is there to explain it. This is @terrajobst's domain, though, so I'll let him comment. You might want to ping him on email.

@Maoni0
Copy link
Member

Maoni0 commented Jun 25, 2019

@davidfowl without the hardlimit config the hard limit is just the total physical memory which is already a field in the GCMemoryInfo struct:

        /// <summary>
        /// Total available memory for the GC to use when the last GC ocurred. By default this is the physical memory on the machine, but it may be customized by specifying a HardLimit.
        /// </summary>
public long TotalAvailableMemoryBytes { get; }

@Maoni0
Copy link
Member

Maoni0 commented Jun 25, 2019

just pinned @terrajobst

@davidfowl
Copy link
Member

@davidfowl without the hardlimit config the hard limit is just the total physical memory which is already a field in the GCMemoryInfo struct:

Yea but don't make me read 2 fields. Can't we just make the value TotalAvailableMemoryBytes in the else case so i don't have to check for a 0 value?

I'm assuming this API also works when I set a percentage as well?

@Maoni0
Copy link
Member

Maoni0 commented Jun 25, 2019

those are 2 different fields, TotalAvailableMemoryBytes is how much total physical memory your process is allowed to use; HardLimit is how much the GC heap is allowed to use. for some folks it's useful to know the distinction so they can decide how much to give to the GC heap vs the other memory usage.

@Maoni0
Copy link
Member

Maoni0 commented Jun 25, 2019

yeh it also works when you set with percentage

@davidfowl
Copy link
Member

those are 2 different fields, TotalAvailableMemoryBytes is how much total physical memory your process is allowed to use; HardLimit is how much the GC heap is allowed to use. for some folks it's useful to know the distinction so they can decide how much to give to the GC heap vs the other memory usage.

I'm all for having 2 values but the interesting question is whether it's useful to return 0 rather than the relevant value the GC will use in absence of the specific hard limit

@Maoni0
Copy link
Member

Maoni0 commented Jun 25, 2019

0 just means GC heap is allowed to use up to TotalAvailableMemoryBytes. we could return either 0 or TotalAvailableMemoryBytes. I can go either way. no strong opinions there.

@davidfowl
Copy link
Member

Great, I suggest we we return TotalAvailableMemoryBytes instead of 0 😄

@jlanng
Copy link
Contributor

jlanng commented Jun 25, 2019

Would be nice if the presence of this config was mentioned in any consequent OOM exceptions

@bartonjs
Copy link
Member

FXDC: LGTM (@dotnet/fxdc)

@Maoni0
Copy link
Member

Maoni0 commented Jun 25, 2019

@bartonjs thanks! I presume this means it's approved

@bartonjs
Copy link
Member

@Maoni0 I was just registering my "vote" and hoping to get a consensus swarm. It clearly didn't happen, though 😄.

@terrajobst
Copy link
Contributor

terrajobst commented Jun 25, 2019

Video

Looks good as proposed.

@jkotas
Copy link
Member

jkotas commented Jun 26, 2019

The documentation for TotalAvailableMemoryBytes says:

        /// <summary>
        /// Total available memory for the GC to use when the last GC occurred. By default this is the physical memory on the machine, but it may be customized by specifying a HardLimit.
        /// </summary>
        public long TotalAvailableMemoryBytes { get; }

Is part of this proposal to change what TotalAvailableMemoryBytes means? If not, I do not understand when the values returned by TotalAvailableMemoryBytes and HardLimit are going to differ - could you please shed some light on it?

@ghost
Copy link
Author

ghost commented Jun 26, 2019

@jkotas Details are in the PR dotnet/corefx#25437 -- TotalAvailableMemoryBytes did not reflect a manually set hard limit before, so I didn't change what it means, just updated the documentation.

@jkotas
Copy link
Member

jkotas commented Jun 26, 2019

I do not think we should be introducing this API. Instead, we should fix TotalAvailableMemoryBytes to return the amount of memory that the GC can play with.

I do not think it makes sense for GCMemoryInfo.TotalAvailableMemoryBytes to return total amount of memory on the machine that has nothing to do with the GC.

What are the use cases for each of GCMemoryInfo.TotalAvailableMemoryBytes and GCMemory.HardLimitBytes APIs?

@Maoni0
Copy link
Member

Maoni0 commented Jun 27, 2019

this is for folks who have significant native memory usage in their managed processes where they want to have the choice to decide how much of the total memory should be given to the GC heap.

@jkotas
Copy link
Member

jkotas commented Jun 27, 2019

This API is a getter. How do folks use this API to decide how much memory to give to the GC heap? Should this API be a setter ?

@Maoni0
Copy link
Member

Maoni0 commented Jun 27, 2019

I view this API for communicating info only, not for modifying. and both values are useful to know. how do you propose we communicate both values to users?

@davidfowl
Copy link
Member

It's also extremely useful for knowing that the set limits are effective and are being applied.

@jkotas
Copy link
Member

jkotas commented Jun 27, 2019

I think GCMemoryInfo.TotalAvailableMemoryBytes should return how much the GC can play with. If there is a artificial hard-limit, it should return the limit. Also, I think it would be reasonable to make this limit settable.

If we need API to return various system enforced limits, I think it should be somewhere else, e.g. a type like System.Diagnostic.Process.

@davidfowl
Copy link
Member

Sounds good to me.

@Maoni0
Copy link
Member

Maoni0 commented Jun 27, 2019

that's reasonable. I'm not sure what Diagnostic.Process returns today if you are running in a container today.

as far as making this a setter - I don't imagine we'll do that for 3.0 because it would mean to define behavior for things like if you are setting a smaller limit than your current GC heap what should happen. if you feel strongly about this please open an issue and we can discuss for a future milestone.

@jkotas
Copy link
Member

jkotas commented Jun 27, 2019

Diagnostic.Process returns today if you are running in a container today.

It returns the cgroup limit: https://github.com/dotnet/corefx/blob/1b6f45ca261467baea62ef577f8b8a7c6cf3b96c/src/System.Diagnostics.Process/src/System/Diagnostics/Process.Linux.cs#L210

@jkotas
Copy link
Member

jkotas commented Jun 27, 2019

as far as making this a setter - I don't imagine we'll do that for 3.0

Agree. I was just trying to describe the larger context.

@jkotas jkotas closed this as completed Jul 8, 2019
Dotnet-GitSync-Bot referenced this issue in Dotnet-GitSync-Bot/corefx Jul 8, 2019
…tnet#25437)

* Add property HardLimitBytes to GCMemoryInfo

This adds a new property HardLimitBytes.

Unlike TotalAvailableMemoryBytes,
this will reflect an explicitly set COMPLUS_GCHeapHardLimit.

It will also reflect the fraction of a container's size that we use,
where TotalAvailableMemoryBytes is the total container size.

Normally, though, it is equal to TotalAvailableMemoryBytes.

Fix #38821

* Remove HardLimitBytes; have TotalAvailableMemoryBytes take on its behavior

* Fix typos

* Separate total_physical_mem and heap_hard_limit
so we can compute highMemoryLoadThresholdBytes and memoryLoadBytes

* Do more work in gc.cpp instead of Gc.cs

* Consistently end names in "Bytes"

Signed-off-by: dotnet-bot <[email protected]>
stephentoub referenced this issue in dotnet/corefx Jul 9, 2019
…5437)

* Add property HardLimitBytes to GCMemoryInfo

This adds a new property HardLimitBytes.

Unlike TotalAvailableMemoryBytes,
this will reflect an explicitly set COMPLUS_GCHeapHardLimit.

It will also reflect the fraction of a container's size that we use,
where TotalAvailableMemoryBytes is the total container size.

Normally, though, it is equal to TotalAvailableMemoryBytes.

Fix #38821

* Remove HardLimitBytes; have TotalAvailableMemoryBytes take on its behavior

* Fix typos

* Separate total_physical_mem and heap_hard_limit
so we can compute highMemoryLoadThresholdBytes and memoryLoadBytes

* Do more work in gc.cpp instead of Gc.cs

* Consistently end names in "Bytes"

Signed-off-by: dotnet-bot <[email protected]>
@msftgits msftgits transferred this issue from dotnet/corefx Feb 1, 2020
@msftgits msftgits added this to the 3.0 milestone Feb 1, 2020
@ghost ghost locked as resolved and limited conversation to collaborators Dec 12, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
api-approved API was approved in API review, it can be implemented area-System.Runtime
Projects
None yet
Development

Successfully merging a pull request may close this issue.

8 participants