test_framework.py revision 5cf51bb7d718bb7730440dab6ddbff7721497274
1#!/usr/bin/env python
2# Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
3# for details. All rights reserved. Use of this source code is governed by a
4# BSD-style license that can be found in the LICENSE file.
5
6# Run D8 or DX on 'third_party/framework/framework_<version>.jar'.
7# Report Golem-compatible CodeSize and RunTimeRaw values:
8#
9#     <NAME>(CodeSize): <size>
10#     <NAME>(RunTimeRaw>: <time> ms
11#
12# and also detailed segment sizes for each dex segment:
13#
14#    <NAME>-Code(CodeSize): <size>
15#    <NAME>-AnnotationSets(CodeSize): <size>
16#    ...
17#
18# Uses the DexSegment Java tool (Gradle target).
19
20from __future__ import print_function
21from glob import glob
22import argparse
23import os
24import re
25import subprocess
26import sys
27import time
28
29import utils
30
31DX_JAR = os.path.join(utils.REPO_ROOT, 'tools', 'linux', 'dx', 'framework',
32    'dx.jar')
33D8_JAR = os.path.join(utils.REPO_ROOT, 'build', 'libs', 'd8.jar')
34FRAMEWORK_JAR = os.path.join('third_party', 'framework',
35    'framework_160115954.jar')
36DEX_SEGMENTS_JAR = os.path.join(utils.REPO_ROOT, 'build', 'libs',
37    'dexsegments.jar')
38DEX_SEGMENTS_RESULT_PATTERN = re.compile('- ([^:]+): ([0-9]+)')
39MIN_SDK_VERSION = '24'
40
41def parse_arguments():
42  parser = argparse.ArgumentParser(
43      description = 'Run D8 or DX on third_party/framework/framework*.jar.'
44          ' Report Golem-compatible CodeSize and RunTimeRaw values.')
45  parser.add_argument('--tool',
46      choices = ['dx', 'd8', 'd8-release'],
47      required = True,
48      help = 'Compiler tool to use.')
49  parser.add_argument('--name',
50      required = True,
51      help = 'Results will be printed using the specified benchmark name (e.g.'
52          ' <NAME>(CodeSize): <bytes>)')
53  return parser.parse_args()
54
55# Return a dictionary: {segment_name -> segments_size}
56def getDexSegmentSizes(dex_files):
57  assert len(dex_files) > 0
58  cmd = ['java', '-jar', DEX_SEGMENTS_JAR]
59  cmd.extend(dex_files)
60  utils.PrintCmd(cmd)
61  output = subprocess.check_output(cmd)
62
63  matches = DEX_SEGMENTS_RESULT_PATTERN.findall(output)
64
65  if matches is None or len(matches) == 0:
66    raise Exception('DexSegments failed to return any output for' \
67        ' these files: {}'.format(dex_files))
68
69  result = {}
70
71  for match in matches:
72    result[match[0]] = int(match[1])
73
74  return result
75
76def Main():
77  args = parse_arguments()
78
79  with utils.TempDir() as temp_dir:
80    if args.tool == 'dx':
81      jar_file = DX_JAR
82      jar_args = ['--output=' + temp_dir, '--multi-dex',
83          '--min-sdk-version=' + MIN_SDK_VERSION, '--dex']
84    else:
85      jar_file = D8_JAR
86      jar_args = ['--output', temp_dir, '--min-sdk-version', MIN_SDK_VERSION]
87      if args.tool == 'd8-release':
88        jar_args.append('--release')
89
90    cmd = ['java', '-jar', jar_file] + jar_args + [FRAMEWORK_JAR]
91
92    utils.PrintCmd(cmd)
93
94    t0 = time.time()
95    subprocess.check_call(cmd)
96    dt = time.time() - t0
97
98    dex_files = [f for f in glob(os.path.join(temp_dir, '*.dex'))]
99    code_size = 0
100    for dex_file in dex_files:
101      code_size += os.path.getsize(dex_file)
102
103    print('{}(RunTimeRaw): {} ms'
104      .format(args.name, 1000.0 * dt))
105
106    print('{}(CodeSize): {}'
107      .format(args.name, code_size))
108
109    for segment_name, size in getDexSegmentSizes(dex_files).items():
110      print('{}-{}(CodeSize): {}'
111          .format(args.name, segment_name, size))
112
113if __name__ == '__main__':
114  sys.exit(Main())
115