blob: 8014c39ba20a94a62f3394b217e05015f0ed1047 [file] [log] [blame]
Lalit Magantic893b172022-03-07 15:57:59 +00001#!/usr/bin/env python3
2# Copyright (C) 2021 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
16import argparse
17import os
18import re
19import signal
20import sys
21import subprocess
22
23import psutil
24
25ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
26
27REGEX = re.compile(
28 '.*Trace loaded: ([0-9.]+) MB in ([0-9.]+)s \(([0-9.]+) MB/s\)')
29
30
31def run_tp_until_ingestion(args, env):
32 tp_args = [os.path.join(args.out, 'trace_processor_shell'), args.trace_file]
33 if not args.ftrace_raw:
34 tp_args.append('--no-ftrace-raw')
35 tp = subprocess.Popen(
36 tp_args,
37 stdin=subprocess.PIPE,
Lalit Maganti8cafb582022-06-23 13:18:52 +010038 stdout=None if args.verbose else subprocess.DEVNULL,
Lalit Magantic893b172022-03-07 15:57:59 +000039 stderr=subprocess.PIPE,
40 universal_newlines=True,
41 env=env)
42
43 lines = []
44 while True:
45 line = tp.stderr.readline()
Lalit Maganti8cafb582022-06-23 13:18:52 +010046 if args.verbose:
47 sys.stderr.write(line)
Lalit Magantic893b172022-03-07 15:57:59 +000048 lines.append(line)
49
50 match = REGEX.match(line)
51 if match:
52 break
53
54 if tp.poll():
55 break
56
57 ret = tp.poll()
58 fail = ret is not None and ret > 0
59 if fail:
60 print("Failed")
61 for line in lines:
62 sys.stderr.write(line)
63 return tp, fail, match[2]
64
65
66def heap_profile_run(args, dump_at_max: bool):
67 profile_args = [
68 os.path.join(ROOT_DIR, 'tools', 'heap_profile'), '-i', '1', '-n',
69 'trace_processor_shell', '--print-config'
70 ]
71 if dump_at_max:
72 profile_args.append('--dump-at-max')
73 config = subprocess.check_output(
74 profile_args,
75 stderr=subprocess.DEVNULL,
76 )
77
78 out_file = os.path.join(
79 args.result, args.result_prefix + ('max' if dump_at_max else 'rest'))
80 perfetto_args = [
81 os.path.join(args.out, 'perfetto'), '-c', '-', '--txt', '-o', out_file
82 ]
83 profile = subprocess.Popen(
84 perfetto_args,
85 stdin=subprocess.PIPE,
Lalit Maganti8cafb582022-06-23 13:18:52 +010086 stdout=None if args.verbose else subprocess.DEVNULL,
87 stderr=None if args.verbose else subprocess.DEVNULL)
Lalit Magantic893b172022-03-07 15:57:59 +000088 profile.stdin.write(config)
89 profile.stdin.close()
90
91 env = {
92 'LD_PRELOAD': os.path.join(args.out, 'libheapprofd_glibc_preload.so'),
93 'TRACE_PROCESSOR_NO_MMAP': '1',
94 'PERFETTO_HEAPPROFD_BLOCKING_INIT': '1'
95 }
96 (tp, fail, _) = run_tp_until_ingestion(args, env)
97
98 profile.send_signal(signal.SIGINT)
99 profile.wait()
100
101 tp.stdin.close()
102 tp.wait()
103
104 if fail:
105 os.remove(out_file)
106
107
108def regular_run(args):
109 env = {'TRACE_PROCESSOR_NO_MMAP': '1'}
110 (tp, fail, time) = run_tp_until_ingestion(args, env)
111
112 p = psutil.Process(tp.pid)
113 mem = 0
114 for m in p.memory_maps():
115 mem += m.anonymous
116
117 tp.stdin.close()
118 tp.wait()
119
120 print(f'Time taken: {time}s, Memory: {mem / 1024.0 / 1024.0}MB')
121
122
123def only_sort_run(args):
124 env = {
125 'TRACE_PROCESSOR_NO_MMAP': '1',
126 'TRACE_PROCESSOR_SORT_ONLY': '1',
127 }
128 (tp, fail, time) = run_tp_until_ingestion(args, env)
129
130 tp.stdin.close()
131 tp.wait()
132
133 print(f'Time taken: {time}s')
134
135
136def main():
137 parser = argparse.ArgumentParser(
138 description="This script measures the running time of "
139 "ingesting a trace with trace processor as well as profiling "
140 "trace processor's memory usage with heapprofd")
141 parser.add_argument('--out', type=str, help='Out directory', required=True)
142 parser.add_argument(
143 '--result', type=str, help='Result directory', required=True)
144 parser.add_argument(
145 '--result-prefix', type=str, help='Result file prefix', required=True)
146 parser.add_argument(
147 '--ftrace-raw',
148 action='store_true',
149 help='Whether to ingest ftrace into raw table',
150 default=False)
Lalit Magantiae023282022-06-07 17:55:19 +0000151 parser.add_argument(
152 '--kill-existing',
153 action='store_true',
Lalit Maganti8cafb582022-06-23 13:18:52 +0100154 help='Kill traced, perfetto_cmd and trace processor shell if running')
155 parser.add_argument(
156 '--verbose',
157 action='store_true',
158 help='Logs all stderr and stdout from subprocesses')
Lalit Magantic893b172022-03-07 15:57:59 +0000159 parser.add_argument('trace_file', type=str, help='Path to trace')
160 args = parser.parse_args()
161
Lalit Magantiae023282022-06-07 17:55:19 +0000162 if args.kill_existing:
163 subprocess.run(['killall', 'traced'],
164 stdout=subprocess.DEVNULL,
165 stderr=subprocess.DEVNULL)
166 subprocess.run(['killall', 'perfetto'],
167 stdout=subprocess.DEVNULL,
168 stderr=subprocess.DEVNULL)
169 subprocess.run(['killall', 'trace_processor_shell'],
170 stdout=subprocess.DEVNULL,
171 stderr=subprocess.DEVNULL)
172
Lalit Magantic893b172022-03-07 15:57:59 +0000173 traced = subprocess.Popen([os.path.join(args.out, 'traced')],
Lalit Maganti8cafb582022-06-23 13:18:52 +0100174 stdout=None if args.verbose else subprocess.DEVNULL,
175 stderr=None if args.verbose else subprocess.DEVNULL)
Lalit Magantic893b172022-03-07 15:57:59 +0000176 print('Heap profile dump at max')
177 heap_profile_run(args, dump_at_max=True)
178 print('Heap profile dump at resting')
179 heap_profile_run(args, dump_at_max=False)
180 print('Regular run')
181 regular_run(args)
182 print('Only sort run')
183 only_sort_run(args)
184
185 traced.send_signal(signal.SIGINT)
186 traced.wait()
187
188
189if __name__ == "__main__":
190 main()