Skip to content

Commit

Permalink
feat(json): Improve structure performance
Browse files Browse the repository at this point in the history
  • Loading branch information
PerfectSlayer committed Dec 4, 2024
1 parent 1776ab7 commit 7c3d6e2
Show file tree
Hide file tree
Showing 3 changed files with 129 additions and 19 deletions.
8 changes: 8 additions & 0 deletions components/json/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1 +1,9 @@
plugins {
id("me.champeau.jmh")
}

apply(from = "$rootDir/gradle/java.gradle")

jmh {
version = "1.28"
}
106 changes: 106 additions & 0 deletions components/json/src/jmh/java/datadog/json/JsonWriterBenchmark.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package datadog.json;

import static java.util.concurrent.TimeUnit.MICROSECONDS;
import static org.openjdk.jmh.annotations.Mode.AverageTime;

import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.infra.Blackhole;

@BenchmarkMode(AverageTime)
@OutputTimeUnit(MICROSECONDS)
@Fork(value = 1)
@SuppressWarnings("unused")
public class JsonWriterBenchmark {
@Benchmark
public void writeSimpleArray(Blackhole blackhole) {
try (JsonWriter writer = new JsonWriter()) {
writer
.beginArray()
.beginObject()
.name("true")
.value(true)
.endObject()
.beginObject()
.name("false")
.value(false)
.endObject()
.endArray();
blackhole.consume(writer.toString());
}
}

@Benchmark
public void writeComplexArray(Blackhole blackhole) {
try (JsonWriter writer = new JsonWriter()) {
writer
.beginArray()
.value("first level")
.beginArray()
.value("second level")
.beginArray()
.value("third level")
.beginObject()
.name("key")
.value("value")
.endObject()
.beginObject()
.name("key")
.value("value")
.endObject()
.endArray() // second level
.beginObject()
.name("key")
.value("value")
.endObject()
.endArray() // first level
.beginObject()
.name("key")
.value("value")
.endObject()
.value("last value")
.endArray();
blackhole.consume(writer.toString());
}
}

@Benchmark
public void writeComplexObject(Blackhole blackhole) {
try (JsonWriter writer = new JsonWriter()) {
writer
.beginObject()
.name("attrs")
.beginObject()
.name("attr1")
.value("value1")
.name("attr2")
.value("value2")
.endObject()
.name("data")
.beginArray()
.beginObject()
.name("x")
.value(1)
.name("y")
.value(12.3)
.endObject()
.beginObject()
.name("x")
.value(2)
.name("y")
.value(4.56)
.endObject()
.beginObject()
.name("x")
.value(3)
.name("y")
.value(789)
.endObject()
.endArray()
.endObject();
blackhole.consume(writer.toString());
}
}
}
34 changes: 15 additions & 19 deletions components/json/src/main/java/datadog/json/SafeJsonStructure.java
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
package datadog.json;

import static java.util.stream.Collectors.joining;

import java.util.ArrayDeque;
import java.util.Deque;
import java.util.BitSet;

/**
* This {@link JsonStructure} performs minimal structure checks to ensure the built JSON is
* coherent.
*/
class SafeJsonStructure implements JsonStructure {
private final Deque<Boolean> structure;
private final BitSet structure;
private int depth;
private boolean complete;

SafeJsonStructure() {
this.structure = new ArrayDeque<>();
this.structure = new BitSet();
this.depth = -1;
this.complete = false;
}

Expand All @@ -23,21 +22,21 @@ public void beginObject() {
if (this.complete) {
throw new IllegalStateException("Object is complete");
}
this.structure.add(true);
this.structure.set(++this.depth);
}

@Override
public boolean objectStarted() {
return !this.structure.isEmpty() && this.structure.peekLast();
return this.depth >= 0 && this.structure.get(this.depth);
}

@Override
public void endObject() {
if (!objectStarted()) {
throw new IllegalStateException("Object not started");
}
this.structure.removeLast();
if (this.structure.isEmpty()) {
this.depth--;
if (this.depth < 0) {
this.complete = true;
}
}
Expand All @@ -47,21 +46,21 @@ public void beginArray() {
if (this.complete) {
throw new IllegalStateException("Object is complete");
}
this.structure.offer(false);
this.structure.clear(++this.depth);
}

@Override
public boolean arrayStarted() {
return !this.structure.isEmpty() && !this.structure.peekLast();
return this.depth >= 0 && !this.structure.get(this.depth);
}

@Override
public void endArray() {
if (!arrayStarted()) {
throw new IllegalStateException("Array not started");
}
this.structure.removeLast();
if (this.structure.isEmpty()) {
this.depth--;
if (this.depth < 0) {
this.complete = true;
}
}
Expand All @@ -78,16 +77,13 @@ public void addValue() {
if (this.complete) {
throw new IllegalStateException("Object is complete");
}
if (this.structure.isEmpty()) {
if (this.depth < 0) {
this.complete = true;
}
}

@Override
public String toString() {
return (this.complete ? "complete" : "")
+ this.structure.stream()
.map(b -> b ? "object start" : "array start")
.collect(joining(","));
return (this.complete ? "complete" : "") + this.structure;
}
}

0 comments on commit 7c3d6e2

Please sign in to comment.