summaryrefslogtreecommitdiff
path: root/simpleperf/scripts/pprof_proto_generator.py
diff options
context:
space:
mode:
Diffstat (limited to 'simpleperf/scripts/pprof_proto_generator.py')
-rwxr-xr-xsimpleperf/scripts/pprof_proto_generator.py87
1 files changed, 22 insertions, 65 deletions
diff --git a/simpleperf/scripts/pprof_proto_generator.py b/simpleperf/scripts/pprof_proto_generator.py
index c6355947..d0b4da95 100755
--- a/simpleperf/scripts/pprof_proto_generator.py
+++ b/simpleperf/scripts/pprof_proto_generator.py
@@ -30,8 +30,8 @@ import os
import os.path
from simpleperf_report_lib import ReportLib
-from utils import Addr2Nearestline, extant_dir, find_real_dso_path, find_tool_path, flatten_arg_list
-from utils import log_info, log_exit, ReadElf
+from utils import Addr2Nearestline, bytes_to_str, extant_dir, find_tool_path, flatten_arg_list
+from utils import log_info, log_exit, str_to_bytes
try:
import profile_pb2
except ImportError:
@@ -40,13 +40,13 @@ except ImportError:
def load_pprof_profile(filename):
profile = profile_pb2.Profile()
with open(filename, "rb") as f:
- profile.ParseFromString(f.read())
+ profile.ParseFromString(bytes_to_str(f.read()))
return profile
def store_pprof_profile(filename, profile):
with open(filename, 'wb') as f:
- f.write(profile.SerializeToString())
+ f.write(str_to_bytes(profile.SerializeToString()))
class PprofProfilePrinter(object):
@@ -256,8 +256,6 @@ class PprofProfileGenerator(object):
kallsyms = 'binary_cache/kallsyms'
if os.path.isfile(kallsyms):
self.lib.SetKallsymsFile(kallsyms)
- if config.get('show_art_frames'):
- self.lib.ShowArtFrames()
self.comm_filter = set(config['comm_filters']) if config.get('comm_filters') else None
if config.get('pid_filters'):
self.pid_filter = {int(x) for x in config['pid_filters']}
@@ -268,7 +266,6 @@ class PprofProfileGenerator(object):
else:
self.tid_filter = None
self.dso_filter = set(config['dso_filters']) if config.get('dso_filters') else None
- self.max_chain_length = config['max_chain_length']
self.profile = profile_pb2.Profile()
self.profile.string_table.append('')
self.string_table = {}
@@ -282,10 +279,6 @@ class PprofProfileGenerator(object):
self.function_map = {}
self.function_list = []
- # Map from dso_name in perf.data to (binary path, build_id).
- self.binary_map = {}
- self.read_elf = ReadElf(self.config['ndk_path'])
-
def gen(self):
# 1. Process all samples in perf.data, aggregate samples.
while True:
@@ -305,9 +298,9 @@ class PprofProfileGenerator(object):
sample.add_value(sample_type_id, 1)
sample.add_value(sample_type_id + 1, report_sample.period)
if self._filter_symbol(symbol):
- location_id = self.get_location_id(report_sample.ip, symbol)
+ location_id = self.get_location_id(symbol.vaddr_in_file, symbol)
sample.add_location_id(location_id)
- for i in range(max(0, callchain.nr - self.max_chain_length), callchain.nr):
+ for i in range(callchain.nr):
entry = callchain.entries[i]
if self._filter_symbol(symbol):
location_id = self.get_location_id(entry.ip, entry.symbol)
@@ -335,12 +328,12 @@ class PprofProfileGenerator(object):
if self.comm_filter:
if sample.thread_comm not in self.comm_filter:
return False
- if self.pid_filter:
- if sample.pid not in self.pid_filter:
- return False
- if self.tid_filter:
- if sample.tid not in self.tid_filter:
- return False
+ if self.pid_filter:
+ if sample.pid not in self.pid_filter:
+ return False
+ if self.tid_filter:
+ if sample.tid not in self.tid_filter:
+ return False
return True
def _filter_symbol(self, symbol):
@@ -377,10 +370,10 @@ class PprofProfileGenerator(object):
return sample_type_id
def get_location_id(self, ip, symbol):
- binary_path, build_id = self.get_binary(symbol.dso_name)
- mapping_id = self.get_mapping_id(symbol.mapping[0], binary_path, build_id)
+ mapping_id = self.get_mapping_id(symbol.mapping[0], symbol.dso_name)
location = Location(mapping_id, ip, symbol.vaddr_in_file)
- function_id = self.get_function_id(symbol.symbol_name, binary_path, symbol.symbol_addr)
+ function_id = self.get_function_id(symbol.symbol_name, symbol.dso_name,
+ symbol.symbol_addr)
if function_id:
# Add Line only when it has a valid function id, see http://b/36988814.
# Default line info only contains the function name
@@ -397,8 +390,11 @@ class PprofProfileGenerator(object):
self.location_map[location.key] = location
return location.id
- def get_mapping_id(self, report_mapping, filename, build_id):
+ def get_mapping_id(self, report_mapping, filename):
filename_id = self.get_string_id(filename)
+ build_id = self.lib.GetBuildIdForPath(filename)
+ if build_id and build_id[0:2] == "0x":
+ build_id = build_id[2:]
build_id_id = self.get_string_id(build_id)
mapping = Mapping(report_mapping.start, report_mapping.end,
report_mapping.pgoff, filename_id, build_id_id)
@@ -411,37 +407,6 @@ class PprofProfileGenerator(object):
self.mapping_map[mapping.key] = mapping
return mapping.id
- def get_binary(self, dso_name):
- """ Return (binary_path, build_id) for a given dso_name. """
- value = self.binary_map.get(dso_name)
- if value:
- return value
-
- binary_path = dso_name
- build_id = ''
-
- # The build ids in perf.data are padded to 20 bytes, but pprof needs without padding.
- # So read build id from the binary in binary_cache, and check it with build id in
- # perf.data.
- build_id_in_perf_data = self.lib.GetBuildIdForPath(dso_name)
- if build_id_in_perf_data:
- # Try elf_path in binary cache.
- elf_path = find_real_dso_path(dso_name, self.config['binary_cache_dir'])
- if elf_path:
- elf_build_id = self.read_elf.get_build_id(elf_path, False)
- if build_id_in_perf_data == self.read_elf.pad_build_id(elf_build_id):
- build_id = elf_build_id
- binary_path = elf_path
-
- if not build_id and build_id_in_perf_data.startswith('0x'):
- # Fallback to the way used by TrimZeroesFromBuildIDString() in quipper.
- build_id = build_id_in_perf_data[2:] # remove '0x'
- padding = '0' * 8
- while build_id.endswith(padding):
- build_id = build_id[:-len(padding)]
- self.binary_map[dso_name] = (binary_path, build_id)
- return (binary_path, build_id)
-
def get_mapping(self, mapping_id):
return self.mapping_list[mapping_id - 1] if mapping_id > 0 else None
@@ -474,12 +439,10 @@ class PprofProfileGenerator(object):
if not self.config.get('binary_cache_dir'):
log_info("Can't generate line information because binary_cache is missing.")
return
- if not find_tool_path('llvm-symbolizer', self.config['ndk_path']):
- log_info("Can't generate line information because can't find llvm-symbolizer.")
+ if not find_tool_path('addr2line', self.config['ndk_path']):
+ log_info("Can't generate line information because can't find addr2line.")
return
- # We have changed dso names to paths in binary_cache in self.get_binary(). So no need to
- # pass binary_cache_dir to addr2line.
- addr2line = Addr2Nearestline(self.config['ndk_path'], None, True)
+ addr2line = Addr2Nearestline(self.config['ndk_path'], self.config['binary_cache_dir'], True)
# 2. Put all needed addresses to it.
for location in self.location_list:
@@ -597,11 +560,7 @@ def main():
Use samples only in threads with selected thread ids.""")
parser.add_argument('--dso', nargs='+', action='append', help="""
Use samples only in selected binaries.""")
- parser.add_argument('--max_chain_length', type=int, default=1000000000, help="""
- Maximum depth of samples to be converted.""") # Large value as infinity standin.
parser.add_argument('--ndk_path', type=extant_dir, help='Set the path of a ndk release.')
- parser.add_argument('--show_art_frames', action='store_true',
- help='Show frames of internal methods in the ART Java interpreter.')
args = parser.parse_args()
if args.show:
@@ -619,8 +578,6 @@ def main():
config['tid_filters'] = flatten_arg_list(args.tid)
config['dso_filters'] = flatten_arg_list(args.dso)
config['ndk_path'] = args.ndk_path
- config['show_art_frames'] = args.show_art_frames
- config['max_chain_length'] = args.max_chain_length
generator = PprofProfileGenerator(config)
profile = generator.gen()
store_pprof_profile(config['output_file'], profile)