Re: RFR: 8333396: Use StringBuilder internally for java.text.Format.* formatting [v19]

2024-07-09 Thread lingjun-cg
> ### 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.0");
> }
> 
> @Benchmark
> public void testNewAndFormat() throws InterruptedException {
> new DecimalFormat("#0.0").format(9524234.1236457);
> }
> 
> @Benchmark
> public void testNewOnly() throws InterruptedException {
> new DecimalFormat("#0.0");
> }
> 
> @Benchmark
> public void testFormatOnly() throws InterruptedException {
> format.format(9524234.1236457);
> }
> }
> 
> 
> ### Test result
>  Current JDK before optimize
> 
>  Benchmark Mode  CntScore   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  CntScore   Error  Units
> JmhDecimalFormat.testFormatOnlyavgt   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  CntScore   Error  Units
> JmhDecimalFormat.testFormatOnlyavgt   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:

  896: Use StringBuilder internally for java.text.Format.* formatting

-

Changes:
  - all: https://git.openjdk.org/jdk/pull/19513/files
  - new: https://git.openjdk.org/jdk/pull/19513/files/5fda8747..6573e413

Webrevs:
 - full: https://webrevs.openjdk.org/?repo=jdk=19513=18
 - incr: https://webrevs.openjdk.org/?repo=jdk=19513=17-18

  Stats: 1 line in 1 file changed: 0 ins; 0 del; 1 mod
  Patch: https://git.openjdk.org/jdk/pull/19513.diff
  Fetch: git fetch https://git.openjdk.org/jdk.git pull/19513/head:pull/19513

PR: https://git.openjdk.org/jdk/pull/19513


Re: RFR: 8333396: Use StringBuilder internally for java.text.Format.* formatting [v17]

2024-07-08 Thread lingjun-cg
On Mon, 8 Jul 2024 17:31:53 GMT, Justin Lu  wrote:

> I believe the `static MessageFormat.format(...` also has similar incorrect 
> "this is equivalent ..." wording, if you could please include that as well. I 
> think we should also rename the issue (and CSR) as well since the scope has 
> changed. Something along the lines of "Use StringBuilder internally for 
> java.text.Format.* formatting".

Thanks for checking carefully. Updated.

-

PR Comment: https://git.openjdk.org/jdk/pull/19513#issuecomment-2216286724


Re: RFR: 8333396: Use StringBuilder internally for java.text.Format.* formatting [v18]

2024-07-08 Thread lingjun-cg
> ### 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.0");
> }
> 
> @Benchmark
> public void testNewAndFormat() throws InterruptedException {
> new DecimalFormat("#0.0").format(9524234.1236457);
> }
> 
> @Benchmark
> public void testNewOnly() throws InterruptedException {
> new DecimalFormat("#0.0");
> }
> 
> @Benchmark
> public void testFormatOnly() throws InterruptedException {
> format.format(9524234.1236457);
> }
> }
> 
> 
> ### Test result
>  Current JDK before optimize
> 
>  Benchmark Mode  CntScore   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  CntScore   Error  Units
> JmhDecimalFormat.testFormatOnlyavgt   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  CntScore   Error  Units
> JmhDecimalFormat.testFormatOnlyavgt   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:

  896: Use StringBuilder internally for java.text.Format.* formatting

-

Changes:
  - all: https://git.openjdk.org/jdk/pull/19513/files
  - new: https://git.openjdk.org/jdk/pull/19513/files/d675bcbf..5fda8747

Webrevs:
 - full: https://webrevs.openjdk.org/?repo=jdk=19513=17
 - incr: https://webrevs.openjdk.org/?repo=jdk=19513=16-17

  Stats: 4 lines in 1 file changed: 0 ins; 3 del; 1 mod
  Patch: https://git.openjdk.org/jdk/pull/19513.diff
  Fetch: git fetch https://git.openjdk.org/jdk.git pull/19513/head:pull/19513

PR: https://git.openjdk.org/jdk/pull/19513


Re: RFR: 8333396: Performance regression of DecimalFormat.format [v16]

2024-07-07 Thread lingjun-cg
On Fri, 5 Jul 2024 16:54:41 GMT, Justin Lu  wrote:

> Following up on my previous comment regarding the _untrue wording_.
> 
> I no longer think we can just split the implementation and specification 
> portion of this PR into two issues, since if we backport the implementation 
> only, the specification would now be violated for the back-ported releases. 
> We may have to just include the specification in this issue as well, (which 
> will require a CSR and no longer means we can backport this change).

A CSR request created: https://bugs.openjdk.org/browse/JDK-8335834

-

PR Comment: https://git.openjdk.org/jdk/pull/19513#issuecomment-2212946822


Re: RFR: 8333396: Performance regression of DecimalFormat.format [v17]

2024-07-07 Thread lingjun-cg
> ### 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.0");
> }
> 
> @Benchmark
> public void testNewAndFormat() throws InterruptedException {
> new DecimalFormat("#0.0").format(9524234.1236457);
> }
> 
> @Benchmark
> public void testNewOnly() throws InterruptedException {
> new DecimalFormat("#0.0");
> }
> 
> @Benchmark
> public void testFormatOnly() throws InterruptedException {
> format.format(9524234.1236457);
> }
> }
> 
> 
> ### Test result
>  Current JDK before optimize
> 
>  Benchmark Mode  CntScore   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  CntScore   Error  Units
> JmhDecimalFormat.testFormatOnlyavgt   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  CntScore   Error  Units
> JmhDecimalFormat.testFormatOnlyavgt   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:

  896: Performance regression of DecimalFormat.format

-

Changes:
  - all: https://git.openjdk.org/jdk/pull/19513/files
  - new: https://git.openjdk.org/jdk/pull/19513/files/7122c2c8..d675bcbf

Webrevs:
 - full: https://webrevs.openjdk.org/?repo=jdk=19513=16
 - incr: https://webrevs.openjdk.org/?repo=jdk=19513=15-16

  Stats: 5 lines in 1 file changed: 0 ins; 4 del; 1 mod
  Patch: https://git.openjdk.org/jdk/pull/19513.diff
  Fetch: git fetch https://git.openjdk.org/jdk.git pull/19513/head:pull/19513

PR: https://git.openjdk.org/jdk/pull/19513


Re: RFR: 8333396: Performance regression of DecimalFormat.format [v8]

2024-07-03 Thread lingjun-cg
On Tue, 25 Jun 2024 19:33:02 GMT, Naoto Sato  wrote:

>> I did not mean to introduce a public API for this change (if we do, the fix 
>> cannot be backported). I thought we could define a package private one, but 
>> based on your observation, it may get messier... So I agree that falling 
>> back to `StringBuf` is the way to go, IMO.
>
>> So, considering all the information given, is it enough to start our new 
>> review process? @naotoj @liach @justin-curtis-lu
> 
> Well, I was suggesting the same buffer proxying for other Format classes than 
> NumberFormat subclasses, such as DateFormat so that they would have the same 
> performance benefit. Would you be willing to do that too?

Thanks all for your valuable suggestions. All suggestions were accepted.  Is it 
enough to start our new review process? @naotoj @justin-curtis-lu @liach 
@irisclark

-

PR Comment: https://git.openjdk.org/jdk/pull/19513#issuecomment-2207831524


Re: RFR: 8333396: Performance regression of DecimalFormat.format [v16]

2024-07-01 Thread lingjun-cg
> ### 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.0");
> }
> 
> @Benchmark
> public void testNewAndFormat() throws InterruptedException {
> new DecimalFormat("#0.0").format(9524234.1236457);
> }
> 
> @Benchmark
> public void testNewOnly() throws InterruptedException {
> new DecimalFormat("#0.0");
> }
> 
> @Benchmark
> public void testFormatOnly() throws InterruptedException {
> format.format(9524234.1236457);
> }
> }
> 
> 
> ### Test result
>  Current JDK before optimize
> 
>  Benchmark Mode  CntScore   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  CntScore   Error  Units
> JmhDecimalFormat.testFormatOnlyavgt   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  CntScore   Error  Units
> JmhDecimalFormat.testFormatOnlyavgt   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:

  896: Performance regression of DecimalFormat.format

-

Changes:
  - all: https://git.openjdk.org/jdk/pull/19513/files
  - new: https://git.openjdk.org/jdk/pull/19513/files/da09d85a..7122c2c8

