Optimize parsing 19 digit longs by marschall · Pull Request #865 · FasterXML/jackson-core (original) (raw)

Parsing 19 digit long values is significantly slower than parsing 18 digit long values as we are hitting a slow path that does a string allocation.

19 digit long values are quite common when a random number generator is used to generate long values.

We have to pay attention that we only use this fast path if the value is a valid long. This can be achieved by calling #inLongRange first.

In the following synthetic microbenchmark a throughput increase of about 33% with a drastic reduction in the allocation rate can be achieved.

@OutputTimeUnit(TimeUnit.SECONDS) public class JacksonStdLongReadVanilla {

private static final JsonFactory JSON_FACTORY = new JsonFactory();

private static final String JSON;

static {
    StringBuilder json = new StringBuilder();
    Random random = new Random(0L);
    json.append('[');
    for (int i = 0; i < 1_000; i++) {
        if (i > 0) {
            json.append(',');
        }
        json.append(random.nextLong());
    }
    json.append(']');
    JSON = json.toString();
}

@Benchmark
public void parseLong(Blackhole blackhole) throws IOException {
    try (JsonParser parser = JSON_FACTORY.createParser(JSON)) {
        parser.nextToken();

        JsonToken nextToken = parser.nextToken();
        while (nextToken == JsonToken.VALUE_NUMBER_INT) {
            blackhole.consume(parser.getLongValue());
            nextToken = parser.nextToken();
        }
    }
}

}

If we have a look at the allocations before we see that it is dominated by byte[] allocations for String allocations

allocation-site-before

Resulting in many gcs

gcs-before

With the changes in this PR the byte[] and String allocations are gone

allocation-site-after

Resulting in no more gcs

gcs-after