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

8303078: Reduce allocations when pretty printing JCTree during compilation #12667

Closed

Conversation

dreis2211
Copy link
Contributor

@dreis2211 dreis2211 commented Feb 20, 2023

Hi,

I've been recently optimizing a few project pipelines and always noticed that their compilation step is somewhat "expensive". Zooming into the issue always revealed Lombok to be a larger contributor. Unfortunately, I can't get rid of Lombok in this customer project (before you ask).

Apparently, Lombok is printing the respective JCTree here and there to check for type matches. I can't imagine this to be super efficient, but that's how it is at the moment.
image

Anyhow, regardless of the Lombok inefficiencies I think there are some optimization opportunities in the JDK itself.

  1. Overall, Pretty.visitSelect accounts for 8-10% of the total allocations in this project. And among those there are StringBuilder allocations coming from the following:
    public void visitSelect(JCFieldAccess tree) {
        try {
            printExpr(tree.selected, TreeInfo.postfixPrec);
            // StringBuilder allocations hiding in here.
            print("." + tree.name);
        } catch (IOException e) {
            throw new UncheckedIOException(e);
        }
    }

This PR splits the print calls into two separate ones to avoid this String concatenation.

...
            printExpr(tree.selected, TreeInfo.postfixPrec);
            print('.');
            print(tree.name);
...