Webrevs:
 - full: https://webrevs.openjdk.org/?repo=jdk=19513=15
 - incr: https://webrevs.openjdk.org/?repo=jdk=19513=14-15

  Stats: 6 lines in 2 files changed: 0 ins; 0 del; 6 mod
  Patch: https://git.openjdk.org/jdk/pull/19513.diff
  Fetch: git fetch https://git.openjdk.org/jdk.git pull/19513/head:pull/19513

PR: https://git.openjdk.org/jdk/pull/19513


Re: RFR: 8333396: Performance regression of DecimalFormat.format [v15]

2024-06-30 Thread lingjun-cg
> ### 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.0");
> }
> 
> @Benchmark
> public void testNewAndFormat() throws InterruptedException {
> new DecimalFormat("#0.0").format(9524234.1236457);
> }
> 
> @Benchmark
> public void testNewOnly() throws InterruptedException {
> new DecimalFormat("#0.0");
> }
> 
> @Benchmark
> public void testFormatOnly() throws InterruptedException {
> format.format(9524234.1236457);
> }
> }
> 
> 
> ### Test result
>  Current JDK before optimize
> 
>  Benchmark Mode  CntScore   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  CntScore   Error  Units
> JmhDecimalFormat.testFormatOnlyavgt   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  CntScore   Error  Units
> JmhDecimalFormat.testFormatOnlyavgt   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:

  896: Performance regression of DecimalFormat.format

-

Changes:
  - all: https://git.openjdk.org/jdk/pull/19513/files
  - new: https://git.openjdk.org/jdk/pull/19513/files/b5bdc733..da09d85a

Webrevs:
 - full: https://webrevs.openjdk.org/?repo=jdk=19513=14
 - incr: https://webrevs.openjdk.org/?repo=jdk=19513=13-14

  Stats: 9 lines in 3 files changed: 0 ins; 6 del; 3 mod
  Patch: https://git.openjdk.org/jdk/pull/19513.diff
  Fetch: git fetch https://git.openjdk.org/jdk.git pull/19513/head:pull/19513

PR: https://git.openjdk.org/jdk/pull/19513


Re: RFR: 8333396: Performance regression of DecimalFormat.format [v14]

2024-06-27 Thread lingjun-cg
> ### 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.0");
> }
> 
> @Benchmark
> public void testNewAndFormat() throws InterruptedException {
> new DecimalFormat("#0.0").format(9524234.1236457);
> }
> 
> @Benchmark
> public void testNewOnly() throws InterruptedException {
> new DecimalFormat("#0.0");
> }
> 
> @Benchmark
> public void testFormatOnly() throws InterruptedException {
> format.format(9524234.1236457);
> }
> }
> 
> 
> ### Test result
>  Current JDK before optimize
> 
>  Benchmark Mode  CntScore   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  CntScore   Error  Units
> JmhDecimalFormat.testFormatOnlyavgt   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  CntScore   Error  Units
> JmhDecimalFormat.testFormatOnlyavgt   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 two additional 
commits since the last revision:

 - 896: Performance regression of DecimalFormat.format
 - 896: Performance regression of DecimalFormat.format

-

Changes:
  - all: https://git.openjdk.org/jdk/pull/19513/files
  - new: https://git.openjdk.org/jdk/pull/19513/files/f1b88f36..b5bdc733

Webrevs:
 - full: https://webrevs.openjdk.org/?repo=jdk=19513=13
 - incr: https://webrevs.openjdk.org/?repo=jdk=19513=12-13

  Stats: 310 lines in 6 files changed: 233 ins; 71 del; 6 mod
  Patch: https://git.openjdk.org/jdk/pull/19513.diff
  Fetch: git fetch https://git.openjdk.org/jdk.git pull/19513/head:pull/19513

PR: https://git.openjdk.org/jdk/pull/19513


Re: RFR: 8333396: Performance regression of DecimalFormat.format [v12]

2024-06-27 Thread lingjun-cg
On Thu, 27 Jun 2024 05:08:06 GMT, Justin Lu  wrote:

>> lingjun-cg has updated the pull request incrementally with one additional 
>> commit since the last revision:
>> 
>>   896: Performance regression of DecimalFormat.format
>
> src/java.base/share/classes/java/text/StringBufFactory.java line 45:
> 
>> 43: }
>> 44: 
>> 45: private static class StringBufferImpl implements Format.StringBuf {
> 
> The implementations may be more concise as a `record class`

I know little about `record class`, it seems `record class` is help to model 
data aggregation, but here it act as a proxy class.

-

PR Review Comment: https://git.openjdk.org/jdk/pull/19513#discussion_r1656957129


Re: RFR: 8333396: Performance regression of DecimalFormat.format [v13]

2024-06-27 Thread lingjun-cg
> ### 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.0");
> }
> 
> @Benchmark
> public void testNewAndFormat() throws InterruptedException {
> new DecimalFormat("#0.0").format(9524234.1236457);
> }
> 
> @Benchmark
> public void testNewOnly() throws InterruptedException {
> new DecimalFormat("#0.0");
> }
> 
> @Benchmark
> public void testFormatOnly() throws InterruptedException {
> format.format(9524234.1236457);
> }
> }
> 
> 
> ### Test result
>  Current JDK before optimize
> 
>  Benchmark Mode  CntScore   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  CntScore   Error  Units
> JmhDecimalFormat.testFormatOnlyavgt   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  CntScore   Error  Units
> JmhDecimalFormat.testFormatOnlyavgt   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:

  896: Performance regression of DecimalFormat.format

-

Changes:
  - all: https://git.openjdk.org/jdk/pull/19513/files
  - new: https://git.openjdk.org/jdk/pull/19513/files/7eb9b523..f1b88f36

Webrevs:
 - full: https://webrevs.openjdk.org/?repo=jdk=19513=12
 - incr: https://webrevs.openjdk.org/?repo=jdk=19513=11-12

  Stats: 247 lines in 11 files changed: 78 ins; 63 del; 106 mod
  Patch: https://git.openjdk.org/jdk/pull/19513.diff
  Fetch: git fetch https://git.openjdk.org/jdk.git pull/19513/head:pull/19513

PR: https://git.openjdk.org/jdk/pull/19513


Re: RFR: 8333396: Performance regression of DecimalFormat.format [v8]

2024-06-26 Thread lingjun-cg
On Tue, 25 Jun 2024 19:33:02 GMT, Naoto Sato  wrote:

> > So, considering all the information given, is it enough to start our new 
> > review process? @naotoj @liach @justin-curtis-lu
> 
> Well, I was suggesting the same buffer proxying for other Format classes than 
> NumberFormat subclasses, such as DateFormat so that they would have the same 
> performance benefit. Would you be willing to do that too?

Sure. All `Format`'s subclasses has been replaced with buffer proxying. After 
that I run the benchmark test with averageTime mode. The result show the 
StringBuilder has take effect. 
Please review again. @naotoj @liach @justin-curtis-lu 

| Testcase | JDK 11  | JDK 22 | Current JDK |
| - | - |- | - |
| java.text.NumberFormat#format(double)| 362.221  | 636.049 | 351.913|
| java.text.DateFormat#format(java.util.Date)| 362.273|944.733|317.436|
|java.text.MessageFormat#format| 599.146| 937.717|499.584|
|java.text.ListFormat#format| N/A | 464.123|318.978|

-

PR Comment: https://git.openjdk.org/jdk/pull/19513#issuecomment-2191307113


Re: RFR: 8333396: Performance regression of DecimalFormat.format [v12]

2024-06-26 Thread lingjun-cg
> ### 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.0");
> }
> 
> @Benchmark
> public void testNewAndFormat() throws InterruptedException {
> new DecimalFormat("#0.0").format(9524234.1236457);
> }
> 
> @Benchmark
> public void testNewOnly() throws InterruptedException {
> new DecimalFormat("#0.0");
> }
> 
> @Benchmark
> public void testFormatOnly() throws InterruptedException {
> format.format(9524234.1236457);
> }
> }
> 
> 
> ### Test result
>  Current JDK before optimize
> 
>  Benchmark Mode  CntScore   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  CntScore   Error  Units
> JmhDecimalFormat.testFormatOnlyavgt   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  CntScore   Error  Units
> JmhDecimalFormat.testFormatOnlyavgt   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:

  896: Performance regression of DecimalFormat.format

