From bcb1d4aca2165e6ad9de2ce81344fa4ba5a03cfd Mon Sep 17 00:00:00 2001 From: William Hu <32604217+williamhu99@users.noreply.github.com> Date: Thu, 6 Aug 2020 20:02:41 -0700 Subject: [PATCH] Wrote benchmark tests for the zPages module (#1504) * Removed URLEncoder * Fixed typo * Added URLDecoding * Included comment for string replacement * Added unit tests for special characters in span names * Resolved URL decoding issues * Moved url decoding to parseQueryMap and updated the corresponding unit tests * Added a README file for zPage quickstart * Add images for README * Updated README * Add frontend images * Add backend images * Added our design doc * Added details on package * Reworded a few lines * Moved DESIGN.md to a docs folder and changed gradle config to implementation * Changed wording regarding HttpServer requirement * Added zpages folder under docs, resolved broken image links * Resolved comments for the design md file * Made a few wording changes * Wrote a benchmark test for TracezSpanBuckets (#23) * Scaffolded logic for basic benchmark tests * Wrote benchmark tests for TracezSpanBuckets * Updated README with benchmark tests * Changed the wording slightly * Updated README file (#25) * Wrote benchmark tests for TracezDataAggregator (#24) * Scaffolded logic for basic benchmark tests * Wrote benchmark tests for TracezSpanBuckets * Updated README with benchmark tests * Changed the wording slightly * Added a set of benchmark tests for TracezDataAggregator * Modified README formatting * Changed benchmark test to negate dead code elimination * Added Javadocs to the TracezDataAggregator benchmark tests * Removed benchmark results from README and added a param to the TracezDataAggregator benchmark tests * Update sdk_extensions/zpages/src/jmh/java/io/opentelemetry/sdk/extensions/zpages/TracezDataAggregatorBenchmark.java Co-authored-by: Anuraag Agrawal * Added multiple param values for TracezDataAggregatorBenchmark Co-authored-by: Terry Wang Co-authored-by: Anuraag Agrawal --- sdk_extensions/zpages/README.md | 17 +- sdk_extensions/zpages/build.gradle | 8 + .../zpages/TracezDataAggregatorBenchmark.java | 166 ++++++++++++++++++ .../zpages/TracezSpanBucketsBenchmark.java | 91 ++++++++++ 4 files changed, 279 insertions(+), 3 deletions(-) create mode 100644 sdk_extensions/zpages/src/jmh/java/io/opentelemetry/sdk/extensions/zpages/TracezDataAggregatorBenchmark.java create mode 100644 sdk_extensions/zpages/src/jmh/java/io/opentelemetry/sdk/extensions/zpages/TracezSpanBucketsBenchmark.java diff --git a/sdk_extensions/zpages/README.md b/sdk_extensions/zpages/README.md index b8069feb94b..8ed5f0100f6 100644 --- a/sdk_extensions/zpages/README.md +++ b/sdk_extensions/zpages/README.md @@ -1,8 +1,8 @@ -# OpenTelemetry SDK Contrib - zPages +# OpenTelemetry SDK Extension zPages [![Javadocs][javadoc-image]][javadoc-url] -This module contains code for OpenTelemetry's Java zPages, which are a collection of dynamic HTML +This module contains code for the OpenTelemetry Java zPages, which are a collection of dynamic HTML web pages that display stats and trace data. * Java 7 compatible. @@ -98,4 +98,15 @@ details. For example, here are the details of the `ChildSpan` latency sample (ro The /traceconfigz zPage displays information about the currently active tracing configuration and provides an interface for users to modify relevant parameters. Here is what the web page looks like: -![traceconfigz](img/traceconfigz.png) \ No newline at end of file +![traceconfigz](img/traceconfigz.png) + +## Benchmark Testing + +This module contains two sets of benchmark tests: one for adding spans to an instance of +TracezSpanBuckets and another for retrieving counts and spans with TracezDataAggregator. You can run +the tests yourself with the following commands: + +``` +./gradlew -PjmhIncludeSingleClass=TracezSpanBucketsBenchmark clean :opentelemetry-sdk-extension-zpages:jmh +./gradlew -PjmhIncludeSingleClass=TracezDataAggregatorBenchmark clean :opentelemetry-sdk-extension-zpages:jmh +``` diff --git a/sdk_extensions/zpages/build.gradle b/sdk_extensions/zpages/build.gradle index 03fa9264523..5322ba81bf8 100644 --- a/sdk_extensions/zpages/build.gradle +++ b/sdk_extensions/zpages/build.gradle @@ -2,6 +2,7 @@ plugins { id "java" id "maven-publish" + id "me.champeau.gradle.jmh" id "ru.vyarus.animalsniffer" } @@ -22,3 +23,10 @@ dependencies { signature "org.codehaus.mojo.signature:java17:1.0@signature" } + +animalsniffer { + // Don't check sourceSets.jmh and sourceSets.test + sourceSets = [ + sourceSets.main + ] +} diff --git a/sdk_extensions/zpages/src/jmh/java/io/opentelemetry/sdk/extensions/zpages/TracezDataAggregatorBenchmark.java b/sdk_extensions/zpages/src/jmh/java/io/opentelemetry/sdk/extensions/zpages/TracezDataAggregatorBenchmark.java new file mode 100644 index 00000000000..6e1dae95809 --- /dev/null +++ b/sdk_extensions/zpages/src/jmh/java/io/opentelemetry/sdk/extensions/zpages/TracezDataAggregatorBenchmark.java @@ -0,0 +1,166 @@ +/* + * Copyright 2020, OpenTelemetry Authors + * + * Licensed 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 io.opentelemetry.sdk.extensions.zpages; + +import io.opentelemetry.sdk.OpenTelemetrySdk; +import io.opentelemetry.trace.Span; +import io.opentelemetry.trace.Status; +import io.opentelemetry.trace.Tracer; +import java.util.concurrent.TimeUnit; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Threads; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; + +/** Benchmark class for {@link TracezDataAggregator}. */ +@State(Scope.Benchmark) +public class TracezDataAggregatorBenchmark { + + private static final String runningSpan = "RUNNING_SPAN"; + private static final String latencySpan = "LATENCY_SPAN"; + private static final String errorSpan = "ERROR_SPAN"; + private final Tracer tracer = + OpenTelemetrySdk.getTracerProvider().get("TracezDataAggregatorBenchmark"); + private final TracezSpanProcessor spanProcessor = TracezSpanProcessor.newBuilder().build(); + private final TracezDataAggregator dataAggregator = new TracezDataAggregator(spanProcessor); + + @Param({"1", "10", "1000", "1000000"}) + private int numberOfSpans; + + @Setup(Level.Trial) + public final void setup() { + for (int i = 0; i < numberOfSpans; i++) { + tracer.spanBuilder(runningSpan).startSpan(); + tracer.spanBuilder(latencySpan).startSpan().end(); + Span error = tracer.spanBuilder(errorSpan).startSpan(); + error.setStatus(Status.UNKNOWN); + error.end(); + } + } + + /** Get span counts with 1 thread. */ + @Benchmark + @Threads(value = 1) + @Fork(1) + @Warmup(iterations = 5, time = 1) + @Measurement(iterations = 10, time = 1) + @OutputTimeUnit(TimeUnit.MILLISECONDS) + public void getCounts_01Thread(Blackhole blackhole) { + blackhole.consume(dataAggregator.getRunningSpanCounts()); + blackhole.consume(dataAggregator.getSpanLatencyCounts()); + blackhole.consume(dataAggregator.getErrorSpanCounts()); + } + + /** Get span counts with 5 threads. */ + @Benchmark + @Threads(value = 5) + @Fork(1) + @Warmup(iterations = 5, time = 1) + @Measurement(iterations = 10, time = 1) + @OutputTimeUnit(TimeUnit.MILLISECONDS) + public void getCounts_05Threads(Blackhole blackhole) { + blackhole.consume(dataAggregator.getRunningSpanCounts()); + blackhole.consume(dataAggregator.getSpanLatencyCounts()); + blackhole.consume(dataAggregator.getErrorSpanCounts()); + } + + /** Get span counts with 10 threads. */ + @Benchmark + @Threads(value = 10) + @Fork(1) + @Warmup(iterations = 5, time = 1) + @Measurement(iterations = 10, time = 1) + @OutputTimeUnit(TimeUnit.MILLISECONDS) + public void getCounts_10Threads(Blackhole blackhole) { + blackhole.consume(dataAggregator.getRunningSpanCounts()); + blackhole.consume(dataAggregator.getSpanLatencyCounts()); + blackhole.consume(dataAggregator.getErrorSpanCounts()); + } + + /** Get span counts with 20 threads. */ + @Benchmark + @Threads(value = 20) + @Fork(1) + @Warmup(iterations = 5, time = 1) + @Measurement(iterations = 10, time = 1) + @OutputTimeUnit(TimeUnit.MILLISECONDS) + public void getCounts_20Threads(Blackhole blackhole) { + blackhole.consume(dataAggregator.getRunningSpanCounts()); + blackhole.consume(dataAggregator.getSpanLatencyCounts()); + blackhole.consume(dataAggregator.getErrorSpanCounts()); + } + + /** Get spans with 1 thread. */ + @Benchmark + @Threads(value = 1) + @Fork(1) + @Warmup(iterations = 5, time = 1) + @Measurement(iterations = 10, time = 1) + @OutputTimeUnit(TimeUnit.MILLISECONDS) + public void getSpans_01Thread(Blackhole blackhole) { + blackhole.consume(dataAggregator.getRunningSpans(runningSpan)); + blackhole.consume(dataAggregator.getOkSpans(latencySpan, 0, Long.MAX_VALUE)); + blackhole.consume(dataAggregator.getErrorSpans(errorSpan)); + } + + /** Get spans with 5 threads. */ + @Benchmark + @Threads(value = 5) + @Fork(1) + @Warmup(iterations = 5, time = 1) + @Measurement(iterations = 10, time = 1) + @OutputTimeUnit(TimeUnit.MILLISECONDS) + public void getSpans_05Threads(Blackhole blackhole) { + blackhole.consume(dataAggregator.getRunningSpans(runningSpan)); + blackhole.consume(dataAggregator.getOkSpans(latencySpan, 0, Long.MAX_VALUE)); + blackhole.consume(dataAggregator.getErrorSpans(errorSpan)); + } + + /** Get spans with 10 threads. */ + @Benchmark + @Threads(value = 10) + @Fork(1) + @Warmup(iterations = 5, time = 1) + @Measurement(iterations = 10, time = 1) + @OutputTimeUnit(TimeUnit.MILLISECONDS) + public void getSpans_10Threads(Blackhole blackhole) { + blackhole.consume(dataAggregator.getRunningSpans(runningSpan)); + blackhole.consume(dataAggregator.getOkSpans(latencySpan, 0, Long.MAX_VALUE)); + blackhole.consume(dataAggregator.getErrorSpans(errorSpan)); + } + + /** Get spans with 20 threads. */ + @Benchmark + @Threads(value = 20) + @Fork(1) + @Warmup(iterations = 5, time = 1) + @Measurement(iterations = 10, time = 1) + @OutputTimeUnit(TimeUnit.MILLISECONDS) + public void getSpans_20Threads(Blackhole blackhole) { + blackhole.consume(dataAggregator.getRunningSpans(runningSpan)); + blackhole.consume(dataAggregator.getOkSpans(latencySpan, 0, Long.MAX_VALUE)); + blackhole.consume(dataAggregator.getErrorSpans(errorSpan)); + } +} diff --git a/sdk_extensions/zpages/src/jmh/java/io/opentelemetry/sdk/extensions/zpages/TracezSpanBucketsBenchmark.java b/sdk_extensions/zpages/src/jmh/java/io/opentelemetry/sdk/extensions/zpages/TracezSpanBucketsBenchmark.java new file mode 100644 index 00000000000..da44734c197 --- /dev/null +++ b/sdk_extensions/zpages/src/jmh/java/io/opentelemetry/sdk/extensions/zpages/TracezSpanBucketsBenchmark.java @@ -0,0 +1,91 @@ +/* + * Copyright 2020, OpenTelemetry Authors + * + * Licensed 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 io.opentelemetry.sdk.extensions.zpages; + +import io.opentelemetry.sdk.OpenTelemetrySdk; +import io.opentelemetry.sdk.trace.ReadableSpan; +import io.opentelemetry.trace.Span; +import io.opentelemetry.trace.Tracer; +import java.util.concurrent.TimeUnit; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Threads; +import org.openjdk.jmh.annotations.Warmup; + +/** Benchmark class for {@link TracezSpanBuckets}. */ +@State(Scope.Benchmark) +public class TracezSpanBucketsBenchmark { + + private static final String spanName = "BENCHMARK_SPAN"; + private static ReadableSpan readableSpan; + private TracezSpanBuckets bucket; + + @Setup(Level.Trial) + public final void setup() { + bucket = new TracezSpanBuckets(); + Tracer tracer = OpenTelemetrySdk.getTracerProvider().get("TracezZPageBenchmark"); + Span span = tracer.spanBuilder(spanName).startSpan(); + span.end(); + readableSpan = (ReadableSpan) span; + } + + @Benchmark + @Threads(value = 1) + @Fork(1) + @Warmup(iterations = 5, time = 1) + @Measurement(iterations = 10, time = 1) + @OutputTimeUnit(TimeUnit.MILLISECONDS) + public void addToBucket_01Thread() { + bucket.addToBucket(readableSpan); + } + + @Benchmark + @Threads(value = 5) + @Fork(1) + @Warmup(iterations = 5, time = 1) + @Measurement(iterations = 10, time = 1) + @OutputTimeUnit(TimeUnit.MILLISECONDS) + public void addToBucket_05Threads() { + bucket.addToBucket(readableSpan); + } + + @Benchmark + @Threads(value = 10) + @Fork(1) + @Warmup(iterations = 5, time = 1) + @Measurement(iterations = 10, time = 1) + @OutputTimeUnit(TimeUnit.MILLISECONDS) + public void addToBucket_10Threads() { + bucket.addToBucket(readableSpan); + } + + @Benchmark + @Threads(value = 20) + @Fork(1) + @Warmup(iterations = 5, time = 1) + @Measurement(iterations = 10, time = 1) + @OutputTimeUnit(TimeUnit.MILLISECONDS) + public void addToBucket_20Threads() { + bucket.addToBucket(readableSpan); + } +}