Secondly, the print method takes an Object which seems like a good fit for another (private?) variant of it that only takes a char. By this we would probably avoid any eventual boxing and avoid any conversion with Convert.escapeUnicode(s.toString()) that seems superfluous for chars like ., , or any braces like (, { etc.

This is currently a draft PR as long as the scope is not clarified. It currently only includes the necessary changes that would optimize the particular use-case. But there are more cases where e.g. the new char variant could be used and/or any String concatenation could be split into separate print calls.

Let me know what you think and if I should include the other cases as well. If you think this is worthwhile, I'd appreciate if this is is sponsored. (Including creating an issue as I can't do this myself apparently. I will of course squash everything together with the proper issue ID once available.)

I've contributed before, so the CLA should be signed.

Cheers,
Christoph


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-8303078: Reduce allocations when pretty printing JCTree during compilation

Reviewers

Reviewing

Using git

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

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

Using Skara CLI tools

Checkout this PR locally:
$ git pr checkout 12667

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

Using diff file

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

@bridgekeeper
Copy link

bridgekeeper bot commented Feb 20, 2023

👋 Welcome back dreis2211! 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 Feb 20, 2023

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

  • compiler

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 compiler compiler-dev@openjdk.org label Feb 20, 2023
@dreis2211
Copy link
Contributor Author

dreis2211 commented Feb 22, 2023

With the patch applied I can reduce things for an internal product.

Some specs about the project:

~2500 classes
Average size: ~76 lines
Largest class: ~2500 lines
Mostly hand-written, but some auto-generated protobuf files (I'd say 90/10 split)

CPU profile before
image

CPU profile after
image

Allocation profile before
image

Allocation profile after
image

Mode Frames matched before Frames matched after
cpu 2.27% 1.42%
alloc 7.09% 4.13%

In terms of timings I couldn't measure anything substantially on the actual project. Neither a regression, nor a substantial improvement. But it's not so much about time anyhow but about the allocations here. The overall goal is to reduce impact on GC that is using 27% of the CPU frames (to give you some more background). Obviously, this is not coming from the JDK alone and Lombok is a major contributor here, but the JDK can ease the impact of Lombok here I'd say.
image

Admittedly, it's more on the smaller end of things and a smaller knob in terms of GC improvements.

Let me know if you need more information.

@dreis2211
Copy link
Contributor Author

In terms of some more absolute allocation numbers:

Before (TOP 3 => ~5,6GB)

       bytes  percent  samples  top
  ----------  -------  -------  ---
  3581028736   26.79%    10682  byte[]
  1291159216    9.66%     3930  java.lang.Object[]
   740065552    5.54%     2161  java.lang.String

After (TOP 3 => ~5,4GB)

      bytes  percent  samples  top
  ----------  -------  -------  ---
  3376915824   26.33%    11615  byte[]
  1284160152   10.01%     3847  java.lang.Object[]
   730100712    5.69%     2023  java.lang.String

StringBuilder savings account for an additional 62MB

Copy link
Contributor

@jonathan-gibbons jonathan-gibbons left a comment

Choose a reason for hiding this comment

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

If we proceed with this, I would recommend looking for other possible uses of the new method.

A simple grep shows 129 single character strings, of which 97 are arguments to print.

Separate but related, I note that a similar class, DocPretty.java, has 75 single character strings, of which 68 are arguments to print.

Overall changing the coding style to use out.print(char) seems worthwhile.

@dreis2211
Copy link
Contributor Author

dreis2211 commented Feb 22, 2023

@jonathan-gibbons Thanks for your review.

If we proceed with this, I would recommend looking for other possible uses of the new method.

That's the idea - there are multiple cases where this could be used. I'll push an updated version that already changes things to make reviewing a bit easier.

EDIT: Done.

@jonathan-gibbons
Copy link
Contributor

jonathan-gibbons commented Feb 22, 2023

Filed JDK-8303078

You might want to un-Draft the PR, and prefix the title with JDK-8303078:

@jonathan-gibbons
Copy link
Contributor

There are 19 instances of string concatenation in print arguments, for your consideration as well.

@dreis2211 dreis2211 force-pushed the jctree-pretty-print-allocations branch from c4a003c to 846c8eb Compare February 22, 2023 15:19
@dreis2211 dreis2211 changed the title Reduce allocations when pretty printing JCTree during compilation 8303078: Reduce allocations when pretty printing JCTree during compilation Feb 22, 2023
@dreis2211 dreis2211 force-pushed the jctree-pretty-print-allocations branch from 846c8eb to 3efe9d5 Compare February 22, 2023 15:23
@dreis2211 dreis2211 marked this pull request as ready for review February 22, 2023 15:28
@dreis2211
Copy link
Contributor Author

@jonathan-gibbons Made the adjustments to Pretty.

@dreis2211 dreis2211 force-pushed the jctree-pretty-print-allocations branch from 3efe9d5 to 45d1219 Compare February 22, 2023 15:31
@openjdk openjdk bot added the rfr Pull request is ready for review label Feb 22, 2023
@openjdk
Copy link

openjdk bot commented Feb 22, 2023

@dreis2211 Please do not rebase or force-push to an active PR as it invalidates existing review comments. Note for future reference, the bots always squash all changes into a single commit automatically as part of the integration. See OpenJDK Developers’ Guide for more information.

@mlbridge
Copy link

mlbridge bot commented Feb 22, 2023

Webrevs

Copy link
Contributor

@vicente-romero-oracle vicente-romero-oracle left a comment

Choose a reason for hiding this comment

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

this is looking good, I think that once the changes to DocPretty.java, as Jon suggested, are included in this patch it should be good to go

@dreis2211
Copy link
Contributor Author

@vicente-romero-oracle & @jonathan-gibbons made the adjustments to DocPretty now as well.

@dreis2211
Copy link
Contributor Author

There are some test failures in langtools/tier1 that seem related. Will check

@jonathan-gibbons
Copy link
Contributor

I confirm that all the langtools tests now pass, at least on my local laptop.

Copy link
Contributor

@jonathan-gibbons jonathan-gibbons left a comment

Choose a reason for hiding this comment

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

Thanks for updating DocPretty.java to follow the same conventions as Pretty.java, even though it was probably not required for your Lombok-based use-case.

I've gone through all the latest patch, and run all the langtools tests as well. All pass on my laptop, and there is no reason to expect any cross-platform issues.

I'll mark it Approved, but while not strictly necessary, I recommend that you wait for Vicente's approval as well, in case he has any final comments.

@openjdk
Copy link

openjdk bot commented Feb 23, 2023

@dreis2211 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:

8303078: Reduce allocations when pretty printing JCTree during compilation

Reviewed-by: jjg, vromero

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 66 new commits pushed to the master branch:

  • 23e9d9d: 8302811: NMT.random_reallocs_vm fails if NMT is off
  • fcaf871: 8302028: Port fdlibm atan2 to Java
  • 07e976a: 8303081: Serial: Remove unused VM_MarkSweep
  • 8de841d: 8302667: Improve message format when failing to load symbols or libraries
  • f893d23: 8303024: (fs) WindowsFileSystem.supportedFileAttributeViews can use Set.of
  • d7ada66: 8303084: G1 Heap region liveness verification has inverted return value
  • 5d7e7e2: 8302760: Improve liveness/remembered set verification for G1
  • b0e0f37: 8303067: G1: Remove unimplemented G1FullGCScope::heap_transition
  • 1a62a12: 8302880: Fix includes in g1ConcurrentMarkObjArrayProcessor files
  • ee37af4: 8302975: Remove redundant mark verification during G1 Full GC
  • ... and 56 more: https://git.openjdk.org/jdk/compare/71cf7c4409025c87ac786a54171f00de69fe5317...master

As there are no conflicts, your changes will automatically be rebased on top of these commits when integrating. If you prefer to avoid this automatic rebasing, please check the documentation for the /integrate command for further details.

As you do not have Committer status in this project an existing Committer must agree to sponsor your change. Possible candidates are the reviewers of this PR (@jonathan-gibbons, @vicente-romero-oracle) but any other Committer may sponsor as well.

➡️ To flag this PR as ready for integration with the above commit message, type /integrate in a new comment. (Afterwards, your sponsor types /sponsor in a new comment to perform the integration).

@openjdk openjdk bot added the ready Pull request is ready to be integrated label Feb 23, 2023
Copy link
Contributor

@vicente-romero-oracle vicente-romero-oracle left a comment

Choose a reason for hiding this comment

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

looks good. I will run an internal test that executes all regression tests in all supported platforms just to be xtra sure

@vicente-romero-oracle
Copy link
Contributor

looks good. I will run an internal test that executes all regression tests in all supported platforms just to be xtra sure

all green :)

@dreis2211
Copy link
Contributor Author

/integrate

@openjdk openjdk bot added the sponsor Pull request is ready to be sponsored label Feb 23, 2023
@openjdk
Copy link

openjdk bot commented Feb 23, 2023

@dreis2211
Your change (at version 03e9893) is now ready to be sponsored by a Committer.

@mlbridge
Copy link

mlbridge bot commented Feb 23, 2023

Mailing list message from Jonathan Gibbons on compiler-dev:

Regarding paranoia: I'll address that in the PR, I'd like to record the
suggestion there, but probably agree with your suggestion to leave it as is.

Regarding the scary comment: the comment goes back to pre-module days,
when more people were helping themselves to using notionally internal
JDK API.? Now that the internals are encapsulated, the scary comment
seems less important, and might even go away, or be replaced by a single
notice higher up. (It's helpful to have a place we can point to that
says, "you were warned...").? We have already removed the scary warning
from the `jdk.javadoc` module, but that code has the added advantage of
having `.internal.` in the name of the relevant packages.

-- Jon

On 2/22/23 11:02 AM, Christoph Dreis wrote:

@jonathan-gibbons
Copy link
Contributor

/sponsor

@openjdk
Copy link

openjdk bot commented Feb 23, 2023

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

Your commit was automatically rebased without conflicts.

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

openjdk bot commented Feb 23, 2023

@jonathan-gibbons @dreis2211 Pushed as commit 58ca711.

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

@dreis2211
Copy link
Contributor Author

Thanks @jonathan-gibbons & @vicente-romero-oracle for your active advice, reviewing and sponsoring :)

@jonathan-gibbons
Copy link
Contributor

Thanks @jonathan-gibbons & @vicente-romero-oracle for your active advice, reviewing and sponsoring :)

You're welcome; thanks for the contribution.

@vicente-romero-oracle
Copy link
Contributor

Thanks @jonathan-gibbons & @vicente-romero-oracle for your active advice, reviewing and sponsoring :)

You're welcome; thanks for the contribution.

+1

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