-

Changes:
  - all: https://git.openjdk.org/jdk/pull/19513/files
  - new: https://git.openjdk.org/jdk/pull/19513/files/b6646c5d..7eb9b523

Webrevs:
 - full: https://webrevs.openjdk.org/?repo=jdk=19513=11
 - incr: https://webrevs.openjdk.org/?repo=jdk=19513=10-11

  Stats: 242 lines in 9 files changed: 220 ins; 0 del; 22 mod
  Patch: https://git.openjdk.org/jdk/pull/19513.diff
  Fetch: git fetch https://git.openjdk.org/jdk.git pull/19513/head:pull/19513

PR: https://git.openjdk.org/jdk/pull/19513


Re: RFR: 8333396: Performance regression of DecimalFormat.format [v11]

2024-06-24 Thread lingjun-cg
> ### 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.0");
> }
> 
> @Benchmark
> public void testNewAndFormat() throws InterruptedException {
> new DecimalFormat("#0.0").format(9524234.1236457);
> }
> 
> @Benchmark
> public void testNewOnly() throws InterruptedException {
> new DecimalFormat("#0.0");
> }
> 
> @Benchmark
> public void testFormatOnly() throws InterruptedException {
> format.format(9524234.1236457);
> }
> }
> 
> 
> ### Test result
>  Current JDK before optimize
> 
>  Benchmark Mode  CntScore   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  CntScore   Error  Units
> JmhDecimalFormat.testFormatOnlyavgt   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  CntScore   Error  Units
> JmhDecimalFormat.testFormatOnlyavgt   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:

  896: Performance regression of DecimalFormat.format

-

Changes:
  - all: https://git.openjdk.org/jdk/pull/19513/files
  - new: https://git.openjdk.org/jdk/pull/19513/files/67c724c7..b6646c5d

Webrevs:
 - full: https://webrevs.openjdk.org/?repo=jdk=19513=10
 - incr: https://webrevs.openjdk.org/?repo=jdk=19513=09-10

  Stats: 305 lines in 6 files changed: 158 ins; 122 del; 25 mod
  Patch: https://git.openjdk.org/jdk/pull/19513.diff
  Fetch: git fetch https://git.openjdk.org/jdk.git pull/19513/head:pull/19513

PR: https://git.openjdk.org/jdk/pull/19513


Re: RFR: 8333396: Performance regression of DecimalFormat.format [v8]

2024-06-24 Thread lingjun-cg
On Thu, 20 Jun 2024 18:58:27 GMT, Naoto Sato  wrote:

>> lingjun-cg has updated the pull request incrementally with one additional 
>> commit since the last revision:
>> 
>>   896: Performance regression of DecimalFormat.format
>
> I did not mean to introduce a public API for this change (if we do, the fix 
> cannot be backported). I thought we could define a package private one, but 
> based on your observation, it may get messier... So I agree that falling back 
> to `StringBuf` is the way to go, IMO.

So, considering all the information given, is it enough to start our new review 
process? @naotoj @liach @justin-curtis-lu

-

PR Comment: https://git.openjdk.org/jdk/pull/19513#issuecomment-2187842086


Re: RFR: 8333396: Performance regression of DecimalFormat.format [v10]

2024-06-21 Thread lingjun-cg
On Fri, 21 Jun 2024 07:25:27 GMT, lingjun-cg  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.0");
>> }
>> 
>> @Benchmark
>> public void testNewAndFormat() throws InterruptedException {
>> new DecimalFormat("#0.0").format(9524234.1236457);
>> }
>> 
>> @Benchmark
>> public void testNewOnly() throws InterruptedException {
>> new DecimalFormat("#0.0");
>> }
>> 
>> @Benchmark
>> public void testFormatOnly() throws InterruptedException {
>> format.format(9524234.1236457);
>> }
>> }
>> 
>> 
>> ### Test result
>>  Current JDK before optimize
>> 
>>  Benchmark Mode  CntScore   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  CntScore   Error  Units
>> JmhDecimalFormat.testFormatOnlyavgt   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  CntScore   Error  Units
>> JmhDecimalFormat.testFormatOnlyavgt   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:
> 
>   896: Performance regression of DecimalFormat.format

Updates:
1. Add package private interface `StringBuf` into `Format` as an inner class. 
Like `java.text.Format.FieldDelegate` that used by `Format` implemetations.
2. Add `boolean isInternalSubclass` into all `Format` implemetations that in 
package `java.text`.

-

PR Comment: https://git.openjdk.org/jdk/pull/19513#issuecomment-2182167568


Re: RFR: 8333396: Performance regression of DecimalFormat.format [v10]

2024-06-21 Thread lingjun-cg
> ### 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.0");
> }
> 
> @Benchmark
> public void testNewAndFormat() throws InterruptedException {
> new DecimalFormat("#0.0").format(9524234.1236457);
> }
> 
> @Benchmark
> public void testNewOnly() throws InterruptedException {
> new DecimalFormat("#0.0");
> }
> 
> @Benchmark
> public void testFormatOnly() throws InterruptedException {
> format.format(9524234.1236457);
> }
> }
> 
> 
> ### Test result
>  Current JDK before optimize
> 
>  Benchmark Mode  CntScore   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  CntScore   Error  Units
> JmhDecimalFormat.testFormatOnlyavgt   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  CntScore   Error  Units
> JmhDecimalFormat.testFormatOnlyavgt   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:

  896: Performance regression of DecimalFormat.format

-

Changes:
  - all: https://git.openjdk.org/jdk/pull/19513/files
  - new: https://git.openjdk.org/jdk/pull/19513/files/9a6f646f..67c724c7

Webrevs:
 - full: https://webrevs.openjdk.org/?repo=jdk=19513=09
 - incr: https://webrevs.openjdk.org/?repo=jdk=19513=08-09

  Stats: 2 lines in 1 file changed: 0 ins; 1 del; 1 mod
  Patch: https://git.openjdk.org/jdk/pull/19513.diff
  Fetch: git fetch https://git.openjdk.org/jdk.git pull/19513/head:pull/19513

PR: https://git.openjdk.org/jdk/pull/19513


Re: RFR: 8333396: Performance regression of DecimalFormat.format [v9]

2024-06-21 Thread lingjun-cg
> ### 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.0");
> }
> 
> @Benchmark
> public void testNewAndFormat() throws InterruptedException {
> new DecimalFormat("#0.0").format(9524234.1236457);
> }
> 
> @Benchmark
> public void testNewOnly() throws InterruptedException {
> new DecimalFormat("#0.0");
> }
> 
> @Benchmark
> public void testFormatOnly() throws InterruptedException {
> format.format(9524234.1236457);
> }
> }
> 
> 
> ### Test result
>  Current JDK before optimize
> 
>  Benchmark Mode  CntScore   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  CntScore   Error  Units
> JmhDecimalFormat.testFormatOnlyavgt   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  CntScore   Error  Units
> JmhDecimalFormat.testFormatOnlyavgt   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:

  896: Performance regression of DecimalFormat.format

-

Changes:
  - all: https://git.openjdk.org/jdk/pull/19513/files
  - new: https://git.openjdk.org/jdk/pull/19513/files/1fde6a60..9a6f646f

Webrevs:
 - full: https://webrevs.openjdk.org/?repo=jdk=19513=08
 - incr: https://webrevs.openjdk.org/?repo=jdk=19513=07-08

  Stats: 348 lines in 11 files changed: 198 ins; 65 del; 85 mod
  Patch: https://git.openjdk.org/jdk/pull/19513.diff
  Fetch: git fetch https://git.openjdk.org/jdk.git pull/19513/head:pull/19513

PR: https://git.openjdk.org/jdk/pull/19513


Re: RFR: 8333396: Performance regression of DecimalFormat.format [v8]

2024-06-20 Thread lingjun-cg
On Thu, 20 Jun 2024 21:53:25 GMT, Justin Lu  wrote:

> > It requires append(int), but the Appendable has no such method.
> 
> If via `Appendable` we don't have access to `append(int)`, can we simply 
> `append(String.valueOf(int))`. And similarly for `append(char[], int, int)`, 
> can we `append(String.valueOf(char[], int, int))`.
> 
> According to the method descriptions in `AbstractStringBuilder`, this should 
> behaviorally be the same. That way we don't have to add any new classes, and 
> can continue with the generic implementation.

