Add some dex splitter guava benchmarks
Change-Id: Ic60d8dabc824a7568963622ea47d3d6200cd441e
diff --git a/src/test/sampleApks/split/src/com/android/tools/r8/sample/split/R8Activity.java b/src/test/sampleApks/split/src/com/android/tools/r8/sample/split/R8Activity.java
index 307cac9..7ed223f 100644
--- a/src/test/sampleApks/split/src/com/android/tools/r8/sample/split/R8Activity.java
+++ b/src/test/sampleApks/split/src/com/android/tools/r8/sample/split/R8Activity.java
@@ -8,10 +8,23 @@
import android.os.Bundle;
import com.android.tools.r8.sample.split.R;
import com.android.tools.r8.sample.split.SplitClass;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Multiset;
+import com.google.common.collect.ConcurrentHashMultiset;
import java.util.ArrayList;
import java.util.List;
-
+/**
+ * Benchmarking of splits. Generally the naming is like this:
+ * Base -> Split (no postfix)
+ * Base -> Base (Local, to get the corresponding performance if no split involved)
+ * Split -> Split (SplitLocal)
+ * Split -> Base (SplitCallback)
+ * Base no call overhead (Baseline)
+ * In most of these cases we have the methods duplicated between the SplitClass and this class.
+ * This is to enable output of the split and not split version of the code without having to
+ * run in two different build configurations (i.e., with and without using split code)
+ */
public class R8Activity extends Activity {
// Enables easy splitting of iterations to better see effect of jit in later versions of art
public static final int ITERATIONS = 100000;
@@ -35,6 +48,14 @@
}
System.out.println("Call Total: " + total);
+
+ total = 0;
+ for (int i = 0; i < SPLITS; i++) {
+ total += benchmarkCallSplitLocal();
+ }
+ System.out.println("CallSplitLocal Total: " + total);
+
+
total = 0;
for (int i = 0; i < SPLITS; i++) {
total += benchmarkCallLocal();
@@ -83,6 +104,19 @@
}
System.out.println("LargeMethodCallLocal Total: " + total);
+ total = 0;
+ for (int i = 0; i < SPLITS; i++) {
+ total += benchmarkGuava();
+ }
+ System.out.println("Guava Total: " + total);
+
+
+ total = 0;
+ for (int i = 0; i < SPLITS; i++) {
+ total += benchmarkGuavaLocal();
+ }
+ System.out.println("GuavaLocal Total: " + total);
+
}
private long benchmarkCall() {
@@ -97,6 +131,23 @@
return timeElapsed;
}
+ private long benchmarkGuava() {
+ SplitClass split = new SplitClass(3);
+ long start = System.nanoTime();
+ res = split.guava(ITERATIONS / SPLITS / 10);
+ long finish = System.nanoTime();
+ long timeElapsed = (finish - start) / 1000;
+ return timeElapsed;
+ }
+
+ private long benchmarkGuavaLocal() {
+ long start = System.nanoTime();
+ res = guava(ITERATIONS / SPLITS / 10);
+ long finish = System.nanoTime();
+ long timeElapsed = (finish - start) / 1000;
+ return timeElapsed;
+ }
+
private long benchmarkCallLocal() {
long start = System.nanoTime();
for (int i = 0; i < ITERATIONS / SPLITS; i++) {
@@ -108,6 +159,15 @@
return timeElapsed;
}
+ private long benchmarkCallSplitLocal() {
+ SplitClass split = new SplitClass(3);
+ long start = System.nanoTime();
+ split.callSplitLocal();
+ long finish = System.nanoTime();
+ long timeElapsed = (finish - start) / 1000;
+ return timeElapsed;
+ }
+
private long benchmarkCallBaseline() {
SplitClass split = new SplitClass(3);
long start = System.nanoTime();
@@ -198,6 +258,32 @@
return timeElapsed;
}
+ public int guava(int iterations) {
+ for (int i = 0; i < iterations; i++) {
+ int result = 0;
+ ImmutableList<String> a = ImmutableList.of(
+ "foo",
+ "bar",
+ "foobar",
+ "last");
+ if (a.contains("foobar")) {
+ result++;
+ }
+ if (a.subList(0, 2).contains("last")) {
+ throw new RuntimeException("WAT");
+ }
+ result = a.size();
+ Multiset<String> set = ConcurrentHashMultiset.create();
+ for (int j = 0; j < 100; j++) {
+ set.add(a.get(j%4));
+ }
+ for (String s : a) {
+ result += set.count(s);
+ }
+ }
+ return 42;
+ }
+
public int calculate(int x) {
int result = 2;
for (int i = 0; i < 42; i++) {
diff --git a/src/test/sampleApks/split/src/com/android/tools/r8/sample/split/SplitClass.java b/src/test/sampleApks/split/src/com/android/tools/r8/sample/split/SplitClass.java
index b493326..d257c16 100644
--- a/src/test/sampleApks/split/src/com/android/tools/r8/sample/split/SplitClass.java
+++ b/src/test/sampleApks/split/src/com/android/tools/r8/sample/split/SplitClass.java
@@ -5,6 +5,9 @@
package com.android.tools.r8.sample.split;
import com.android.tools.r8.sample.split.R8Activity;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Multiset;
+import com.google.common.collect.ConcurrentHashMultiset;
public class SplitClass {
int initialValue;
@@ -13,8 +16,6 @@
this.initialValue = initialValue;
}
-
-
public int calculate(int x) {
int result = 2;
for (int i = 0; i < 42; i++) {
@@ -23,6 +24,33 @@
return result;
}
+ public int guava(int iterations) {
+ for (int i = 0; i < iterations; i++) {
+ int result = 0;
+ ImmutableList<String> a = ImmutableList.of(
+ "foo",
+ "bar",
+ "foobar",
+ "last");
+ if (a.contains("foobar")) {
+ result++;
+ }
+ if (a.subList(0, 2).contains("last")) {
+ throw new RuntimeException("WAT");
+ }
+ result = a.size();
+ Multiset<String> set = ConcurrentHashMultiset.create();
+ for (int j = 0; j < 100; j++) {
+ set.add(a.get(j%4));
+ }
+ for (String s : a) {
+ result += set.count(s);
+ }
+ }
+ return 42;
+
+ }
+
public int largeMethod(int x, int y) {
int a = x + y;
int b;
@@ -104,6 +132,16 @@
return a + b - c * x;
}
+ public int callSplitLocal() {
+ SplitClass split = new SplitClass(initialValue);
+ for (int i = 0; i < R8Activity.ITERATIONS / R8Activity.SPLITS; i++) {
+ // Ensure no dead code elimination.
+ initialValue = split.calculate(i);
+ }
+ return initialValue;
+ }
+
+
public int callBase() {
BaseClass base = new BaseClass(initialValue);
for (int i = 0; i < R8Activity.ITERATIONS / R8Activity.SPLITS; i++) {
diff --git a/tools/build_sample_apk.py b/tools/build_sample_apk.py
index b74356b..5f53196 100755
--- a/tools/build_sample_apk.py
+++ b/tools/build_sample_apk.py
@@ -85,6 +85,10 @@
def get_android_jar(api):
return os.path.join(utils.REPO_ROOT, ANDROID_JAR.format(api=api))
+def get_guava_jar():
+ return os.path.join(utils.REPO_ROOT,
+ 'third_party/gradle-plugin/com/google/guava/guava/22.0/guava-22.0.jar')
+
def get_sample_dir(app):
return os.path.join(utils.REPO_ROOT, 'src', 'test', 'sampleApks', app)
@@ -132,8 +136,11 @@
with utils.ChangedWorkingDirectory(get_sample_dir(app)):
files = glob.glob(SRC_LOCATION.format(app=app))
command = [DEFAULT_JAVAC,
- '-classpath', get_android_jar(api),
- '-sourcepath', '%s:%s' % (get_src_path(app), get_gen_path(app)),
+ '-classpath', '%s:%s' % (get_android_jar(api), get_guava_jar()),
+ '-sourcepath', '%s:%s:%s' % (
+ get_src_path(app),
+ get_gen_path(app),
+ get_guava_jar()),
'-d', get_bin_path(app)]
command.extend(files)
utils.PrintCmd(command)
@@ -149,6 +156,8 @@
'--classpath', get_android_jar(api),
'--min-api', str(api)]
command.extend(files)
+ command.append(get_guava_jar())
+
utils.PrintCmd(command)
subprocess.check_call(command)
@@ -253,7 +262,7 @@
start(app)
# We could do better here by continiously parsing the logcat for a marker, but
# this works nicely with the current setup.
- time.sleep(8)
+ time.sleep(12)
kill(app)
return float(store_or_print_benchmarks(stop_logcat(logcat), output_dir))