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

JDK-8320061: [nmt] Multiple issues with peak accounting #16675

Conversation

tstuefe
Copy link
Member

@tstuefe tstuefe commented Nov 15, 2023

There are multiple issues with peak printing.

  1. Peak values are not considered when deciding whether allocations fall above the scale threshold:

NMT omits printing information if the values, expressed with the current NMT scale, don't rise above 0. For example, jcmd myprog VM.native_memory scale=g only shows allocations above 1GB. However, we should also show information that had historically large values, even if their current value is small or even 0.

A typical example is compiler memory usage, which can reach large peaks during VM initialization and may fall to insignificant numbers afterward. We still want to see those peaks.

  1. We decided to make peak printing a release-build feature with JDK-8317772, but peak printing for virtual memory is still debug-only

  2. There is a bug in that VirtualMemory::peak that causes the peak value to be wrong; it gets not updated from the actual peak but from the commit increase, so the value shown is too low if we committed in multiple steps. That can be simply observed by "largest_committed" being smaller than "committed", e.g.: (mmap: reserved=1048576KB, committed=12928KB, largest_committed=64KB)

  3. Finally, we really should have better regression tests for peak accounting.


This patch fixes points (1)..(3).

The majority of changes affect test cases, though, because many tests expect NMT to print nothing for allocations that are close to or at zero. But since we now print historical peaks even if current values are low (which is the point of this patch) these tests break.

I found that we have a lot of duplicated coding in the tests and reduced that with some common utility classes.

Tests:

  • locally tested runtime/NMT and the full gtest suite on x64 release, fastdebug and x86 fastdebug.
  • GHA

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-8320061: [nmt] Multiple issues with peak accounting (Enhancement - P4)

Reviewers

Reviewing

Using git

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

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

Using Skara CLI tools

Checkout this PR locally:
$ git pr checkout 16675

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

Using diff file

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

Webrev

Link to Webrev Comment

@bridgekeeper
Copy link

bridgekeeper bot commented Nov 15, 2023

👋 Welcome back stuefe! 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 Nov 15, 2023

@tstuefe The following labels will be automatically applied to this pull request:

  • core-libs
  • hotspot-runtime

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

@openjdk openjdk bot added hotspot-runtime hotspot-runtime-dev@openjdk.org core-libs core-libs-dev@openjdk.org labels Nov 15, 2023
@tstuefe
Copy link
Member Author

tstuefe commented Nov 15, 2023

/label remove core-libs

@openjdk openjdk bot removed the core-libs core-libs-dev@openjdk.org label Nov 15, 2023
@openjdk
Copy link

openjdk bot commented Nov 15, 2023

@tstuefe
The core-libs label was successfully removed.

@tstuefe tstuefe marked this pull request as ready for review November 15, 2023 13:56
@openjdk openjdk bot added the rfr Pull request is ready for review label Nov 15, 2023
@mlbridge
Copy link

mlbridge bot commented Nov 15, 2023

Webrevs

@tstuefe
Copy link
Member Author

tstuefe commented Nov 22, 2023

Friendly ping.

@tstuefe
Copy link
Member Author

tstuefe commented Nov 24, 2023

Ping @jdksjolen and @gerardziemski ? Would be nice to have this fixed in 22.

@jdksjolen
Copy link
Contributor

Hi Thomas, I'll take a look.

Copy link
Contributor

@jdksjolen jdksjolen left a comment

Choose a reason for hiding this comment

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

The HotSpot code looks good generally. The test utilities are nice to see.

I've looked through the test changes, but it seems that some change what the test does while some simply refactor the tests to use the new utilities. It would have been nice to have those in separate commtis to make reviewing easier. What is the idea behind changing the tests?

src/hotspot/share/nmt/memReporter.cpp Outdated Show resolved Hide resolved
src/hotspot/share/nmt/memReporter.cpp Show resolved Hide resolved
Comment on lines 213 to 215
// We omit printing altogether if:
// - the current reserved value falls below scale
// - none of the historic peaks (malloc, mmap committed, arena) raised above scale either
Copy link
Contributor