If do that ,there is some performance degradation.

Benchmark  Mode  Cnt   
Score   Error  Units
AppendableTest.tesAppendableAppendCharAsciiavgt   50  
33.628 ± 0.263  ns/op
AppendableTest.tesAppendableAppendCharMixNoAsciiChars  avgt   50  
33.522 ± 0.245  ns/op
AppendableTest.testAppendableAppendInt avgt   50  
32.602 ± 0.186  ns/op
AppendableTest.testStringBufferAppendCharArrayAsciiavgt   50  
31.028 ± 0.134  ns/op
AppendableTest.testStringBufferAppendCharArrayMixNoAsciiChars  avgt   50  
31.075 ± 0.158  ns/op
AppendableTest.testStringBufferAppendInt   avgt   50  
25.706 ± 0.268  ns/op



@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 AppendableTest {

private StringBuffer sb;
private Appendable appendable;
private char[] asciiChars;
private char[] mixNoAsciiChars;

@Setup(Level.Iteration)
public void setup() {
sb = new StringBuffer();
appendable = sb;
asciiChars = "Criticism appears to Anatole France the most recent and 
possibly the ultimate evolution".toCharArray();
mixNoAsciiChars = "The 测试数据 above mentioned two volumes of poetry were 
followed by many works in prose, which we shall notice. France’s critical 
writings".toCharArray();
}

@Benchmark
public void testStringBufferAppendInt() throws InterruptedException {
sb.append(12345890);
}

@Benchmark
public void testAppendableAppendInt() throws InterruptedException, 
IOException {
appendable.append(String.valueOf(12345890));
}

@Benchmark
public void testStringBufferAppendCharArrayAscii() throws 
InterruptedException {
sb.append(asciiChars, 40, 18);
}

@Benchmark
public void tesAppendableAppendCharAscii() throws InterruptedException, 
IOException {
appendable.append(new String(asciiChars, 40, 18));
}

@Benchmark
public void testStringBufferAppendCharArrayMixNoAsciiChars() throws 
InterruptedException {
sb.append(mixNoAsciiChars, 40, 18);
}

@Benchmark
public void tesAppendableAppendCharMixNoAsciiChars() throws 
InterruptedException, IOException {
appendable.append(new String(mixNoAsciiChars, 40, 18));
}
}

-

PR Comment: https://git.openjdk.org/jdk/pull/19513#issuecomment-2181851223


Re: RFR: 8333396: Performance regression of DecimalFormat.format [v8]

2024-06-19 Thread lingjun-cg
On Tue, 18 Jun 2024 10:00:33 GMT, lingjun-cg  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.0");
>> }
>> 
>> @Benchmark
>> public void testNewAndFormat() throws InterruptedException {
>> new DecimalFormat("#0.0").format(9524234.1236457);
>> }
>> 
>> @Benchmark
>> public void testNewOnly() throws InterruptedException {
>> new DecimalFormat("#0.0");
>> }
>> 
>> @Benchmark
>> public void testFormatOnly() throws InterruptedException {
>> format.format(9524234.1236457);
>> }
>> }
>> 
>> 
>> ### Test result
>>  Current JDK before optimize
>> 
>>  Benchmark Mode  CntScore   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  CntScore   Error  Units
>> JmhDecimalFormat.testFormatOnlyavgt   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  CntScore   Error  Units
>> JmhDecimalFormat.testFormatOnlyavgt   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:
> 
>   896: Performance regression of DecimalFormat.format

If change the visibility of `java.lang.AbstractStringBuilder` from 
package-private to public, it seems more simple.
The `AbstractStringBuilder` is a sealed class, user code cannot extend it, and 
it also used by other class like `String`.

-

PR Comment: https://git.openjdk.org/jdk/pull/19513#issuecomment-2179655141


Re: RFR: 8333396: Performance regression of DecimalFormat.format [v8]

2024-06-18 Thread lingjun-cg
On Wed, 19 Jun 2024 02:12:01 GMT, lingjun-cg  wrote:

