Add script to run kotlin benchmarks

Supports running on device with --use-device

Supports benchmarks ['rgx', 'deltablue', 'sta', 'empty'], passed in with --benchmark

Api level is set with --api

--no-build (don't rebuilt r8) for golem support

Change-Id: I725e2ca02d62a33c68cee0aa887fc2b0a39c65f1
diff --git a/tools/build_sample_apk.py b/tools/build_sample_apk.py
index 5f53196..9053e23 100755
--- a/tools/build_sample_apk.py
+++ b/tools/build_sample_apk.py
@@ -17,7 +17,7 @@
 import utils
 import uuid
 
-ANDROID_JAR = 'third_party/android_jar/lib-v{api}/android.jar'
+
 DEFAULT_AAPT = 'aapt' # Assume in path.
 DEFAULT_D8 = os.path.join(utils.REPO_ROOT, 'tools', 'd8.py')
 DEFAULT_DEXSPLITTER = os.path.join(utils.REPO_ROOT, 'tools', 'dexsplitter.py')
@@ -82,8 +82,6 @@
   utils.makedirs_if_needed(bin_path)
   return bin_path
 
-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,
@@ -112,7 +110,7 @@
   with utils.ChangedWorkingDirectory(get_sample_dir(app)):
     args = ['package',
             '-v', '-f',
-            '-I', get_android_jar(api),
+            '-I', utils.get_android_jar(api),
             '-M', 'AndroidManifest.xml',
             '-A', 'assets',
             '-S', 'res',
@@ -126,7 +124,7 @@
   with utils.ChangedWorkingDirectory(get_sample_dir(app)):
     args = ['package',
             '-v', '-f',
-            '-I', get_android_jar(api),
+            '-I', utils.get_android_jar(api),
             '-M', 'split_manifest/AndroidManifest.xml',
             '-S', 'res',
             '-F', os.path.join(get_bin_path(app), 'split_resources.ap_')]
@@ -135,8 +133,9 @@
 def compile_with_javac(api, app):
   with utils.ChangedWorkingDirectory(get_sample_dir(app)):
     files = glob.glob(SRC_LOCATION.format(app=app))
+    classpath = '%s:%s' % (utils.get_android_jar(api), get_guava_jar())
     command = [DEFAULT_JAVAC,
-               '-classpath', '%s:%s' % (get_android_jar(api), get_guava_jar()),
+               '-classpath', classpath,
                '-sourcepath', '%s:%s:%s' % (
                    get_src_path(app),
                    get_gen_path(app),
@@ -153,7 +152,7 @@
         files.append(os.path.join(root, filename))
   command = [DEFAULT_D8,
              '--output', get_bin_path(app),
-             '--classpath', get_android_jar(api),
+             '--classpath', utils.get_android_jar(api),
              '--min-api', str(api)]
   command.extend(files)
   command.append(get_guava_jar())
diff --git a/tools/run_kotlin_benchmarks.py b/tools/run_kotlin_benchmarks.py
new file mode 100755
index 0000000..7f13989
--- /dev/null
+++ b/tools/run_kotlin_benchmarks.py
@@ -0,0 +1,108 @@
+#!/usr/bin/env python
+# Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+# Script for running kotlin based benchmarks
+
+import optparse
+import os
+import subprocess
+import sys
+import toolhelper
+import utils
+
+
+BENCHMARK_ROOT = os.path.join(utils.REPO_ROOT, 'third_party', 'benchmarks',
+                              'kotlin-benches')
+
+BENCHMARK_PATTERN = '{benchmark}/kotlin/perf/build/libs/perf-1.0-BENCH.jar'
+BENCHMARK_MAIN_CLASS = 'com.android.kt.bms.cli.Runner'
+ART = os.path.join(utils.TOOLS_DIR, 'linux', 'art', 'bin', 'art')
+
+PROGUARD_CONF = """
+# From Android rules
+-keepclasseswithmembers public class * {
+  public static void main(java.lang.String[]);
+}
+# Disable obfuscation to only focus on shrinking
+-dontobfuscate
+# Once we're ready for optimization, we might want to relax access modifiers.
+-allowaccessmodification
+"""
+
+DEVICE_TEMP='/data/local/temp/bench'
+
+
+def parse_options():
+  result = optparse.OptionParser()
+  result.add_option('--api',
+                    help='Android api level',
+                    default='26',
+                    choices=['21', '22', '23', '24', '25', '26'])
+  result.add_option('--benchmark',
+                    help='The benchmark to run',
+                    default='rgx',
+                    choices=['rgx', 'deltablue', 'sta', 'empty'])
+  result.add_option('--no-build',
+                    help='Don\'t build r8',
+                    default=False, action='store_true')
+  result.add_option('--use-device',
+                    help='Run the benchmark on an attaced device',
+                    default=False, action='store_true')
+  return result.parse_args()
+
+
+def get_jar_for_benchmark(benchmark):
+  return os.path.join(BENCHMARK_ROOT,
+                      BENCHMARK_PATTERN.format(benchmark=benchmark))
+
+def run_art(dex):
+  command = ['bash', ART, '-cp', dex, BENCHMARK_MAIN_CLASS]
+  utils.PrintCmd(command)
+  benchmark_output = subprocess.check_output(command)
+  return get_result(benchmark_output)
+
+def adb(args):
+  command = ['adb'] + args
+  utils.PrintCmd(command)
+  return subprocess.check_output(['adb'] + args)
+
+def get_result(output):
+  # There is a lot of debug output, with the actual results being in the line with:
+  # RESULTS,KtBench,KtBench,15719
+  # structure.
+  for result in [s for s in output.splitlines() if s.startswith('RESULTS')]:
+    return s.split('RESULTS,KtBench,KtBench,')[1]
+
+def run_art_device(dex):
+  adb(['wait-for-device', 'root'])
+  device_dst = os.path.join(DEVICE_TEMP, os.path.basename(dex))
+  adb(['push', dex, device_dst])
+  benchmark_output = adb(['shell', 'dalvikvm', '-cp', device_dst, BENCHMARK_MAIN_CLASS])
+  return get_result(benchmark_output)
+
+def Main():
+  (options, args) = parse_options()
+  temp = '/tmp/output'
+  dex_path = os.path.join(temp, "classes.jar")
+  proguard_conf = os.path.join(temp, 'proguard.conf')
+  with open(proguard_conf, 'w') as f:
+    f.write(PROGUARD_CONF)
+  benchmark_jar = get_jar_for_benchmark(options.benchmark)
+  r8_args = [
+      '--lib', utils.get_android_jar(26), # Only works with api 26
+      '--output', dex_path,
+      '--pg-conf', proguard_conf,
+      '--min-api', str(options.api),
+      benchmark_jar
+  ]
+  toolhelper.run('r8', r8_args, build=not options.no_build)
+  if options.use_device:
+    result = run_art_device(dex_path)
+  else:
+    result = run_art(dex_path)
+  print('Kotlin_{}(RunTimeRaw): {} ms'.format(options.benchmark, result))
+
+if __name__ == '__main__':
+  sys.exit(Main())
diff --git a/tools/utils.py b/tools/utils.py
index 851f3bd..766f3da 100644
--- a/tools/utils.py
+++ b/tools/utils.py
@@ -13,6 +13,7 @@
 import tarfile
 import tempfile
 
+ANDROID_JAR = 'third_party/android_jar/lib-v{api}/android.jar'
 TOOLS_DIR = os.path.abspath(os.path.normpath(os.path.join(__file__, '..')))
 REPO_ROOT = os.path.realpath(os.path.join(TOOLS_DIR, '..'))
 MEMORY_USE_TMP_FILE = 'memory_use.tmp'
@@ -288,3 +289,6 @@
       env = {"LD_LIBRARY_PATH":
         os.path.join(TOOLS_DIR, 'linux', 'art', 'lib')}
     )
+
+def get_android_jar(api):
+  return os.path.join(REPO_ROOT, ANDROID_JAR.format(api=api))