Jetty-based benchmark for memory usage
MODIFY
benchmark/benchmark.gradle
benchmark/benchmark.gradle
@@ -7,6 +7,11 @@ apply from: "${rootDir}/gradle/java.gradle"
dependencies {
jmh group: 'io.opentelemetry', name: 'opentelemetry-api', version: '0.3.0'
jmh deps.bytebuddyagent
+
+ jmh 'javax.servlet:javax.servlet-api:4.0.1'
+ jmh 'com.google.http-client:google-http-client:1.19.0'
+ jmh 'org.eclipse.jetty:jetty-server:9.4.1.v20170120'
+ jmh 'org.eclipse.jetty:jetty-servlet:9.4.1.v20170120'
}
jmh {
@@ -25,6 +30,7 @@ jmh {
// profilers = ['stack:lines=5;detailLine=true;period=5;excludePackages=true']
// Use profilers to collect additional data. Supported profilers: [cl, comp, gc, stack, perf, perfnorm, perfasm, xperf, xperfasm, hs_cl, hs_comp, hs_gc, hs_rt, hs_thr]
+ profilers = ['io.opentelemetry.benchmark.UsedMemoryProfiler', 'gc']
// humanOutputFile = project.file("${project.buildDir}/reports/jmh/human.txt") // human-readable output file
// operationsPerInvocation = 10 // Operations per invocation.

ADD
benchmark/src/jmh/java/io/opentelemetry/benchmark/HttpBenchmark.java
+/*
+ * Copyright The 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.benchmark;
+
+import io.opentelemetry.benchmark.classes.HttpClass;
+import java.io.IOException;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.util.component.AbstractLifeCycle;
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.Fork;
+import org.openjdk.jmh.annotations.Level;
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.Setup;
+import org.openjdk.jmh.annotations.State;
+import org.openjdk.jmh.annotations.TearDown;
+
+public class HttpBenchmark {
+
+ @State(Scope.Benchmark)
+ public static class BenchmarkState {
+ @Setup(Level.Trial)
+ public void doSetup() {
+ try {
+ jettyServer = new HttpClass().buildJettyServer();
+ jettyServer.start();
+ // Make sure it's actually running
+ while (!AbstractLifeCycle.STARTED.equals(jettyServer.getState())) {
+ Thread.sleep(500);
+ }
+ } catch (final Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @TearDown(Level.Trial)
+ public void doTearDown() {
+ try {
+ jettyServer.stop();
+ } catch (final Exception e) {
+ e.printStackTrace();
+ } finally {
+ jettyServer.destroy();
+ }
+ }
+
+ HttpClass http = new HttpClass();
+ Server jettyServer;
+ }
+
+ @Benchmark
+ public void testMakingRequest(final BenchmarkState state) throws IOException {
+ state.http.executeRequest();
+ }
+
+ @Fork(
+ jvmArgsAppend = {
+ "-javaagent:/path/to/opentelemetry-auto-instr-java/java-agent/build/libs/opentelemetry-auto.jar",
+ "-Dota.exporter.jar=/path/to/opentelemetry-auto-instr-java/auto-exporters/logging/build/libs/opentelemetry-auto-exporters-logging-or-other-exporter.jar"
+ })
+ public static class WithAgent extends ClassRetransformingBenchmark {}
+}

ADD
benchmark/src/jmh/java/io/opentelemetry/benchmark/UsedMemoryProfiler.java
+/*
+ * Copyright The 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.benchmark;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import org.openjdk.jmh.infra.BenchmarkParams;
+import org.openjdk.jmh.infra.IterationParams;
+import org.openjdk.jmh.profile.InternalProfiler;
+import org.openjdk.jmh.results.AggregationPolicy;
+import org.openjdk.jmh.results.IterationResult;
+import org.openjdk.jmh.results.Result;
+import org.openjdk.jmh.results.ScalarResult;
+
+public class UsedMemoryProfiler implements InternalProfiler {
+ private long totalHeapBefore;
+ private long usedHeapBefore;
+
+ @Override
+ public String getDescription() {
+ return "Used memory heap profiler";
+ }
+
+ @Override
+ public void beforeIteration(
+ final BenchmarkParams benchmarkParams, final IterationParams iterationParams) {
+ System.gc();
+ System.runFinalization();
+
+ totalHeapBefore = Runtime.getRuntime().totalMemory();
+ usedHeapBefore = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
+ }
+
+ @Override
+ public Collection<? extends Result> afterIteration(
+ final BenchmarkParams benchmarkParams,
+ final IterationParams iterationParams,
+ final IterationResult result) {
+
+ final long totalHeap = Runtime.getRuntime().totalMemory();
+ final long usedHeap = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
+
+ final Collection<ScalarResult> results = new ArrayList<>();
+ results.add(
+ new ScalarResult("heap.total.before", totalHeapBefore, "bytes", AggregationPolicy.AVG));
+ results.add(
+ new ScalarResult("heap.used.before", usedHeapBefore, "bytes", AggregationPolicy.AVG));
+ results.add(new ScalarResult("heap.total.after", totalHeap, "bytes", AggregationPolicy.AVG));
+ results.add(new ScalarResult("heap.used.after", usedHeap, "bytes", AggregationPolicy.AVG));
+
+ return results;
+ }
+}

ADD
benchmark/src/jmh/java/io/opentelemetry/benchmark/classes/HttpClass.java
+/*
+ * Copyright The 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.benchmark.classes;
+
+import com.google.api.client.http.GenericUrl;
+import com.google.api.client.http.HttpRequest;
+import com.google.api.client.http.HttpRequestFactory;
+import com.google.api.client.http.javanet.NetHttpTransport;
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import javax.servlet.ServletException;
+import javax.servlet.annotation.WebServlet;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.servlet.ServletContextHandler;
+
+public class HttpClass {
+ private String contextPath = "/path";
+ private Integer port = 18888;
+
+ public Server buildJettyServer() {
+ System.setProperty("org.eclipse.jetty.util.log.class", "org.eclipse.jetty.util.log.StdErrLog");
+ System.setProperty("org.eclipse.jetty.LEVEL", "WARN");
+
+ Server jettyServer = new Server(new InetSocketAddress("localhost", port));
+ ServletContextHandler servletContext = new ServletContextHandler();
+
+ servletContext.addServlet(HttpClassServlet.class, contextPath);
+ jettyServer.setHandler(servletContext);
+ return jettyServer;
+ }
+
+ @WebServlet
+ public static class HttpClassServlet extends HttpServlet {
+ @Override
+ protected void doGet(final HttpServletRequest req, final HttpServletResponse resp)
+ throws ServletException, IOException {
+ try {
+ Thread.sleep(10);
+ } catch (Exception e) {
+ }
+ resp.setContentType("application/json");
+ resp.setStatus(HttpServletResponse.SC_OK);
+ resp.getWriter().println("{ \"status\": \"ok\"}");
+ }
+ }
+
+ private HttpRequestFactory requestFactory = new NetHttpTransport().createRequestFactory();
+
+ public void executeRequest() throws IOException {
+ String url = "http://localhost:" + port + contextPath;
+
+ HttpRequest request = requestFactory.buildGetRequest(new GenericUrl(url));
+ request.setThrowExceptionOnExecuteError(false);
+ request.execute();
+ }
+}

Jetty-based benchmark for memory usage (#329)