Skip to content

Conversation

caspernorrbin
Copy link
Member

@caspernorrbin caspernorrbin commented Oct 6, 2025

Hi everyone,

The current os:: layer on Linux hides whether the JVM is running inside a container or not. When running inside a container, we replace machine values with container values where applicable, without telling the user of these methods. For most use cases, this is fine, users only care about the returned value. But for other use cases, where the value originated is important. Two examples:

  • A user might need the physical cpu count of the machine, but os::active_processor_count() only returns the limited container value, which also represents something slightly different.
  • A user might want the container memory limit and the physical RAM size, but os::physical_memory() only gives one number.

To solve this, every function that mixed container/machine values now has to explicit variants, prefixed with machine_ and container_. These use the bool return + out-parameter interface, with the container functions only working on Linux. The original methods remain and continue to return the same mixed values.

In addition, container-specific accessors for the memory soft limit and the memory throttle limit have been added, as these values matter when running in a containerized environment.

OSContainer::active_processor_count() has also been changed to return double instead of int. The previous implementation rounded the quota/period ratio up to produce an integer for os::active_processor_count(). Now, when the value is requested directly from the new container API it makes more sense to preserve this fraction rather than rounding it up. We can thus keep the exact value for those that want it, then round it up to keep the same behavior in os::active_processor_count().

Testing:

  • Oracle tiers 1-5
  • Container tests on cgroup v1 and v2 hosts.

Progress

  • Change must be properly reviewed (1 review required, with at least 1 Reviewer)
  • Change must not contain extraneous whitespace
  • Commit message must refer to an issue

Issue

  • JDK-8367319: Add os interfaces to get machine and container values separately (Enhancement - P4)

Reviewing

Using git

Checkout this PR locally:
$ git fetch https://git.openjdk.org/jdk.git pull/27646/head:pull/27646
$ git checkout pull/27646

Update a local copy of the PR:
$ git checkout pull/27646
$ git pull https://git.openjdk.org/jdk.git pull/27646/head

Using Skara CLI tools

Checkout this PR locally:
$ git pr checkout 27646

View PR using the GUI difftool:
$ git pr show -t 27646

Using diff file

Download this PR as a diff file:
https://git.openjdk.org/jdk/pull/27646.diff

Using Webrev

Link to Webrev Comment

@bridgekeeper
Copy link

bridgekeeper bot commented Oct 6, 2025

👋 Welcome back cnorrbin! A progress list of the required criteria for merging this PR into master will be added to the body of your pull request. There are additional pull request commands available for use with this pull request.

@openjdk
Copy link

openjdk bot commented Oct 6, 2025

❗ This change is not yet ready to be integrated.
See the Progress checklist in the description for automated requirements.

@openjdk openjdk bot changed the title 8367319 8367319: Add os interfaces to get machine and container values separately Oct 6, 2025
@openjdk
Copy link

openjdk bot commented Oct 6, 2025

@caspernorrbin The following label will be automatically applied to this pull request:

  • hotspot

When this pull request is ready to be reviewed, an "RFR" email will be sent to the corresponding mailing list. If you would like to change these labels, use the /label pull request command.

@openjdk openjdk bot added the rfr Pull request is ready for review label Oct 6, 2025
@mlbridge
Copy link

mlbridge bot commented Oct 6, 2025

Webrevs

@albertnetymk
Copy link
Member

For most use cases, this is fine, users only care about the returned value. But for other use cases, where the value originated is important.

Then, is it possible to keep the original API for "most use cases"? For others, they can query is_containerized and new machine_ APIs.

The current proposed API kind of forces all users to distinguish btw inside a container or not, even though most use cases don't care.

@caspernorrbin
Copy link
Member Author

Then, is it possible to keep the original API for "most use cases"? For others, they can query is_containerized and new machine_ APIs.

The current proposed API kind of forces all users to distinguish btw inside a container or not, even though most use cases don't care.

The original API is untouched, so "most use cases" can still use that without ever worrying about containers. The machine_ functions is simply an add-on to that API. Both the examples above remain unchanged, os:: active_processor_count() still returns both machine/container values, and os::physical_memory() still returns the appropriate memory limit.

@albertnetymk
Copy link
Member

The original API is untouched, ...

I see; I misunderstood the proposal. Then, there are 3 sets of public APIs, generic, machine_, and container_. I'd expect most use the generic ones and some might query the machine_ ones, so I don't see much need for container_ ones to be public APIs. YMMV.

Copy link
Contributor

@jerboaa jerboaa left a comment

Choose a reason for hiding this comment

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

This will conflict mightily with the refactoring that I'm working on for https://bugs.openjdk.org/browse/JDK-8365606

}

double os::container_processor_count() {
assert(is_containerized(), "must be running containerized");
Copy link
Contributor

Choose a reason for hiding this comment

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

This is the equivalent of assert(false). Shouldn't this be ShouldNotReachHere()?

@dholmes-ora
Copy link
Member

A user might need the physical cpu count of the machine, but os::active_processor_count() only returns the limited container value, which also represents something slightly different.

That is a mis-characterization of the API. active_processor_count() tells you how many logical processors are available to the JVM process. That can be very different to the "physical" (**) number of processors due to partitioning at various levels (e.g. virtualization, containerization), as well as direct restrictions through API's like taskset.

(**) "physical" actually has no meaning these days. There is some value you can obtain through the operating system that provides the maximum number of processors that the operating system can see (and thus make available to the JVM).

@dholmes-ora
Copy link
Member

What is a "machine" here? Historically we have misused "physical" to mean what does a bare-metal OS report on a bare-metal piece of hardware. But that became inaccurate decades ago once virtualization/hypervisors arrived. So we've adjusted API's (e.g. MXBeans) to report whatever the "operating system" reports. The problem there is some things the operating system reports take into account the presence of containers, and others do not. This has always been a problem with these container environments - they should be invisible to software but they are not.

To support this, an os::is_containerized function should also be added.

For a long time this was an impossible question to answer accurately - we could query whether cgroups were configured on a system but we couldn't ask if the JVM process was running under any cgroup constraints - has that changed?

I would like to get a better idea of what kinds of "machine" information we need to query and how it will be used. I mean, how does it help to know a "machine" has 256 processors if the various software layers only make 16 available to you?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
hotspot [email protected] rfr Pull request is ready for review
Development

Successfully merging this pull request may close these issues.

4 participants