>> src/java.base/share/classes/java/text/Format.java line 278:
>> 
>>> 276:  * {@code false} otherwise
>>> 277:  */
>>> 278: boolean isInternalSubclass() {
>> 
>> Since this is defined in Format, can we apply similar changes of 
>> StringBuilder formatting to the other Format subclasses beyond just 
>> NumberFormat.
>> 
>> For example, in DateFormat, something such as,
>> 
>> 
>>  T formatWithGeneric(Date date,
>>T toAppendTo,
>>FieldPosition pos) {
>> throw new UnsupportedOperationException("Subclasses should override 
>> this method");
>> }
>
> ok. I will update it if we have a conclusion about using  `StringBuf` or 
> using ``.

This  comment inspire me that  use '' in 
`SimpleDateFormat` is impossible, because the 'Appendable' lack of necessary 
`append` method which SimpleDateFormat requires.
So we need discuss whether `StringBuf` is a better solution?

-

PR Review Comment: https://git.openjdk.org/jdk/pull/19513#discussion_r1645309140


Re: RFR: 8333396: Performance regression of DecimalFormat.format [v8]

2024-06-18 Thread lingjun-cg
On Tue, 18 Jun 2024 20:39:30 GMT, Justin Lu  wrote:

>> lingjun-cg has updated the pull request incrementally with one additional 
>> commit since the last revision:
>> 
>>   896: Performance regression of DecimalFormat.format
>
> src/java.base/share/classes/java/text/ChoiceFormat.java line 561:
> 
>> 559: toAppendTo.append(choiceFormats[i]);
>> 560: } catch (IOException ioe) {
>> 561: throw new UncheckedIOException(ioe.getMessage(), ioe);
> 
> Perhaps `AssertionError` instead of `UncheckedIOException` is better suited 
> here and in the other ocurrences.

This can be removed if using `StringBuf`.

-

PR Review Comment: https://git.openjdk.org/jdk/pull/19513#discussion_r1645304136


Re: RFR: 8333396: Performance regression of DecimalFormat.format [v8]

2024-06-18 Thread lingjun-cg
On Tue, 18 Jun 2024 20:36:52 GMT, Justin Lu  wrote:

>> lingjun-cg has updated the pull request incrementally with one additional 
>> commit since the last revision:
>> 
>>   896: Performance regression of DecimalFormat.format
>
> src/java.base/share/classes/java/text/Format.java line 278:
> 
>> 276:  * {@code false} otherwise
>> 277:  */
>> 278: boolean isInternalSubclass() {
> 
> Since this is defined in Format, can we apply similar changes of 
> StringBuilder formatting to the other Format subclasses beyond just 
> NumberFormat.
> 
> For example, in DateFormat, something such as,
> 
> 
>  T formatWithGeneric(Date date,
>T toAppendTo,
>FieldPosition pos) {
> throw new UnsupportedOperationException("Subclasses should override 
> this method");
> }

ok. I will update it if we have a conclusion about using  `StringBuf` or using 
``.

-

PR Review Comment: https://git.openjdk.org/jdk/pull/19513#discussion_r1645300958


Re: RFR: 8333396: Performance regression of DecimalFormat.format [v8]

2024-06-18 Thread lingjun-cg
On Tue, 18 Jun 2024 10:00:33 GMT, lingjun-cg  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.0");
>> }
>> 
>> @Benchmark
>> public void testNewAndFormat() throws InterruptedException {
>> new DecimalFormat("#0.0").format(9524234.1236457);
>> }
>> 
>> @Benchmark
>> public void testNewOnly() throws InterruptedException {
>> new DecimalFormat("#0.0");
>> }
>> 
>> @Benchmark
>> public void testFormatOnly() throws InterruptedException {
>> format.format(9524234.1236457);
>> }
>> }
>> 
>> 
>> ### Test result
>>  Current JDK before optimize
>> 
>>  Benchmark Mode  CntScore   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  CntScore   Error  Units
>> JmhDecimalFormat.testFormatOnlyavgt   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  CntScore   Error  Units
>> JmhDecimalFormat.testFormatOnlyavgt   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:
> 
>   896: Performance regression of DecimalFormat.format

Using ` ` instead of  `StringBuf` seems a 
good idea, but it has a disadvantage. The `Appendable` defines only 3 `append` 
methods which cannot cover some cases.  For example, this method 
`SimpleDateFormat#format(Date, StringBuffer, FieldDelegate)` contains the 
following code:


case TAG_QUOTE_CHARS:
toAppendTo.append(compiledPattern, i, count);
i += count;
break;


It requires `append(char[], int, int)`, but the `Appendable` has no such method.
So it's difficult to use  ` ` in methods 
`String DateFormat.format(Date date), String ListFormat.format(List 
input) and, String MessageFormat.format(Object obj)`.

The method in `java.text.MessageFormat#subformat` contains the following code:

int argumentNumber = argumentNumbers[i];
if (arguments == null || argumentNumber >= arguments.length) {
result.append('{').append(argumentNumber).append('}');
continue;
}

It requires `append(int)`, but the `Appendable` has no such method.

To sum up
1. ` ` is clear, but lack of extensibility
2. StringBuf is not so clear, but it's more extensibility. We can add 
`append(char[], int, int)` to `StringBuf` to support `SimpleDateFormat`.
3.  New interface StringBuf no need to handle IOException, but use ` ` need to add a lot of try...catch statements around 
the append method.
4. 
So it seems `StringBuf` is better if we want to fix the problem in 
`DateFormat,ListFormat,MessageFormat` in unique way. 
I look forward to your reply. @naotoj @liach @justin-curtis-lu

Using ` ` instead of  `StringBuf` seems a 
good idea, but it has a disadvantage. The `Appendable` defines only 3 `append` 
methods which cannot cover some cases.  For example, this method 
`SimpleDateFormat#format(Date, StringBuffer, FieldDelegate)` contains the 
following code:


case TAG_QUOTE_CH

Re: RFR: 8333396: Performance regression of DecimalFormat.format [v5]

2024-06-18 Thread lingjun-cg
On Mon, 17 Jun 2024 18:17:06 GMT, Justin Lu  wrote:

>>> I second Justin's suggestion here. The change should benefit every 
>>> implementation in the JDK, not only NumberFormat. Also, I might suggest 
>>> renaming the new class, as it is kind of long/redundant. How about using 
>>> something as simple as "StringBuf"?
>> 
>> Thanks for your comment. The long name bother me for a while. I have changed 
>> it to ""StringBuf".
>
> Hi @lingjun-cg 
> 
> Thanks for your work here.
> 
> While this would benefit the performance of NumberFormat subclasses, we are 
> hoping that if we are going to make the internal switch to StringBuilder, we 
> can also make similar changes to other Format subclasses as well where 
> applicable. So, we would want `isInternalSubclass()` to be defined at the 
> Format level. Some methods that I can immediately think of would be `String 
> DateFormat.format(Date date)`, `String ListFormat.format(List input)` 
> and, `String MessageFormat.format(Object obj)`.
> 
> I believe @naotoj shares the same sentiment.

@justin-curtis-lu The method `isInternalSubclass` in `DecimalFormat` already 
pulls up to `Format`.
@liach @naotoj Using `Appendable & CharSequence` instead of an interface with a 
limited method is a great idea. Following this idea, I have updated the PR. But 
there are some notes when implementing the idea.

1. Rename `format` to `formatWithGeneric` in DecimalFormat that accepts 
StringBuilder. If not that, throw a  StackOverflowException when run with 
`DecimalFormat.format(double)`. If not rename the format, there are 2 methods 
in DecimalFormat: 
```
   @Override
public StringBuffer format(double number, StringBuffer result,
   FieldPosition fieldPosition) {
return format(number, result, fieldPosition);
}
@Override
 T format(double number, T result,
   FieldPosition fieldPosition) 
{
   }

Because the second parameter type `StringBuffer` of the 1st method is more 
concrete than type `T` of the 2nd method, so the 1st method will call itself 
recursively. 

2. The `Appendable#append(java.lang.CharSequence)` method can throws 
IOException, so there is some messy code handling IOException.

-

PR Comment: https://git.openjdk.org/jdk/pull/19513#issuecomment-2175778275


Re: RFR: 8333396: Performance regression of DecimalFormat.format [v8]

2024-06-18 Thread lingjun-cg
> ### 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.0");
> }
> 
> @Benchmark
> public void testNewAndFormat() throws InterruptedException {
> new DecimalFormat("#0.0").format(9524234.1236457);
> }
> 
> @Benchmark
> public void testNewOnly() throws InterruptedException {
> new DecimalFormat("#0.0");
> }
> 
> @Benchmark
> public void testFormatOnly() throws InterruptedException {
> format.format(9524234.1236457);
> }
> }
> 
> 
> ### Test result
>  Current JDK before optimize
> 
>  Benchmark Mode  CntScore   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  CntScore   Error  Units
> JmhDecimalFormat.testFormatOnlyavgt   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  CntScore   Error  Units
> JmhDecimalFormat.testFormatOnlyavgt   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:

  896: Performance regression of DecimalFormat.format

-

Changes:
  - all: https://git.openjdk.org/jdk/pull/19513/files
  - new: https://git.openjdk.org/jdk/pull/19513/files/e95f0928..1fde6a60

Webrevs:
 - full: https://webrevs.openjdk.org/?repo=jdk=19513=07
 - incr: https://webrevs.openjdk.org/?repo=jdk=19513=06-07

  Stats: 186 lines in 8 files changed: 130 ins; 0 del; 56 mod
  Patch: https://git.openjdk.org/jdk/pull/19513.diff
  Fetch: git fetch https://git.openjdk.org/jdk.git pull/19513/head:pull/19513

PR: https://git.openjdk.org/jdk/pull/19513


Withdrawn: 8333396: Performance regression of DecimalFormat.format

2024-06-18 Thread lingjun-cg
On Mon, 3 Jun 2024 04:18:20 GMT, lingjun-cg  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.0");
> }
> 
> @Benchmark
> public void testNewAndFormat() throws InterruptedException {
> new DecimalFormat("#0.0").format(9524234.1236457);
> }
> 
> @Benchmark
> public void testNewOnly() throws InterruptedException {
> new DecimalFormat("#0.0");
> }
> 
> @Benchmark
> public void testFormatOnly() throws InterruptedException {
> format.format(9524234.1236457);
> }
> }
> 
> 
> ### Test result
>  Current JDK before optimize
> 
>  Benchmark Mode  CntScore   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  CntScore   Error  Units
> JmhDecimalFormat.testFormatOnlyavgt   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  CntScore   Error  Units
> JmhDecimalFormat.testFormatOnlyavgt   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

This pull request has been closed without being integrated.

-

PR: https://git.openjdk.org/jdk/pull/19513


Re: RFR: 8333396: Performance regression of DecimalFormat.format [v7]

2024-06-18 Thread lingjun-cg
> ### 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.0");
> }
> 
> @Benchmark
> public void testNewAndFormat() throws InterruptedException {
> new DecimalFormat("#0.0").format(9524234.1236457);
> }
> 
> @Benchmark
> public void testNewOnly() throws InterruptedException {
> new DecimalFormat("#0.0");
> }
> 
> @Benchmark
> public void testFormatOnly() throws InterruptedException {
> format.format(9524234.1236457);
> }
> }
> 
> 
> ### Test result
>  Current JDK before optimize
> 
>  Benchmark Mode  CntScore   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  CntScore   Error  Units
> JmhDecimalFormat.testFormatOnlyavgt   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  CntScore   Error  Units
> JmhDecimalFormat.testFormatOnlyavgt   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 with a new target base due to a merge 
or a rebase.

-

Changes: https://git.openjdk.org/jdk/pull/19513/files
  Webrev: https://webrevs.openjdk.org/?repo=jdk=19513=06
  Stats: 0 lines in 0 files changed: 0 ins; 0 del; 0 mod
  Patch: https://git.openjdk.org/jdk/pull/19513.diff
  Fetch: git fetch https://git.openjdk.org/jdk.git pull/19513/head:pull/19513

PR: https://git.openjdk.org/jdk/pull/19513


Re: RFR: 8333396: Performance regression of DecimalFormat.format [v5]

2024-06-13 Thread lingjun-cg
On Thu, 13 Jun 2024 17:53:45 GMT, Justin Lu  wrote:

