blob: eec95087ee1d492e6d4381c731a44ffa9fc11f04 [file] [log] [blame]
Florian Mayerc8aa81c2021-04-19 15:16:15 +01001#!/usr/bin/env python3
Florian Mayer801349e2018-11-29 10:15:25 +00002# Copyright (C) 2017 The Android Open Source Project
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
Primiano Tucci11d94e12022-08-02 17:44:33 +010016# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
17# DO NOT EDIT. Auto-generated by tools/gen_amalgamated_python_tools
18# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
19
Florian Mayer801349e2018-11-29 10:15:25 +000020from __future__ import absolute_import
21from __future__ import division
22from __future__ import print_function
23
24import argparse
25import atexit
Florian Mayer801349e2018-11-29 10:15:25 +000026import os
Florian Mayer92c80d82019-09-25 14:00:01 +010027import shutil
Florian Mayer801349e2018-11-29 10:15:25 +000028import signal
29import subprocess
30import sys
31import tempfile
32import time
Florian Mayer15866392020-04-02 11:52:16 +020033import uuid
Florian Mayer801349e2018-11-29 10:15:25 +000034
Primiano Tucci11d94e12022-08-02 17:44:33 +010035
36# ----- Amalgamator: begin of python/perfetto/prebuilts/manifests/traceconv.py
Daniele Di Proiettoe41196d2024-04-10 10:00:00 +000037# This file has been generated by: tools/roll-prebuilts v44.0
Primiano Tucci11d94e12022-08-02 17:44:33 +010038TRACECONV_MANIFEST = [{
39 'arch':
40 'mac-amd64',
41 'file_name':
42 'traceconv',
43 'file_size':
Daniele Di Proiettoe41196d2024-04-10 10:00:00 +000044 8069808,
Primiano Tucci11d94e12022-08-02 17:44:33 +010045 'url':
Daniele Di Proiettoe41196d2024-04-10 10:00:00 +000046 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/mac-amd64/traceconv',
Primiano Tucci11d94e12022-08-02 17:44:33 +010047 'sha256':
Daniele Di Proiettoe41196d2024-04-10 10:00:00 +000048 '7d9c0421235c083932408a5a716372dfddc3a87828b2b3b7e30f8d3aa1c5bf43',
Primiano Tucci11d94e12022-08-02 17:44:33 +010049 'platform':
50 'darwin',
51 'machine': ['x86_64']
52}, {
53 'arch':
54 'mac-arm64',
55 'file_name':
56 'traceconv',
57 'file_size':
Daniele Di Proiettoe41196d2024-04-10 10:00:00 +000058 7529704,
Primiano Tucci11d94e12022-08-02 17:44:33 +010059 'url':
Daniele Di Proiettoe41196d2024-04-10 10:00:00 +000060 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/mac-arm64/traceconv',
Primiano Tucci11d94e12022-08-02 17:44:33 +010061 'sha256':
Daniele Di Proiettoe41196d2024-04-10 10:00:00 +000062 'bffadacd2a6e44a9f5c7b0beb48f3f5d568433fd9d425cdee5342e7f3c112cbb',
Primiano Tucci11d94e12022-08-02 17:44:33 +010063 'platform':
64 'darwin',
65 'machine': ['arm64']
66}, {
67 'arch':
68 'linux-amd64',
69 'file_name':
70 'traceconv',
71 'file_size':
Daniele Di Proiettoe41196d2024-04-10 10:00:00 +000072 8152216,
Primiano Tucci11d94e12022-08-02 17:44:33 +010073 'url':
Daniele Di Proiettoe41196d2024-04-10 10:00:00 +000074 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/linux-amd64/traceconv',
Primiano Tucci11d94e12022-08-02 17:44:33 +010075 'sha256':
Daniele Di Proiettoe41196d2024-04-10 10:00:00 +000076 'b1815e29aabb51deff0c68e3e690c96aedfea0796a0292d5f177815d33584995',
Primiano Tucci11d94e12022-08-02 17:44:33 +010077 'platform':
78 'linux',
79 'machine': ['x86_64']
80}, {
81 'arch':
82 'linux-arm',
83 'file_name':
84 'traceconv',
85 'file_size':
Daniele Di Proiettoe41196d2024-04-10 10:00:00 +000086 6132076,
Primiano Tucci11d94e12022-08-02 17:44:33 +010087 'url':
Daniele Di Proiettoe41196d2024-04-10 10:00:00 +000088 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/linux-arm/traceconv',
Primiano Tucci11d94e12022-08-02 17:44:33 +010089 'sha256':
Daniele Di Proiettoe41196d2024-04-10 10:00:00 +000090 '2b391081ce9ce45d843584816bc11ba7383b634c88ffa75c7dc927a9632e6d28',
Primiano Tucci11d94e12022-08-02 17:44:33 +010091 'platform':
92 'linux',
93 'machine': ['armv6l', 'armv7l', 'armv8l']
94}, {
95 'arch':
96 'linux-arm64',
97 'file_name':
98 'traceconv',
99 'file_size':
Daniele Di Proiettoe41196d2024-04-10 10:00:00 +0000100 7862696,
Primiano Tucci11d94e12022-08-02 17:44:33 +0100101 'url':
Daniele Di Proiettoe41196d2024-04-10 10:00:00 +0000102 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/linux-arm64/traceconv',
Primiano Tucci11d94e12022-08-02 17:44:33 +0100103 'sha256':
Daniele Di Proiettoe41196d2024-04-10 10:00:00 +0000104 'd10a598fb6c14926ceb3afb0fc9841a4924c2fedadf9ef981609781ecb8b338b',
Primiano Tucci11d94e12022-08-02 17:44:33 +0100105 'platform':
106 'linux',
107 'machine': ['aarch64']
108}, {
109 'arch':
110 'android-arm',
111 'file_name':
112 'traceconv',
113 'file_size':
Daniele Di Proiettoe41196d2024-04-10 10:00:00 +0000114 6131288,
Primiano Tucci11d94e12022-08-02 17:44:33 +0100115 'url':
Daniele Di Proiettoe41196d2024-04-10 10:00:00 +0000116 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/android-arm/traceconv',
Primiano Tucci11d94e12022-08-02 17:44:33 +0100117 'sha256':
Daniele Di Proiettoe41196d2024-04-10 10:00:00 +0000118 '3cf391f42bb51e47159b2236b1171cd1bd4461f3e4576b00100f590cf7ff8b2b'
Primiano Tucci11d94e12022-08-02 17:44:33 +0100119}, {
120 'arch':
121 'android-arm64',
122 'file_name':
123 'traceconv',
124 'file_size':
Daniele Di Proiettoe41196d2024-04-10 10:00:00 +0000125 7798968,
Primiano Tucci11d94e12022-08-02 17:44:33 +0100126 'url':
Daniele Di Proiettoe41196d2024-04-10 10:00:00 +0000127 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/android-arm64/traceconv',
Primiano Tucci11d94e12022-08-02 17:44:33 +0100128 'sha256':
Daniele Di Proiettoe41196d2024-04-10 10:00:00 +0000129 '1b17a740ba86a5e218b69dd981d739173515777ee761f3723446f6e400e9367e'
Primiano Tucci11d94e12022-08-02 17:44:33 +0100130}, {
131 'arch':
132 'android-x86',
133 'file_name':
134 'traceconv',
135 'file_size':
Daniele Di Proiettoe41196d2024-04-10 10:00:00 +0000136 8464080,
Primiano Tucci11d94e12022-08-02 17:44:33 +0100137 'url':
Daniele Di Proiettoe41196d2024-04-10 10:00:00 +0000138 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/android-x86/traceconv',
Primiano Tucci11d94e12022-08-02 17:44:33 +0100139 'sha256':
Daniele Di Proiettoe41196d2024-04-10 10:00:00 +0000140 '2dc045a79276e62f71cf40c1e8ee433125785ce32a223ce4c9e5871cacc3940e'
Primiano Tucci11d94e12022-08-02 17:44:33 +0100141}, {
142 'arch':
143 'android-x64',
144 'file_name':
145 'traceconv',
146 'file_size':
Daniele Di Proiettoe41196d2024-04-10 10:00:00 +0000147 8025896,
Primiano Tucci11d94e12022-08-02 17:44:33 +0100148 'url':
Daniele Di Proiettoe41196d2024-04-10 10:00:00 +0000149 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/android-x64/traceconv',
Primiano Tucci11d94e12022-08-02 17:44:33 +0100150 'sha256':
Daniele Di Proiettoe41196d2024-04-10 10:00:00 +0000151 '03db509df8e3816b4c4d78d187d42794b37c3d2c830d85feae0f17a5b581ee53'
Primiano Tucci11d94e12022-08-02 17:44:33 +0100152}, {
153 'arch':
154 'windows-amd64',
155 'file_name':
156 'traceconv.exe',
157 'file_size':
Daniele Di Proiettoe41196d2024-04-10 10:00:00 +0000158 7920128,
Primiano Tucci11d94e12022-08-02 17:44:33 +0100159 'url':
Daniele Di Proiettoe41196d2024-04-10 10:00:00 +0000160 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/windows-amd64/traceconv.exe',
Primiano Tucci11d94e12022-08-02 17:44:33 +0100161 'sha256':
Daniele Di Proiettoe41196d2024-04-10 10:00:00 +0000162 '97b66259d385a5bd482ebb5a21535b67e3836fb0cf7c971bb36d5f5ea00774bd',
Primiano Tucci11d94e12022-08-02 17:44:33 +0100163 'platform':
164 'win32',
165 'machine': ['amd64']
166}]
167
168# ----- Amalgamator: end of python/perfetto/prebuilts/manifests/traceconv.py
169
170# ----- Amalgamator: begin of python/perfetto/prebuilts/perfetto_prebuilts.py
171# Copyright (C) 2021 The Android Open Source Project
172#
173# Licensed under the Apache License, Version 2.0 (the "License");
174# you may not use this file except in compliance with the License.
175# You may obtain a copy of the License at
176#
177# http://www.apache.org/licenses/LICENSE-2.0
178#
179# Unless required by applicable law or agreed to in writing, software
180# distributed under the License is distributed on an "AS IS" BASIS,
181# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
182# See the License for the specific language governing permissions and
183# limitations under the License.
184"""
185Functions to fetch pre-pinned Perfetto prebuilts.
186
187This function is used in different places:
188- Into the //tools/{trace_processor, traceconv} scripts, which are just plain
189 wrappers around executables.
190- Into the //tools/{heap_profiler, record_android_trace} scripts, which contain
191 some other hand-written python code.
192
193The manifest argument looks as follows:
194TRACECONV_MANIFEST = [
195 {
196 'arch': 'mac-amd64',
197 'file_name': 'traceconv',
198 'file_size': 7087080,
199 'url': https://commondatastorage.googleapis.com/.../trace_to_text',
200 'sha256': 7d957c005b0dc130f5bd855d6cec27e060d38841b320d04840afc569f9087490',
201 'platform': 'darwin',
202 'machine': 'x86_64'
203 },
204 ...
205]
206
207The intended usage is:
208
209 from perfetto.prebuilts.manifests.traceconv import TRACECONV_MANIFEST
210 bin_path = get_perfetto_prebuilt(TRACECONV_MANIFEST)
211 subprocess.call(bin_path, ...)
212"""
213
214import hashlib
215import os
216import platform
217import subprocess
218import sys
Lalit Maganti7edd1792024-04-28 20:47:25 +0100219import threading
220
221DOWNLOAD_LOCK = threading.Lock()
Primiano Tucci11d94e12022-08-02 17:44:33 +0100222
223
224def download_or_get_cached(file_name, url, sha256):
225 """ Downloads a prebuilt or returns a cached version
226
227 The first time this is invoked, it downloads the |url| and caches it into
Joseph Koshy5efb8a12022-10-19 12:39:29 +0100228 ~/.local/share/perfetto/prebuilts/$tool_name. On subsequent invocations it
229 just runs the cached version.
Primiano Tucci11d94e12022-08-02 17:44:33 +0100230 """
231 dir = os.path.join(
232 os.path.expanduser('~'), '.local', 'share', 'perfetto', 'prebuilts')
233 os.makedirs(dir, exist_ok=True)
234 bin_path = os.path.join(dir, file_name)
235 sha256_path = os.path.join(dir, file_name + '.sha256')
236 needs_download = True
237
Lalit Maganti7edd1792024-04-28 20:47:25 +0100238 try:
239 # In BatchTraceProcessor, many threads can be trying to execute the below
240 # code in parallel. For this reason, protect the whole operation with a
241 # lock.
242 DOWNLOAD_LOCK.acquire()
Primiano Tucci11d94e12022-08-02 17:44:33 +0100243
Lalit Maganti7edd1792024-04-28 20:47:25 +0100244 # Avoid recomputing the SHA-256 on each invocation. The SHA-256 of the last
245 # download is cached into file_name.sha256, just check if that matches.
246 if os.path.exists(bin_path) and os.path.exists(sha256_path):
247 with open(sha256_path, 'rb') as f:
248 digest = f.read().decode()
249 if digest == sha256:
250 needs_download = False
251
252 if needs_download:
253 # Either the filed doesn't exist or the SHA256 doesn't match.
254 tmp_path = bin_path + '.tmp'
255 print('Downloading ' + url)
256 subprocess.check_call(['curl', '-f', '-L', '-#', '-o', tmp_path, url])
257 with open(tmp_path, 'rb') as fd:
258 actual_sha256 = hashlib.sha256(fd.read()).hexdigest()
259 if actual_sha256 != sha256:
260 raise Exception('Checksum mismatch for %s (actual: %s, expected: %s)' %
261 (url, actual_sha256, sha256))
262 os.chmod(tmp_path, 0o755)
263 os.replace(tmp_path, bin_path)
264 with open(sha256_path, 'w') as f:
265 f.write(sha256)
266 finally:
267 DOWNLOAD_LOCK.release()
Primiano Tucci11d94e12022-08-02 17:44:33 +0100268 return bin_path
269
270
271def get_perfetto_prebuilt(manifest, soft_fail=False, arch=None):
272 """ Downloads the prebuilt, if necessary, and returns its path on disk. """
273 plat = sys.platform.lower()
274 machine = platform.machine().lower()
275 manifest_entry = None
276 for entry in manifest:
277 # If the caller overrides the arch, just match that (for Android prebuilts).
278 if arch:
279 if entry.get('arch') == arch:
280 manifest_entry = entry
281 break
282 continue
283 # Otherwise guess the local machine arch.
284 if entry.get('platform') == plat and machine in entry.get('machine', []):
285 manifest_entry = entry
286 break
287 if manifest_entry is None:
288 if soft_fail:
289 return None
290 raise Exception(
291 ('No prebuilts available for %s-%s\n' % (plat, machine)) +
292 'See https://perfetto.dev/docs/contributing/build-instructions')
293
294 return download_or_get_cached(
295 file_name=manifest_entry['file_name'],
296 url=manifest_entry['url'],
297 sha256=manifest_entry['sha256'])
298
299
300def run_perfetto_prebuilt(manifest):
301 bin_path = get_perfetto_prebuilt(manifest)
302 if sys.platform.lower() == 'win32':
303 sys.exit(subprocess.check_call([bin_path, *sys.argv[1:]]))
304 os.execv(bin_path, [bin_path] + sys.argv[1:])
305
306# ----- Amalgamator: end of python/perfetto/prebuilts/perfetto_prebuilts.py
307
Florian Mayerbd0a62a2019-04-10 11:09:21 +0100308NULL = open(os.devnull)
309NOOUT = {
Primiano Tucci834fdc72019-10-04 11:33:44 +0100310 'stdout': NULL,
311 'stderr': NULL,
Florian Mayerbd0a62a2019-04-10 11:09:21 +0100312}
313
Florian Mayer2007d5c2020-09-08 15:45:44 +0100314UUID = str(uuid.uuid4())[-6:]
Florian Mayerbd0a62a2019-04-10 11:09:21 +0100315
Primiano Tucci834fdc72019-10-04 11:33:44 +0100316PACKAGES_LIST_CFG = '''data_sources {
Florian Mayerc8b28692019-05-16 17:03:21 +0100317 config {
Florian Mayerfe4361d2019-05-14 11:54:00 +0100318 name: "android.packages_list"
Florian Mayerc8b28692019-05-16 17:03:21 +0100319 }
320}
Florian Mayerfe4361d2019-05-14 11:54:00 +0100321'''
322
Florian Mayera8ff9032020-03-04 11:31:48 -0800323CFG_INDENT = ' '
Primiano Tucci834fdc72019-10-04 11:33:44 +0100324CFG = '''buffers {{
Florian Mayer2214c2e2021-02-03 16:54:00 +0000325 size_kb: 63488
Florian Mayer801349e2018-11-29 10:15:25 +0000326}}
327
328data_sources {{
329 config {{
330 name: "android.heapprofd"
331 heapprofd_config {{
Florian Mayer91b3c6d2019-04-10 13:44:37 -0700332 shmem_size_bytes: {shmem_size}
Florian Mayer801349e2018-11-29 10:15:25 +0000333 sampling_interval_bytes: {interval}
334{target_cfg}
Florian Mayer801349e2018-11-29 10:15:25 +0000335 }}
336 }}
337}}
338
339duration_ms: {duration}
Florian Mayer2aab3162019-05-03 16:02:30 +0100340write_into_file: true
Florian Mayer82610462019-04-16 10:26:07 +0100341flush_timeout_ms: 30000
Florian Mayer96f607b2020-01-14 12:57:41 +0000342flush_period_ms: 604800000
Florian Mayer801349e2018-11-29 10:15:25 +0000343'''
344
Florian Mayer96f607b2020-01-14 12:57:41 +0000345# flush_period_ms of 1 week to suppress trace_processor_shell warning.
346
Florian Mayera8312c72019-01-31 13:50:22 +0000347CONTINUOUS_DUMP = """
348 continuous_dump_config {{
349 dump_phase_ms: 0
350 dump_interval_ms: {dump_interval}
351 }}
352"""
353
Florian Mayer2007d5c2020-09-08 15:45:44 +0100354PROFILE_LOCAL_PATH = os.path.join(tempfile.gettempdir(), UUID)
Florian Mayer15866392020-04-02 11:52:16 +0200355
Florian Mayer801349e2018-11-29 10:15:25 +0000356IS_INTERRUPTED = False
Primiano Tucci834fdc72019-10-04 11:33:44 +0100357
Primiano Tuccid3e40bd2021-08-03 10:52:39 +0100358
Florian Mayer801349e2018-11-29 10:15:25 +0000359def sigint_handler(sig, frame):
360 global IS_INTERRUPTED
361 IS_INTERRUPTED = True
362
363
Florian Mayer96f607b2020-01-14 12:57:41 +0000364def print_no_profile_error():
365 print("No profiles generated", file=sys.stderr)
366 print(
Primiano Tuccid3e40bd2021-08-03 10:52:39 +0100367 "If this is unexpected, check "
368 "https://perfetto.dev/docs/data-sources/native-heap-profiler#troubleshooting.",
369 file=sys.stderr)
370
Florian Mayer96f607b2020-01-14 12:57:41 +0000371
Florian Mayerc4de3912020-11-23 14:11:43 +0000372def known_issues_url(number):
373 return ('https://perfetto.dev/docs/data-sources/native-heap-profiler'
374 '#known-issues-android{}'.format(number))
375
Primiano Tuccid3e40bd2021-08-03 10:52:39 +0100376
Florian Mayerc4de3912020-11-23 14:11:43 +0000377KNOWN_ISSUES = {
Primiano Tuccid3e40bd2021-08-03 10:52:39 +0100378 '10': known_issues_url(10),
379 'Q': known_issues_url(10),
380 '11': known_issues_url(11),
381 'R': known_issues_url(11),
Florian Mayerc4de3912020-11-23 14:11:43 +0000382}
383
Primiano Tuccid3e40bd2021-08-03 10:52:39 +0100384
Florian Mayerc4de3912020-11-23 14:11:43 +0000385def maybe_known_issues():
386 release_or_codename = subprocess.check_output(
Primiano Tuccid3e40bd2021-08-03 10:52:39 +0100387 ['adb', 'shell', 'getprop',
388 'ro.build.version.release_or_codename']).decode('utf-8').strip()
Florian Mayerc4de3912020-11-23 14:11:43 +0000389 return KNOWN_ISSUES.get(release_or_codename, None)
390
Primiano Tuccid3e40bd2021-08-03 10:52:39 +0100391
Florian Mayer9a904742020-04-28 18:40:52 +0200392SDK = {
393 'R': 30,
394}
395
Primiano Tuccid3e40bd2021-08-03 10:52:39 +0100396
Florian Mayer9a904742020-04-28 18:40:52 +0200397def release_or_newer(release):
Primiano Tuccid3e40bd2021-08-03 10:52:39 +0100398 sdk = int(
399 subprocess.check_output(
400 ['adb', 'shell', 'getprop',
401 'ro.system.build.version.sdk']).decode('utf-8').strip())
Florian Mayer9a904742020-04-28 18:40:52 +0200402 if sdk >= SDK[release]:
403 return True
404 codename = subprocess.check_output(
Primiano Tuccid3e40bd2021-08-03 10:52:39 +0100405 ['adb', 'shell', 'getprop',
406 'ro.build.version.codename']).decode('utf-8').strip()
Florian Mayer9a904742020-04-28 18:40:52 +0200407 return codename == release
408
Primiano Tuccid3e40bd2021-08-03 10:52:39 +0100409
Florian Mayerbe1e4252021-05-26 15:49:21 +0100410ORDER = ['-n', '-p', '-i', '-o']
411
Primiano Tuccid3e40bd2021-08-03 10:52:39 +0100412
Florian Mayerbe1e4252021-05-26 15:49:21 +0100413def arg_order(action):
414 result = len(ORDER)
415 for opt in action.option_strings:
416 if opt in ORDER:
417 result = min(ORDER.index(opt), result)
418 return result, action.option_strings[0].strip('-')
419
Primiano Tuccid3e40bd2021-08-03 10:52:39 +0100420
Florian Mayerbe1e4252021-05-26 15:49:21 +0100421def print_options(parser):
422 for action in sorted(parser._actions, key=arg_order):
423 if action.help is argparse.SUPPRESS:
424 continue
425 opts = ', '.join('`' + x + '`' for x in action.option_strings)
Primiano Tuccid3e40bd2021-08-03 10:52:39 +0100426 metavar = '' if action.metavar is None else ' _' + action.metavar + '_'
Florian Mayerbe1e4252021-05-26 15:49:21 +0100427 print('{}{}'.format(opts, metavar))
428 print(': {}'.format(action.help))
429 print()
430
Primiano Tuccid3e40bd2021-08-03 10:52:39 +0100431
Florian Mayer801349e2018-11-29 10:15:25 +0000432def main(argv):
433 parser = argparse.ArgumentParser()
Primiano Tucci834fdc72019-10-04 11:33:44 +0100434 parser.add_argument(
435 "-i",
436 "--interval",
437 help="Sampling interval. "
438 "Default 4096 (4KiB)",
439 type=int,
440 default=4096)
441 parser.add_argument(
442 "-d",
443 "--duration",
Florian Mayer2ad38612020-08-06 10:35:31 +0100444 help="Duration of profile (ms). 0 to run until interrupted. "
445 "Default: until interrupted by user.",
Primiano Tucci834fdc72019-10-04 11:33:44 +0100446 type=int,
Florian Mayer2ad38612020-08-06 10:35:31 +0100447 default=0)
Florian Mayer19ec17e2020-06-10 16:09:12 +0200448 # This flag is a no-op now. We never start heapprofd explicitly using system
449 # properties.
Primiano Tucci834fdc72019-10-04 11:33:44 +0100450 parser.add_argument(
451 "--no-start", help="Do not start heapprofd.", action='store_true')
452 parser.add_argument(
453 "-p",
454 "--pid",
455 help="Comma-separated list of PIDs to "
456 "profile.",
457 metavar="PIDS")
458 parser.add_argument(
459 "-n",
460 "--name",
461 help="Comma-separated list of process "
462 "names to profile.",
463 metavar="NAMES")
464 parser.add_argument(
465 "-c",
466 "--continuous-dump",
467 help="Dump interval in ms. 0 to disable continuous dump.",
468 type=int,
469 default=0)
470 parser.add_argument(
Florian Mayer39ddaad2020-06-25 19:58:00 +0200471 "--heaps",
472 help="Comma-separated list of heaps to collect, e.g: malloc,art. "
473 "Requires Android 12.",
474 metavar="HEAPS")
Hector Dearman091a54e2020-08-03 11:17:13 +0100475 parser.add_argument(
Florian Mayered4b1c02020-07-28 16:56:30 +0100476 "--all-heaps",
477 action="store_true",
Primiano Tuccid3e40bd2021-08-03 10:52:39 +0100478 help="Collect allocations from all heaps registered by target.")
Florian Mayer39ddaad2020-06-25 19:58:00 +0200479 parser.add_argument(
Florian Mayercad84b72020-11-24 14:26:32 +0000480 "--no-android-tree-symbolization",
481 action="store_true",
482 help="Do not symbolize using currently lunched target in the "
Primiano Tuccid3e40bd2021-08-03 10:52:39 +0100483 "Android tree.")
Florian Mayercad84b72020-11-24 14:26:32 +0000484 parser.add_argument(
Primiano Tucci834fdc72019-10-04 11:33:44 +0100485 "--disable-selinux",
486 action="store_true",
487 help="Disable SELinux enforcement for duration of "
488 "profile.")
489 parser.add_argument(
490 "--no-versions",
491 action="store_true",
492 help="Do not get version information about APKs.")
493 parser.add_argument(
494 "--no-running",
495 action="store_true",
Florian Mayer615fbc92019-12-18 16:29:07 +0000496 help="Do not target already running processes. Requires Android 11.")
Primiano Tucci834fdc72019-10-04 11:33:44 +0100497 parser.add_argument(
498 "--no-startup",
499 action="store_true",
500 help="Do not target processes that start during "
Florian Mayer615fbc92019-12-18 16:29:07 +0000501 "the profile. Requires Android 11.")
Primiano Tucci834fdc72019-10-04 11:33:44 +0100502 parser.add_argument(
503 "--shmem-size",
504 help="Size of buffer between client and "
505 "heapprofd. Default 8MiB. Needs to be a power of two "
506 "multiple of 4096, at least 8192.",
507 type=int,
508 default=8 * 1048576)
509 parser.add_argument(
510 "--block-client",
511 help="When buffer is full, block the "
512 "client to wait for buffer space. Use with caution as "
513 "this can significantly slow down the client. "
514 "This is the default",
515 action="store_true")
516 parser.add_argument(
Florian Mayere17af212019-11-13 10:04:03 +0000517 "--block-client-timeout",
518 help="If --block-client is given, do not block any allocation for "
519 "longer than this timeout (us).",
520 type=int)
521 parser.add_argument(
Primiano Tucci834fdc72019-10-04 11:33:44 +0100522 "--no-block-client",
523 help="When buffer is full, stop the "
524 "profile early.",
525 action="store_true")
526 parser.add_argument(
527 "--idle-allocations",
528 help="Keep track of how many "
529 "bytes were unused since the last dump, per "
530 "callstack",
531 action="store_true")
532 parser.add_argument(
533 "--dump-at-max",
Florian Mayer2fcb7dd2020-04-27 15:26:47 +0200534 help="Dump the maximum memory usage "
Primiano Tucci834fdc72019-10-04 11:33:44 +0100535 "rather than at the time of the dump.",
536 action="store_true")
537 parser.add_argument(
Florian Mayerf9cd8532020-04-21 12:18:10 +0200538 "--disable-fork-teardown",
539 help="Do not tear down client in forks. This can be useful for programs "
540 "that use vfork. Android 11+ only.",
541 action="store_true")
542 parser.add_argument(
Primiano Tucci834fdc72019-10-04 11:33:44 +0100543 "--simpleperf",
544 action="store_true",
545 help="Get simpleperf profile of heapprofd. This is "
546 "only for heapprofd development.")
547 parser.add_argument(
Lalit Maganti9d035022022-06-13 17:40:31 +0100548 "--traceconv-binary", help="Path to local trace to text. For debugging.")
Primiano Tucci834fdc72019-10-04 11:33:44 +0100549 parser.add_argument(
Ryan Savitski4bb2b222022-11-17 18:08:03 +0000550 "--no-annotations",
551 help="Do not suffix the pprof function names with Android ART mode "
552 "annotations such as [jit].",
553 action="store_true")
554 parser.add_argument(
Primiano Tucci834fdc72019-10-04 11:33:44 +0100555 "--print-config",
556 action="store_true",
557 help="Print config instead of running. For debugging.")
Florian Mayere9a55c62020-04-14 16:39:34 +0200558 parser.add_argument(
559 "-o",
560 "--output",
561 help="Output directory.",
562 metavar="DIRECTORY",
563 default=None)
Florian Mayerbe1e4252021-05-26 15:49:21 +0100564 parser.add_argument(
Primiano Tuccid3e40bd2021-08-03 10:52:39 +0100565 "--print-options", action="store_true", help=argparse.SUPPRESS)
Florian Mayer0eee91b2019-05-10 10:36:16 +0100566
Florian Mayer801349e2018-11-29 10:15:25 +0000567 args = parser.parse_args()
Florian Mayerbe1e4252021-05-26 15:49:21 +0100568 if args.print_options:
569 print_options(parser)
570 return 0
Florian Mayer801349e2018-11-29 10:15:25 +0000571 fail = False
Florian Mayerf40dedd2019-07-19 13:08:48 +0100572 if args.block_client and args.no_block_client:
Primiano Tucci834fdc72019-10-04 11:33:44 +0100573 print(
574 "FATAL: Both block-client and no-block-client given.", file=sys.stderr)
Florian Mayerf40dedd2019-07-19 13:08:48 +0100575 fail = True
Florian Mayera774cb72019-04-29 14:20:43 +0100576 if args.pid is None and args.name is None:
577 print("FATAL: Neither PID nor NAME given.", file=sys.stderr)
Florian Mayer801349e2018-11-29 10:15:25 +0000578 fail = True
579 if args.duration is None:
580 print("FATAL: No duration given.", file=sys.stderr)
581 fail = True
582 if args.interval is None:
583 print("FATAL: No interval given.", file=sys.stderr)
584 fail = True
Florian Mayer91b3c6d2019-04-10 13:44:37 -0700585 if args.shmem_size % 4096:
586 print("FATAL: shmem-size is not a multiple of 4096.", file=sys.stderr)
587 fail = True
588 if args.shmem_size < 8192:
589 print("FATAL: shmem-size is less than 8192.", file=sys.stderr)
590 fail = True
591 if args.shmem_size & (args.shmem_size - 1):
592 print("FATAL: shmem-size is not a power of two.", file=sys.stderr)
593 fail = True
Florian Mayer0eee91b2019-05-10 10:36:16 +0100594
Florian Mayer801349e2018-11-29 10:15:25 +0000595 target_cfg = ""
Florian Mayerf40dedd2019-07-19 13:08:48 +0100596 if not args.no_block_client:
Florian Mayer2ad38612020-08-06 10:35:31 +0100597 target_cfg += CFG_INDENT + "block_client: true\n"
Florian Mayere17af212019-11-13 10:04:03 +0000598 if args.block_client_timeout:
Florian Mayer2ad38612020-08-06 10:35:31 +0100599 target_cfg += (
Primiano Tuccid3e40bd2021-08-03 10:52:39 +0100600 CFG_INDENT +
601 "block_client_timeout_us: %s\n" % args.block_client_timeout)
Florian Mayer400e4432019-05-29 11:53:20 +0100602 if args.no_startup:
Florian Mayer2ad38612020-08-06 10:35:31 +0100603 target_cfg += CFG_INDENT + "no_startup: true\n"
Florian Mayer400e4432019-05-29 11:53:20 +0100604 if args.no_running:
Florian Mayer2ad38612020-08-06 10:35:31 +0100605 target_cfg += CFG_INDENT + "no_running: true\n"
Florian Mayer8707d4d2019-07-16 11:17:46 +0100606 if args.dump_at_max:
Florian Mayer2ad38612020-08-06 10:35:31 +0100607 target_cfg += CFG_INDENT + "dump_at_max: true\n"
Florian Mayerf9cd8532020-04-21 12:18:10 +0200608 if args.disable_fork_teardown:
Florian Mayer2ad38612020-08-06 10:35:31 +0100609 target_cfg += CFG_INDENT + "disable_fork_teardown: true\n"
Florian Mayered4b1c02020-07-28 16:56:30 +0100610 if args.all_heaps:
Florian Mayer2ad38612020-08-06 10:35:31 +0100611 target_cfg += CFG_INDENT + "all_heaps: true\n"
Florian Mayer801349e2018-11-29 10:15:25 +0000612 if args.pid:
Florian Mayer0eee91b2019-05-10 10:36:16 +0100613 for pid in args.pid.split(','):
614 try:
615 pid = int(pid)
616 except ValueError:
617 print("FATAL: invalid PID %s" % pid, file=sys.stderr)
618 fail = True
Florian Mayer2ad38612020-08-06 10:35:31 +0100619 target_cfg += CFG_INDENT + 'pid: {}\n'.format(pid)
Florian Mayer801349e2018-11-29 10:15:25 +0000620 if args.name:
Florian Mayer0eee91b2019-05-10 10:36:16 +0100621 for name in args.name.split(','):
Florian Mayer2ad38612020-08-06 10:35:31 +0100622 target_cfg += CFG_INDENT + 'process_cmdline: "{}"\n'.format(name)
Florian Mayer39ddaad2020-06-25 19:58:00 +0200623 if args.heaps:
624 for heap in args.heaps.split(','):
Florian Mayer2ad38612020-08-06 10:35:31 +0100625 target_cfg += CFG_INDENT + 'heaps: "{}"\n'.format(heap)
Florian Mayer801349e2018-11-29 10:15:25 +0000626
Florian Mayer0eee91b2019-05-10 10:36:16 +0100627 if fail:
628 parser.print_help()
629 return 1
630
Hector Dearmana9545e52022-05-17 12:23:25 +0100631 traceconv_binary = args.traceconv_binary
Florian Mayer2ad38612020-08-06 10:35:31 +0100632
633 if args.continuous_dump:
634 target_cfg += CONTINUOUS_DUMP.format(dump_interval=args.continuous_dump)
635 cfg = CFG.format(
636 interval=args.interval,
637 duration=args.duration,
638 target_cfg=target_cfg,
639 shmem_size=args.shmem_size)
640 if not args.no_versions:
641 cfg += PACKAGES_LIST_CFG
642
643 if args.print_config:
644 print(cfg)
645 return 0
646
Hector Dearmana9545e52022-05-17 12:23:25 +0100647 # Do this AFTER print_config so we do not download traceconv only to
Florian Mayer2ad38612020-08-06 10:35:31 +0100648 # print out the config.
Hector Dearmana9545e52022-05-17 12:23:25 +0100649 if traceconv_binary is None:
Primiano Tucci11d94e12022-08-02 17:44:33 +0100650 traceconv_binary = get_perfetto_prebuilt(TRACECONV_MANIFEST, soft_fail=True)
Florian Mayer801349e2018-11-29 10:15:25 +0000651
Florian Mayerc4de3912020-11-23 14:11:43 +0000652 known_issues = maybe_known_issues()
653 if known_issues:
654 print('If you are experiencing problems, please see the known issues for '
655 'your release: {}.'.format(known_issues))
656
Florian Mayer230b9552020-07-10 22:11:24 +0100657 # TODO(fmayer): Maybe feature detect whether we can remove traces instead of
658 # this.
659 uuid_trace = release_or_newer('R')
660 if uuid_trace:
661 profile_device_path = '/data/misc/perfetto-traces/profile-' + UUID
662 else:
Primiano Tuccid3e40bd2021-08-03 10:52:39 +0100663 user = subprocess.check_output(['adb', 'shell',
664 'whoami']).decode('utf-8').strip()
Florian Mayer230b9552020-07-10 22:11:24 +0100665 profile_device_path = '/data/misc/perfetto-traces/profile-' + user
666
667 perfetto_cmd = ('CFG=\'{cfg}\'; echo ${{CFG}} | '
668 'perfetto --txt -c - -o ' + profile_device_path + ' -d')
669
Florian Mayer6ae95262018-12-06 16:10:29 +0000670 if args.disable_selinux:
Christopher Phlipotc7d0d3a2022-09-15 11:34:24 -0700671 enforcing = subprocess.check_output(['adb', 'shell',
672 'getenforce']).decode('utf-8').strip()
Primiano Tucci834fdc72019-10-04 11:33:44 +0100673 atexit.register(
674 subprocess.check_call,
Florian Mayer6ae95262018-12-06 16:10:29 +0000675 ['adb', 'shell', 'su root setenforce %s' % enforcing])
676 subprocess.check_call(['adb', 'shell', 'su root setenforce 0'])
Florian Mayer801349e2018-11-29 10:15:25 +0000677
Florian Mayer2b8a3b22019-05-02 18:35:38 +0100678 if args.simpleperf:
Primiano Tucci834fdc72019-10-04 11:33:44 +0100679 subprocess.check_call([
680 'adb', 'shell', 'mkdir -p /data/local/tmp/heapprofd_profile && '
681 'cd /data/local/tmp/heapprofd_profile &&'
682 '(nohup simpleperf record -g -p $(pidof heapprofd) 2>&1 &) '
683 '> /dev/null'
684 ])
Florian Mayer2b8a3b22019-05-02 18:35:38 +0100685
Florian Mayere9a55c62020-04-14 16:39:34 +0200686 profile_target = PROFILE_LOCAL_PATH
687 if args.output is not None:
688 profile_target = args.output
689 else:
690 os.mkdir(profile_target)
691
692 if not os.path.isdir(profile_target):
Primiano Tuccid3e40bd2021-08-03 10:52:39 +0100693 print(
694 "Output directory {} not found".format(profile_target), file=sys.stderr)
Florian Mayere9a55c62020-04-14 16:39:34 +0200695 return 1
696
697 if os.listdir(profile_target):
Primiano Tuccid3e40bd2021-08-03 10:52:39 +0100698 print(
699 "Output directory {} not empty".format(profile_target), file=sys.stderr)
Florian Mayere9a55c62020-04-14 16:39:34 +0200700 return 1
701
Florian Mayer801349e2018-11-29 10:15:25 +0000702 perfetto_pid = subprocess.check_output(
Primiano Tuccid3e40bd2021-08-03 10:52:39 +0100703 ['adb', 'exec-out', perfetto_cmd.format(cfg=cfg)]).strip()
Florian Mayer35647422019-03-07 16:28:10 +0000704 try:
Florian Mayer0bc32522020-04-28 16:35:55 +0200705 perfetto_pid = int(perfetto_pid.strip())
Florian Mayer35647422019-03-07 16:28:10 +0000706 except ValueError:
Primiano Tucci834fdc72019-10-04 11:33:44 +0100707 print("Failed to invoke perfetto: {}".format(perfetto_pid), file=sys.stderr)
Florian Mayer35647422019-03-07 16:28:10 +0000708 return 1
Florian Mayer801349e2018-11-29 10:15:25 +0000709
710 old_handler = signal.signal(signal.SIGINT, sigint_handler)
711 print("Profiling active. Press Ctrl+C to terminate.")
Florian Mayerbd0a62a2019-04-10 11:09:21 +0100712 print("You may disconnect your device.")
Florian Mayer96f607b2020-01-14 12:57:41 +0000713 print()
Florian Mayer801349e2018-11-29 10:15:25 +0000714 exists = True
Florian Mayerbd0a62a2019-04-10 11:09:21 +0100715 device_connected = True
716 while not device_connected or (exists and not IS_INTERRUPTED):
Florian Mayer801349e2018-11-29 10:15:25 +0000717 exists = subprocess.call(
Primiano Tucci834fdc72019-10-04 11:33:44 +0100718 ['adb', 'shell', '[ -d /proc/{} ]'.format(perfetto_pid)], **NOOUT) == 0
Florian Mayerbd0a62a2019-04-10 11:09:21 +0100719 device_connected = subprocess.call(['adb', 'shell', 'true'], **NOOUT) == 0
Florian Mayer801349e2018-11-29 10:15:25 +0000720 time.sleep(1)
Florian Mayer2007d5c2020-09-08 15:45:44 +0100721 print("Waiting for profiler shutdown...")
Florian Mayer801349e2018-11-29 10:15:25 +0000722 signal.signal(signal.SIGINT, old_handler)
723 if IS_INTERRUPTED:
724 # Not check_call because it could have existed in the meantime.
Florian Mayer0bc32522020-04-28 16:35:55 +0200725 subprocess.call(['adb', 'shell', 'kill', '-INT', str(perfetto_pid)])
Florian Mayer2b8a3b22019-05-02 18:35:38 +0100726 if args.simpleperf:
727 subprocess.check_call(['adb', 'shell', 'killall', '-INT', 'simpleperf'])
728 print("Waiting for simpleperf to exit.")
729 while subprocess.call(
Primiano Tucci834fdc72019-10-04 11:33:44 +0100730 ['adb', 'shell', '[ -f /proc/$(pidof simpleperf)/exe ]'], **NOOUT) == 0:
Florian Mayer2b8a3b22019-05-02 18:35:38 +0100731 time.sleep(1)
Primiano Tucci834fdc72019-10-04 11:33:44 +0100732 subprocess.check_call(
Florian Mayer3c57f3f2020-10-01 14:58:08 +0100733 ['adb', 'pull', '/data/local/tmp/heapprofd_profile', profile_target])
Primiano Tuccid3e40bd2021-08-03 10:52:39 +0100734 print("Pulled simpleperf profile to " + profile_target +
735 "/heapprofd_profile")
Florian Mayer801349e2018-11-29 10:15:25 +0000736
Florian Mayerddbe31e2018-11-30 14:49:30 +0000737 # Wait for perfetto cmd to return.
738 while exists:
739 exists = subprocess.call(
740 ['adb', 'shell', '[ -d /proc/{} ]'.format(perfetto_pid)]) == 0
741 time.sleep(1)
742
Florian Mayer2007d5c2020-09-08 15:45:44 +0100743 profile_host_path = os.path.join(profile_target, 'raw-trace')
Primiano Tuccid3e40bd2021-08-03 10:52:39 +0100744 subprocess.check_call(['adb', 'pull', profile_device_path, profile_host_path],
745 stdout=NULL)
Florian Mayer4fc59932020-04-28 17:19:55 +0200746 if uuid_trace:
Primiano Tuccid3e40bd2021-08-03 10:52:39 +0100747 subprocess.check_call(['adb', 'shell', 'rm', profile_device_path],
748 stdout=NULL)
Florian Mayer213c8d42019-12-18 17:10:34 +0000749
Hector Dearmana9545e52022-05-17 12:23:25 +0100750 if traceconv_binary is None:
Florian Mayer2007d5c2020-09-08 15:45:44 +0100751 print('Wrote profile to {}'.format(profile_host_path))
Primiano Tuccid3e40bd2021-08-03 10:52:39 +0100752 print(
753 'This file can be opened using the Perfetto UI, https://ui.perfetto.dev'
754 )
Florian Mayer2007d5c2020-09-08 15:45:44 +0100755 return 0
756
Florian Mayercad84b72020-11-24 14:26:32 +0000757 binary_path = os.getenv('PERFETTO_BINARY_PATH')
758 if not args.no_android_tree_symbolization:
759 product_out = os.getenv('ANDROID_PRODUCT_OUT')
760 if product_out:
761 product_out_symbols = product_out + '/symbols'
762 else:
763 product_out_symbols = None
764
765 if binary_path is None:
766 binary_path = product_out_symbols
767 elif product_out_symbols is not None:
Primiano Tucci09f1bf42023-10-17 15:22:38 +0100768 binary_path += os.pathsep + product_out_symbols
Florian Mayercad84b72020-11-24 14:26:32 +0000769
770 trace_file = os.path.join(profile_target, 'raw-trace')
Florian Mayeredc48102020-12-15 19:38:44 +0000771 concat_files = [trace_file]
Florian Mayercad84b72020-11-24 14:26:32 +0000772
773 if binary_path is not None:
774 with open(os.path.join(profile_target, 'symbols'), 'w') as fd:
775 ret = subprocess.call([
Hector Dearmana9545e52022-05-17 12:23:25 +0100776 traceconv_binary, 'symbolize',
Primiano Tuccid3e40bd2021-08-03 10:52:39 +0100777 os.path.join(profile_target, 'raw-trace')
778 ],
779 env=dict(
780 os.environ, PERFETTO_BINARY_PATH=binary_path),
781 stdout=fd)
Florian Mayercad84b72020-11-24 14:26:32 +0000782 if ret == 0:
Florian Mayeredc48102020-12-15 19:38:44 +0000783 concat_files.append(os.path.join(profile_target, 'symbols'))
Florian Mayercad84b72020-11-24 14:26:32 +0000784 else:
Primiano Tuccid3e40bd2021-08-03 10:52:39 +0100785 print("Failed to symbolize. Continuing without symbols.", file=sys.stderr)
Florian Mayercad84b72020-11-24 14:26:32 +0000786
Florian Mayeredc48102020-12-15 19:38:44 +0000787 proguard_map = os.getenv('PERFETTO_PROGUARD_MAP')
788 if proguard_map is not None:
789 with open(os.path.join(profile_target, 'deobfuscation-packets'), 'w') as fd:
790 ret = subprocess.call([
Hector Dearmana9545e52022-05-17 12:23:25 +0100791 traceconv_binary, 'deobfuscate',
Primiano Tuccid3e40bd2021-08-03 10:52:39 +0100792 os.path.join(profile_target, 'raw-trace')
793 ],
794 env=dict(
795 os.environ, PERFETTO_PROGUARD_MAP=proguard_map),
796 stdout=fd)
Florian Mayeredc48102020-12-15 19:38:44 +0000797 if ret == 0:
Primiano Tuccid3e40bd2021-08-03 10:52:39 +0100798 concat_files.append(os.path.join(profile_target, 'deobfuscation-packets'))
Florian Mayeredc48102020-12-15 19:38:44 +0000799 else:
Primiano Tuccid3e40bd2021-08-03 10:52:39 +0100800 print(
801 "Failed to deobfuscate. Continuing without deobfuscated.",
802 file=sys.stderr)
Florian Mayeredc48102020-12-15 19:38:44 +0000803
804 if len(concat_files) > 1:
Isaac Nickaein1ca57282021-03-15 16:10:59 +0000805 with open(os.path.join(profile_target, 'symbolized-trace'), 'wb') as out:
Florian Mayeredc48102020-12-15 19:38:44 +0000806 for fn in concat_files:
Isaac Nickaein1ca57282021-03-15 16:10:59 +0000807 with open(fn, 'rb') as inp:
Florian Mayeredc48102020-12-15 19:38:44 +0000808 while True:
809 buf = inp.read(4096)
810 if not buf:
811 break
812 out.write(buf)
813 trace_file = os.path.join(profile_target, 'symbolized-trace')
814
Ryan Savitski4bb2b222022-11-17 18:08:03 +0000815 conversion_args = [traceconv_binary, 'profile'] + (
816 ['--no-annotations'] if args.no_annotations else []) + [trace_file]
817 traceconv_output = subprocess.check_output(conversion_args)
Florian Mayer801349e2018-11-29 10:15:25 +0000818 profile_path = None
Hector Dearmana9545e52022-05-17 12:23:25 +0100819 for word in traceconv_output.decode('utf-8').split():
Florian Mayer801349e2018-11-29 10:15:25 +0000820 if 'heap_profile-' in word:
821 profile_path = word
822 if profile_path is None:
Florian Mayer88bca762020-07-28 14:42:15 +0100823 print_no_profile_error()
Florian Mayer801349e2018-11-29 10:15:25 +0000824 return 1
825
826 profile_files = os.listdir(profile_path)
827 if not profile_files:
Florian Mayer88bca762020-07-28 14:42:15 +0100828 print_no_profile_error()
Florian Mayer801349e2018-11-29 10:15:25 +0000829 return 1
830
Florian Mayere9a55c62020-04-14 16:39:34 +0200831 for profile_file in profile_files:
832 shutil.copy(os.path.join(profile_path, profile_file), profile_target)
833
Florian Mayere9a55c62020-04-14 16:39:34 +0200834 symlink_path = None
Primiano Tuccif94e4972021-08-03 11:35:45 +0100835 if not sys.platform.startswith('win'):
836 subprocess.check_call(
Lalit Maganti79c80192021-08-04 15:35:33 +0100837 ['gzip'] + [os.path.join(profile_target, x) for x in profile_files])
Primiano Tuccif94e4972021-08-03 11:35:45 +0100838 if args.output is None:
839 symlink_path = os.path.join(
840 os.path.dirname(profile_target), "heap_profile-latest")
841 if os.path.lexists(symlink_path):
842 os.unlink(symlink_path)
843 os.symlink(profile_target, symlink_path)
Florian Mayer82f43d12019-01-17 14:37:45 +0000844
Florian Mayere9a55c62020-04-14 16:39:34 +0200845 if symlink_path is not None:
Primiano Tuccid3e40bd2021-08-03 10:52:39 +0100846 print("Wrote profiles to {} (symlink {})".format(profile_target,
847 symlink_path))
Florian Mayere9a55c62020-04-14 16:39:34 +0200848 else:
849 print("Wrote profiles to {}".format(profile_target))
850
Primiano Tuccif94e4972021-08-03 11:35:45 +0100851 print("The raw-trace file can be viewed using https://ui.perfetto.dev.")
852 print("The heap_dump.* files can be viewed using pprof/ (Googlers only) " +
853 "or https://www.speedscope.app/.")
854 print("The two above are equivalent. The raw-trace contains the union of " +
855 "all the heap dumps.")
Florian Mayer801349e2018-11-29 10:15:25 +0000856
857
Florian Mayer801349e2018-11-29 10:15:25 +0000858if __name__ == '__main__':
859 sys.exit(main(sys.argv))