On Fri, 5 Jul 2024 15:40:24 GMT, Shaojin Wen <d...@openjdk.org> wrote:
> String.format is widely used, and improving its performance is very > meaningful. This PR can significantly improve the performance of > String.format. Sorry, there are many changes, which will take a lot of time. > I hope you can review it patiently. > > > Improved performance includes the following: > > ## 1. Write directly during the parse process to reduce object allocation. > > In the current Formatter implementation, some objects do not need to be > allocated, such as: > > > class Formatter { > public Formatter format(Locale l, String format, Object ... args) { > List<FormatString> fsa = parse(format); > // ... > } > > static List<FormatString> parse(String s) { > ArrayList<FormatString> al = new ArrayList<>(); > > while (i < max) { > int n = s.indexOf('%', i); > if (n < 0) { > // > al.add(new FixedString(s, i, max)); > } > } > } > } > > In the process of parsing, the content that is not a Specifier is directly > appended without going through FixedString. By directly printing the parsed > FormatString object, there is no need to construct a `List<FormatString> fsa` > to store it. > > ## 2. Fast path print > Use specialized FormatString implementations for single-character and > single-width specifiers to avoid calling the large FormatSpecifier#print > method. > > ## 3. String.format directly calls j.u.Formatter > String.format directly calls j.u.Formatter via SharedSecrets to improve > performance The performance improvement in most scenarios is very significant. The performance of complexFormat/decimalFormat scenes has decreased because the inline root has changed. I have a solution and will submit it after this PR is completed. The content is these two commits: [split print decimal](https://github.com/wenshao/jdk/commit/e3a6fe17912b5c17901e1518e74c9ab9a7e0057f) [refactor parser](https://github.com/wenshao/jdk/commit/0cc63265062d1480bc31e9010f91e83bc7d911f3) Performance numbers under MacBook M1 Pro make test TEST="micro:java.lang.StringFormat" # baseline 982e3f0e14dd4e5d0d13c6c0fe49903a555f5f5e -Benchmark Mode Cnt Score Error Units -StringFormat.complexFormat avgt 15 944.745 ? 70.806 ns/op -StringFormat.decimalFormat avgt 15 285.709 ? 14.579 ns/op -StringFormat.intFormat avgt 15 60.176 ? 1.258 ns/op -StringFormat.intFormatUtf16 avgt 15 124.083 ? 3.547 ns/op -StringFormat.intHexFormat avgt 15 251.195 ? 68.026 ns/op -StringFormat.intHexFormatUtf16 avgt 15 126.030 ? 14.631 ns/op -StringFormat.intHexUFormat avgt 15 201.430 ? 7.106 ns/op -StringFormat.intHexUFormatUtf16 avgt 15 137.988 ? 13.681 ns/op -StringFormat.intIntFormat avgt 15 131.670 ? 6.723 ns/op -StringFormat.intIntFormatUtf16 avgt 15 127.279 ? 2.857 ns/op -StringFormat.intOctalFormat avgt 15 248.651 ? 67.083 ns/op -StringFormat.intOctalFormatUtf16 avgt 15 115.897 ? 2.131 ns/op -StringFormat.lineFormatUtf16 avgt 15 143.465 ? 12.187 ns/op -StringFormat.lineFormat avgt 15 59.753 ? 0.598 ns/op -StringFormat.stringFormat avgt 15 62.188 ? 2.317 ns/op -StringFormat.stringFormatUtf16 avgt 15 158.438 ? 8.377 ns/op -StringFormat.stringIntFormat avgt 15 123.869 ? 4.107 ns/op -StringFormat.stringIntFormatUtf16 avgt 15 173.503 ? 19.792 ns/op -StringFormat.stringIntHexFormat avgt 15 156.958 ? 6.641 ns/op -StringFormat.stringIntHexUFormat avgt 15 163.373 ? 9.474 ns/op -StringFormat.stringIntOctalFormat avgt 15 157.360 ? 6.569 ns/op -StringFormat.stringIntOctalFormatUtf16 avgt 15 147.697 ? 6.050 ns/op -StringFormat.stringIntRFormat avgt 15 137.308 ? 7.921 ns/op -StringFormat.stringIntRFormatUtf16 avgt 15 199.334 ? 6.728 ns/op -StringFormat.stringWidthIntFormat avgt 15 148.663 ? 3.549 ns/op -StringFormat.stringWidthIntFormatUtf16 avgt 15 138.486 ? 3.704 ns/op -StringFormat.widthStringFormat avgt 15 94.476 ? 21.884 ns/op -StringFormat.widthStringFormatUtf16 avgt 15 130.753 ? 3.555 ns/op -StringFormat.widthStringIntFormat avgt 15 153.143 ? 9.967 ns/op -StringFormat.widthStringIntFormatUtf16 avgt 15 162.539 ? 6.323 ns/op # current 5d866bf17d96bd0f0e4545d7eee5912eda2e3a94 +Benchmark Mode Cnt Score Error Units +StringFormat.complexFormat avgt 15 1008.713 ? 86.458 ns/op +StringFormat.decimalFormat avgt 15 386.167 ? 76.843 ns/op +StringFormat.intFormat avgt 15 19.628 ? 0.076 ns/op +StringFormat.intFormatUtf16 avgt 15 25.678 ? 0.224 ns/op +StringFormat.intHexFormat avgt 15 106.220 ? 31.809 ns/op +StringFormat.intHexFormatUtf16 avgt 15 104.698 ? 7.862 ns/op +StringFormat.intHexUFormat avgt 15 99.228 ? 5.523 ns/op +StringFormat.intHexUFormatUtf16 avgt 15 73.016 ? 5.311 ns/op +StringFormat.intIntFormat avgt 15 86.851 ? 3.479 ns/op +StringFormat.intIntFormatUtf16 avgt 15 88.352 ? 4.553 ns/op +StringFormat.intOctalFormat avgt 15 176.610 ? 38.408 ns/op +StringFormat.intOctalFormatUtf16 avgt 15 69.189 ? 1.362 ns/op +StringFormat.lineFormat avgt 15 20.554 ? 0.044 ns/op +StringFormat.lineFormatUtf16 avgt 15 45.253 ? 29.207 ns/op +StringFormat.stringFormat avgt 15 19.869 ? 0.073 ns/op +StringFormat.stringFormatUtf16 avgt 15 25.119 ? 0.065 ns/op +StringFormat.stringIntFormat avgt 15 87.287 ? 2.808 ns/op +StringFormat.stringIntFormatUtf16 avgt 15 76.377 ? 5.036 ns/op +StringFormat.stringIntHexFormat avgt 15 109.946 ? 53.831 ns/op +StringFormat.stringIntHexUFormat avgt 15 117.475 ? 55.030 ns/op +StringFormat.stringIntOctalFormat avgt 15 109.248 ? 5.347 ns/op +StringFormat.stringIntOctalFormatUtf16 avgt 15 167.115 ? 25.219 ns/op +StringFormat.stringIntRFormat avgt 15 95.606 ? 8.299 ns/op +StringFormat.stringIntRFormatUtf16 avgt 15 92.061 ? 17.822 ns/op +StringFormat.stringWidthIntFormat avgt 15 91.130 ? 5.954 ns/op +StringFormat.stringWidthIntFormatUtf16 avgt 15 101.798 ? 7.317 ns/op +StringFormat.widthStringFormat avgt 15 20.644 ? 0.344 ns/op +StringFormat.widthStringFormatUtf16 avgt 15 26.111 ? 0.228 ns/op +StringFormat.widthStringIntFormat avgt 15 79.138 ? 24.128 ns/op +StringFormat.widthStringIntFormatUtf16 avgt 15 54.597 ? 1.191 ns/op | | baseline | current | delta | | --- | --- | --- | --- | | StringFormat.complexFormat | 944.745 | 1008.713 | -6.34% | | StringFormat.decimalFormat | 285.709 | 386.167 | -26.01% | | StringFormat.intFormat | 60.176 | 19.628 | 206.58% | | StringFormat.intFormatUtf16 | 124.083 | 25.678 | 383.23% | | StringFormat.intHexFormat | 251.195 | 106.220 | 136.49% | | StringFormat.intHexFormatUtf16 | 126.030 | 104.698 | 20.37% | | StringFormat.intHexUFormat | 201.430 | 99.228 | 103.00% | | StringFormat.intHexUFormatUtf16 | 137.988 | 73.016 | 88.98% | | StringFormat.intIntFormat | 131.670 | 86.851 | 51.60% | | StringFormat.intIntFormatUtf16 | 127.279 | 88.352 | 44.06% | | StringFormat.intOctalFormat | 248.651 | 176.610 | 40.79% | | StringFormat.intOctalFormatUtf16 | 115.897 | 69.189 | 67.51% | | StringFormat.lineFormatUtf16 | 143.465 | 45.253 | 217.03% | | StringFormat.lineFormat | 59.753 | 20.554 | 190.71% | | StringFormat.stringFormat | 62.188 | 19.869 | 212.99% | | StringFormat.stringFormatUtf16 | 158.438 | 25.119 | 530.75% | | StringFormat.stringIntFormat | 123.869 | 87.287 | 41.91% | | StringFormat.stringIntFormatUtf16 | 173.503 | 76.377 | 127.17% | | StringFormat.stringIntHexFormat | 156.958 | 109.946 | 42.76% | | StringFormat.stringIntHexUFormat | 163.373 | 117.475 | 39.07% | | StringFormat.stringIntOctalFormat | 157.360 | 109.248 | 44.04% | | StringFormat.stringIntOctalFormatUtf16 | 147.697 | 167.115 | -11.62% | | StringFormat.stringIntRFormat | 137.308 | 95.606 | 43.62% | | StringFormat.stringIntRFormatUtf16 | 199.334 | 92.061 | 116.52% | | StringFormat.stringWidthIntFormat | 148.663 | 91.130 | 63.13% | | StringFormat.stringWidthIntFormatUtf16 | 138.486 | 101.798 | 36.04% | | StringFormat.widthStringFormat | 94.476 | 20.644 | 357.64% | | StringFormat.widthStringFormatUtf16 | 130.753 | 26.111 | 400.76% | | StringFormat.widthStringIntFormat | 153.143 | 79.138 | 93.51% | | StringFormat.widthStringIntFormatUtf16 | 162.539 | 54.597 | 197.71% | ------------- PR Comment: https://git.openjdk.org/jdk/pull/20055#issuecomment-2211096061