[go: nahoru, domu]

blob: 6956a800f8e4c0676ec5acf08e9a05c3416b2e6e [file] [log] [blame]
Yuke Liaob3a683e2020-04-29 01:43:591#!/usr/bin/env python
Avi Drissmandfd880852022-09-15 20:11:092# Copyright 2020 The Chromium Authors
Yuke Liaob3a683e2020-04-29 01:43:593# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5"""Downloads pgo profiles for optimizing official Chrome.
6
7This script has the following responsibilities:
81. Download a requested profile if necessary.
92. Return a path to the current profile to feed to the build system.
103. Removed stale profiles (2 days) to save disk spaces because profiles are
11 large (~1GB) and updated frequently (~4 times a day).
12"""
13
14from __future__ import print_function
15
16import argparse
17import os
18import sys
19import time
20
21_SRC_ROOT = os.path.abspath(
22 os.path.join(os.path.dirname(__file__), os.path.pardir))
23sys.path.append(os.path.join(_SRC_ROOT, 'third_party', 'depot_tools'))
24import download_from_google_storage
25
26sys.path.append(os.path.join(_SRC_ROOT, 'build'))
27import gn_helpers
28
29# Absolute path to the directory that stores pgo related state files, which
30# specifcies which profile to update and use.
31_PGO_DIR = os.path.join(_SRC_ROOT, 'chrome', 'build')
32
33# Absolute path to the directory that stores pgo profiles.
34_PGO_PROFILE_DIR = os.path.join(_PGO_DIR, 'pgo_profiles')
35
36
37def _read_profile_name(target):
38 """Read profile name given a target.
39
40 Args:
41 target(str): The target name, such as win32, mac.
42
43 Returns:
44 Name of the profile to update and use, such as:
45 chrome-win32-master-67ad3c89d2017131cc9ce664a1580315517550d1.profdata.
46 """
47 state_file = os.path.join(_PGO_DIR, '%s.pgo.txt' % target)
48 with open(state_file, 'r') as f:
49 profile_name = f.read().strip()
50
Yuke Liaod13db632020-05-03 23:43:2951 return profile_name
Yuke Liaob3a683e2020-04-29 01:43:5952
53
54def _remove_unused_profiles(current_profile_name):
55 """Removes unused profiles, except the current one, to save disk space."""
56 days = 2
57 expiration_duration = 60 * 60 * 24 * days
58 for f in os.listdir(_PGO_PROFILE_DIR):
59 if f == current_profile_name:
60 continue
61
62 p = os.path.join(_PGO_PROFILE_DIR, f)
63 age = time.time() - os.path.getmtime(p)
64 if age > expiration_duration:
65 print('Removing profile %s as it hasn\'t been used in the past %d days' %
66 (p, days))
67 os.remove(p)
68
69
70def _update(args):
71 """Update profile if necessary according to the state file.
72
73 Args:
74 args(dict): A dict of cmd arguments, such as target and gs_url_base.
75
76 Raises:
77 RuntimeError: If failed to download profiles from gcs.
78 """
79 profile_name = _read_profile_name(args.target)
80 profile_path = os.path.join(_PGO_PROFILE_DIR, profile_name)
81 if os.path.isfile(profile_path):
82 os.utime(profile_path, None)
83 return
84
85 gsutil = download_from_google_storage.Gsutil(
86 download_from_google_storage.GSUTIL_DEFAULT_PATH)
87 gs_path = 'gs://' + args.gs_url_base.strip('/') + '/' + profile_name
88 code = gsutil.call('cp', gs_path, profile_path)
89 if code != 0:
90 raise RuntimeError('gsutil failed to download "%s"' % gs_path)
91
92 _remove_unused_profiles(profile_name)
93
94
95def _get_profile_path(args):
96 """Returns an absolute path to the current profile.
97
98 Args:
99 args(dict): A dict of cmd arguments, such as target and gs_url_base.
100
101 Raises:
102 RuntimeError: If the current profile is missing.
103 """
104 profile_path = os.path.join(_PGO_PROFILE_DIR, _read_profile_name(args.target))
105 if not os.path.isfile(profile_path):
Yuke Liaoe1334dbe2020-05-01 20:07:18106 raise RuntimeError(
107 'requested profile "%s" doesn\'t exist, please make sure '
Sebastien Marchand3791a222020-06-19 22:41:47108 '"checkout_pgo_profiles" is set to True in the "custom_vars" section '
109 'of your .gclient file, e.g.: \n'
110 'solutions = [ \n'
111 ' { \n'
112 ' "name": "src", \n'
113 ' # ... \n'
114 ' "custom_vars": { \n'
115 ' "checkout_pgo_profiles": True, \n'
116 ' }, \n'
117 ' }, \n'
118 '], \n'
119 'and then run "gclient runhooks" to download it. You can also simply '
120 'disable the PGO optimizations by setting |chrome_pgo_phase = 0| in '
121 'your GN arguments.'%
Yuke Liaoe1334dbe2020-05-01 20:07:18122 profile_path)
Yuke Liaob3a683e2020-04-29 01:43:59123
124 os.utime(profile_path, None)
125 profile_path.rstrip(os.sep)
126 print(gn_helpers.ToGNString(profile_path))
127
128
129def main():
130 parser = argparse.ArgumentParser(
131 description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
132 parser.add_argument(
133 '--target',
134 required=True,
Jeff Yoon0d2216f2023-04-03 22:11:49135 choices=[
Kuan Huangee676ba2023-08-17 23:18:42136 'win-arm64',
Jeff Yoon158345e2023-04-18 20:37:29137 'win32',
138 'win64',
139 'mac',
140 'mac-arm',
141 'linux',
142 'lacros64',
143 'lacros-arm',
144 'lacros-arm64',
Samuel Huang9e1b4f72023-07-31 14:54:15145 'android-arm32',
146 'android-arm64',
Jeff Yoon0d2216f2023-04-03 22:11:49147 ],
Yuke Liaob3a683e2020-04-29 01:43:59148 help='Identifier of a specific target platform + architecture.')
149 subparsers = parser.add_subparsers()
150
151 parser_update = subparsers.add_parser('update')
152 parser_update.add_argument(
153 '--gs-url-base',
154 required=True,
155 help='The base GS URL to search for the profile.')
156 parser_update.set_defaults(func=_update)
157
158 parser_get_profile_path = subparsers.add_parser('get_profile_path')
159 parser_get_profile_path.set_defaults(func=_get_profile_path)
160
161 args = parser.parse_args()
162 return args.func(args)
163
164
165if __name__ == '__main__':
166 sys.exit(main())