mobile/bind: add Android benchmarks

Since the normal Go benchmark machinery cannot readily be used for
Android apps, a new test, TestJavaSeqBench, is added that builds and
runs the new benchmarkpkg package along with its support Java class
SeqBench. Benchmarkpkg mimics Go benchmarking, in particular it
produces benchcmp compatible output.

Excerpts of the output from a Nexus 5:

BenchmarkJavaEmpty	65536000	26 ns/op
BenchmarkJavaNoargs	256000	7685 ns/op
BenchmarkJavaNoargsDirect	64000	17405 ns/op
BenchmarkJavaOnearg	64000	26887 ns/op
BenchmarkJavaOneret	32000	38325 ns/op
BenchmarkJavaManyargs	32000	41720 ns/op
BenchmarkJavaRefjava	32000	38139 ns/op
BenchmarkJavaRefgo	32000	34403 ns/op
BenchmarkJavaStringShort	32000	32366 ns/op
BenchmarkJavaStringLong	8000	127879 ns/op
BenchmarkJavaSliceShort	32000	42462 ns/op
BenchmarkJavaSliceLong	8000	138391 ns/op
BenchmarkGoEmpty	524288000	3 ns/op
BenchmarkGoNoarg	32000	40342 ns/op
BenchmarkGoOnearg	32000	43529 ns/op
BenchmarkGoOneret	32000	45456 ns/op
BenchmarkGoRefjava	32000	55111 ns/op
BenchmarkGoRefgo	32000	57038 ns/op
BenchmarkGoManyargs	16000	67967 ns/op
BenchmarkGoStringShort	32000	57538 ns/op
BenchmarkGoStringLong	8000	128485 ns/op
BenchmarkGoSliceShort	32000	59279 ns/op
BenchmarkGoSliceLong	4000	411225 ns/op

Benchmarks prefixed with "BenchmarkJava" are for calls from Java into
Go. Benchmarks prefixed with "BenchmarksGo" are the other way around.
Note that all Go benchmarks run against a Java interface implementation
while the Java benchmarks calls Go functions directly. In other words,
every Go call serializes an implicit Java reference, explaining the
higher call times. The JavaRefgo and JavaRefjava tests attempt to
quantify the overhead equivalent for Java.

The "Direct" suffix are for variants that runs the benchmarks from a
new thread or goroutine. For Go it makes little difference, but there
is a noticable speedup when calling Go from Java when there is already
a JNI call context earlier in the stack.

The benchmarks are for Android only for now, but the benchmarkpkg
has been added to the common golang.org/x/mobile/bind package in
anticipation of future iOS support.

Change-Id: I3c948dc710b65bc348e7635416324095060a5beb
Reviewed-on: https://go-review.googlesource.com/20095
Reviewed-by: David Crawshaw <crawshaw@golang.org>
This commit is contained in:
Elias Naur
2016-03-02 13:27:40 +00:00
parent c432672682
commit 45143d8b25
3 changed files with 330 additions and 7 deletions
+146
View File
@@ -0,0 +1,146 @@
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package go;
import android.test.InstrumentationTestCase;
import android.util.Log;
import java.util.Map;
import java.util.HashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
import go.benchmarkpkg.Benchmarkpkg;
public class SeqBench extends InstrumentationTestCase {
public static class AnI extends Benchmarkpkg.I.Stub {
@Override public void F() {
}
}
private static class Benchmarks extends Benchmarkpkg.Benchmarks.Stub {
private static Map<String, Runnable> benchmarks;
private static ExecutorService executor = Executors.newSingleThreadExecutor();
static {
benchmarks = new HashMap<String, Runnable>();
benchmarks.put("Empty", new Runnable() {
@Override public void run() {
}
});
benchmarks.put("Noargs", new Runnable() {
@Override public void run() {
Benchmarkpkg.Noargs();
}
});
benchmarks.put("Onearg", new Runnable() {
@Override public void run() {
Benchmarkpkg.Onearg(0);
}
});
benchmarks.put("Manyargs", new Runnable() {
@Override public void run() {
Benchmarkpkg.Manyargs(0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
}
});
benchmarks.put("Oneret", new Runnable() {
@Override public void run() {
Benchmarkpkg.Oneret();
}
});
final Benchmarkpkg.I javaRef = new AnI();
benchmarks.put("Refjava", new Runnable() {
@Override public void run() {
Benchmarkpkg.Ref(javaRef);
}
});
final Benchmarkpkg.I goRef = Benchmarkpkg.NewI();
benchmarks.put("Refgo", new Runnable() {
@Override public void run() {
Benchmarkpkg.Ref(goRef);
}
});
benchmarks.put("StringShort", new Runnable() {
@Override public void run() {
Benchmarkpkg.String(Benchmarkpkg.ShortString);
}
});
benchmarks.put("StringLong", new Runnable() {
@Override public void run() {
Benchmarkpkg.String(Benchmarkpkg.LongString);
}
});
benchmarks.put("StringShortUnicode", new Runnable() {
@Override public void run() {
Benchmarkpkg.String(Benchmarkpkg.ShortStringUnicode);
}
});
benchmarks.put("StringLongUnicode", new Runnable() {
@Override public void run() {
Benchmarkpkg.String(Benchmarkpkg.LongStringUnicode);
}
});
final byte[] shortSlice = Benchmarkpkg.getShortSlice();
benchmarks.put("SliceShort", new Runnable() {
@Override public void run() {
Benchmarkpkg.Slice(shortSlice);
}
});
final byte[] longSlice = Benchmarkpkg.getLongSlice();
benchmarks.put("SliceLong", new Runnable() {
@Override public void run() {
Benchmarkpkg.Slice(longSlice);
}
});
}
public void RunDirect(String name, final long n) {
final Runnable r = benchmarks.get(name);
try {
executor.submit(new Runnable() {
@Override public void run() {
for (int i = 0; i < n; i++) {
r.run();
}
}
}).get();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public void Run(String name, long n) {
final Runnable r = benchmarks.get(name);
for (int i = 0; i < n; i++) {
r.run();
}
}
@Override public Benchmarkpkg.I NewI() {
return new AnI();
}
@Override public void Ref(Benchmarkpkg.I i) {
}
@Override public void Noargs() {
}
@Override public void Onearg(long i) {
}
@Override public long Oneret() {
return 0;
}
@Override public void Manyargs(long p0, long p1, long p2, long p3, long p4, long p5, long p6, long p7, long gp8, long p9) {
}
@Override public void String(String s) {
}
@Override public void Slice(byte[] s) {
}
}
public void testBenchmark() {
Benchmarkpkg.RunBenchmarks(new Benchmarks());
}
}