-
Notifications
You must be signed in to change notification settings - Fork 117
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Optimize InstantDeserializer
method replaceZeroOffsetAsZIfNecessary()
#266
Conversation
Excellent, thank you @schlosna! I especially appreciate jmh benchmark here. Just one small thing before I can merge this for inclusion in 2.15.0: unless I have asked for a CLA, I'd need it from: https://github.com/FasterXML/jackson/blob/master/contributor-agreement.pdf and the usual way is to print it, fill & sign, scan/photo, email to Thank you again & looking forward to merging this PR! |
Ok, one oddity: new test cases fail on JDK 8 and 11 (see CI run; I had to enable it since it's your first contribution). Possibly related to handling (or not) of colon in time offset parts? |
Avoid expensive regex matcher allocations when replacing zero offset with 'Z'. OpenJDK 17 on x64 Intel(R) Xeon(R) Platinum 8259CL CPU @ 2.50GHz Benchmark Mode Cnt Score Error Units InstantDeserializerBenchmark.index avgt 5 19.543 ± 1.384 ns/op InstantDeserializerBenchmark.regex avgt 5 155.081 ± 3.234 ns/op OpenJDK 17 on aarch64 Apple M1 Pro aarch64 Benchmark Mode Cnt Score Error Units InstantDeserializerBenchmark.index avgt 5 16.855 ± 0.537 ns/op InstantDeserializerBenchmark.regex avgt 5 58.155 ± 1.444 ns/op
Thanks for the quick review @cowtowncoder ! I'll get the CLA reviewed & signed hopefully tomorrow. I removed the commit with additional test cases as I forgot those will fail on JDK 8 & 11 (the test cases also fail on JDK 8 & 11 applied to |
These tests are skipped before JDK 12 as DateTimeFormatter.ISO_INSTANT didn't handle offsets until JDK 12+, see https://bugs.openjdk.org/browse/JDK-8166138
After some needed sleep, I realized why those tests pass on JDK 17+ but did not pass on JDK 8 & 11 and it is the reason we're replacing the zero offset with I've updated the test cases in |
String maybeOffset = text.substring(maybeOffsetIndex); | ||
if ("00".equals(maybeOffset) || "0000".equals(maybeOffset) || "00:00".equals(maybeOffset)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we optimize this using String.regionMatches
?
perhaps using something along the lines of
switch (remaining) {
case 2:
return text.regionmatches..."00" ? text.substring(0, plusIndex) + 'Z' : text;
case 4:
..etc
case 5:
..etc
}
return text;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems reasonable to avoid the substring allocation, updated to use regionMatches
& switch
and reran JMH and tested locally with JDKs 8, 11, 17.
Intel(R) Xeon(R) Platinum 8259CL CPU @ 2.50GHz
JDK 17.0.5, OpenJDK 64-Bit Server VM, 17.0.5+8-LTS
Benchmark Mode Cnt Score Error Units
InstantDeserializerBenchmark.index avgt 5 20.003 ± 0.486 ns/op
InstantDeserializerBenchmark.regex avgt 5 156.174 ± 7.654 ns/op
Intel(R) Xeon(R) Platinum 8259CL CPU @ 2.50GHz
JDK 11.0.16.1, OpenJDK 64-Bit Server VM, 11.0.16.1+9-LTS
Benchmark Mode Cnt Score Error Units
InstantDeserializerBenchmark.index avgt 5 20.818 ± 1.267 ns/op
InstantDeserializerBenchmark.regex avgt 5 192.248 ± 7.341 ns/op
Apple M1 Pro aarch64
JDK 17.0.6, OpenJDK 64-Bit Server VM, 17.0.6+10-LTS
Benchmark Mode Cnt Score Error Units
InstantDeserializerBenchmark.index avgt 5 17.498 ± 0.677 ns/op
InstantDeserializerBenchmark.regex avgt 5 58.096 ± 1.330 ns/op
Apple M1 Pro aarch64
Benchmark Mode Cnt Score Error Units
InstantDeserializerBenchmark.index avgt 5 16.176 ± 7.842 ns/op
InstantDeserializerBenchmark.regex avgt 5 63.201 ± 5.668 ns/op
Ok sounds good; will merge as soon as we get CLA done. Good work everyone! |
I'll submit CLA ASAP, waiting on review right now |
CLA submitted via email |
InstantDeserializer
method replaceZeroOffsetAsZIfNecessary()
Thank you @schlosna -- merged to be included in 2.15.0! |
While reviewing some JFRs from some services that heavily use Jackson for deserializing timestamps, I noticed that
com.fasterxml.jackson.datatype.jsr310.deser.InstantDeserializer.replaceZeroOffsetAsZIfNecessary(String)
was allocating a lot ofint[]
from its use ofjava.util.regex.Pattern.matcher(CharSequence)
to determine whether an input String is a zero offset and if so replace it withZ
.I would like to propose an alternative implementation to avoid expensive regex matcher allocations when replacing zero offset with 'Z'.
Using a JMH benchmark with a variety of generated timestamps I see the following results on x64 (~7x speedup) and aarch64 (~2.5x speedup):
OpenJDK 17.0.6 on x64 Intel(R) Xeon(R) Platinum 8259CL CPU @ 2.50GHz
OpenJDK 17.0.6 on aarch64 Apple M1 Pro