parent
9021f623e1
commit
5e732e35c1
9 changed files with 554 additions and 335 deletions
@ -1,3 +1,4 @@ |
||||
[submodule "third_party/benchmark"] |
||||
path = third_party/benchmark |
||||
url = https://github.com/google/benchmark.git |
||||
|
||||
|
@ -1,319 +0,0 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2009 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protocolbuffers; |
||||
|
||||
import com.google.protobuf.ByteString; |
||||
import com.google.protobuf.CodedInputStream; |
||||
import com.google.protobuf.CodedOutputStream; |
||||
import com.google.protobuf.ExtensionRegistry; |
||||
import com.google.protobuf.Message; |
||||
import com.google.protobuf.benchmarks.Benchmarks.BenchmarkDataset; |
||||
import java.io.ByteArrayInputStream; |
||||
import java.io.ByteArrayOutputStream; |
||||
import java.io.File; |
||||
import java.io.FileNotFoundException; |
||||
import java.io.FileOutputStream; |
||||
import java.io.IOException; |
||||
import java.io.RandomAccessFile; |
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
|
||||
public class ProtoBench { |
||||
|
||||
private static final long MIN_SAMPLE_TIME_MS = 1 * 1000; |
||||
private static final long TARGET_TIME_MS = 5 * 1000; |
||||
|
||||
private ProtoBench() { |
||||
// Prevent instantiation
|
||||
} |
||||
|
||||
public static void main(String[] args) { |
||||
if (args.length < 1) { |
||||
System.err.println("Usage: ./java-benchmark <input data>"); |
||||
System.err.println("input data is in the format of \"benchmarks.proto\""); |
||||
System.exit(1); |
||||
} |
||||
boolean success = true; |
||||
for (int i = 0; i < args.length; i++) { |
||||
success &= runTest(args[i]); |
||||
} |
||||
System.exit(success ? 0 : 1); |
||||
} |
||||
|
||||
public static ExtensionRegistry getExtensionsRegistry(BenchmarkDataset benchmarkDataset) { |
||||
ExtensionRegistry extensions = ExtensionRegistry.newInstance(); |
||||
if (benchmarkDataset.getMessageName().equals("benchmarks.google_message3.GoogleMessage3")) { |
||||
benchmarks.google_message3.BenchmarkMessage38.registerAllExtensions(extensions); |
||||
benchmarks.google_message3.BenchmarkMessage37.registerAllExtensions(extensions); |
||||
benchmarks.google_message3.BenchmarkMessage36.registerAllExtensions(extensions); |
||||
benchmarks.google_message3.BenchmarkMessage35.registerAllExtensions(extensions); |
||||
benchmarks.google_message3.BenchmarkMessage34.registerAllExtensions(extensions); |
||||
benchmarks.google_message3.BenchmarkMessage33.registerAllExtensions(extensions); |
||||
benchmarks.google_message3.BenchmarkMessage32.registerAllExtensions(extensions); |
||||
benchmarks.google_message3.BenchmarkMessage31.registerAllExtensions(extensions); |
||||
benchmarks.google_message3.BenchmarkMessage3.registerAllExtensions(extensions); |
||||
} else if (benchmarkDataset.getMessageName().equals( |
||||
"benchmarks.google_message4.GoogleMessage4")) { |
||||
benchmarks.google_message4.BenchmarkMessage43.registerAllExtensions(extensions); |
||||
benchmarks.google_message4.BenchmarkMessage42.registerAllExtensions(extensions); |
||||
benchmarks.google_message4.BenchmarkMessage41.registerAllExtensions(extensions); |
||||
benchmarks.google_message4.BenchmarkMessage4.registerAllExtensions(extensions); |
||||
} |
||||
|
||||
return extensions; |
||||
} |
||||
|
||||
/** |
||||
* Return an message instance for one specific dataset, and register the extensions for that |
||||
* message. |
||||
*/ |
||||
public static Message registerBenchmarks(BenchmarkDataset benchmarkDataset) { |
||||
if (benchmarkDataset.getMessageName().equals("benchmarks.proto3.GoogleMessage1")) { |
||||
return com.google.protobuf.benchmarks.BenchmarkMessage1Proto3.GoogleMessage1 |
||||
.getDefaultInstance(); |
||||
} else if (benchmarkDataset.getMessageName().equals("benchmarks.proto2.GoogleMessage1")) { |
||||
return com.google.protobuf.benchmarks.BenchmarkMessage1Proto2.GoogleMessage1 |
||||
.getDefaultInstance(); |
||||
} else if (benchmarkDataset.getMessageName().equals("benchmarks.proto2.GoogleMessage2")) { |
||||
return com.google.protobuf.benchmarks.BenchmarkMessage2.GoogleMessage2.getDefaultInstance(); |
||||
} else if (benchmarkDataset.getMessageName(). |
||||
equals("benchmarks.google_message3.GoogleMessage3")) { |
||||
return benchmarks.google_message3.BenchmarkMessage3.GoogleMessage3.getDefaultInstance(); |
||||
} else if (benchmarkDataset.getMessageName(). |
||||
equals("benchmarks.google_message4.GoogleMessage4")) { |
||||
return benchmarks.google_message4.BenchmarkMessage4.GoogleMessage4.getDefaultInstance(); |
||||
} else { |
||||
return null; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Runs a single test. Error messages are displayed to stderr, and the return value indicates |
||||
* general success/failure. |
||||
*/ |
||||
public static boolean runTest(String file) { |
||||
final Message defaultMessage; |
||||
BenchmarkDataset benchmarkDataset; |
||||
ExtensionRegistry extensions; |
||||
final byte[] inputData; |
||||
|
||||
try { |
||||
inputData = readAllBytes(file); |
||||
benchmarkDataset = BenchmarkDataset.parseFrom(inputData); |
||||
} catch (IOException e) { |
||||
System.err.println("Unable to get input data"); |
||||
return false; |
||||
} |
||||
defaultMessage = registerBenchmarks(benchmarkDataset); |
||||
extensions = getExtensionsRegistry(benchmarkDataset); |
||||
if (defaultMessage == null) { |
||||
System.err.println("Unable to get default message " + benchmarkDataset.getMessageName()); |
||||
return false; |
||||
} |
||||
System.out.println("Benchmarking " + benchmarkDataset.getMessageName() + " with file " + file); |
||||
|
||||
try { |
||||
List<byte[]> inputDataList = new ArrayList<byte[]>(); |
||||
List<ByteArrayInputStream> inputStreamList = new ArrayList<ByteArrayInputStream>(); |
||||
List<ByteString> inputStringList = new ArrayList<ByteString>(); |
||||
List<Message> sampleMessageList = new ArrayList<Message>(); |
||||
|
||||
for (int i = 0; i < benchmarkDataset.getPayloadCount(); i++) { |
||||
byte[] singleInputData = benchmarkDataset.getPayload(i).toByteArray(); |
||||
inputDataList.add(benchmarkDataset.getPayload(i).toByteArray()); |
||||
inputStreamList.add(new ByteArrayInputStream(benchmarkDataset.getPayload(i).toByteArray())); |
||||
inputStringList.add(benchmarkDataset.getPayload(i)); |
||||
sampleMessageList.add( |
||||
defaultMessage.newBuilderForType().mergeFrom(singleInputData, extensions).build()); |
||||
} |
||||
|
||||
FileOutputStream devNullTemp = null; |
||||
CodedOutputStream reuseDevNullTemp = null; |
||||
try { |
||||
devNullTemp = new FileOutputStream("/dev/null"); |
||||
reuseDevNullTemp = CodedOutputStream.newInstance(devNullTemp); |
||||
} catch (FileNotFoundException e) { |
||||
// ignore: this is probably Windows, where /dev/null does not exist
|
||||
} |
||||
final FileOutputStream devNull = devNullTemp; |
||||
final CodedOutputStream reuseDevNull = reuseDevNullTemp; |
||||
benchmark( |
||||
"Serialize to byte string", |
||||
inputData.length, |
||||
new Action() { |
||||
public void execute() { |
||||
for (int i = 0; i < sampleMessageList.size(); i++) { |
||||
sampleMessageList.get(i).toByteString(); |
||||
} |
||||
} |
||||
}); |
||||
benchmark( |
||||
"Serialize to byte array", |
||||
inputData.length, |
||||
new Action() { |
||||
public void execute() { |
||||
for (int i = 0; i < sampleMessageList.size(); i++) { |
||||
sampleMessageList.get(i).toByteString(); |
||||
} |
||||
} |
||||
}); |
||||
benchmark( |
||||
"Serialize to memory stream", |
||||
inputData.length, |
||||
new Action() { |
||||
public void execute() throws IOException { |
||||
ByteArrayOutputStream output = new ByteArrayOutputStream(); |
||||
for (int i = 0; i < sampleMessageList.size(); i++) { |
||||
sampleMessageList.get(i).writeTo(output); |
||||
} |
||||
} |
||||
}); |
||||
if (devNull != null) { |
||||
benchmark( |
||||
"Serialize to /dev/null with FileOutputStream", |
||||
inputData.length, |
||||
new Action() { |
||||
public void execute() throws IOException { |
||||
for (int i = 0; i < sampleMessageList.size(); i++) { |
||||
sampleMessageList.get(i).writeTo(devNull); |
||||
} |
||||
} |
||||
}); |
||||
benchmark( |
||||
"Serialize to /dev/null reusing FileOutputStream", |
||||
inputData.length, |
||||
new Action() { |
||||
public void execute() throws IOException { |
||||
for (int i = 0; i < sampleMessageList.size(); i++) { |
||||
sampleMessageList.get(i).writeTo(reuseDevNull); |
||||
reuseDevNull.flush(); // force the write to the OutputStream
|
||||
} |
||||
} |
||||
}); |
||||
} |
||||
benchmark( |
||||
"Deserialize from byte string", |
||||
inputData.length, |
||||
new Action() { |
||||
public void execute() throws IOException { |
||||
for (int i = 0; i < inputStringList.size(); i++) { |
||||
defaultMessage |
||||
.newBuilderForType() |
||||
.mergeFrom(inputStringList.get(i), extensions) |
||||
.build(); |
||||
} |
||||
} |
||||
}); |
||||
benchmark( |
||||
"Deserialize from byte array", |
||||
inputData.length, |
||||
new Action() { |
||||
public void execute() throws IOException { |
||||
for (int i = 0; i < inputDataList.size(); i++) { |
||||
defaultMessage |
||||
.newBuilderForType() |
||||
.mergeFrom(CodedInputStream.newInstance(inputDataList.get(i)), extensions) |
||||
.build(); |
||||
} |
||||
} |
||||
}); |
||||
benchmark( |
||||
"Deserialize from memory stream", |
||||
inputData.length, |
||||
new Action() { |
||||
public void execute() throws IOException { |
||||
for (int i = 0; i < inputStreamList.size(); i++) { |
||||
defaultMessage |
||||
.newBuilderForType() |
||||
.mergeFrom(CodedInputStream.newInstance(inputStreamList.get(i)), extensions) |
||||
.build(); |
||||
inputStreamList.get(i).reset(); |
||||
} |
||||
} |
||||
}); |
||||
System.out.println(); |
||||
return true; |
||||
} catch (Exception e) { |
||||
System.err.println("Error: " + e.getMessage()); |
||||
System.err.println("Detailed exception information:"); |
||||
e.printStackTrace(System.err); |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
private static void benchmark(String name, long dataSize, Action action) throws IOException { |
||||
// Make sure it's JITted "reasonably" hard before running the first progress test
|
||||
for (int i=0; i < 100; i++) { |
||||
action.execute(); |
||||
} |
||||
|
||||
// Run it progressively more times until we've got a reasonable sample
|
||||
int iterations = 1; |
||||
long elapsed = timeAction(action, iterations); |
||||
while (elapsed < MIN_SAMPLE_TIME_MS) { |
||||
iterations *= 2; |
||||
elapsed = timeAction(action, iterations); |
||||
} |
||||
|
||||
// Upscale the sample to the target time. Do this in floating point arithmetic
|
||||
// to avoid overflow issues.
|
||||
iterations = (int) ((TARGET_TIME_MS / (double) elapsed) * iterations); |
||||
elapsed = timeAction(action, iterations); |
||||
System.out.println(name + ": " + iterations + " iterations in " |
||||
+ (elapsed/1000f) + "s; " |
||||
+ (iterations * dataSize) / (elapsed * 1024 * 1024 / 1000f) |
||||
+ "MB/s"); |
||||
} |
||||
|
||||
private static long timeAction(Action action, int iterations) throws IOException { |
||||
System.gc(); |
||||
long start = System.currentTimeMillis(); |
||||
for (int i = 0; i < iterations; i++) { |
||||
action.execute(); |
||||
} |
||||
long end = System.currentTimeMillis(); |
||||
return end - start; |
||||
} |
||||
|
||||
private static byte[] readAllBytes(String filename) throws IOException { |
||||
RandomAccessFile file = new RandomAccessFile(new File(filename), "r"); |
||||
byte[] content = new byte[(int) file.length()]; |
||||
file.readFully(content); |
||||
return content; |
||||
} |
||||
|
||||
/** |
||||
* Interface used to capture a single action to benchmark. |
||||
*/ |
||||
interface Action { |
||||
void execute() throws IOException; |
||||
} |
||||
} |
@ -0,0 +1,7 @@ |
||||
#! /bin/sh |
||||
|
||||
oldpwd=`pwd` |
||||
cd "../third_party" |
||||
git submodule update --init -r |
||||
cd benchmark && cmake -DCMAKE_BUILD_TYPE=Release && make && cd .. |
||||
cd "$oldpwd" |
@ -0,0 +1,148 @@ |
||||
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<!-- |
||||
~ Copyright 2011 Google Inc. |
||||
~ |
||||
~ 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. |
||||
--> |
||||
|
||||
<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/maven-v4_0_0.xsd"> |
||||
<modelVersion>4.0.0</modelVersion> |
||||
<!-- <parent> |
||||
<groupId>com.google.protobuf</groupId> |
||||
<artifactId>protobuf-parent</artifactId> |
||||
<version>3.5.0</version> |
||||
</parent> |
||||
|
||||
<packaging>pom</packaging> --> |
||||
<artifactId>protobuf-java-benchmark</artifactId> |
||||
<groupId>com.google.protocolbuffers</groupId> |
||||
<version>1.0.0</version> |
||||
<name>Protocol Buffers [Benchmark]</name> |
||||
<description> |
||||
The benchmark tools for Protobuf Java. |
||||
</description> |
||||
|
||||
<dependencies> |
||||
<dependency> |
||||
<groupId>com.google.protobuf</groupId> |
||||
<artifactId>protobuf-java</artifactId> |
||||
<version>3.5.0</version> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>com.google.caliper</groupId> |
||||
<artifactId>caliper</artifactId> |
||||
<version>1.0-beta-2</version> |
||||
</dependency> |
||||
</dependencies> |
||||
|
||||
<build> |
||||
<pluginManagement> |
||||
<plugins> |
||||
<plugin> |
||||
<groupId>org.apache.maven.plugins</groupId> |
||||
<artifactId>maven-assembly-plugin</artifactId> |
||||
<version>2.4.1</version> |
||||
<configuration> |
||||
<!-- get all project dependencies --> |
||||
<descriptorRefs> |
||||
<descriptorRef>jar-with-dependencies</descriptorRef> |
||||
</descriptorRefs> |
||||
<!-- MainClass in mainfest make a executable jar --> |
||||
<archive> |
||||
<manifest> |
||||
<mainClass>com.mkyong.core.utils.App</mainClass> |
||||
</manifest> |
||||
</archive> |
||||
|
||||
</configuration> |
||||
<executions> |
||||
<execution> |
||||
<id>make-assembly</id> |
||||
<!-- bind to the packaging phase --> |
||||
<phase>package</phase> |
||||
<goals> |
||||
<goal>single</goal> |
||||
</goals> |
||||
</execution> |
||||
</executions> |
||||
</plugin> |
||||
<plugin> |
||||
<groupId>org.apache.maven.plugins</groupId> |
||||
<artifactId>maven-compiler-plugin</artifactId> |
||||
<version>3.5.1</version> |
||||
<configuration> |
||||
<source>1.8</source> |
||||
<target>1.8</target> |
||||
</configuration> |
||||
</plugin> |
||||
<plugin> |
||||
<groupId>org.apache.maven.plugins</groupId> |
||||
<artifactId>maven-jar-plugin</artifactId> |
||||
<version>2.5</version> |
||||
<configuration> |
||||
<archive> |
||||
<manifest> |
||||
<addClasspath>true</addClasspath> |
||||
<mainClass>com.google.protocolbuffers.ProtoBench</mainClass> |
||||
</manifest> |
||||
</archive> |
||||
</configuration> |
||||
</plugin> |
||||
<plugin> |
||||
<groupId>org.apache.maven.plugins</groupId> |
||||
<artifactId>maven-source-plugin</artifactId> |
||||
<version>2.4</version> |
||||
<executions> |
||||
<execution> |
||||
<id>attach-sources</id> |
||||
<goals> |
||||
<goal>jar-no-fork</goal> |
||||
</goals> |
||||
</execution> |
||||
</executions> |
||||
</plugin> |
||||
<plugin> |
||||
<groupId>org.apache.maven.plugins</groupId> |
||||
<artifactId>maven-shade-plugin</artifactId> |
||||
<version>2.3</version> |
||||
<executions> |
||||
<execution> |
||||
<phase>package</phase> |
||||
<goals> |
||||
<goal>shade</goal> |
||||
</goals> |
||||
<configuration> |
||||
<shadedArtifactAttached>true</shadedArtifactAttached> |
||||
<shadedClassifierName>all</shadedClassifierName> |
||||
<transformers> |
||||
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> |
||||
<manifestEntries> |
||||
<Premain-Class>com.google.monitoring.runtime.instrumentation.AllocationInstrumenter</Premain-Class> |
||||
<Can-Redefine-Classes>true</Can-Redefine-Classes> |
||||
<Can-Retransform-Classes>true</Can-Retransform-Classes> |
||||
</manifestEntries> |
||||
</transformer> |
||||
</transformers> |
||||
</configuration> |
||||
</execution> |
||||
</executions> |
||||
</plugin> |
||||
</plugins> |
||||
</pluginManagement> |
||||
</build> |
||||
|
||||
</project> |
||||
|
@ -0,0 +1,155 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2009 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
package com.google.protocolbuffers; |
||||
|
||||
import com.google.caliper.BeforeExperiment; |
||||
import com.google.caliper.Benchmark; |
||||
import com.google.caliper.Param; |
||||
import com.google.caliper.runner.CaliperMain; |
||||
import com.google.protobuf.ByteString; |
||||
import com.google.protobuf.CodedInputStream; |
||||
import com.google.protobuf.CodedOutputStream; |
||||
import com.google.protobuf.ExtensionRegistry; |
||||
import com.google.protobuf.Message; |
||||
import com.google.protobuf.benchmarks.Benchmarks.BenchmarkDataset; |
||||
import java.io.ByteArrayInputStream; |
||||
import java.io.ByteArrayOutputStream; |
||||
import java.io.File; |
||||
import java.io.FileNotFoundException; |
||||
import java.io.FileOutputStream; |
||||
import java.io.IOException; |
||||
import java.io.PrintWriter; |
||||
import java.io.RandomAccessFile; |
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
|
||||
|
||||
public class ProtoBench { |
||||
|
||||
private ProtoBench() { |
||||
// Prevent instantiation
|
||||
} |
||||
|
||||
public static void main(String[] args) { |
||||
if (args.length < 1) { |
||||
System.err.println("Usage: ./java-benchmark <input data>"); |
||||
System.err.println("input data is in the format of \"benchmarks.proto\""); |
||||
System.exit(1); |
||||
} |
||||
boolean success = true; |
||||
for (int i = 0; i < args.length; i++) { |
||||
success &= runTest(args[i]); |
||||
} |
||||
System.exit(success ? 0 : 1); |
||||
} |
||||
|
||||
/** |
||||
* Runs a single test with specific test data. Error messages are displayed to stderr, |
||||
* and the return value indicates general success/failure. |
||||
*/ |
||||
public static boolean runTest(String file) { |
||||
byte[] inputData; |
||||
BenchmarkDataset benchmarkDataset; |
||||
try { |
||||
inputData = readAllBytes(file); |
||||
benchmarkDataset = BenchmarkDataset.parseFrom(inputData); |
||||
} catch (IOException e) { |
||||
System.err.println("Unable to get input data"); |
||||
return false; |
||||
} |
||||
|
||||
List<String> argsList = getCaliperOption(benchmarkDataset); |
||||
if (argsList == null) { |
||||
System.err.println("Unable to get default message " + benchmarkDataset.getMessageName()); |
||||
return false; |
||||
} |
||||
argsList.add("-DdataFile=" + file); |
||||
argsList.add("com.google.protocolbuffers.ProtoBenchCaliper"); |
||||
|
||||
try { |
||||
String args[] = new String[argsList.size()]; |
||||
argsList.toArray(args); |
||||
CaliperMain.exitlessMain(args, |
||||
new PrintWriter(System.out, true), new PrintWriter(System.err, true)); |
||||
return true; |
||||
} catch (Exception e) { |
||||
System.err.println("Error: " + e.getMessage()); |
||||
System.err.println("Detailed exception information:"); |
||||
e.printStackTrace(System.err); |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
|
||||
private static List<String> getCaliperOption(final BenchmarkDataset benchmarkDataset) { |
||||
List<String> temp = new ArrayList<String>(); |
||||
if (benchmarkDataset.getMessageName().equals("benchmarks.proto3.GoogleMessage1")) { |
||||
temp.add("-DbenchmarkMessageType=GOOGLE_MESSAGE1_PROTO3"); |
||||
} else if (benchmarkDataset.getMessageName().equals("benchmarks.proto2.GoogleMessage1")) { |
||||
temp.add("-DbenchmarkMessageType=GOOGLE_MESSAGE1_PROTO2"); |
||||
} else if (benchmarkDataset.getMessageName().equals("benchmarks.proto2.GoogleMessage2")) { |
||||
temp.add("-DbenchmarkMessageType=GOOGLE_MESSAGE2"); |
||||
} else if (benchmarkDataset.getMessageName(). |
||||
equals("benchmarks.google_message3.GoogleMessage3")) { |
||||
temp.add("-DbenchmarkMessageType=GOOGLE_MESSAGE3"); |
||||
for (String opt : ProtoBenchCaliper |
||||
.BenchmarkMessageType.GOOGLE_MESSAGE3.getSpecificCaliperOption()) { |
||||
temp.add(opt); |
||||
} |
||||
} else if (benchmarkDataset.getMessageName(). |
||||
equals("benchmarks.google_message4.GoogleMessage4")) { |
||||
temp.add("-DbenchmarkMessageType=GOOGLE_MESSAGE4"); |
||||
for (String opt : ProtoBenchCaliper |
||||
.BenchmarkMessageType.GOOGLE_MESSAGE4.getSpecificCaliperOption()) { |
||||
temp.add(opt); |
||||
} |
||||
} else { |
||||
return null; |
||||
} |
||||
|
||||
temp.add("-i"); |
||||
temp.add("runtime"); |
||||
temp.add("-b"); |
||||
String benchmarkNames = "serializeToByteString,serializeToByteArray,serializeToMemoryStream" |
||||
+ ",deserializeFromByteString,deserializeFromByteArray,deserializeFromMemoryStream"; |
||||
temp.add(benchmarkNames); |
||||
|
||||
return temp; |
||||
} |
||||
|
||||
public static byte[] readAllBytes(String filename) throws IOException { |
||||
RandomAccessFile file = new RandomAccessFile(new File(filename), "r"); |
||||
byte[] content = new byte[(int) file.length()]; |
||||
file.readFully(content); |
||||
return content; |
||||
} |
||||
} |
@ -0,0 +1,210 @@ |
||||
|
||||
package com.google.protocolbuffers; |
||||
|
||||
import com.google.caliper.BeforeExperiment; |
||||
import com.google.caliper.Benchmark; |
||||
import com.google.caliper.Param; |
||||
import com.google.protobuf.ByteString; |
||||
import com.google.protobuf.CodedOutputStream; |
||||
import com.google.protobuf.ExtensionRegistry; |
||||
import com.google.protobuf.Message; |
||||
import com.google.protobuf.benchmarks.Benchmarks.BenchmarkDataset; |
||||
import java.io.ByteArrayInputStream; |
||||
import java.io.ByteArrayOutputStream; |
||||
import java.io.FileNotFoundException; |
||||
import java.io.FileOutputStream; |
||||
import java.io.IOException; |
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
|
||||
public class ProtoBenchCaliper { |
||||
public enum BenchmarkMessageType { |
||||
GOOGLE_MESSAGE1_PROTO3 { |
||||
@Override ExtensionRegistry getExtensionRegistry() { return ExtensionRegistry.newInstance(); } |
||||
@Override |
||||
Message getDefaultInstance() { |
||||
return com.google.protobuf.benchmarks.BenchmarkMessage1Proto3.GoogleMessage1 |
||||
.getDefaultInstance(); |
||||
} |
||||
@Override String[] getSpecificCaliperOption() { return null; } |
||||
}, |
||||
GOOGLE_MESSAGE1_PROTO2 { |
||||
@Override ExtensionRegistry getExtensionRegistry() { return ExtensionRegistry.newInstance(); } |
||||
@Override |
||||
Message getDefaultInstance() { |
||||
return com.google.protobuf.benchmarks.BenchmarkMessage1Proto2.GoogleMessage1 |
||||
.getDefaultInstance(); |
||||
} |
||||
@Override String[] getSpecificCaliperOption() { return null; } |
||||
}, |
||||
GOOGLE_MESSAGE2 { |
||||
@Override ExtensionRegistry getExtensionRegistry() { return ExtensionRegistry.newInstance(); } |
||||
@Override |
||||
Message getDefaultInstance() { |
||||
return com.google.protobuf.benchmarks.BenchmarkMessage2.GoogleMessage2.getDefaultInstance(); |
||||
} |
||||
@Override String[] getSpecificCaliperOption() { return null; } |
||||
}, |
||||
GOOGLE_MESSAGE3 { |
||||
@Override |
||||
ExtensionRegistry getExtensionRegistry() { |
||||
ExtensionRegistry extensions = ExtensionRegistry.newInstance(); |
||||
benchmarks.google_message3.BenchmarkMessage38.registerAllExtensions(extensions); |
||||
benchmarks.google_message3.BenchmarkMessage37.registerAllExtensions(extensions); |
||||
benchmarks.google_message3.BenchmarkMessage36.registerAllExtensions(extensions); |
||||
benchmarks.google_message3.BenchmarkMessage35.registerAllExtensions(extensions); |
||||
benchmarks.google_message3.BenchmarkMessage34.registerAllExtensions(extensions); |
||||
benchmarks.google_message3.BenchmarkMessage33.registerAllExtensions(extensions); |
||||
benchmarks.google_message3.BenchmarkMessage32.registerAllExtensions(extensions); |
||||
benchmarks.google_message3.BenchmarkMessage31.registerAllExtensions(extensions); |
||||
benchmarks.google_message3.BenchmarkMessage3.registerAllExtensions(extensions); |
||||
return extensions; |
||||
} |
||||
@Override |
||||
Message getDefaultInstance() { |
||||
return benchmarks.google_message3.BenchmarkMessage3.GoogleMessage3.getDefaultInstance(); |
||||
} |
||||
@Override |
||||
String[] getSpecificCaliperOption() { |
||||
String[] opt = new String[1]; |
||||
opt[0] = "-Cinstrument.runtime.options.timingInterval=3000ms"; |
||||
return opt; |
||||
} |
||||
}, |
||||
GOOGLE_MESSAGE4 { |
||||
@Override |
||||
ExtensionRegistry getExtensionRegistry() { |
||||
ExtensionRegistry extensions = ExtensionRegistry.newInstance(); |
||||
benchmarks.google_message4.BenchmarkMessage43.registerAllExtensions(extensions); |
||||
benchmarks.google_message4.BenchmarkMessage42.registerAllExtensions(extensions); |
||||
benchmarks.google_message4.BenchmarkMessage41.registerAllExtensions(extensions); |
||||
benchmarks.google_message4.BenchmarkMessage4.registerAllExtensions(extensions); |
||||
return extensions; |
||||
} |
||||
@Override |
||||
Message getDefaultInstance() { |
||||
return benchmarks.google_message4.BenchmarkMessage4.GoogleMessage4.getDefaultInstance(); |
||||
} |
||||
@Override |
||||
String[] getSpecificCaliperOption() { |
||||
String[] opt = new String[1]; |
||||
opt[0] = "-Cinstrument.runtime.options.timingInterval=3000ms"; |
||||
return opt; |
||||
} |
||||
}; |
||||
|
||||
abstract ExtensionRegistry getExtensionRegistry(); |
||||
abstract Message getDefaultInstance(); |
||||
abstract String[] getSpecificCaliperOption(); |
||||
} |
||||
|
||||
@Param |
||||
private BenchmarkMessageType benchmarkMessageType; |
||||
@Param |
||||
private String dataFile; |
||||
|
||||
private byte[] inputData; |
||||
private BenchmarkDataset benchmarkDataset; |
||||
private Message defaultMessage; |
||||
private ExtensionRegistry extensions; |
||||
private List<byte[]> inputDataList; |
||||
private List<ByteArrayInputStream> inputStreamList; |
||||
private List<ByteString> inputStringList; |
||||
private List<Message> sampleMessageList; |
||||
private int counter; |
||||
private FileOutputStream devNull; |
||||
private CodedOutputStream reuseDevNull; |
||||
|
||||
@BeforeExperiment |
||||
void setUp() throws IOException { |
||||
inputData = ProtoBench.readAllBytes(dataFile); |
||||
benchmarkDataset = BenchmarkDataset.parseFrom(inputData); |
||||
defaultMessage = benchmarkMessageType.getDefaultInstance(); |
||||
extensions = benchmarkMessageType.getExtensionRegistry(); |
||||
inputDataList = new ArrayList<byte[]>(); |
||||
inputStreamList = new ArrayList<ByteArrayInputStream>(); |
||||
inputStringList = new ArrayList<ByteString>(); |
||||
sampleMessageList = new ArrayList<Message>(); |
||||
|
||||
for (int i = 0; i < benchmarkDataset.getPayloadCount(); i++) { |
||||
byte[] singleInputData = benchmarkDataset.getPayload(i).toByteArray(); |
||||
inputDataList.add(benchmarkDataset.getPayload(i).toByteArray()); |
||||
inputStreamList.add(new ByteArrayInputStream( |
||||
benchmarkDataset.getPayload(i).toByteArray())); |
||||
inputStringList.add(benchmarkDataset.getPayload(i)); |
||||
sampleMessageList.add( |
||||
defaultMessage.newBuilderForType().mergeFrom(singleInputData, extensions).build()); |
||||
} |
||||
devNull = null; |
||||
reuseDevNull = null; |
||||
|
||||
try { |
||||
devNull = new FileOutputStream("/dev/null"); |
||||
reuseDevNull = CodedOutputStream.newInstance(devNull); |
||||
} catch (FileNotFoundException e) { |
||||
// ignore: this is probably Windows, where /dev/null does not exist
|
||||
} |
||||
|
||||
counter = 0; |
||||
} |
||||
|
||||
|
||||
@Benchmark |
||||
void serializeToByteString(int reps) throws IOException { |
||||
for (int i = 0; i < reps; i++) { |
||||
sampleMessageList.get(counter % sampleMessageList.size()).toByteString(); |
||||
counter++; |
||||
} |
||||
} |
||||
|
||||
@Benchmark |
||||
void serializeToByteArray(int reps) throws IOException { |
||||
for (int i = 0; i < reps; i++) { |
||||
sampleMessageList.get(counter % sampleMessageList.size()).toByteArray(); |
||||
counter++; |
||||
} |
||||
} |
||||
|
||||
@Benchmark |
||||
void serializeToMemoryStream(int reps) throws IOException { |
||||
for (int i = 0; i < reps; i++) { |
||||
ByteArrayOutputStream output = new ByteArrayOutputStream(); |
||||
sampleMessageList.get(counter % sampleMessageList.size()).writeTo(output); |
||||
counter++; |
||||
} |
||||
} |
||||
|
||||
@Benchmark |
||||
void deserializeFromByteString(int reps) throws IOException { |
||||
for (int i = 0; i < reps; i++) { |
||||
defaultMessage |
||||
.newBuilderForType() |
||||
.mergeFrom(inputStringList.get(counter % inputStringList.size()), extensions) |
||||
.build(); |
||||
counter++; |
||||
} |
||||
} |
||||
|
||||
@Benchmark |
||||
void deserializeFromByteArray(int reps) throws IOException { |
||||
for (int i = 0; i < reps; i++) { |
||||
defaultMessage |
||||
.newBuilderForType() |
||||
.mergeFrom(inputDataList.get(counter % inputDataList.size()), extensions) |
||||
.build(); |
||||
counter++; |
||||
} |
||||
} |
||||
|
||||
@Benchmark |
||||
void deserializeFromMemoryStream(int reps) throws IOException { |
||||
for (int i = 0; i < reps; i++) { |
||||
defaultMessage |
||||
.newBuilderForType() |
||||
.mergeFrom(inputStreamList.get(counter % inputStreamList.size()), extensions) |
||||
.build(); |
||||
inputStreamList.get(counter % inputStreamList.size()).reset(); |
||||
counter++; |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue