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();
+    }
   }
 }