Choose a reason for hiding this comment

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

We omit printing altogether if all of the following values fall below the scale:
-  the current reserved value falls below scale
-  the historic peaks (malloc, mmap, committed, arena)

Perhaps this reads a bit better, rather than inversing the condition in the first bullet when writing out the second one.

src/hotspot/share/nmt/memReporter.cpp Outdated Show resolved Hide resolved
src/hotspot/share/nmt/memReporter.cpp Outdated Show resolved Hide resolved
test/hotspot/jtreg/runtime/NMT/HugeArenaTracking.java Outdated Show resolved Hide resolved
test/hotspot/jtreg/runtime/NMT/MallocTestType.java Outdated Show resolved Hide resolved
Comment on lines 802 to 822
while (needleIdx < needles.length && haystackIdx < haystack.length && (started == false || found == true)) {
if (verbose) {
System.out.println("" + haystackIdx + ":" + haystack[haystackIdx]);
}
found = haystack[haystackIdx].contains(needles[needleIdx]);
if (found) {
if (verbose) {
System.out.println("Matches pattern " + needleIdx + " (\"" + haystack[haystackIdx] + "\")");
}
started = true;
needleIdx++;
}
haystackIdx++;
}
if (needleIdx < needles.length) {
String err = "First unmatched: \"" + needles[needleIdx] + "\"";
if (!verbose) { // don't print twice
reportDiagnosticSummary();
}
throw new RuntimeException(err);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Splitting this up into multiple loops would simplify the code significantly imho, no need for two boolean flags for a start. Also, what does the !verbose check do exactly? Doesn't seem like it would be print twice without it, to me.

if (needles.length == 0) return;

int haystackStart = 0;
for (int i = 0; i < haystack.length; i++) {
     if (haystack[i].contains(needles[0])) {
      hayStackStart = i+1;
      return;
    }
}

for (int i = 1; i < needles.length; i++) {
    if (verbose && haystackStart + i < haystack.length) {
        System.out.println("" + haystackStart + i + ":" + haystack[haystackStart + i]);
    }
    if (haystackStart + i >= haystack.length
        || !haystack[haystackStart + i].contains(needles[i])) {
        String err = "First unmatched: \"" + needles[needleIdx] + "\"";
        if (!verbose) { // don't print twice
            reportDiagnosticSummary();
        }
        throw new RuntimeException(err);
    }
    if (verbose) {
        System.out.println("Matches pattern " + needleIdx + " (\"" + haystack[haystackStart + i] + "\")");
    }
}

Copy link
Member Author

Choose a reason for hiding this comment

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

Splitting this up into multiple loops would simplify the code significantly imho, no need for two boolean flags for a start.

If verbose=true, we print the haystack, with pattern matches marked. Your version omits printing for all lines until a needle is found, and only prints from the second needle on. Meaning, if the first pattern does not match, we don't see output. Arguably, that is the point where you need the output for test analysis.

Okay, I can give it a try.

Also, what does the !verbose check do exactly? Doesn't seem like it would be print twice without it, to me.

If an error happened, we print diagnostic summary (which mimics the behavior of all other "shouldBlaBla()" functions). So, we print twice if we run with verbose and run into an error.

Copy link
Member Author

Choose a reason for hiding this comment

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

Okay, I rewrote it in the style you prefer, while keeping the logs I wanted intact; this does not look much clearer to me tbh. I found the first version more elegant, since it was a one-loop state machine and could be easily adapted to other uses (e.g. scanning for pattern that are not in directly consecutive lines, but interspersed)

No matter. I got it to work, lets keep it this way.

Copy link
Contributor

Choose a reason for hiding this comment

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

If an error happened, we print diagnostic summary (which mimics the behavior of all other "shouldBlaBla()" functions). So, we print twice if we run with verbose and run into an error.

Thank you for explaining!

I found the first version more elegant, since it was a one-loop state machine and could be easily adapted to other uses (e.g. scanning for pattern that are not in directly consecutive lines, but interspersed)

That's just differing taste then, thank you for taking the effort to try out my idea :-).

@tstuefe
Copy link
Member Author

tstuefe commented Nov 24, 2023

The HotSpot code looks good generally. The test utilities are nice to see.

Hi Johan,

thanks for taking a look!

I've looked through the test changes, but it seems that some change what the test does while some simply refactor the tests to use the new utilities. It would have been nice to have those in separate commtis to make reviewing easier. What is the idea behind changing the tests?

The tests needed to be adapted, since they all expected entries to vanish when their current value is low. But that's exactly what this patch tries to fix: to preserve all the historical peaks. Because of that, a bunch of tests broke.

I only touched tests that had been broken by the NMT change. I did not change other tests. I did, however, add more tests for detailled "mmap" and "arena" numbers)

