blob: e5e09cedfcef3b3693dbee58c95cf4ae2e954fe0 [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,
38 stdout=subprocess.DEVNULL,
39 stderr=subprocess.PIPE,
40 universal_newlines=True,
41 env=env)
42
43 lines = []
44 while True:
45 line = tp.stderr.readline()
46 lines.append(line)
47
48 match = REGEX.match(line)
49 if match:
50 break
51
52 if tp.poll():
53 break
54
55 ret = tp.poll()
56 fail = ret is not None and ret > 0
57 if fail:
58 print("Failed")
59 for line in lines:
60 sys.stderr.write(line)
61 return tp, fail, match[2]
62
63
64def heap_profile_run(args, dump_at_max: bool):
65 profile_args = [
66 os.path.join(ROOT_DIR, 'tools', 'heap_profile'), '-i', '1', '-n',
67 'trace_processor_shell', '--print-config'
68 ]
69 if dump_at_max:
70 profile_args.append('--dump-at-max')
71 config = subprocess.check_output(
72 profile_args,
73 stderr=subprocess.DEVNULL,
74 )
75
76 out_file = os.path.join(
77 args.result, args.result_prefix + ('max' if dump_at_max else 'rest'))
78 perfetto_args = [
79 os.path.join(args.out, 'perfetto'), '-c', '-', '--txt', '-o', out_file
80 ]
81 profile = subprocess.Popen(
82 perfetto_args,
83 stdin=subprocess.PIPE,
84 stdout=subprocess.DEVNULL,
85 stderr=subprocess.DEVNULL)
86 profile.stdin.write(config)
87 profile.stdin.close()
88
89 env = {
90 'LD_PRELOAD': os.path.join(args.out, 'libheapprofd_glibc_preload.so'),
91 'TRACE_PROCESSOR_NO_MMAP': '1',
92 'PERFETTO_HEAPPROFD_BLOCKING_INIT': '1'
93 }
94 (tp, fail, _) = run_tp_until_ingestion(args, env)
95
96 profile.send_signal(signal.SIGINT)
97 profile.wait()
98
99 tp.stdin.close()
100 tp.wait()
101
102 if fail:
103 os.remove(out_file)
104
105
106def regular_run(args):
107 env = {'TRACE_PROCESSOR_NO_MMAP': '1'}
108 (tp, fail, time) = run_tp_until_ingestion(args, env)
109
110 p = psutil.Process(tp.pid)
111 mem = 0
112 for m in p.memory_maps():
113 mem += m.anonymous
114
115 tp.stdin.close()
116 tp.wait()
117
118 print(f'Time taken: {time}s, Memory: {mem / 1024.0 / 1024.0}MB')
119
120
121def only_sort_run(args):
122 env = {
123 'TRACE_PROCESSOR_NO_MMAP': '1',
124 'TRACE_PROCESSOR_SORT_ONLY': '1',
125 }
126 (tp, fail, time) = run_tp_until_ingestion(args, env)
127
128 tp.stdin.close()
129 tp.wait()
130
131 print(f'Time taken: {time}s')
132
133
134def main():
135 parser = argparse.ArgumentParser(
136 description="This script measures the running time of "
137 "ingesting a trace with trace processor as well as profiling "
138 "trace processor's memory usage with heapprofd")
139 parser.add_argument('--out', type=str, help='Out directory', required=True)
140 parser.add_argument(
141 '--result', type=str, help='Result directory', required=True)
142 parser.add_argument(
143 '--result-prefix', type=str, help='Result file prefix', required=True)
144 parser.add_argument(
145 '--ftrace-raw',
146 action='store_true',
147 help='Whether to ingest ftrace into raw table',
148 default=False)
149 parser.add_argument('trace_file', type=str, help='Path to trace')
150 args = parser.parse_args()
151
Lalit Magantic893b172022-03-07 15:57:59 +0000152 traced = subprocess.Popen([os.path.join(args.out, 'traced')],
153 stdout=subprocess.DEVNULL,
154 stderr=subprocess.DEVNULL)
155 print('Heap profile dump at max')
156 heap_profile_run(args, dump_at_max=True)
157 print('Heap profile dump at resting')
158 heap_profile_run(args, dump_at_max=False)
159 print('Regular run')
160 regular_run(args)
161 print('Only sort run')
162 only_sort_run(args)
163
164 traced.send_signal(signal.SIGINT)
165 traced.wait()
166
167
168if __name__ == "__main__":
169 main()