jdk icon indicating copy to clipboard operation
jdk copied to clipboard

8335366: Improve String.format performance with fastpath

Open wenshao opened this issue 7 months ago • 12 comments

We need a String format solution with good performance. String Template was once expected, but it has been removed. j.u.Formatter is powerful, but its performance is not good enough.

This PR implements a subset of j.u.Formatter capabilities. The performance is good enough that it is a fastpath for commonly used functions. When the supported functions are exceeded, it will fall back to using j.u.Formatter.

The performance of this implementation is good enough, the fastpath has low detection cost, There is no noticeable performance degradation when falling back to j.u.Formatter via fastpath.

Below is a comparison of String.format and concat-based and StringBuilder:

  • benchmark java code
public class StringFormat {
    @Benchmark
    public String stringIntFormat() {
        return "%s %d".formatted(s, i);
    }

    @Benchmark
    public String stringIntConcat() {
        return s + " " + i;
    }

    @Benchmark
    public String stringIntStringBuilder() {
        return new StringBuilder(s).append(" ").append(i).toString();
    }
}
  • benchmark number on macbook m1 pro
Benchmark                            Mode  Cnt   Score   Error  Units
StringFormat.stringIntConcat         avgt   15   6.541 ? 0.056  ns/op
StringFormat.stringIntFormat         avgt   15  17.399 ? 0.133  ns/op
StringFormat.stringIntStringBuilder  avgt   15   8.004 ? 0.063  ns/op

From the above data, we can see that the implementation of fastpath reduces the performance difference between String.format and StringBuilder from 10 times to 2~3 times.

The implementation of fastpath supports the following four specifiers, which can appear at most twice and support a width of 1 to 9.

d
x
X
s

If necessary, we can add a few more.

Below is a comparison of performance numbers running on a MacBook M1, showing a significant performance improvement.

-Benchmark                          Mode  Cnt    Score    Error  Units (baseline)
-StringFormat.complexFormat         avgt   15  895.954 ? 52.541  ns/op
-StringFormat.decimalFormat         avgt   15  277.420 ? 18.254  ns/op
-StringFormat.stringFormat          avgt   15   66.787 ?  2.715  ns/op
-StringFormat.stringIntFormat       avgt   15   81.046 ?  1.879  ns/op
-StringFormat.widthStringFormat     avgt   15   38.897 ?  0.114  ns/op
-StringFormat.widthStringIntFormat  avgt   15  109.841 ?  1.028  ns/op

+Benchmark                          Mode  Cnt    Score    Error  Units (current f925339e93fdf7a281462554ce5d73139bd0f0cd)
+StringFormat.complexFormat         avgt   15  863.156 ? 42.140  ns/op
+StringFormat.decimalFormat         avgt   15  287.342 ? 19.896  ns/op
+StringFormat.stringFormat          avgt   15    6.738 ?  0.027  ns/op
+StringFormat.stringIntFormat       avgt   15   17.046 ?  0.090  ns/op
+StringFormat.widthStringFormat     avgt   15    8.993 ?  0.073  ns/op
+StringFormat.widthStringIntFormat  avgt   15   17.602 ?  0.014  ns/op

Progress

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

Issue

  • JDK-8335366: Improve String.format performance with fastpath (Enhancement - P4)

Reviewing

Using git

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

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

Using Skara CLI tools

Checkout this PR locally:
$ git pr checkout 19956

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

Using diff file

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

Webrev

Link to Webrev Comment

wenshao avatar Jun 29 '24 11:06 wenshao