diff options
5 files changed, 329 insertions, 0 deletions
diff --git a/microbenchmark-template/README.md b/microbenchmark-template/README.md new file mode 100644 index 00000000000..8beaf58c640 --- /dev/null +++ b/microbenchmark-template/README.md @@ -0,0 +1 @@ +Template for quickly write micro-benchmarks with JMH diff --git a/microbenchmark-template/pom.xml b/microbenchmark-template/pom.xml new file mode 100644 index 00000000000..32659e1d664 --- /dev/null +++ b/microbenchmark-template/pom.xml @@ -0,0 +1,85 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.codehaus.sonar</groupId> + <artifactId>sonar</artifactId> + <version>5.1-SNAPSHOT</version> + </parent> + <artifactId>microbenchmark-template</artifactId> + <packaging>jar</packaging> + + <dependencies> + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>sonar-batch-protocol</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>com.esotericsoftware</groupId> + <artifactId>kryo-shaded</artifactId> + <version>3.0.0</version> + </dependency> + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>sonar-plugin-api</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>com.google.code.gson</groupId> + <artifactId>gson</artifactId> + </dependency> + <dependency> + <groupId>org.openjdk.jmh</groupId> + <artifactId>jmh-core</artifactId> + <version>${jmh.version}</version> + </dependency> + <dependency> + <groupId>org.openjdk.jmh</groupId> + <artifactId>jmh-generator-annprocess</artifactId> + <version>${jmh.version}</version> + <scope>provided</scope> + </dependency> + + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>sonar-testing-harness</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> + </dependencies> + + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + <jmh.version>1.1.1</jmh.version> + <uberjar.name>microbenchmark</uberjar.name> + </properties> + + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-shade-plugin</artifactId> + <version>2.2</version> + <executions> + <execution> + <phase>package</phase> + <goals> + <goal>shade</goal> + </goals> + <configuration> + <finalName>${uberjar.name}</finalName> + <transformers> + <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> + <mainClass>org.openjdk.jmh.Main</mainClass> + </transformer> + </transformers> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> + +</project> diff --git a/microbenchmark-template/run.sh b/microbenchmark-template/run.sh new file mode 100755 index 00000000000..10d0c60f6b3 --- /dev/null +++ b/microbenchmark-template/run.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +mvn clean install +java -jar target/microbenchmark.jar -i 5 -wi 5 -f 5 diff --git a/microbenchmark-template/src/main/java/org/sonar/microbenchmark/SerializationBenchmark.java b/microbenchmark-template/src/main/java/org/sonar/microbenchmark/SerializationBenchmark.java new file mode 100644 index 00000000000..c392d7cf841 --- /dev/null +++ b/microbenchmark-template/src/main/java/org/sonar/microbenchmark/SerializationBenchmark.java @@ -0,0 +1,162 @@ +/* + * markdown-benchmark + * Copyright (C) 2009 ${owner} + * dev@sonar.codehaus.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.microbenchmark; + +import com.esotericsoftware.kryo.Kryo; +import com.esotericsoftware.kryo.io.Output; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.stream.JsonWriter; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.sonar.batch.protocol.Constants; +import org.sonar.batch.protocol.output.BatchOutput; + +import java.io.BufferedOutputStream; +import java.io.BufferedWriter; +import java.io.Externalizable; +import java.io.File; +import java.io.FileOutputStream; +import java.io.FileWriter; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.io.ObjectOutputStream; +import java.io.OutputStream; +import java.io.Serializable; + +@State(Scope.Thread) +public class SerializationBenchmark { + + File outputFile; + private final Gson gson = new GsonBuilder().create(); + + @Setup + public void setup() throws Exception { + outputFile = File.createTempFile("microbenchmark", ".out"); + } + + @Benchmark + public void write_gson() throws Exception { + JsonWriter writer = new JsonWriter(new BufferedWriter(new FileWriter(outputFile, false))); + writer.beginArray(); + for (int i = 0; i < 10000; i++) { + Issue issue = new Issue(); + issue.uuid = "UUID_" + i; + issue.severity = "BLOCKER"; + issue.message = "this is the message of issue " + i; + issue.line = i; + issue.author = "someone"; + gson.toJson(issue, Issue.class, writer); + } + writer.endArray(); + writer.close(); + } + + @Benchmark + public void write_protobuf() throws Exception { + // Write stream of objects with delimiter + // An alternative can be http://stackoverflow.com/a/21870564/229031 + try (OutputStream out = new BufferedOutputStream(new FileOutputStream(outputFile, false))) { + for (int i = 0; i < 10000; i++) { + BatchOutput.ReportIssue.Builder issueBuilder = BatchOutput.ReportIssue.newBuilder(); + issueBuilder.setUuid("UUID_" + i); + issueBuilder.setSeverity(Constants.Severity.BLOCKER); + issueBuilder.setMsg("this is the message of issue " + i); + issueBuilder.setLine(i); + issueBuilder.setAuthorLogin("someone"); + issueBuilder.build().writeDelimitedTo(out); + } + } + } + + @Benchmark + public void write_serializable() throws Exception { + try (ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(outputFile, false)))) { + for (int i = 0; i < 10000; i++) { + Issue issue = new Issue(); + issue.uuid = "UUID_" + i; + issue.severity = "BLOCKER"; + issue.message = "this is the message of issue " + i; + issue.line = i; + issue.author = "someone"; + out.writeObject(issue); + } + } + } + + @Benchmark + public void write_externalizable() throws Exception { + try (ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(outputFile, false)))) { + for (int i = 0; i < 10000; i++) { + ExternalizableIssue issue = new ExternalizableIssue(); + issue.uuid = "UUID_" + i; + issue.severity = "BLOCKER"; + issue.message = "this is the message of issue " + i; + issue.line = i; + issue.author = "someone"; + out.writeObject(issue); + } + } + } + + @Benchmark + public void write_kryo() throws Exception { + Kryo kryo = new Kryo(); + OutputStream stream = new BufferedOutputStream(new FileOutputStream(outputFile, false)); + Output output = new Output(stream); + for (int i = 0; i < 10000; i++) { + Issue issue = new Issue(); + issue.uuid = "UUID_" + i; + issue.severity = "BLOCKER"; + issue.message = "this is the message of issue " + i; + issue.line = i; + issue.author = "someone"; + kryo.writeObject(output, issue); + } + output.close(); + } + + public static class Issue implements Serializable { + String uuid, severity, message, author; + int line; + } + + public static class ExternalizableIssue implements Externalizable { + String uuid, severity, message, author; + int line; + + @Override + public void writeExternal(ObjectOutput out) throws IOException { + out.writeObject(uuid); + out.writeObject(severity); + out.writeObject(message); + out.writeObject(author); + out.writeInt(line); + } + + @Override + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + throw new UnsupportedOperationException(); + } + } +} diff --git a/microbenchmark-template/src/test/java/org/sonar/microbenchmark/SerializationBenchmarkTest.java b/microbenchmark-template/src/test/java/org/sonar/microbenchmark/SerializationBenchmarkTest.java new file mode 100644 index 00000000000..11fd98223eb --- /dev/null +++ b/microbenchmark-template/src/test/java/org/sonar/microbenchmark/SerializationBenchmarkTest.java @@ -0,0 +1,77 @@ +package org.sonar.microbenchmark; + +import org.apache.commons.io.FileUtils; +import org.junit.Before; +import org.junit.Test; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.OutputStream; +import java.util.zip.Deflater; + +public class SerializationBenchmarkTest { + + SerializationBenchmark benchmark = new SerializationBenchmark(); + + @Before + public void setUp() throws Exception { + benchmark.setup(); + } + + @Test + public void size_of_gson_output() throws Exception { + benchmark.write_gson(); + System.out.println("GSON: " + sizeOf(benchmark.outputFile)); + System.out.println("GSON (zipped): " + sizeOf(zipFile(benchmark.outputFile))); + } + + @Test + public void size_of_protobuf_output() throws Exception { + benchmark.write_protobuf(); + System.out.println("Protocol Buffers: " + sizeOf(benchmark.outputFile)); + System.out.println("Protocol Buffers (zipped): " + sizeOf(zipFile(benchmark.outputFile))); + } + + @Test + public void size_of_serializable_output() throws Exception { + benchmark.write_serializable(); + System.out.println("java.io.Serializable: " + sizeOf(benchmark.outputFile)); + System.out.println("java.io.Serializable (zipped): " + sizeOf(zipFile(benchmark.outputFile))); + } + + @Test + public void size_of_externalizable_output() throws Exception { + benchmark.write_externalizable(); + System.out.println("java.io.Externalizable: " + sizeOf(benchmark.outputFile)); + System.out.println("java.io.Externalizable (zipped): " + sizeOf(zipFile(benchmark.outputFile))); + } + + @Test + public void size_of_kryo_output() throws Exception { + benchmark.write_kryo(); + System.out.println("Kryo: " + sizeOf(benchmark.outputFile)); + System.out.println("Kryo (zipped): " + sizeOf(zipFile(benchmark.outputFile))); + } + + private String sizeOf(File file) { + return FileUtils.byteCountToDisplaySize(FileUtils.sizeOf(file)); + } + + private File zipFile(File input) throws Exception { + File zipFile = new File(input.getAbsolutePath() + ".zip"); + Deflater deflater = new Deflater(); + byte[] content = FileUtils.readFileToByteArray(input); + deflater.setInput(content); + OutputStream outputStream = new FileOutputStream(zipFile); + deflater.finish(); + byte[] buffer = new byte[1024]; + while (!deflater.finished()) { + int count = deflater.deflate(buffer); // returns the generated code... index + outputStream.write(buffer, 0, count); + } + outputStream.close(); + deflater.end(); + + return zipFile; + } +} |