>> lingjun-cg has updated the pull request incrementally with one additional 
>> commit since the last revision:
>> 
>>   896: Performance regression of DecimalFormat.format
>
> src/java.base/share/classes/java/text/CompactNumberFormat.java line 885:
> 
>> 883: }
>> 884: 
>> 885: private StringBuilderBufferProxy format(BigInteger number, 
>> StringBuilderBufferProxy result,
> 
> While the DecimalFormat and CompactNumberFormat BigInteger and BigDecimal 
> `format` methods will always return a StringBuffer, we must change the method 
> signatures to use the proxy, otherwise we would need to define alternate 
> methods all the way at the `Format.FieldDelegate` level. So I think this is a 
> lesser of two evils.

I'm not sure what you mean. Would you suggest add two new methods that accept 
StringBuilderBufferProxy and keep the origin methods that accept StringBuffer? 
Like this:

interface FieldDelegate {

public void formatted(Format.Field attr, Object value, int start,
  int end, StringBuffer buffer);

public void formatted(int fieldID, Format.Field attr, Object value,
  int start, int end, StringBuffer buffer);

public void formatted(Format.Field attr, Object value, int start,
  int end, StringBuilderBufferProxy buffer);

public void formatted(int fieldID, Format.Field attr, Object value,
  int start, int end, StringBuilderBufferProxy 
buffer);
}

But DecimalFormat#subformatNumber is a common method that only accept 
StringBuilderBufferProxy, and CompactNumberFormat#format(BigDecimal) call it, 
so CompactNumberFormat#format(BigDecimal) need change signature.

-

PR Review Comment: https://git.openjdk.org/jdk/pull/19513#discussion_r1639197282


Re: RFR: 8333396: Performance regression of DecimalFormat.format [v5]

2024-06-13 Thread lingjun-cg
On Thu, 13 Jun 2024 19:40:49 GMT, Chen Liang  wrote:

>> lingjun-cg has updated the pull request incrementally with one additional 
>> commit since the last revision:
>> 
>>   896: Performance regression of DecimalFormat.format
>
> src/java.base/share/classes/java/text/StringBuilderBufferProxy.java line 108:
> 
>> 106: }
>> 107: 
>> 108: class StringBuilderImpl implements StringBuilderBufferProxy {
> 
> Avoid adding nested classes to interfaces, which are public. These classes 
> are publicly accessible under reflection, and we want to avoid more of such 
> occurrences. See 
> https://bugs.openjdk.org/browse/JDK-8308040?focusedId=14581402=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#comment-14581402

Thanks for your suggestion. I split this class into 2 classes: one is the 
interface, the other is the factory class with package-private.

-

PR Review Comment: https://git.openjdk.org/jdk/pull/19513#discussion_r1639179219


Re: RFR: 8333396: Performance regression of DecimalFormat.format [v5]

2024-06-13 Thread lingjun-cg
On Thu, 13 Jun 2024 19:40:48 GMT, Naoto Sato  wrote:

> I second Justin's suggestion here. The change should benefit every 
> implementation in the JDK, not only NumberFormat. Also, I might suggest 
> renaming the new class, as it is kind of long/redundant. How about using 
> something as simple as "StringBuf"?

Thanks for your comment. The long name bother me for a while. I have changed it 
to ""StringBuf".

-

PR Comment: https://git.openjdk.org/jdk/pull/19513#issuecomment-2167144044


Re: RFR: 8333396: Performance regression of DecimalFormat.format [v6]

2024-06-13 Thread lingjun-cg
> ### 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.0");
> }
> 
> @Benchmark
> public void testNewAndFormat() throws InterruptedException {
> new DecimalFormat("#0.0").format(9524234.1236457);
> }
> 
> @Benchmark
> public void testNewOnly() throws InterruptedException {
> new DecimalFormat("#0.0");
> }
> 
> @Benchmark
> public void testFormatOnly() throws InterruptedException {
> format.format(9524234.1236457);
> }
> }
> 
> 
> ### Test result
>  Current JDK before optimize
> 
>  Benchmark Mode  CntScore   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  CntScore   Error  Units
> JmhDecimalFormat.testFormatOnlyavgt   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  CntScore   Error  Units
> JmhDecimalFormat.testFormatOnlyavgt   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:

  896: Performance regression of DecimalFormat.format

-

Changes:
  - all: https://git.openjdk.org/jdk/pull/19513/files
  - new: https://git.openjdk.org/jdk/pull/19513/files/1ab65e18..d590f132

Webrevs:
 - full: https://webrevs.openjdk.org/?repo=jdk=19513=05
 - incr: https://webrevs.openjdk.org/?repo=jdk=19513=04-05

  Stats: 467 lines in 11 files changed: 222 ins; 188 del; 57 mod
  Patch: https://git.openjdk.org/jdk/pull/19513.diff
  Fetch: git fetch https://git.openjdk.org/jdk.git pull/19513/head:pull/19513

PR: https://git.openjdk.org/jdk/pull/19513


Re: RFR: 8333396: Performance regression of DecimalFormat.format [v4]

2024-06-12 Thread lingjun-cg
On Tue, 4 Jun 2024 19:44:57 GMT, Naoto Sato  wrote:

>> lingjun-cg has updated the pull request incrementally with one additional 
>> commit since the last revision:
>> 
>>   896: Performance regression of DecimalFormat.format
>
> Also it would be helpful to compare the performance without biased locking in 
> JDK11.

@naotoj The above contains the result of JDK11 with disabled and enabled biased 
locking. It seems the key is the biased locking. Now our application use 
DecimalFormat.format() seriously,  the performance is declining when migrate 
from JDK 11 to JDK 21.  Could you give some suggestion?Thanks.

-

PR Comment: https://git.openjdk.org/jdk/pull/19513#issuecomment-2162813093


Re: RFR: 8333396: Performance regression of DecimalFormat.format [v5]

2024-06-04 Thread lingjun-cg
> ### 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.0");
> }
> 
> @Benchmark
> public void testNewAndFormat() throws InterruptedException {
> new DecimalFormat("#0.0").format(9524234.1236457);
> }
> 
> @Benchmark
> public void testNewOnly() throws InterruptedException {
> new DecimalFormat("#0.0");
> }
> 
> @Benchmark
> public void testFormatOnly() throws InterruptedException {
> format.format(9524234.1236457);
> }
> }
> 
> 
> ### Test result
>  Current JDK before optimize
> 
>  Benchmark Mode  CntScore   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  CntScore   Error  Units
> JmhDecimalFormat.testFormatOnlyavgt   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  CntScore   Error  Units
> JmhDecimalFormat.testFormatOnlyavgt   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:

  896: Performance regression of DecimalFormat.format

-

Changes:
  - all: https://git.openjdk.org/jdk/pull/19513/files
  - new: https://git.openjdk.org/jdk/pull/19513/files/6210c61e..1ab65e18

Webrevs:
 - full: https://webrevs.openjdk.org/?repo=jdk=19513=04
 - incr: https://webrevs.openjdk.org/?repo=jdk=19513=03-04

  Stats: 45 lines in 8 files changed: 37 ins; 0 del; 8 mod
  Patch: https://git.openjdk.org/jdk/pull/19513.diff
  Fetch: git fetch https://git.openjdk.org/jdk.git pull/19513/head:pull/19513

PR: https://git.openjdk.org/jdk/pull/19513


Re: RFR: 8333396: Performance regression of DecimalFormat.format [v4]

2024-06-04 Thread lingjun-cg
On Tue, 4 Jun 2024 19:44:57 GMT, Naoto Sato  wrote:

> Also it would be helpful to compare the performance without biased locking in 
> JDK11.

If run in JDK11 without biased locking, the performance is as same as run in 
current JDK.

-

PR Comment: https://git.openjdk.org/jdk/pull/19513#issuecomment-2148719265


Integrated: 8333462: Performance regression of new DecimalFormat() when compare to jdk11

2024-06-04 Thread lingjun-cg
On Tue, 4 Jun 2024 02:32:28 GMT, lingjun-cg  wrote:

