Loading... (original) (raw)

As Martin Buchholz pointed out way back in

JDK-6898220

, java.util.Formatter is allocation intense and can be further optimized. Here are a few pretty straightforward things:

- avoid converting data back and forth between String, StringBuilder and char[] (especially using String.toCharArray()), instead try to operate on StringBuilders as much as possible. I consider getting rid of System.arraycopy a nice cleanup, too.
- regex: avoid using m.group on single-char groups, instead use m.start(idx)/m.end(idx) and charAt().
- parse: return the ArrayList directly instead of converting it to FormatSpecifier[]; since the recipient simply iterates over the specifiers once, converting to array is wasteful
- FixedString: constant string expressions were substrings, which since 7u6 copies the data. By instead saving the offset and rely on range-based append methods of StringBuilder a small speedup is achieved.

The code can be further optimized using

JDK-8041972

(parsing index, width, precision without intermediate substrings gains a few percent for complex cases) and perhaps

JDK-8050114

, but I will file separate RFEs for those.

Internal microbenchmarks show speedups ranging from 10-30%; some examples (Intel(R) Core(TM) i5-3320M CPU @ 2.60GHz, Linux 3.13):

Benchmark Mode Samples Score Score error Units
old.FormatBench.formatDecimal thrpt 20 2120314.923 48250.799 ops/s
new.FormatBench.formatDecimal thrpt 20 2739464.530 70673.303 ops/s # 1.29x

old.FormatBench.formatHex thrpt 20 1741011.847 28234.553 ops/s
new.FormatBench.formatHex thrpt 20 2172309.104 34826.348 ops/s # 1.25x

old.FormatBench.formatDouble thrpt 20 1199099.261 40828.750 ops/s
new.FormatBench.formatDouble thrpt 20 1334265.418 20479.704 ops/s # 1.11x

old.FormatBench.formatString thrpt 20 2437233.293 45434.999 ops/s
new.FormatBench.formatString thrpt 20 3183689.809 52892.969 ops/s # 1.30x

old.FormatBench.formatComplex thrpt 20 489896.437 9006.345 ops/s
new.FormatBench.formatComplex thrpt 20 578696.625 8039.759 ops/s # 1.18x

old.FormatBench.formatScience thrpt 20 938680.776 11932.883 ops/s
new.FormatBench.formatScience thrpt 20 1119664.074 14700.473 ops/s # 1.19x

package org.sample;

import org.openjdk.jmh.annotations.*;
import java.math.BigInteger;

@State(Scope.Thread)
public class FormatBench {

public int value = 4711;

public int width = 6;

public float pi = (float)Math.PI;

public String str = "foo";

@Benchmark
public String formatDecimal() {
return String.format("%d", value);
}

@Benchmark
public String formatHex() {
return String.format("%06x", value);
}

@Benchmark
public String formatDouble() {
return String.format("%.4f", pi);
}

@Benchmark
public String formatScience() {
return String.format("%5.5e", pi);
}

@Benchmark
public String formatComplex() {
return String.format(" %04x %05x %06x %05x", value, value, value, value);
}

@Benchmark
public String formatString() {
return String.format("%s", str);
}