<i18n dev> RFR: 8335791: Speed up j.u.Formatter & String.format
Chen Liang
liach at openjdk.org
Fri Jul 5 20:00:36 UTC 2024
On Fri, 5 Jul 2024 15:40:24 GMT, Shaojin Wen <duke at openjdk.org> wrote:
> String.format is widely used, and improving its performance is very meaningful. This PR can significantly improve the performance of String.format. Sorry, there are many changes, which will take a lot of time. I hope you can review it patiently.
>
>
> Improved performance includes the following:
>
> ## 1. Write directly during the parse process to reduce object allocation.
>
> In the current Formatter implementation, some objects do not need to be allocated, such as:
>
>
> class Formatter {
> public Formatter format(Locale l, String format, Object ... args) {
> List<FormatString> fsa = parse(format);
> // ...
> }
>
> static List<FormatString> parse(String s) {
> ArrayList<FormatString> al = new ArrayList<>();
>
> while (i < max) {
> int n = s.indexOf('%', i);
> if (n < 0) {
> //
> al.add(new FixedString(s, i, max));
> }
> }
> }
> }
>
> In the process of parsing, the content that is not a Specifier is directly appended without going through FixedString. By directly printing the parsed FormatString object, there is no need to construct a `List<FormatString> fsa` to store it.
>
> ## 2. Fast path print
> Use specialized FormatString implementations for single-character and single-width specifiers to avoid calling the large FormatSpecifier#print method.
>
> ## 3. String.format directly calls j.u.Formatter
> String.format directly calls j.u.Formatter via SharedSecrets to improve performance
src/java.base/share/classes/java/lang/String.java line 4548:
> 4546: }
> 4547:
> 4548: private static class StringFormat {
Since we want to avoid new classes on startup, we should change the lazy initialization pattern to:
private static @Stable JavaUtilFormatterAccess jufa;
private static JavaUtilFormatterAccess formatterAccess() {
var access = jufa;
if (access = null) {
// We can assert not null on the getJUFA result
return jufa = SharedSecrets.getJavaUtilFormatterAccess();
}
return access;
}
using benign race.
src/java.base/share/classes/java/util/Formatter.java line 3107:
> 3105: if (fmt.locale() != l)
> 3106: fmt = new Formatter(fmt.out(), l);
> 3107: ((Formattable)arg).formatTo(fmt, Flags.NONE, -1, -1);
You can use pattern matching for instanceof to avoid a cast here.
src/java.base/share/classes/java/util/Formatter.java line 5260:
> 5258: }
> 5259:
> 5260: static final FormatString[] specifiers = new FormatString[128];
Suggestion:
static final @Stable FormatString[] specifiers = new FormatString[128];
-------------
PR Review Comment: https://git.openjdk.org/jdk/pull/20055#discussion_r1667064117
PR Review Comment: https://git.openjdk.org/jdk/pull/20055#discussion_r1667087769
PR Review Comment: https://git.openjdk.org/jdk/pull/20055#discussion_r1667091143
More information about the i18n-dev
mailing list