> Run the below benchmark test  ,it show the average time of new 
> DecimalFormat()  increase 18% when compare to jdk 11.
> 
> the result with jdk 11:
> 
> Benchmark  Mode  CntScore   Error  Units
> JmhDecimalFormat.testNewOnly   avgt   50  248.300 ? 5.158  ns/op
> 
> 
> the result with current jdk:
> 
> Benchmark  Mode  CntScore   Error  Units
> JmhDecimalFormat.testNewOnly   avgt   50  303.381 ? 5.252  ns/op
> 
> 
> 
> @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 {
> 
> @Setup(Level.Trial)
> public void setup() {
> }
> 
> @Benchmark
> public void testNewOnly() throws InterruptedException {
> new DecimalFormat("#0.0");
> }
> }
> 
> 
> Compare the flame graph it shows the 
> java.text.DecimalFormatSymbols#findNonFormatChar takes a significant time. 
> After replacing  the lambda implementation with a simple loop , it shows 
> nearly the same performance as jdk 11.
> 
> 
> Benchmark  Mode  CntScore   Error  Units
> JmhDecimalFormat.testNewOnly   avgt   50  209.874 ? 9.951  ns/op
> 
> 
> [flame-graph-jdk11-jdk21.zip](https://github.com/user-attachments/files/15541764/flame-graph-jdk11-jdk21.zip)

This pull request has now been integrated.

Changeset: d8261279
Author:lingjun.cg 
Committer: Denghui Dong 
URL:   
https://git.openjdk.org/jdk/commit/d826127970bd2ae8bf4cacc3c55634dc5af307c4
Stats: 8 lines in 1 file changed: 3 ins; 0 del; 5 mod

8333462: Performance regression of new DecimalFormat() when compare to jdk11

Reviewed-by: liach, naoto, jlu

-

PR: https://git.openjdk.org/jdk/pull/19534


Re: RFR: 8333462: Performance regression of new DecimalFormat() when compare to jdk11 [v2]

2024-06-04 Thread lingjun-cg
> Run the below benchmark test  ,it show the average time of new 
> DecimalFormat()  increase 18% when compare to jdk 11.
> 
> the result with jdk 11:
> 
> Benchmark  Mode  CntScore   Error  Units
> JmhDecimalFormat.testNewOnly   avgt   50  248.300 ? 5.158  ns/op
> 
> 
> the result with current jdk:
> 
> Benchmark  Mode  CntScore   Error  Units
> JmhDecimalFormat.testNewOnly   avgt   50  303.381 ? 5.252  ns/op
> 
> 
> 
> @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 {
> 
> @Setup(Level.Trial)
> public void setup() {
> }
> 
> @Benchmark
> public void testNewOnly() throws InterruptedException {
> new DecimalFormat("#0.0");
> }
> }
> 
> 
> Compare the flame graph it shows the 
> java.text.DecimalFormatSymbols#findNonFormatChar takes a significant time. 
> After replacing  the lambda implementation with a simple loop , it shows 
> nearly the same performance as jdk 11.
> 
> 
> Benchmark  Mode  CntScore   Error  Units
> JmhDecimalFormat.testNewOnly   avgt   50  209.874 ? 9.951  ns/op
> 
> 
> [flame-graph-jdk11-jdk21.zip](https://github.com/user-attachments/files/15541764/flame-graph-jdk11-jdk21.zip)

lingjun-cg has updated the pull request incrementally with one additional 
commit since the last revision:

  8333462: Performance regression of new DecimalFormat() when compare to jdk11

-

Changes:
  - all: https://git.openjdk.org/jdk/pull/19534/files
  - new: https://git.openjdk.org/jdk/pull/19534/files/a230ce00..d5b9ccfb

Webrevs:
 - full: https://webrevs.openjdk.org/?repo=jdk=19534=01
 - incr: https://webrevs.openjdk.org/?repo=jdk=19534=00-01

  Stats: 4 lines in 1 file changed: 1 ins; 0 del; 3 mod
  Patch: https://git.openjdk.org/jdk/pull/19534.diff
  Fetch: git fetch https://git.openjdk.org/jdk.git pull/19534/head:pull/19534

PR: https://git.openjdk.org/jdk/pull/19534


Re: RFR: 8333396: Performance regression of DecimalFormat.format [v4]

2024-06-04 Thread lingjun-cg
> ### 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.0");
> }
> 
> @Benchmark
> public void testNewAndFormat() throws InterruptedException {
> new DecimalFormat("#0.0").format(9524234.1236457);
> }
> 
> @Benchmark
> public void testNewOnly() throws InterruptedException {
> new DecimalFormat("#0.0");
> }
> 
> @Benchmark
> public void testFormatOnly() throws InterruptedException {
> format.format(9524234.1236457);
> }
> }
> 
> 
> ### Test result
>  Current JDK before optimize
> 
>  Benchmark Mode  CntScore   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  CntScore   Error  Units
> JmhDecimalFormat.testFormatOnlyavgt   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  CntScore   Error  Units
> JmhDecimalFormat.testFormatOnlyavgt   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:

  896: Performance regression of DecimalFormat.format

-

Changes:
  - all: https://git.openjdk.org/jdk/pull/19513/files
  - new: https://git.openjdk.org/jdk/pull/19513/files/0a581428..6210c61e

Webrevs:
 - full: https://webrevs.openjdk.org/?repo=jdk=19513=03
 - incr: https://webrevs.openjdk.org/?repo=jdk=19513=02-03

  Stats: 3 lines in 1 file changed: 0 ins; 0 del; 3 mod
  Patch: https://git.openjdk.org/jdk/pull/19513.diff
  Fetch: git fetch https://git.openjdk.org/jdk.git pull/19513/head:pull/19513

PR: https://git.openjdk.org/jdk/pull/19513


Re: RFR: 8333396: Performance regression of DecimalFormat.format [v3]

2024-06-04 Thread lingjun-cg
On Tue, 4 Jun 2024 07:54:56 GMT, kuaiwei  wrote:

> > > Hi, I think you can add the jmh test case.
> > 
> > 
> > [#19513 
> > (comment)](https://github.com/openjdk/jdk/pull/19513#issue-2330131051) 
> > already contains the test case.
> 
> I mean it can be added as a test case in test/micro and be evaluated in 
> future build.

Thanks for your remainder. There exist a JMH  test case which named  
'test/micro/org/openjdk/bench/java/text/DefFormatterBench.java'.

This JMH test case run in throughput mode.
If  run without the patch, the output is:

Benchmark  Mode  Cnt ScoreError   Units
DefFormatterBench.testDefNumberFormatter  thrpt5  1842.666 ? 83.694  ops/ms


If run with after apply the patch, the output is:

Benchmark  Mode  Cnt Score Error   Units
DefFormatterBench.testDefNumberFormatter  thrpt5  3988.274 ? 513.434  ops/ms


The score is increased by  (3988.274-1842.666)/1842.666 = 116%.

-

PR Comment: https://git.openjdk.org/jdk/pull/19513#issuecomment-2146983441


Re: RFR: 8333396: Performance regression of DecimalFormat.format [v3]

2024-06-04 Thread lingjun-cg
On Tue, 4 Jun 2024 07:21:15 GMT, kuaiwei  wrote:

> Hi, I think you can add the jmh test case.

https://github.com/openjdk/jdk/pull/19513#issue-2330131051 already contains the 
test case.

-

PR Comment: https://git.openjdk.org/jdk/pull/19513#issuecomment-2146844849


RFR: 8333462: Performance regression of new DecimalFormat() when compare to jdk11

2024-06-03 Thread lingjun-cg
Run the below benchmark test  ,it show the average time of new DecimalFormat()  
increase 18% when compare to jdk 11.

the result with jdk 11:

Benchmark  Mode  CntScore   Error  Units
JmhDecimalFormat.testNewOnly   avgt   50  248.300 ? 5.158  ns/op


the result with current jdk:

Benchmark  Mode  CntScore   Error  Units
JmhDecimalFormat.testNewOnly   avgt   50  303.381 ? 5.252  ns/op



@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 {

@Setup(Level.Trial)
public void setup() {
}

@Benchmark
public void testNewOnly() throws InterruptedException {
new DecimalFormat("#0.0");
}
}


Compare the flame graph it shows the 
java.text.DecimalFormatSymbols#findNonFormatChar takes a significant time. 
After replacing  the lambda implementation with a simple loop , it shows nearly 
the same performance as jdk 11.


Benchmark  Mode  CntScore   Error  Units
JmhDecimalFormat.testNewOnly   avgt   50  209.874 ? 9.951  ns/op


[flame-graph-jdk11-jdk21.zip](https://github.com/user-attachments/files/15541764/flame-graph-jdk11-jdk21.zip)

-

Commit messages:
 - 8333462: Performance regression of new DecimalFormat() when compare to jdk11

Changes: https://git.openjdk.org/jdk/pull/19534/files
  Webrev: https://webrevs.openjdk.org/?repo=jdk=19534=00
  Issue: https://bugs.openjdk.org/browse/JDK-8333462
  Stats: 6 lines in 1 file changed: 2 ins; 0 del; 4 mod
  Patch: https://git.openjdk.org/jdk/pull/19534.diff
  Fetch: git fetch https://git.openjdk.org/jdk.git pull/19534/head:pull/19534

PR: https://git.openjdk.org/jdk/pull/19534


Re: RFR: 8333396: Performance regression of DecimalFormat.format [v3]

2024-06-03 Thread lingjun-cg
> ### 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.
> 
> ### Test result
> 
> @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.0");
> }
> 
> @Benchmark
> public void testNewAndFormat() throws InterruptedException {
> new DecimalFormat("#0.0").format(9524234.1236457);
> }
> 
> @Benchmark
> public void testNewOnly() throws InterruptedException {
> new DecimalFormat("#0.0");
> }
> 
> @Benchmark
> public void testFormatOnly() throws InterruptedException {
> format.format(9524234.1236457);
> }
> }
> 
>  Current JDK before optimize
> 
>  Benchmark Mode  CntScore   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  CntScore   Error  Units
> JmhDecimalFormat.testFormatOnlyavgt   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  CntScore   Error  Units
> JmhDecimalFormat.testFormatOnlyavgt   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:

  896: Performance regression of DecimalFormat.format

