On Tue, 18 Jun 2024 10:00:33 GMT, lingjun-cg <d...@openjdk.org> wrote:
>> ### Performance regression of DecimalFormat.format >> From the output of perf, we can see the hottest regions contain atomic >> instructions. But when run with JDK 11, there is no such problem. The >> reason is the removed biased locking. >> The DecimalFormat uses StringBuffer everywhere, and StringBuffer itself >> contains many synchronized methods. >> So I added support for some new methods that accept StringBuilder which is >> lock-free. >> >> ### Benchmark testcase >> >> @BenchmarkMode(Mode.AverageTime) >> @Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS) >> @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) >> @State(Scope.Thread) >> @OutputTimeUnit(TimeUnit.NANOSECONDS) >> public class JmhDecimalFormat { >> >> private DecimalFormat format; >> >> @Setup(Level.Trial) >> public void setup() { >> format = new DecimalFormat("#0.00000"); >> } >> >> @Benchmark >> public void testNewAndFormat() throws InterruptedException { >> new DecimalFormat("#0.00000").format(9524234.1236457); >> } >> >> @Benchmark >> public void testNewOnly() throws InterruptedException { >> new DecimalFormat("#0.00000"); >> } >> >> @Benchmark >> public void testFormatOnly() throws InterruptedException { >> format.format(9524234.1236457); >> } >> } >> >> >> ### Test result >> #### Current JDK before optimize >> >> Benchmark Mode Cnt Score Error Units >> JmhDecimalFormat.testFormatOnly avgt 50 642.099 ? 1.253 ns/op >> JmhDecimalFormat.testNewAndFormat avgt 50 989.307 ? 3.676 ns/op >> JmhDecimalFormat.testNewOnly avgt 50 303.381 ? 5.252 ns/op >> >> >> >> #### Current JDK after optimize >> >> Benchmark Mode Cnt Score Error Units >> JmhDecimalFormat.testFormatOnly avgt 50 351.499 ? 0.761 ns/op >> JmhDecimalFormat.testNewAndFormat avgt 50 615.145 ? 2.478 ns/op >> JmhDecimalFormat.testNewOnly avgt 50 209.874 ? 9.951 ns/op >> >> >> ### JDK 11 >> >> Benchmark Mode Cnt Score Error Units >> JmhDecimalFormat.testFormatOnly avgt 50 364.214 ? 1.191 ns/op >> JmhDecimalFormat.testNewAndFormat avgt 50 658.699 ? 2.311 ns/op >> JmhDecimalFormat.testNewOnly avgt 50 248.300 ? 5.158 ns/op > > lingjun-cg has updated the pull request incrementally with one additional > commit since the last revision: > > 8333396: Performance regression of DecimalFormat.format > If not that, throw a StackOverflowException when run with > DecimalFormat.format(double) I'm not sure I understand this point. I think this is on the right track and looks much better with the generic implementation. 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. 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 extends Appendable & CharSequence> T formatWithGeneric(Date date, T toAppendTo, FieldPosition pos) { throw new UnsupportedOperationException("Subclasses should override this method"); } ------------- PR Review: https://git.openjdk.org/jdk/pull/19513#pullrequestreview-2126447188 PR Review Comment: https://git.openjdk.org/jdk/pull/19513#discussion_r1645029030 PR Review Comment: https://git.openjdk.org/jdk/pull/19513#discussion_r1645026453