On Wed, 26 Jun 2024 09:43:32 GMT, lingjun-cg <d...@openjdk.org> wrote:

>> ### Performance regression of DecimalFormat.format
>> From the output of perf, we can see the hottest regions contain atomic 
>> instructions.  But when run with JDK 11, there is no such problem. The 
>> reason is the removed biased locking.  
>> The DecimalFormat uses StringBuffer everywhere, and StringBuffer itself 
>> contains many synchronized methods.
>> So I added support for some new methods that accept StringBuilder which is 
>> lock-free.
>> 
>> ### Benchmark testcase
>> 
>> @BenchmarkMode(Mode.AverageTime)
>> @Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS)
>> @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS)
>> @State(Scope.Thread)
>> @OutputTimeUnit(TimeUnit.NANOSECONDS)
>> public class JmhDecimalFormat {
>> 
>>     private DecimalFormat format;
>> 
>>     @Setup(Level.Trial)
>>     public void setup() {
>>         format = new DecimalFormat("#0.00000");
>>     }
>> 
>>     @Benchmark
>>     public void testNewAndFormat() throws InterruptedException {
>>         new DecimalFormat("#0.00000").format(9524234.1236457);
>>     }
>> 
>>     @Benchmark
>>     public void testNewOnly() throws InterruptedException {
>>         new DecimalFormat("#0.00000");
>>     }
>> 
>>     @Benchmark
>>     public void testFormatOnly() throws InterruptedException {
>>         format.format(9524234.1236457);
>>     }
>> }
>> 
>> 
>> ### Test result
>> #### Current JDK before optimize
>> 
>>  Benchmark                             Mode  Cnt    Score   Error  Units
>> JmhDecimalFormat.testFormatOnly       avgt   50  642.099 ? 1.253  ns/op
>> JmhDecimalFormat.testNewAndFormat     avgt   50  989.307 ? 3.676  ns/op
>> JmhDecimalFormat.testNewOnly          avgt   50  303.381 ? 5.252  ns/op
>> 
>> 
>> 
>> #### Current JDK after optimize
>> 
>> Benchmark                          Mode  Cnt    Score   Error  Units
>> JmhDecimalFormat.testFormatOnly    avgt   50  351.499 ? 0.761  ns/op
>> JmhDecimalFormat.testNewAndFormat  avgt   50  615.145 ? 2.478  ns/op
>> JmhDecimalFormat.testNewOnly       avgt   50  209.874 ? 9.951  ns/op
>> 
>> 
>> ### JDK 11 
>> 
>> Benchmark                          Mode  Cnt    Score   Error  Units
>> JmhDecimalFormat.testFormatOnly    avgt   50  364.214 ? 1.191  ns/op
>> JmhDecimalFormat.testNewAndFormat  avgt   50  658.699 ? 2.311  ns/op
>> JmhDecimalFormat.testNewOnly       avgt   50  248.300 ? 5.158  ns/op
>
> lingjun-cg has updated the pull request incrementally with one additional 
> commit since the last revision:
> 
>   8333396: Performance regression of DecimalFormat.format

Thanks for the changes. Since this is a performance improvement, I also would 
like to have the microbenchmark that you used as the test case.

src/java.base/share/classes/java/text/Format.java line 427:

> 425:     /**
> 426:      * Used to distinguish JDK internal subclass and user-defined 
> subclass
> 427:      * of {code Format}.

There are a lot of places which is missing `@` for `code` tag in the comments.

src/java.base/share/classes/java/text/Format.java line 434:

> 432:     boolean isInternalSubclass() {
> 433:         return false;
> 434:     }

Do we need this? Should comparing the package name with 'java.text' be 
sufficient?

src/java.base/share/classes/java/text/Format.java line 438:

> 436:     /**
> 437:      * StringBuf is the minimal common interface of {code StringBuffer} 
> and {code StringBuilder}.
> 438:      * It used by the various {code Format} implementations as the 
> internal string buffer.

typo: "is" is missing

src/java.base/share/classes/java/text/Format.java line 440:

> 438:      * It used by the various {code Format} implementations as the 
> internal string buffer.
> 439:      */
> 440:     interface StringBuf {

Can we make it `sealed`?

src/java.base/share/classes/java/text/ListFormat.java line 365:

> 363:             return format(input, new StringBuffer(),
> 364:                     DontCareFieldPosition.INSTANCE).toString();
> 365:         }

Since `ListFormat` is a final class, no need to have a condition, always use 
StringBuilder version.

src/java.base/share/classes/java/text/StringBufFactory.java line 35:

> 33:  * a better performance.
> 34:  */
> 35: final class StringBufFactory {

Add a private no-arg constructor so that no instance can be created for 
`StringBufFactory` itself.

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

PR Review: https://git.openjdk.org/jdk/pull/19513#pullrequestreview-2143027077
PR Review Comment: https://git.openjdk.org/jdk/pull/19513#discussion_r1655560390
PR Review Comment: https://git.openjdk.org/jdk/pull/19513#discussion_r1655563089
PR Review Comment: https://git.openjdk.org/jdk/pull/19513#discussion_r1655565976
PR Review Comment: https://git.openjdk.org/jdk/pull/19513#discussion_r1655559020
PR Review Comment: https://git.openjdk.org/jdk/pull/19513#discussion_r1655566915
PR Review Comment: https://git.openjdk.org/jdk/pull/19513#discussion_r1655571771

Reply via email to