-

Changes:
  - all: https://git.openjdk.org/jdk/pull/19513/files
  - new: https://git.openjdk.org/jdk/pull/19513/files/b48962b5..0a581428

Webrevs:
 - full: https://webrevs.openjdk.org/?repo=jdk=19513=02
 - incr: https://webrevs.openjdk.org/?repo=jdk=19513=01-02

  Stats: 6 lines in 1 file changed: 0 ins; 2 del; 4 mod
  Patch: https://git.openjdk.org/jdk/pull/19513.diff
  Fetch: git fetch https://git.openjdk.org/jdk.git pull/19513/head:pull/19513

PR: https://git.openjdk.org/jdk/pull/19513


Re: RFR: 8333396: Performance regression of new DecimalFormat and DecimalFormat.format [v2]

2024-06-03 Thread lingjun-cg
On Mon, 3 Jun 2024 06:13:35 GMT, lingjun-cg  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.
>> 
>> ### Performance regression of new DecimalFormat
>> After comparing the flame graph between current jdk and jdk 11,  the method 
>> java.text.DecimalFormatSymbols#findNonFormatChar takes a significant time.  
>> The performance becomes as good as jdk11 after replacing it with a simple 
>> loop implementation.
>> 
>> 
>> 
>> ### Test result
>> 
>> @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.0");
>> }
>> 
>> @Benchmark
>> public void testNewAndFormat() throws InterruptedException {
>> new DecimalFormat("#0.0").format(9524234.1236457);
>> }
>> 
>> @Benchmark
>> public void testNewOnly() throws InterruptedException {
>> new DecimalFormat("#0.0");
>> }
>> 
>> @Benchmark
>> public void testFormatOnly() throws InterruptedException {
>> format.format(9524234.1236457);
>> }
>> }
>> 
>>  Current JDK before optimize
>> 
>>  Benchmark Mode  CntScore   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  CntScore   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  CntScore   Error  Units
>> JmhDecimalFormat.testFormatOnlyavgt   50  364.214 ? 1.191  ns/op
>> JmhDecimalFormat.testNewAndForma...
>
> lingjun-cg has updated the pull request incrementally with one additional 
> commit since the last revision:
> 
>   896: Performance regression of new DecimalFormat and 
> DecimalFormat.format

Hi naotaoj,
What I mean "performance regression" is compare to JDK 11. We have an 
server side application that use DecimalFormat.format API seriously. When 
migrate it from JDK 11 to JDK 21, we found a performance  degradation.
So I write the JMH test case "JmhDecimalFormat".  It show that there a 
performance regression since JDK 21.

These are the perfasm output for running JMH on both JDK 11 and JDK21. There 
are some  hot regions around the atomic instructions in JDK 21, but no such 
problem in JDK 11.
[jdk11.txt](https://github.com/user-attachments/files/15541278/jdk11.txt)
[jdk21.txt](https://github.com/user-attachments/files/15541279/jdk21.txt)

Maybe the [JEP 374: Deprecate and Disable Biased 
Locking](https://openjdk.org/jeps/374) is the reason?
So I run the benchmark on JDK 11 again but with option '-XX:-UseBiasedLocking', 
 there only a minor gap between jdk11 and jdk 21.

OK, return to my patch. java.text use StringBuffer internally,  but nearly all 
methods in StringBuffer are synchronized:

@Override
public synchronized StringBuffer append(Object obj) {

}

@Override
@IntrinsicCandidate
public synchronized StringBuffer append(String str) {
...
}


>From the above analysis, the atomic instructions slow down 
>DecimalFormat.format, and StringBuffer's synchronized methods generate there 
>atomic instructions. So If remove these synchronized methods, it will get a 
>better performance.
So I replace StringBuffer with StringBuilder in  java.text.NumberFormat.

public final String format(double number) {
// Use fast-path for double result if t

Re: RFR: 8333396: Performance regression of new DecimalFormat and DecimalFormat.format [v2]

2024-06-03 Thread lingjun-cg
> ### 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.
> 
> ### Performance regression of new DecimalFormat
> After comparing the flame graph between current jdk and jdk 11,  the method 
> java.text.DecimalFormatSymbols#findNonFormatChar takes a significant time.  
> The performance becomes as good as jdk11 after replacing it with a simple 
> loop implementation.
> 
> 
> 
> ### Test result
> 
> @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.0");
> }
> 
> @Benchmark
> public void testNewAndFormat() throws InterruptedException {
> new DecimalFormat("#0.0").format(9524234.1236457);
> }
> 
> @Benchmark
> public void testNewOnly() throws InterruptedException {
> new DecimalFormat("#0.0");
> }
> 
> @Benchmark
> public void testFormatOnly() throws InterruptedException {
> format.format(9524234.1236457);
> }
> }
> 
>  Current JDK before optimize
> 
>  Benchmark Mode  CntScore   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  CntScore   Error  Units
> JmhDecimalFormat.testFormatOnlyavgt   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.testFormatOnlyavgt   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:

  896: Performance regression of new DecimalFormat and DecimalFormat.format

-

Changes:
  - all: https://git.openjdk.org/jdk/pull/19513/files
  - new: https://git.openjdk.org/jdk/pull/19513/files/a6755f8f..b48962b5

Webrevs:
 - full: https://webrevs.openjdk.org/?repo=jdk=19513=01
 - incr: https://webrevs.openjdk.org/?repo=jdk=19513=00-01

  Stats: 1 line in 1 file changed: 0 ins; 0 del; 1 mod
  Patch: https://git.openjdk.org/jdk/pull/19513.diff
  Fetch: git fetch https://git.openjdk.org/jdk.git pull/19513/head:pull/19513

PR: https://git.openjdk.org/jdk/pull/19513


RFR: 8333396: Performance regression of new DecimalFormat and DecimalFormat.format

2024-06-02 Thread lingjun-cg
### 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.

### Performance regression of new DecimalFormat
After comparing the flame graph between current jdk and jdk 11,  the method 
java.text.DecimalFormatSymbols#findNonFormatChar takes a significant time.  The 
performance becomes as good as jdk11 after replacing it with a simple loop 
implementation.

-

Commit messages:
 - 896: Performance regression of new DecimalFormat and DecimalFormat.format

Changes: https://git.openjdk.org/jdk/pull/19513/files
  Webrev: https://webrevs.openjdk.org/?repo=jdk=19513=00
  Issue: https://bugs.openjdk.org/browse/JDK-896
  Stats: 318 lines in 11 files changed: 268 ins; 0 del; 50 mod
  Patch: https://git.openjdk.org/jdk/pull/19513.diff
  Fetch: git fetch https://git.openjdk.org/jdk.git pull/19513/head:pull/19513

PR: https://git.openjdk.org/jdk/pull/19513