Skip to content

Conversation

@wenshao
Copy link
Contributor

@wenshao wenshao commented Sep 29, 2023

Improve the performance of StringBuilder's append(boolean) and append(null).

When the coder is latin1, treat null/fals/true as an int. If the coder is utf16, treat it as a long, use ByteArrayLittleEndian.setInt/setLong to write it into buf.

The performance numbers under MacBookPro M1 Max are as follows:

-Benchmark                             Mode  Cnt   Score   Error  Units
-StringBuilders.toStringCharWithBool8  avgt   15  15.766 ? 0.355  ns/op
-StringBuilders.toStringCharWithNull8  avgt   15  10.723 ? 0.019  ns/op

+Benchmark                             Mode  Cnt   Score   Error  Units
+StringBuilders.toStringCharWithBool8  avgt   15  13.023 ? 0.141  ns/op (+21.07)
+StringBuilders.toStringCharWithNull8  avgt   15  8.480  ? 0.027  ns/op (+26.46)

Please review and don't hesitate to critique my approach and patch.


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

Reviewers

Reviewing

Using git

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

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

Using Skara CLI tools

Checkout this PR locally:
$ git pr checkout 15990

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

Using diff file

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

@wenshao wenshao changed the title optimization StringBuilder.append(boolean) and append(null) Optimization for StringBuilder.append boolean and null Sep 29, 2023
@bridgekeeper
Copy link

bridgekeeper bot commented Sep 29, 2023

👋 Welcome back wenshao! 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.

@wenshao wenshao changed the title Optimization for StringBuilder.append boolean and null Optimization for StringBuilder append boolean and null Sep 29, 2023
@openjdk
Copy link

openjdk bot commented Sep 29, 2023

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

  • core-libs

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.

@altrisi

This comment was marked as resolved.

@wenshao
Copy link
Contributor Author

wenshao commented Oct 3, 2023

@cl4es could you please review my code? Thank you!

@cl4es
Copy link
Member

cl4es commented Oct 3, 2023

Are these common enough that 2-3ns/op is a real win on any real app?

Instead of obfuscating core library code with ByteArrayLittleEndian I really want us to spend some time analyzing the trivial byte[] write operations and investigate if/how JITs can be improved here.

@wenshao
Copy link
Contributor Author

wenshao commented Oct 3, 2023

Are these common enough that 2-3ns/op is a real win on any real app?

Instead of obfuscating core library code with ByteArrayLittleEndian I really want us to spend some time analyzing the trivial byte[] write operations and investigate if/how JITs can be improved here.

I think StringBuilder.append(boolean/null) are common operations, and now we know that using ByteArrayLittleEndian can improve performance. Does JIT have any plans to do such optimization?

@liach
Copy link
Member

liach commented Oct 8, 2023