@tstuefe
Copy link
Member Author

tstuefe commented Nov 27, 2023

@jdksjolen are we good? (sorry, 22 deadline nears)

Copy link
Contributor

@jdksjolen jdksjolen left a comment

Choose a reason for hiding this comment

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

Yup, we're good! LGTM.

@openjdk
Copy link

openjdk bot commented Nov 27, 2023

@tstuefe This change now passes all automated pre-integration checks.

ℹ️ This project also has non-automated pre-integration requirements. Please see the file CONTRIBUTING.md for details.

After integration, the commit message for the final commit will be:

8320061: [nmt] Multiple issues with peak accounting

Reviewed-by: jsjolen, mbaesken

You can use pull request commands such as /summary, /contributor and /issue to adjust it as needed.

At the time when this comment was updated there had been no new commits pushed to the master branch. If another commit should be pushed before you perform the /integrate command, your PR will be automatically rebased. If you prefer to avoid any potential automatic rebasing, please check the documentation for the /integrate command for further details.

➡️ To integrate this PR with the above commit message to the master branch, type /integrate in a new comment.

@openjdk openjdk bot added the ready Pull request is ready to be integrated label Nov 27, 2023
@tstuefe
Copy link
Member Author

tstuefe commented Nov 27, 2023

Yup, we're good! LGTM.

Thanks @jdksjolen ! Anyone else willing to give a second review? @gerardziemski maybe?

Copy link
Member

@MBaesken MBaesken left a comment

Choose a reason for hiding this comment

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

seems a couple of tests need the copyright year update like test/hotspot/jtreg/runtime/NMT/MallocRoundingReportTest.java .
Otherwise looks okay.

@tstuefe
Copy link
Member Author

tstuefe commented Nov 28, 2023

seems a couple of tests need the copyright year update like test/hotspot/jtreg/runtime/NMT/MallocRoundingReportTest.java . Otherwise looks okay.

Many thanks, Matthias!

Copyrights fixed. I'll wait for a last GHA run, then push.

@tstuefe
Copy link
Member Author

tstuefe commented Nov 28, 2023

/integrate

@openjdk
Copy link

openjdk bot commented Nov 28, 2023

Going to push as commit dc256fb.
Since your change was applied there have been 3 commits pushed to the master branch:

  • adad132: 8320767: Use := wherever possible in spec.gmk.in
  • 69c0b24: 8320714: java/util/Locale/LocaleProvidersRun.java and java/util/ResourceBundle/modules/visibility/VisibilityTest.java timeout after passing
  • 66ae6d5: 8320899: Select the correct Makefile when running make in build directory

Your commit was automatically rebased without conflicts.

@openjdk openjdk bot added the integrated Pull request has been integrated label Nov 28, 2023
@openjdk openjdk bot closed this Nov 28, 2023
@openjdk openjdk bot removed ready Pull request is ready to be integrated rfr Pull request is ready for review labels Nov 28, 2023
@openjdk
Copy link

openjdk bot commented Nov 28, 2023

@tstuefe Pushed as commit dc256fb.

💡 You may see a message that your pull request was closed with unmerged commits. This can be safely ignored.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
hotspot-runtime hotspot-runtime-dev@openjdk.org integrated Pull request has been integrated
Development

Successfully merging this pull request may close these issues.

3 participants