You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@zipkin.apache.org by an...@apache.org on 2019/05/15 09:40:57 UTC
[incubator-zipkin] branch master updated: Add benchmark of jackson
span decoder. (#2592)
This is an automated email from the ASF dual-hosted git repository.
anuraaga pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-zipkin.git
The following commit(s) were added to refs/heads/master by this push:
new 41225ba Add benchmark of jackson span decoder. (#2592)
41225ba is described below
commit 41225ba98a1f9dfe8d64cf12b76c00500dbf70d4
Author: Anuraag Agrawal <an...@gmail.com>
AuthorDate: Wed May 15 18:40:50 2019 +0900
Add benchmark of jackson span decoder. (#2592)
* Add benchmark of jackson span decoder.
* Header
---
.../java/zipkin2/codec/JacksonSpanDecoder.java | 243 +++++++++++++++++++++
.../java/zipkin2/codec/JsonCodecBenchmarks.java | 10 +-
...ecoderTest.java => JacksonSpanDecoderTest.java} | 30 ++-
.../java/zipkin2/codec/MoshiSpanDecoderTest.java | 8 +-
4 files changed, 284 insertions(+), 7 deletions(-)
diff --git a/benchmarks/src/main/java/zipkin2/codec/JacksonSpanDecoder.java b/benchmarks/src/main/java/zipkin2/codec/JacksonSpanDecoder.java
new file mode 100644
index 0000000..7f55e21
--- /dev/null
+++ b/benchmarks/src/main/java/zipkin2/codec/JacksonSpanDecoder.java
@@ -0,0 +1,243 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package zipkin2.codec;
+
+import com.fasterxml.jackson.core.JsonFactory;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonToken;
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+import zipkin2.Annotation;
+import zipkin2.Endpoint;
+import zipkin2.Span;
+import zipkin2.internal.ReadBuffer;
+
+public final class JacksonSpanDecoder {
+
+ static final JsonFactory JSON_FACTORY = new JsonFactory();
+
+ public static List<Span> decodeList(byte[] spans) {
+ try {
+ return decodeList(JSON_FACTORY.createParser(spans));
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+
+ public static List<Span> decodeList(ByteBuffer spans) {
+ try {
+ return decodeList(JSON_FACTORY.createParser(ReadBuffer.wrapUnsafe(spans)));
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+
+ public static Span decodeOne(byte[] span) {
+ try {
+ return decodeOne(JSON_FACTORY.createParser(span));
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+
+ public static Span decodeOne(ByteBuffer span) {
+ try {
+ return decodeOne(JSON_FACTORY.createParser(ReadBuffer.wrapUnsafe(span)));
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+
+ static List<Span> decodeList(JsonParser jsonParser) {
+ List<Span> out = new ArrayList<>();
+
+ try {
+ if (jsonParser.nextToken() != JsonToken.START_ARRAY) {
+ throw new IOException("Not a valid JSON array, start token: " + jsonParser.currentToken());
+ }
+
+ while (jsonParser.nextToken() != JsonToken.END_ARRAY) {
+ out.add(parseSpan(jsonParser));
+ }
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+
+ return out;
+ }
+
+ static Span decodeOne(JsonParser jsonParser) {
+ try {
+ if (!jsonParser.hasCurrentToken()) {
+ jsonParser.nextToken();
+ }
+ return parseSpan(jsonParser);
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+
+ static Span parseSpan(JsonParser jsonParser) throws IOException {
+ if (!jsonParser.isExpectedStartObjectToken()) {
+ throw new IOException("Not a valid JSON object, start token: " +
+ jsonParser.currentToken());
+ }
+
+ Span.Builder result = Span.newBuilder();
+
+ while (jsonParser.nextToken() != JsonToken.END_OBJECT) {
+ String fieldName = jsonParser.currentName();
+ JsonToken value = jsonParser.nextToken();
+ if (value == JsonToken.VALUE_NULL) {
+ continue;
+ }
+ switch (fieldName) {
+ case "traceId":
+ result.traceId(jsonParser.getValueAsString());
+ break;
+ case "parentId":
+ result.parentId(jsonParser.getValueAsString());
+ break;
+ case "id":
+ result.id(jsonParser.getValueAsString());
+ break;
+ case "kind":
+ result.kind(Span.Kind.valueOf(jsonParser.getValueAsString()));
+ break;
+ case "name":
+ result.name(jsonParser.getValueAsString());
+ break;
+ case "timestamp":
+ result.timestamp(jsonParser.getValueAsLong());
+ break;
+ case "duration":
+ result.duration(jsonParser.getValueAsLong());
+ break;
+ case "localEndpoint":
+ result.localEndpoint(parseEndpoint(jsonParser));
+ break;
+ case "remoteEndpoint":
+ result.remoteEndpoint(parseEndpoint(jsonParser));
+ break;
+ case "annotations":
+ if (!jsonParser.isExpectedStartArrayToken()) {
+ throw new IOException("Invalid span, expecting annotations array start, got: " +
+ value);
+ }
+ while (jsonParser.nextToken() != JsonToken.END_ARRAY) {
+ Annotation a = parseAnnotation(jsonParser);
+ result.addAnnotation(a.timestamp(), a.value());
+ }
+ break;
+ case "tags":
+ if (value != JsonToken.START_OBJECT) {
+ throw new IOException("Invalid span, expecting tags object, got: " + value);
+ }
+ while (jsonParser.nextToken() != JsonToken.END_OBJECT) {
+ result.putTag(jsonParser.currentName(), jsonParser.nextTextValue());
+ }
+ break;
+ case "debug":
+ result.debug(jsonParser.getBooleanValue());
+ break;
+ case "shared":
+ result.shared(jsonParser.getBooleanValue());
+ break;
+ default:
+ jsonParser.skipChildren();
+ }
+ }
+
+ return result.build();
+ }
+
+ static Endpoint parseEndpoint(JsonParser jsonParser) throws IOException {
+ if (!jsonParser.isExpectedStartObjectToken()) {
+ throw new IOException("Not a valid JSON object, start token: " +
+ jsonParser.currentToken());
+ }
+
+ String serviceName = null, ipv4 = null, ipv6 = null;
+ int port = 0;
+
+ while (jsonParser.nextToken() != JsonToken.END_OBJECT) {
+ String fieldName = jsonParser.currentName();
+ JsonToken value = jsonParser.nextToken();
+ if (value == JsonToken.VALUE_NULL) {
+ continue;
+ }
+
+ switch (fieldName) {
+ case "serviceName":
+ serviceName = jsonParser.getValueAsString();
+ break;
+ case "ipv4":
+ ipv4 = jsonParser.getValueAsString();
+ break;
+ case "ipv6":
+ ipv6 = jsonParser.getValueAsString();
+ break;
+ case "port":
+ port = jsonParser.getValueAsInt();
+ break;
+ default:
+ jsonParser.skipChildren();
+ }
+ }
+
+ if (serviceName == null && ipv4 == null && ipv6 == null && port == 0) return null;
+ return Endpoint.newBuilder()
+ .serviceName(serviceName)
+ .ip(ipv4)
+ .ip(ipv6)
+ .port(port)
+ .build();
+ }
+
+ static Annotation parseAnnotation(JsonParser jsonParser) throws IOException {
+ if (!jsonParser.isExpectedStartObjectToken()) {
+ throw new IOException("Not a valid JSON object, start token: " +
+ jsonParser.currentToken());
+ }
+
+ long timestamp = 0;
+ String value = null;
+
+ while (jsonParser.nextToken() != JsonToken.END_OBJECT) {
+ String fieldName = jsonParser.currentName();
+
+ switch (fieldName) {
+ case "timestamp":
+ timestamp = jsonParser.getValueAsLong();
+ break;
+ case "value":
+ value = jsonParser.getValueAsString();
+ break;
+ default:
+ jsonParser.skipChildren();
+ }
+ }
+
+ if (timestamp == 0 || value == null) {
+ throw new IllegalStateException("Incomplete annotation at " + jsonParser.currentToken());
+ }
+ return Annotation.create(timestamp, value);
+ }
+}
diff --git a/benchmarks/src/main/java/zipkin2/codec/JsonCodecBenchmarks.java b/benchmarks/src/main/java/zipkin2/codec/JsonCodecBenchmarks.java
index abe5cbd..d68c3e8 100644
--- a/benchmarks/src/main/java/zipkin2/codec/JsonCodecBenchmarks.java
+++ b/benchmarks/src/main/java/zipkin2/codec/JsonCodecBenchmarks.java
@@ -68,6 +68,10 @@ public class JsonCodecBenchmarks {
encodedBuf.release();
}
+ @Benchmark public List<Span> bytes_jacksonDecoder() {
+ return JacksonSpanDecoder.decodeList(encodedBytes);
+ }
+
@Benchmark public List<Span> bytes_moshiDecoder() {
return MOSHI.decodeList(encodedBytes);
}
@@ -76,6 +80,10 @@ public class JsonCodecBenchmarks {
return SpanBytesDecoder.JSON_V2.decodeList(encodedBytes);
}
+ @Benchmark public List<Span> bytebuffer_jacksonDecoder() {
+ return JacksonSpanDecoder.decodeList(encodedBuf.nioBuffer());
+ }
+
@Benchmark public List<Span> bytebuffer_moshiDecoder() {
return MOSHI.decodeList(encodedBuf.nioBuffer());
}
@@ -87,7 +95,7 @@ public class JsonCodecBenchmarks {
// Convenience main entry-point
public static void main(String[] args) throws Exception {
Options opt = new OptionsBuilder()
- .include(".*" + JsonCodecBenchmarks.class.getSimpleName())
+ .include(".*" + JsonCodecBenchmarks.class.getSimpleName() + ".*")
.addProfiler("gc")
.build();
diff --git a/benchmarks/src/test/java/zipkin2/codec/MoshiSpanDecoderTest.java b/benchmarks/src/test/java/zipkin2/codec/JacksonSpanDecoderTest.java
similarity index 61%
copy from benchmarks/src/test/java/zipkin2/codec/MoshiSpanDecoderTest.java
copy to benchmarks/src/test/java/zipkin2/codec/JacksonSpanDecoderTest.java
index 7e61f8e..dab51a7 100644
--- a/benchmarks/src/test/java/zipkin2/codec/MoshiSpanDecoderTest.java
+++ b/benchmarks/src/test/java/zipkin2/codec/JacksonSpanDecoderTest.java
@@ -21,20 +21,42 @@ import io.netty.buffer.PooledByteBufAllocator;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
+import static zipkin2.TestObjects.CLIENT_SPAN;
import static zipkin2.TestObjects.TRACE;
-public class MoshiSpanDecoderTest {
+public class JacksonSpanDecoderTest {
byte[] encoded = SpanBytesEncoder.JSON_V2.encodeList(TRACE);
+ byte[] encodedSpan = SpanBytesEncoder.JSON_V2.encode(CLIENT_SPAN);
@Test public void decodeList_bytes() {
- assertThat(new MoshiSpanDecoder().decodeList(encoded))
+ assertThat(JacksonSpanDecoder.decodeList(encoded))
.isEqualTo(TRACE);
}
@Test public void decodeList_byteBuffer() {
ByteBuf encodedBuf = PooledByteBufAllocator.DEFAULT.buffer(encoded.length);
encodedBuf.writeBytes(encoded);
- assertThat(new MoshiSpanDecoder().decodeList(encoded))
- .isEqualTo(TRACE);
+ try {
+ assertThat(JacksonSpanDecoder.decodeList(encodedBuf.nioBuffer()))
+ .isEqualTo(TRACE);
+ } finally {
+ encodedBuf.release();
+ }
+ }
+
+ @Test public void decodeOne() {
+ assertThat(JacksonSpanDecoder.decodeOne(encodedSpan))
+ .isEqualTo(CLIENT_SPAN);
+ }
+
+ @Test public void decodeOne_byteBuffer() {
+ ByteBuf encodedBuf = PooledByteBufAllocator.DEFAULT.buffer(encodedSpan.length);
+ encodedBuf.writeBytes(encodedSpan);
+ try {
+ assertThat(JacksonSpanDecoder.decodeOne(encodedBuf.nioBuffer()))
+ .isEqualTo(CLIENT_SPAN);
+ } finally {
+ encodedBuf.release();
+ }
}
}
diff --git a/benchmarks/src/test/java/zipkin2/codec/MoshiSpanDecoderTest.java b/benchmarks/src/test/java/zipkin2/codec/MoshiSpanDecoderTest.java
index 7e61f8e..62bee5f 100644
--- a/benchmarks/src/test/java/zipkin2/codec/MoshiSpanDecoderTest.java
+++ b/benchmarks/src/test/java/zipkin2/codec/MoshiSpanDecoderTest.java
@@ -34,7 +34,11 @@ public class MoshiSpanDecoderTest {
@Test public void decodeList_byteBuffer() {
ByteBuf encodedBuf = PooledByteBufAllocator.DEFAULT.buffer(encoded.length);
encodedBuf.writeBytes(encoded);
- assertThat(new MoshiSpanDecoder().decodeList(encoded))
- .isEqualTo(TRACE);
+ try {
+ assertThat(new MoshiSpanDecoder().decodeList(encodedBuf.nioBuffer()))
+ .isEqualTo(TRACE);
+ } finally {
+ encodedBuf.release();
+ }
}
}