Add script to test framework.jar with D8/DX

Bug:
Change-Id: I31997be2909fd3b91b1ec28b2b516ad6737d1c26
diff --git a/tools/test_framework.py b/tools/test_framework.py
new file mode 100755
index 0000000..f404a86
--- /dev/null
+++ b/tools/test_framework.py
@@ -0,0 +1,114 @@
+#!/usr/bin/env python
+# Copyright (c) 2017, 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.
+
+# Run D8 or DX on 'third_party/framework/framework_<version>.jar'.
+# Report Golem-compatible CodeSize and RunTimeRaw values:
+#
+#     <NAME>(CodeSize): <size>
+#     <NAME>(RunTimeRaw>: <time> ms
+#
+# and also detailed segment sizes for each dex segment:
+#
+#    <NAME>-Code(CodeSize): <size>
+#    <NAME>-AnnotationSets(CodeSize): <size>
+#    ...
+#
+# Uses the DexSegment Java tool (Gradle target).
+
+from __future__ import print_function
+from glob import glob
+import argparse
+import os
+import re
+import subprocess
+import sys
+import time
+
+import utils
+
+DX_JAR = os.path.join(utils.REPO_ROOT, 'tools', 'linux', 'dx', 'framework',
+    'dx.jar')
+D8_JAR = os.path.join(utils.REPO_ROOT, 'build', 'libs', 'd8.jar')
+FRAMEWORK_JAR = os.path.join('third_party', 'framework',
+    'framework_160115954.jar')
+DEX_SEGMENTS_JAR = os.path.join(utils.REPO_ROOT, 'build', 'libs',
+    'dexsegments.jar')
+DEX_SEGMENTS_RESULT_PATTERN = re.compile('- ([^:]+): ([0-9]+)')
+MIN_SDK_VERSION = '24'
+
+def parse_arguments():
+  parser = argparse.ArgumentParser(
+      description = 'Run D8 or DX on third_party/framework/framework*.jar.'
+          ' Report Golem-compatible CodeSize and RunTimeRaw values.')
+  parser.add_argument('--tool',
+      choices = ['dx', 'd8', 'd8-release'],
+      required = True,
+      help = 'Compiler tool to use.')
+  parser.add_argument('--name',
+      required = True,
+      help = 'Results will be printed using the specified benchmark name (e.g.'
+          ' <NAME>(CodeSize): <bytes>)')
+  return parser.parse_args()
+
+# Return a dictionary: {segment_name -> segments_size}
+def getDexSegmentSizes(dex_files):
+  assert len(dex_files) > 0
+  cmd = ['java', '-jar', DEX_SEGMENTS_JAR]
+  cmd.extend(dex_files)
+  utils.PrintCmd(cmd)
+  output = subprocess.check_output(cmd)
+
+  matches = DEX_SEGMENTS_RESULT_PATTERN.findall(output)
+
+  if matches is None or len(matches) == 0:
+    raise Exception('DexSegments failed to return any output for' \
+        ' these files: {}'.format(dex_files))
+
+  result = {}
+
+  for match in matches:
+    result[match[0]] = int(match[1])
+
+  return result
+
+def Main():
+  args = parse_arguments()
+
+  with utils.TempDir() as temp_dir:
+    if args.tool == 'dx':
+      jar_file = DX_JAR
+      jar_args = ['--output=' + temp_dir, '--multi-dex',
+          '--min-sdk-version=' + MIN_SDK_VERSION, '--dex']
+    else:
+      jar_file = D8_JAR
+      jar_args = ['--output', temp_dir, '--min-sdk-version', MIN_SDK_VERSION]
+      if args.tool == 'd8-release':
+        jar_args.append('--release')
+
+    cmd = ['java', '-jar', jar_file] + jar_args + [FRAMEWORK_JAR]
+
+    utils.PrintCmd(cmd)
+
+    t0 = time.time()
+    subprocess.check_call(cmd)
+    dt = time.time() - t0
+
+    dex_files = [f for f in glob(os.path.join(temp_dir, '*.dex'))]
+    code_size = 0
+    for dex_file in dex_files:
+      code_size += os.path.getsize(dex_file)
+
+    print('{}(RunTimeRaw): {} ms'
+      .format(args.name, 1000.0 * dt))
+
+    print('{}(CodeSize): {}'
+      .format(args.name, code_size))
+
+    for segment_name, size in getDexSegmentSizes(dex_files).items():
+      print('{}-{}(CodeSize): {}'
+          .format(args.name, segment_name, size))
+
+if __name__ == '__main__':
+  sys.exit(Main())