test_framework.py revision fc34cd80f0abbae2372f5d8203363ecc2cd58f08
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, DX or Goyt on 'third_party/framework/framework_<version>.jar'.
7# Report Golem-compatible CodeSize and RunTimeRaw values:
8#
9#     <NAME>-Total(CodeSize): <size>
10#     <NAME>-Total(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')
34GOYT_EXE = os.path.join('third_party', 'goyt',
35    'goyt_160525751')
36FRAMEWORK_JAR = os.path.join('third_party', 'framework',
37    'framework_160115954.jar')
38DEX_SEGMENTS_JAR = os.path.join(utils.REPO_ROOT, 'build', 'libs',
39    'dexsegments.jar')
40DEX_SEGMENTS_RESULT_PATTERN = re.compile('- ([^:]+): ([0-9]+)')
41MIN_SDK_VERSION = '24'
42
43def parse_arguments():
44  parser = argparse.ArgumentParser(
45      description = 'Run D8, DX or Goyt on'
46          ' third_party/framework/framework*.jar.'
47          ' Report Golem-compatible CodeSize and RunTimeRaw values.')
48  parser.add_argument('--tool',
49      choices = ['dx', 'd8', 'd8-release', 'goyt'],
50      required = True,
51      help = 'Compiler tool to use.')
52  parser.add_argument('--name',
53      required = True,
54      help = 'Results will be printed using the specified benchmark name (e.g.'
55          ' <NAME>-<segment>(CodeSize): <bytes>)')
56  parser.add_argument('--print-memoryuse',
57      help = 'Prints the line \'<NAME>(MemoryUse):' +
58             ' <mem>\' at the end where <mem> is the peak' +
59             ' peak resident set size (VmHWM) in bytes.',
60      default = False,
61      action = 'store_true')
62  return parser.parse_args()
63
64# Return a dictionary: {segment_name -> segments_size}
65def getDexSegmentSizes(dex_files):
66  assert len(dex_files) > 0
67  cmd = ['java', '-jar', DEX_SEGMENTS_JAR]
68  cmd.extend(dex_files)
69  utils.PrintCmd(cmd)
70  output = subprocess.check_output(cmd)
71
72  matches = DEX_SEGMENTS_RESULT_PATTERN.findall(output)
73
74  if matches is None or len(matches) == 0:
75    raise Exception('DexSegments failed to return any output for' \
76        ' these files: {}'.format(dex_files))
77
78  result = {}
79
80  for match in matches:
81    result[match[0]] = int(match[1])
82
83  return result
84
85def Main():
86  args = parse_arguments()
87
88  with utils.TempDir() as temp_dir:
89
90    if args.tool in ['dx', 'goyt']:
91      tool_args = ['--dex', '--output=' + temp_dir, '--multi-dex',
92          '--min-sdk-version=' + MIN_SDK_VERSION]
93
94    if args.tool == 'goyt':
95      tool_file = GOYT_EXE
96      tool_args = ['--num-threads=4'] + tool_args
97    elif args.tool == 'dx':
98      tool_file = DX_JAR
99    else:
100      tool_file = D8_JAR
101      tool_args = ['--output', temp_dir, '--min-api', MIN_SDK_VERSION]
102      if args.tool == 'd8-release':
103        tool_args.append('--release')
104
105
106    cmd = []
107
108    track_memory_file = None
109    if args.print_memoryuse:
110      track_memory_file = os.path.join(temp_dir, utils.MEMORY_USE_TMP_FILE)
111      cmd.extend(['tools/track_memory.sh', track_memory_file])
112
113    if tool_file.endswith('.jar'):
114      cmd.extend(['java', '-jar'])
115
116    cmd.extend([tool_file] + tool_args + [FRAMEWORK_JAR])
117
118    utils.PrintCmd(cmd)
119
120    t0 = time.time()
121    subprocess.check_call(cmd)
122    dt = time.time() - t0
123
124    if args.print_memoryuse:
125      print('{}(MemoryUse): {}'
126          .format(args.name, utils.grep_memoryuse(track_memory_file)))
127
128    dex_files = [f for f in glob(os.path.join(temp_dir, '*.dex'))]
129    code_size = 0
130    for dex_file in dex_files:
131      code_size += os.path.getsize(dex_file)
132
133    print('{}-Total(RunTimeRaw): {} ms'
134      .format(args.name, 1000.0 * dt))
135
136    print('{}-Total(CodeSize): {}'
137      .format(args.name, code_size))
138
139    for segment_name, size in getDexSegmentSizes(dex_files).items():
140      print('{}-{}(CodeSize): {}'
141          .format(args.name, segment_name, size))
142
143if __name__ == '__main__':
144  sys.exit(Main())
145