On Mon, 1 Jul 2024 19:17:50 GMT, Shaojin Wen <d...@openjdk.org> wrote:

>> 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                ...
>
> Shaojin Wen has updated the pull request incrementally with one additional 
> commit since the last revision:
> 
>   improve StringFormat benchmark

I updated the StringFormat benchmark. Here are the performance numbers on a 
MacBook M1 Pro:

# baseline 5d866bf17d96bd0f0e4545d7eee5912eda2e3a94
-Benchmark                               Mode  Cnt    Score    Error  Units
-StringFormat.complexFormat              avgt   15  980.323 ? 77.227  ns/op
-StringFormat.decimalFormat              avgt   15  277.042 ? 17.070  ns/op
-StringFormat.intFormat                  avgt   15   61.400 ?  0.269  ns/op
-StringFormat.intFormatUtf16             avgt   15  126.581 ?  2.270  ns/op
-StringFormat.intHexFormat               avgt   15  232.125 ? 79.431  ns/op
-StringFormat.intHexFormatUtf16          avgt   15  113.980 ?  1.537  ns/op
-StringFormat.intHexUFormat              avgt   15  202.426 ? 10.029  ns/op
-StringFormat.intHexUFormatUtf16         avgt   15  132.994 ?  3.183  ns/op
-StringFormat.intIntFormat               avgt   15  138.301 ?  7.932  ns/op
-StringFormat.intIntFormatUtf16          avgt   15  131.910 ?  7.142  ns/op
-StringFormat.intOctalFormat             avgt   15  249.411 ? 89.041  ns/op
-StringFormat.intOctalFormatUtf16        avgt   15  117.244 ?  1.426  ns/op
-StringFormat.stringFormat               avgt   15   63.645 ?  3.791  ns/op
-StringFormat.stringFormatUtf16          avgt   15  150.495 ?  9.363  ns/op
-StringFormat.stringIntFormat            avgt   15  123.888 ?  4.177  ns/op
-StringFormat.stringIntFormatUtf16       avgt   15  174.825 ? 18.766  ns/op
-StringFormat.stringIntHexFormat         avgt   15  150.750 ?  4.177  ns/op
-StringFormat.stringIntHexUFormat        avgt   15  162.287 ?  5.530  ns/op
-StringFormat.stringIntOctalFormat       avgt   15  157.474 ?  6.569  ns/op
-StringFormat.stringIntOctalFormatUtf16  avgt   15  151.507 ? 20.590  ns/op
-StringFormat.stringIntRFormat           avgt   15  135.326 ?  1.884  ns/op
-StringFormat.stringIntRFormatUtf16      avgt   15  196.023 ?  6.874  ns/op
-StringFormat.stringWidthIntFormat       avgt   15  151.324 ?  2.308  ns/op
-StringFormat.stringWidthIntFormatUtf16  avgt   15  136.286 ?  2.770  ns/op
-StringFormat.widthStringFormat          avgt   15   93.960 ? 22.499  ns/op
-StringFormat.widthStringFormatUtf16     avgt   15  127.997 ? 18.408  ns/op
-StringFormat.widthStringIntFormat       avgt   15  150.131 ? 12.496  ns/op
-StringFormat.widthStringIntFormatUtf16  avgt   15  159.734 ?  3.821  ns/op

