JDK-8315923 : pretouch_memory by atomic-add-0 fragments huge pages unexpectedly
  • Type: Bug
  • Component: hotspot
  • Sub-Component: runtime
  • Affected Version: 21,22
  • Priority: P4
  • Status: Resolved
  • Resolution: Fixed
  • OS: linux
  • CPU: generic
  • Submitted: 2023-09-08
  • Updated: 2024-10-23
  • Resolved: 2024-01-26
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 21 JDK 23
21.0.5Fixed 23 b08Fixed
Related Reports
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Description
Since JDK-8272807 (version 18 b10), the implementation of os::pretouch_memory got updated from volatile-write-0 to each page in a range, to atomic-add-0, which was to "permit use of memory concurrently with pretouch". 

However when we have options -XX:+AlwaysPreTouch -XX:+UseTransparentHugePages together for an app using huge amount of memory like >200GiB. According to logs of numastat -mnv, the transparent huge pages would be fragmented into regular pages unexpectedly. Later on kernel would try to assemble all regular pages (for example 4KB) to make up  huge pages (in this case 2MB) gradually. This procedure would cause minutes or longer than half an hour, which impacted the performance on not only the startup phase, but also eventual scores of some key benchmarks especially those highly counting on 99th percentile response-time ones.

From the viewpoint of kernel, if we use “load” instruction in the first place (such as volatile-add-0, or atomic-add-0), kernel actually doesn’t allocate any page, but use “zero” page (it is a special page with all 0) instead. The following write (store instructions) will trigger COW (copy-on-write). But kernel will allocate small pages instead of huge pages for COW. Later on, the huge pages are installed by the dedicated kernel thread asynchronously. Kernel did allocate huge page for COW prior v5.8, but the behavior was changed due to commit https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=3917c80280c9 (“thp: change CoW semantics for anon-THP”).

Therefore, the issue behaves differently with various Linux versions, 4.18 is fine while almost all recent ones like 5.8+, 6.x could show same problem. We could not go back to use volatile-write-0, or revert kernels to the last-known-good point. Instead, madvise call with MADV_POPULATE_WRITE (since Linux 5.14) can be the right way of pretouching memory, and it works well with both regular and huge pages.
Comments
The "size" of pretouch is required, while the "size" of useMemory is not used. So I think it is safe to remove the second one. Edit: the first one is also not required as it is constant.
23-10-2024

The test added by this seems to cause warnings as errors when using clang on Linux (clang15 is used) : /jdk/test/hotspot/gtest/runtime/test_os_linux.cpp:363:28: error: lambda capture 'size' is not required to be captured for this use [-Werror,-Wunused-lambda-capture] auto pretouch = [heap, size](Thread*, int) { ~~^~~~ /jdk/test/hotspot/gtest/runtime/test_os_linux.cpp:366:29: error: lambda capture 'size' is not used [-Werror,-Wunused-lambda-capture] auto useMemory = [heap, size](Thread*, int) { should we remove size ?
07-10-2024

[jdk21u-fix-request] Approval Request from Liming Liu
10-07-2024

A pull request was submitted for review. Branch: master URL: https://git.openjdk.org/jdk21u-dev/pull/825 Date: 2024-07-05 08:55:58 +0000
09-07-2024

Changeset: a65a8952 Author: Liming Liu <limingliu@os.amperecomputing.com> Committer: Thomas Stuefe <stuefe@openjdk.org> Date: 2024-01-26 16:42:46 +0000 URL: https://git.openjdk.org/jdk/commit/a65a89522d2f24b1767e1c74f6689a22ea32ca6a
26-01-2024

A pull request was submitted for review. URL: https://git.openjdk.org/jdk/pull/15781 Date: 2023-09-18 07:37:26 +0000
27-09-2023