Can you try replacing the individual char puts with putStringAt with constant arguments "null" "false" "true" and check the performance results? I expect the benchmarks to show copying a constant byte array in full (the latin-1 bytes are stored in those string constants, not sure about how it's carried out exactly) versus putting the bytes into string with unaligned writes.

@wenshao
Copy link
Contributor Author

wenshao commented Oct 10, 2023

Can you try replacing the individual char puts with putStringAt with constant arguments "null" "false" "true" and check the performance results? I expect the benchmarks to show copying a constant byte array in full (the latin-1 bytes are stored in those string constants, not sure about how it's carried out exactly) versus putting the bytes into string with unaligned writes.

The implementation using append(b ? "true" : "false") will be slower than the baseline version

    public AbstractStringBuilder append(boolean b) {
        if (isLatin1()) {
            return append(b ? "true" : "false");
        }
        ...
    }

@bridgekeeper
Copy link

bridgekeeper bot commented Nov 7, 2023

@wenshao This pull request has been inactive for more than 4 weeks and will be automatically closed if another 4 weeks passes without any activity. To avoid this, simply add a new comment to the pull request. Feel free to ask for assistance if you need help with progressing this pull request towards integration!

@bridgekeeper
Copy link

bridgekeeper bot commented Dec 5, 2023

@wenshao This pull request has been inactive for more than 8 weeks and will now be automatically closed. If you would like to continue working on this pull request in the future, feel free to reopen it! This can be done using the /open pull request command.

@bridgekeeper bridgekeeper bot closed this Dec 5, 2023
@wenshao
Copy link
Contributor Author

wenshao commented Jan 22, 2024

/open

@openjdk openjdk bot reopened this Jan 22, 2024
@openjdk
Copy link

openjdk bot commented Jan 22, 2024

@wenshao This pull request is now open

@cl4es
Copy link
Member

cl4es commented Feb 2, 2024

We now have a PR for merging stores efficiently: #16245 It would be good to run the microbenchmarks you have evaluated here on that PR branch and see if that optimization narrows the gap. I have some hope we'll be able to dial back the use of ByteArray(LittleEndian) without sacrificing performance.

@wenshao
Copy link
Contributor Author

wenshao commented Feb 7, 2024

PR #16245 performs better

  • MacBookPro M1 Pro
Benchmark                             Mode  Cnt   Score   Error  Units # master
StringBuilders.toStringCharWithBool8  avgt   15  16.127 ? 0.223  ns/op

Benchmark                             Mode  Cnt   Score   Error  Units # pr/15990
StringBuilders.toStringCharWithBool8  avgt   15  13.955 ? 0.181  ns/op

Benchmark                             Mode  Cnt   Score   Error  Units # pr/16245
StringBuilders.toStringCharWithBool8  avgt   15  12.519 ? 0.228  ns/op

@bridgekeeper
Copy link

bridgekeeper bot commented Mar 6, 2024

@wenshao This pull request has been inactive for more than 4 weeks and will be automatically closed if another 4 weeks passes without any activity. To avoid this, simply add a new comment to the pull request. Feel free to ask for assistance if you need help with progressing this pull request towards integration!

*/
abstract sealed class AbstractStringBuilder implements Appendable, CharSequence
permits StringBuilder, StringBuffer {

Copy link
Member

Choose a reason for hiding this comment

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

Suggested change

Redundant line.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This extra line existed before this PR

@wenshao
Copy link
Contributor Author

wenshao commented Mar 8, 2024

The current implementation will have performance degradation when the coder is UTF16, but if combined with PR #16245, it will have very good performance.

The performance numbers under MacBookPro M1 Max are as follows:

Benchmark                                  Mode  Cnt    Score    Error  Units  # master
StringBuilders.toStringCharUTF16WithBool8  avgt   15   40.139 ?  0.113  ns/op
StringBuilders.toStringCharUTF16WithNull8  avgt   15   90.630 ?  5.380  ns/op
StringBuilders.toStringCharWithBool8       avgt   15   89.899 ?  2.695  ns/op
StringBuilders.toStringCharWithNull8       avgt   15   25.028 ?  0.150  ns/op

Benchmark                                  Mode  Cnt    Score    Error  Units  # PR 15990 (0d4d519) current version
StringBuilders.toStringCharUTF16WithBool8  avgt   15   44.336 ?  0.190  ns/op
StringBuilders.toStringCharUTF16WithNull8  avgt   15  126.908 ? 22.450  ns/op
StringBuilders.toStringCharWithBool8       avgt   15   64.320 ?  1.573  ns/op
StringBuilders.toStringCharWithNull8       avgt   15   23.825 ?  0.152  ns/op

Benchmark                                  Mode  Cnt    Score    Error  Units  # PR 16245
StringBuilders.toStringCharUTF16WithBool8  avgt   15   39.976 ?  0.179  ns/op
StringBuilders.toStringCharUTF16WithNull8  avgt   15   90.817 ?  5.681  ns/op
StringBuilders.toStringCharWithBool8       avgt   15   36.279 ?  1.273  ns/op
StringBuilders.toStringCharWithNull8       avgt   15   21.696 ?  0.109  ns/op

Benchmark                                  Mode  Cnt    Score    Error  Units  # PR 16245 + 15990
StringBuilders.toStringCharUTF16WithBool8  avgt   15   18.389 ?  0.408  ns/op
StringBuilders.toStringCharUTF16WithNull8  avgt   15   12.929 ?  0.023  ns/op
StringBuilders.toStringCharWithBool8       avgt   15   12.395 ?  0.176  ns/op
StringBuilders.toStringCharWithNull8       avgt   15    7.999 ?  0.109  ns/op

@openjdk
Copy link

openjdk bot commented Mar 13, 2024

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

@bridgekeeper
Copy link

bridgekeeper bot commented Apr 11, 2024

@wenshao This pull request has been inactive for more than 4 weeks and will be automatically closed if another 4 weeks passes without any activity. To avoid this, simply add a new comment to the pull request. Feel free to ask for assistance if you need help with progressing this pull request towards integration!

@bridgekeeper
Copy link

bridgekeeper bot commented May 9, 2024

@wenshao This pull request has been inactive for more than 8 weeks and will now be automatically closed. If you would like to continue working on this pull request in the future, feel free to reopen it! This can be done using the /open pull request command.

@bridgekeeper bridgekeeper bot closed this May 9, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Development

Successfully merging this pull request may close these issues.

5 participants