OpenJDK25 added implementations of DoubleToDecimal and FloatToDecimal that encode directly to Latin1 bytes without any allocations: openjdk/jdk@9d20b58
If this was public API, it could be used pretty easily within UTF8JsonGenerator for some fairly massive performance benefits when serializing large numbers of floating point numbers -- something that's very common with GeoJSON.
@Override
public void writeNumber(double d) throws IOException {
if (this._outputTail + DoubleToDecimal.MAX_CHARS >= this._outputEnd) {
this._flushBuffer();
}
this._outputTail = DoubleToDecimal.LATIN1.putDecimal(this._outputBuffer, this._outputTail, d);
}
A simple benchmark that tests this change by writing a 10k element float/double array to a null output stream shows that this approach is nearly 3x as fast, even when the relevant internal utility is copied out of the JDK (removing the requirement of --add-opens).
Benchmark (type) (mode) Mode Cnt Score Error Units
WriteFloatingPointArray.write FLOAT VANILLA thrpt 4 1934.454 ± 84.062 ops/s
WriteFloatingPointArray.write:gc.alloc.rate.norm FLOAT VANILLA thrpt 4 880296.792 ± 0.825 B/op
WriteFloatingPointArray.write FLOAT JACKSON_FAST thrpt 4 2116.445 ± 52.042 ops/s
WriteFloatingPointArray.write:gc.alloc.rate.norm FLOAT JACKSON_FAST thrpt 4 880263.591 ± 248.715 B/op
WriteFloatingPointArray.write FLOAT JDK_INTERNAL thrpt 4 3708.587 ± 491.341 ops/s
WriteFloatingPointArray.write:gc.alloc.rate.norm FLOAT JDK_INTERNAL thrpt 4 383.432 ± 12.262 B/op
WriteFloatingPointArray.write FLOAT JDK_COPY thrpt 4 3623.090 ± 240.293 ops/s
WriteFloatingPointArray.write:gc.alloc.rate.norm FLOAT JDK_COPY thrpt 4 383.387 ± 13.224 B/op
WriteFloatingPointArray.write DOUBLE VANILLA thrpt 4 1268.260 ± 39.709 ops/s
WriteFloatingPointArray.write:gc.alloc.rate.norm DOUBLE VANILLA thrpt 4 1040193.112 ± 0.036 B/op
WriteFloatingPointArray.write DOUBLE JACKSON_FAST thrpt 4 1532.169 ± 190.942 ops/s
WriteFloatingPointArray.write:gc.alloc.rate.norm DOUBLE JACKSON_FAST thrpt 4 1040192.921 ± 0.115 B/op
WriteFloatingPointArray.write DOUBLE JDK_INTERNAL thrpt 4 2788.184 ± 497.046 ops/s
WriteFloatingPointArray.write:gc.alloc.rate.norm DOUBLE JDK_INTERNAL thrpt 4 315.239 ± 35.377 B/op
WriteFloatingPointArray.write DOUBLE JDK_COPY thrpt 4 2704.880 ± 379.627 ops/s
WriteFloatingPointArray.write:gc.alloc.rate.norm DOUBLE JDK_COPY thrpt 4 315.170 ± 34.143 B/op
Based on these results it seems like it would be valuable to optimize Jackson's copy of *ToDecimal and bring back USE_FAST_DOUBLE_WRITER for modern JDKs? I'm not positive but I don't believe the JDK's implementation of these directly into jackson-core due to licensing, and I suspect relying on --add-opens java.base/jdk.internal.math=ALL-UNNAMED is not a good approach for a general purpose library.
OpenJDK25 added implementations of
DoubleToDecimalandFloatToDecimalthat encode directly to Latin1 bytes without any allocations: openjdk/jdk@9d20b58If this was public API, it could be used pretty easily within UTF8JsonGenerator for some fairly massive performance benefits when serializing large numbers of floating point numbers -- something that's very common with GeoJSON.
A simple benchmark that tests this change by writing a 10k element float/double array to a null output stream shows that this approach is nearly 3x as fast, even when the relevant internal utility is copied out of the JDK (removing the requirement of
--add-opens).Based on these results it seems like it would be valuable to optimize Jackson's copy of
*ToDecimaland bring backUSE_FAST_DOUBLE_WRITERfor modern JDKs? I'm not positive but I don't believe the JDK's implementation of these directly into jackson-core due to licensing, and I suspect relying on--add-opens java.base/jdk.internal.math=ALL-UNNAMEDis not a good approach for a general purpose library.