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')
38MIN_SDK_VERSION = '24'
39
40def parse_arguments():
41  parser = argparse.ArgumentParser(
42      description = 'Run D8, DX or Goyt on'
43          ' third_party/framework/framework*.jar.'
44          ' Report Golem-compatible CodeSize and RunTimeRaw values.')
45  parser.add_argument('--tool',
46      choices = ['dx', 'd8', 'd8-release', 'goyt'],
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>-<segment>(CodeSize): <bytes>)')
53  parser.add_argument('--print-memoryuse',
54      help = 'Prints the line \'<NAME>(MemoryUse):' +
55             ' <mem>\' at the end where <mem> is the peak' +
56             ' peak resident set size (VmHWM) in bytes.',
57      default = False,
58      action = 'store_true')
59  return parser.parse_args()
60
61def Main():
62  args = parse_arguments()
63
64  with utils.TempDir() as temp_dir:
65
66    if args.tool in ['dx', 'goyt']:
67      tool_args = ['--dex', '--output=' + temp_dir, '--multi-dex',
68          '--min-sdk-version=' + MIN_SDK_VERSION]
69
70    if args.tool == 'goyt':
71      tool_file = GOYT_EXE
72      tool_args = ['--num-threads=4'] + tool_args
73    elif args.tool == 'dx':
74      tool_file = DX_JAR
75    else:
76      tool_file = D8_JAR
77      tool_args = ['--output', temp_dir, '--min-api', MIN_SDK_VERSION]
78      if args.tool == 'd8-release':
79        tool_args.append('--release')
80
81
82    cmd = []
83
84    track_memory_file = None
85    if args.print_memoryuse:
86      track_memory_file = os.path.join(temp_dir, utils.MEMORY_USE_TMP_FILE)
87      cmd.extend(['tools/track_memory.sh', track_memory_file])
88
89    if tool_file.endswith('.jar'):
90      cmd.extend(['java', '-jar'])
91
92    cmd.extend([tool_file] + tool_args + [FRAMEWORK_JAR])
93
94    utils.PrintCmd(cmd)
95
96    t0 = time.time()
97    subprocess.check_call(cmd)
98    dt = time.time() - t0
99
100    if args.print_memoryuse:
101      print('{}(MemoryUse): {}'
102          .format(args.name, utils.grep_memoryuse(track_memory_file)))
103
104    dex_files = [f for f in glob(os.path.join(temp_dir, '*.dex'))]
105    code_size = 0
106    for dex_file in dex_files:
107      code_size += os.path.getsize(dex_file)
108
109    print('{}-Total(RunTimeRaw): {} ms'
110      .format(args.name, 1000.0 * dt))
111
112    print('{}-Total(CodeSize): {}'
113      .format(args.name, code_size))
114
115    utils.print_dexsegments(args.name, dex_files)
116
117if __name__ == '__main__':
118  sys.exit(Main())
119