# current 392898703ce9907b84d51098ef7b8f536d355742
+Benchmark                               Mode  Cnt    Score    Error  Units
+StringFormat.complexFormat              avgt   15  909.352 ? 46.681  ns/op
+StringFormat.decimalFormat              avgt   15  290.069 ? 20.778  ns/op
+StringFormat.intFormat                  avgt   15   11.211 ?  0.047  ns/op
+StringFormat.intFormatUtf16             avgt   15   11.799 ?  0.032  ns/op
+StringFormat.intHexFormat               avgt   15   35.550 ?  7.420  ns/op
+StringFormat.intHexFormatUtf16          avgt   15   35.680 ?  1.608  ns/op
+StringFormat.intHexUFormat              avgt   15   31.229 ?  3.043  ns/op
+StringFormat.intHexUFormatUtf16         avgt   15   46.915 ?  7.014  ns/op
+StringFormat.intIntFormat               avgt   15   31.573 ?  0.539  ns/op
+StringFormat.intIntFormatUtf16          avgt   15   31.595 ?  0.345  ns/op
+StringFormat.intOctalFormat             avgt   15  265.869 ? 60.233  ns/op
+StringFormat.intOctalFormatUtf16        avgt   15  153.843 ? 18.901  ns/op
+StringFormat.stringFormat               avgt   15   10.852 ?  0.009  ns/op
+StringFormat.stringFormatUtf16          avgt   15   13.422 ?  0.203  ns/op
+StringFormat.stringIntFormat            avgt   15   36.833 ?  5.495  ns/op
+StringFormat.stringIntFormatUtf16       avgt   15   21.482 ?  0.043  ns/op
+StringFormat.stringIntHexFormat         avgt   15   19.926 ?  0.041  ns/op
+StringFormat.stringIntHexUFormat        avgt   15   19.954 ?  0.055  ns/op
+StringFormat.stringIntOctalFormat       avgt   15  137.748 ?  1.796  ns/op
+StringFormat.stringIntOctalFormatUtf16  avgt   15  126.615 ? 13.933  ns/op
+StringFormat.stringIntRFormat           avgt   15   37.231 ?  2.449  ns/op
+StringFormat.stringIntRFormatUtf16      avgt   15   38.406 ?  0.577  ns/op
+StringFormat.stringWidthIntFormat       avgt   15   43.897 ?  6.464  ns/op
+StringFormat.stringWidthIntFormatUtf16  avgt   15   28.683 ?  2.147  ns/op
+StringFormat.widthStringFormat          avgt   15   11.421 ?  0.021  ns/op
+StringFormat.widthStringFormatUtf16     avgt   15   12.228 ?  0.023  ns/op
+StringFormat.widthStringIntFormat       avgt   15   38.051 ?  6.635  ns/op
+StringFormat.widthStringIntFormatUtf16  avgt   15   23.347 ?  1.049  ns/op+


In the scenario where the performance is improved or worse through fastpath and 
then falls back to j.u.Formatter, it is confusing.

|   | baseline  | current | delta |
| --- | --- | --- | --- |
| StringFormat.complexFormat | 980.323 | 909.352 | 7.80% |
| StringFormat.decimalFormat | 277.042 | 290.069 | -4.49% |
| StringFormat.intOctalFormat | 249.411 | 265.869 | -6.19% |
| StringFormat.intOctalFormatUtf16 | 117.244 | 153.843 | -23.79% |
| StringFormat.stringIntOctalFormat | 157.474 | 137.748 | 14.32% |
| StringFormat.stringIntOctalFormatUtf16 | 151.507 | 126.615 | 19.66% |

In other scenarios hit by fastpath, the performance is significantly improved.

|   | baseline  | current | delta |
| --- | --- | --- | --- |
| StringFormat.intFormat | 61.400 | 11.211 | 447.68% |
| StringFormat.intFormatUtf16 | 126.581 | 11.799 | 972.81% |
| StringFormat.intHexFormat | 232.125 | 35.550 | 552.95% |
| StringFormat.intHexFormatUtf16 | 113.980 | 35.680 | 219.45% |
| StringFormat.intHexUFormat | 202.426 | 31.229 | 548.20% |
| StringFormat.intHexUFormatUtf16 | 132.994 | 46.915 | 183.48% |
| StringFormat.intIntFormat | 138.301 | 31.573 | 338.04% |
| StringFormat.intIntFormatUtf16 | 131.910 | 31.595 | 317.50% |
| StringFormat.stringFormat | 63.645 | 10.852 | 486.48% |
| StringFormat.stringFormatUtf16 | 150.495 | 13.422 | 1021.26% |
| StringFormat.stringIntFormat | 123.888 | 36.833 | 236.35% |
| StringFormat.stringIntFormatUtf16 | 174.825 | 21.482 | 713.82% |
| StringFormat.stringIntHexFormat | 150.750 | 19.926 | 656.55% |
| StringFormat.stringIntHexUFormat | 162.287 | 19.954 | 713.31% |
| StringFormat.stringIntRFormat | 135.326 | 37.231 | 263.48% |
| StringFormat.stringIntRFormatUtf16 | 196.023 | 38.406 | 410.40% |
| StringFormat.stringWidthIntFormat | 151.324 | 43.897 | 244.73% |
| StringFormat.stringWidthIntFormatUtf16 | 136.286 | 28.683 | 375.15% |
| StringFormat.widthStringFormat | 93.960 | 11.421 | 722.70% |
| StringFormat.widthStringFormatUtf16 | 127.997 | 12.228 | 946.75% |
| StringFormat.widthStringIntFormat | 150.131 | 38.051 | 294.55% |
| StringFormat.widthStringIntFormatUtf16 | 159.734 | 23.347 | 584.17% |

-------------

PR Comment: https://git.openjdk.org/jdk/pull/19956#issuecomment-2201575948

Reply via email to