summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYabin Cui <yabinc@google.com>2022-03-24 17:33:08 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2022-03-24 17:33:08 +0000
commited8610fedf6a3087962e78756b6c1521e7f515ba (patch)
treea6fa5066efe7d13b7af34e11fa3b324b7efce95c
parentdf6aafabd3ab6996ac086be32cf941d6bf7f327e (diff)
parenta9a6f4b64db7c65ae4011296759f781dc3f32ca6 (diff)
downloadextras-ed8610fedf6a3087962e78756b6c1521e7f515ba.tar.gz
Merge changes Id3087199,I707cf4dd,I64e3d7fc,I4c9cdc63 am: 1ea3d5fc2e am: a9a6f4b64d
Original change: https://android-review.googlesource.com/c/platform/system/extras/+/2041023 Change-Id: Ie9fca87869811a392b1461fc3b10c965bbfa7d9f
-rwxr-xr-xsimpleperf/scripts/annotate.py25
-rwxr-xr-xsimpleperf/scripts/bin/android/arm/simpleperfbin2807668 -> 2812664 bytes
-rwxr-xr-xsimpleperf/scripts/bin/android/arm64/simpleperfbin3810832 -> 3819224 bytes
-rwxr-xr-xsimpleperf/scripts/bin/android/x86/simpleperfbin4372260 -> 4386820 bytes
-rwxr-xr-xsimpleperf/scripts/bin/android/x86_64/simpleperfbin4249312 -> 4244008 bytes
-rwxr-xr-xsimpleperf/scripts/bin/darwin/x86_64/libsimpleperf_report.dylibbin13978839 -> 13980215 bytes
-rwxr-xr-xsimpleperf/scripts/bin/darwin/x86_64/simpleperfbin13918013 -> 13902701 bytes
-rwxr-xr-xsimpleperf/scripts/bin/linux/x86_64/libsimpleperf_report.sobin7219712 -> 7208384 bytes
-rwxr-xr-xsimpleperf/scripts/bin/linux/x86_64/simpleperfbin7193024 -> 7181056 bytes
-rwxr-xr-xsimpleperf/scripts/bin/windows/x86_64/libsimpleperf_report.dllbin5598720 -> 5583872 bytes
-rwxr-xr-xsimpleperf/scripts/bin/windows/x86_64/simpleperf.exebin4654080 -> 4638208 bytes
-rwxr-xr-xsimpleperf/scripts/gecko_profile_generator.py13
-rwxr-xr-xsimpleperf/scripts/inferno/inferno.py6
-rwxr-xr-xsimpleperf/scripts/pprof_proto_generator.py20
-rwxr-xr-xsimpleperf/scripts/report_html.py9
-rwxr-xr-xsimpleperf/scripts/report_sample.py12
-rw-r--r--simpleperf/scripts/simpleperf_report_lib.py10
-rw-r--r--simpleperf/scripts/simpleperf_utils.py48
-rwxr-xr-xsimpleperf/scripts/stackcollapse.py15
-rw-r--r--simpleperf/scripts/test/pprof_proto_generator_test.py2
-rw-r--r--simpleperf/scripts/test/report_lib_test.py29
21 files changed, 59 insertions, 130 deletions
diff --git a/simpleperf/scripts/annotate.py b/simpleperf/scripts/annotate.py
index ecfb2fdb..7bf8fe92 100755
--- a/simpleperf/scripts/annotate.py
+++ b/simpleperf/scripts/annotate.py
@@ -146,7 +146,7 @@ class SourceFileAnnotator(object):
def __init__(self, config):
# check config variables
- config_names = ['perf_data_list', 'source_dirs', 'comm_filters', 'dso_filters', 'ndk_path']
+ config_names = ['perf_data_list', 'source_dirs', 'dso_filters', 'ndk_path']
for name in config_names:
if name not in config:
log_exit('config [%s] is missing' % name)
@@ -161,7 +161,6 @@ class SourceFileAnnotator(object):
self.config = config
self.symfs_dir = symfs_dir
self.kallsyms = kallsyms
- self.comm_filter = set(config['comm_filters']) if config.get('comm_filters') else None
self.dso_filter = set(config['dso_filters']) if config.get('dso_filters') else None
config['annotate_dest_dir'] = 'annotated_files'
@@ -193,16 +192,12 @@ class SourceFileAnnotator(object):
lib.SetSymfs(self.symfs_dir)
if self.kallsyms:
lib.SetKallsymsFile(self.kallsyms)
- if self.config.get('sample_filter'):
- lib.SetSampleFilter(self.config.get('sample_filter'))
lib.SetReportOptions(self.config['report_lib_options'])
while True:
sample = lib.GetNextSample()
if sample is None:
lib.Close()
break
- if not self._filter_sample(sample):
- continue
symbols = []
symbols.append(lib.GetSymbolOfCurrentSample())
callchain = lib.GetCallChainOfCurrentSample()
@@ -216,13 +211,6 @@ class SourceFileAnnotator(object):
self.addr2line.add_addr(symbol.dso_name, build_id, symbol.symbol_addr,
symbol.symbol_addr)
- def _filter_sample(self, sample):
- """Return true if the sample can be used."""
- if self.comm_filter:
- if sample.thread_comm not in self.comm_filter:
- return False
- return True
-
def _filter_symbol(self, symbol):
if not self.dso_filter or symbol.dso_name in self.dso_filter:
return True
@@ -242,16 +230,12 @@ class SourceFileAnnotator(object):
lib.SetSymfs(self.symfs_dir)
if self.kallsyms:
lib.SetKallsymsFile(self.kallsyms)
- if self.config.get('sample_filter'):
- lib.SetSampleFilter(self.config.get('sample_filter'))
lib.SetReportOptions(self.config['report_lib_options'])
while True:
sample = lib.GetNextSample()
if sample is None:
lib.Close()
break
- if not self._filter_sample(sample):
- continue
self._generate_periods_for_sample(lib, sample)
def _generate_periods_for_sample(self, lib, sample):
@@ -479,12 +463,9 @@ def main():
help='show raw period instead of percentage')
parser.add_argument('--summary-width', type=int, default=80, help='max width of summary file')
sample_filter_group = parser.add_argument_group('Sample filter options')
- parser.add_sample_filter_options(sample_filter_group)
- sample_filter_group.add_argument('--comm', nargs='+', action='append', help="""
- Use samples only in threads with selected names.""")
sample_filter_group.add_argument('--dso', nargs='+', action='append', help="""
Use samples only in selected binaries.""")
- parser.add_report_lib_options()
+ parser.add_report_lib_options(sample_filter_group=sample_filter_group)
args = parser.parse_args()
config = {}
@@ -492,12 +473,10 @@ def main():
if not config['perf_data_list']:
config['perf_data_list'].append('perf.data')
config['source_dirs'] = flatten_arg_list(args.source_dirs)
- config['comm_filters'] = flatten_arg_list(args.comm)
config['dso_filters'] = flatten_arg_list(args.dso)
config['ndk_path'] = args.ndk_path
config['raw_period'] = args.raw_period
config['summary_width'] = args.summary_width
- config['sample_filter'] = args.sample_filter
config['report_lib_options'] = args.report_lib_options
annotator = SourceFileAnnotator(config)
diff --git a/simpleperf/scripts/bin/android/arm/simpleperf b/simpleperf/scripts/bin/android/arm/simpleperf
index 5ccbd4f1..db2fde7f 100755
--- a/simpleperf/scripts/bin/android/arm/simpleperf
+++ b/simpleperf/scripts/bin/android/arm/simpleperf
Binary files differ
diff --git a/simpleperf/scripts/bin/android/arm64/simpleperf b/simpleperf/scripts/bin/android/arm64/simpleperf
index 862e4d93..785b6e33 100755
--- a/simpleperf/scripts/bin/android/arm64/simpleperf
+++ b/simpleperf/scripts/bin/android/arm64/simpleperf
Binary files differ
diff --git a/simpleperf/scripts/bin/android/x86/simpleperf b/simpleperf/scripts/bin/android/x86/simpleperf
index a78e0514..97a168d5 100755
--- a/simpleperf/scripts/bin/android/x86/simpleperf
+++ b/simpleperf/scripts/bin/android/x86/simpleperf
Binary files differ
diff --git a/simpleperf/scripts/bin/android/x86_64/simpleperf b/simpleperf/scripts/bin/android/x86_64/simpleperf
index 8872cf4a..c250c450 100755
--- a/simpleperf/scripts/bin/android/x86_64/simpleperf
+++ b/simpleperf/scripts/bin/android/x86_64/simpleperf
Binary files differ
diff --git a/simpleperf/scripts/bin/darwin/x86_64/libsimpleperf_report.dylib b/simpleperf/scripts/bin/darwin/x86_64/libsimpleperf_report.dylib
index 32631f67..191e51f8 100755
--- a/simpleperf/scripts/bin/darwin/x86_64/libsimpleperf_report.dylib
+++ b/simpleperf/scripts/bin/darwin/x86_64/libsimpleperf_report.dylib
Binary files differ
diff --git a/simpleperf/scripts/bin/darwin/x86_64/simpleperf b/simpleperf/scripts/bin/darwin/x86_64/simpleperf
index c4daaf2b..1a6a8875 100755
--- a/simpleperf/scripts/bin/darwin/x86_64/simpleperf
+++ b/simpleperf/scripts/bin/darwin/x86_64/simpleperf
Binary files differ
diff --git a/simpleperf/scripts/bin/linux/x86_64/libsimpleperf_report.so b/simpleperf/scripts/bin/linux/x86_64/libsimpleperf_report.so
index 6f148a8e..ca444ec9 100755
--- a/simpleperf/scripts/bin/linux/x86_64/libsimpleperf_report.so
+++ b/simpleperf/scripts/bin/linux/x86_64/libsimpleperf_report.so
Binary files differ
diff --git a/simpleperf/scripts/bin/linux/x86_64/simpleperf b/simpleperf/scripts/bin/linux/x86_64/simpleperf
index f2968884..dca7b30d 100755
--- a/simpleperf/scripts/bin/linux/x86_64/simpleperf
+++ b/simpleperf/scripts/bin/linux/x86_64/simpleperf
Binary files differ
diff --git a/simpleperf/scripts/bin/windows/x86_64/libsimpleperf_report.dll b/simpleperf/scripts/bin/windows/x86_64/libsimpleperf_report.dll
index 074bff34..b49e8f8f 100755
--- a/simpleperf/scripts/bin/windows/x86_64/libsimpleperf_report.dll
+++ b/simpleperf/scripts/bin/windows/x86_64/libsimpleperf_report.dll
Binary files differ
diff --git a/simpleperf/scripts/bin/windows/x86_64/simpleperf.exe b/simpleperf/scripts/bin/windows/x86_64/simpleperf.exe
index fc98293a..9838e771 100755
--- a/simpleperf/scripts/bin/windows/x86_64/simpleperf.exe
+++ b/simpleperf/scripts/bin/windows/x86_64/simpleperf.exe
Binary files differ
diff --git a/simpleperf/scripts/gecko_profile_generator.py b/simpleperf/scripts/gecko_profile_generator.py
index 683a5696..396c9a58 100755
--- a/simpleperf/scripts/gecko_profile_generator.py
+++ b/simpleperf/scripts/gecko_profile_generator.py
@@ -295,8 +295,6 @@ def _gecko_profile(
record_file: str,
symfs_dir: Optional[str],
kallsyms_file: Optional[str],
- comm_filter: Set[str],
- sample_filter: Optional[str],
report_lib_options: ReportLibOptions) -> GeckoProfile:
"""convert a simpleperf profile to gecko format"""
lib = ReportLib()
@@ -307,8 +305,6 @@ def _gecko_profile(
lib.SetRecordFile(record_file)
if kallsyms_file is not None:
lib.SetKallsymsFile(kallsyms_file)
- if sample_filter:
- lib.SetSampleFilter(sample_filter)
lib.SetReportOptions(report_lib_options)
arch = lib.GetArch()
@@ -323,9 +319,6 @@ def _gecko_profile(
if sample is None:
lib.Close()
break
- if comm_filter:
- if sample.thread_comm not in comm_filter:
- continue
event = lib.GetEventOfCurrentSample()
symbol = lib.GetSymbolOfCurrentSample()
callchain = lib.GetCallChainOfCurrentSample()
@@ -404,18 +397,12 @@ def main() -> None:
parser.add_argument('--kallsyms', help='Set the path to find kernel symbols.')
parser.add_argument('-i', '--record_file', nargs='?', default='perf.data',
help='Default is perf.data.')
- sample_filter_group = parser.add_argument_group('Sample filter options')
- parser.add_sample_filter_options(sample_filter_group)
- sample_filter_group.add_argument('--comm', nargs='+', action='append', help="""
- Use samples only in threads with selected names.""")
parser.add_report_lib_options()
args = parser.parse_args()
profile = _gecko_profile(
record_file=args.record_file,
symfs_dir=args.symfs,
kallsyms_file=args.kallsyms,
- comm_filter=set(flatten_arg_list(args.comm)),
- sample_filter=args.sample_filter,
report_lib_options=args.report_lib_options)
json.dump(profile, sys.stdout, sort_keys=True)
diff --git a/simpleperf/scripts/inferno/inferno.py b/simpleperf/scripts/inferno/inferno.py
index 42cbeaca..ccf1b6b6 100755
--- a/simpleperf/scripts/inferno/inferno.py
+++ b/simpleperf/scripts/inferno/inferno.py
@@ -111,8 +111,6 @@ def parse_samples(process, args, sample_filter_fn):
lib.SetRecordFile(record_file)
if kallsyms_file:
lib.SetKallsymsFile(kallsyms_file)
- if args.sample_filter:
- lib.SetSampleFilter(args.sample_filter)
lib.SetReportOptions(args.report_lib_options)
process.cmd = lib.GetRecordCmd()
product_props = lib.MetaInfo().get("product_props")
@@ -308,8 +306,8 @@ def main():
report_group.add_argument('--symfs', help="""Set the path to find binaries with symbols and
debug info.""")
report_group.add_argument('--title', help='Show a title in the report.')
- parser.add_sample_filter_options(report_group, False)
- parser.add_report_lib_options(report_group)
+ parser.add_report_lib_options(
+ report_group, sample_filter_group=report_group, sample_filter_with_pid_shortcut=False)
debug_group = parser.add_argument_group('Debug options')
debug_group.add_argument('--disable_adb_root', action='store_true', help="""Force adb to run
diff --git a/simpleperf/scripts/pprof_proto_generator.py b/simpleperf/scripts/pprof_proto_generator.py
index e3e2d11f..57c988b9 100755
--- a/simpleperf/scripts/pprof_proto_generator.py
+++ b/simpleperf/scripts/pprof_proto_generator.py
@@ -270,7 +270,6 @@ class PprofProfileGenerator(object):
config['binary_cache_dir'] = 'binary_cache'
if not os.path.isdir(config['binary_cache_dir']):
config['binary_cache_dir'] = None
- self.comm_filter = set(config['comm_filters']) if config.get('comm_filters') else 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()
@@ -303,8 +302,6 @@ class PprofProfileGenerator(object):
if self.config.get('show_art_frames'):
self.lib.ShowArtFrames()
- if self.config.get('sample_filter'):
- self.lib.SetSampleFilter(self.config['sample_filter'])
self.lib.SetReportOptions(self.config['report_lib_options'])
comments = [
@@ -328,9 +325,6 @@ class PprofProfileGenerator(object):
symbol = self.lib.GetSymbolOfCurrentSample()
callchain = self.lib.GetCallChainOfCurrentSample()
- if not self._filter_report_sample(report_sample):
- continue
-
sample_type_id = self.get_sample_type_id(event.name)
sample = Sample()
sample.add_value(sample_type_id, 1)
@@ -378,13 +372,6 @@ class PprofProfileGenerator(object):
return self.profile
- def _filter_report_sample(self, sample):
- """Return true if the sample can be used."""
- if self.comm_filter:
- if sample.thread_comm not in self.comm_filter:
- return False
- return True
-
def _filter_symbol(self, symbol):
if not self.dso_filter or symbol.dso_name in self.dso_filter:
return True
@@ -636,12 +623,9 @@ def main():
'-j', '--jobs', type=int, default=os.cpu_count(),
help='Use multithreading to speed up source code annotation.')
sample_filter_group = parser.add_argument_group('Sample filter options')
- parser.add_sample_filter_options(sample_filter_group)
- sample_filter_group.add_argument('--comm', nargs='+', action='append', help="""
- Use samples only in threads with selected names.""")
sample_filter_group.add_argument('--dso', nargs='+', action='append', help="""
Use samples only in selected binaries.""")
- parser.add_report_lib_options()
+ parser.add_report_lib_options(sample_filter_group=sample_filter_group)
args = parser.parse_args()
if args.show:
@@ -653,11 +637,9 @@ def main():
config = {}
config['output_file'] = args.output_file
- config['comm_filters'] = flatten_arg_list(args.comm)
config['dso_filters'] = flatten_arg_list(args.dso)
config['ndk_path'] = args.ndk_path
config['max_chain_length'] = args.max_chain_length
- config['sample_filter'] = args.sample_filter
config['report_lib_options'] = args.report_lib_options
generator = PprofProfileGenerator(config)
for record_file in args.record_file:
diff --git a/simpleperf/scripts/report_html.py b/simpleperf/scripts/report_html.py
index 9c00131b..56f8dae5 100755
--- a/simpleperf/scripts/report_html.py
+++ b/simpleperf/scripts/report_html.py
@@ -620,9 +620,7 @@ class RecordData(object):
self.gen_addr_hit_map_in_record_info = False
self.binary_finder = BinaryFinder(binary_cache_path, ReadElf(ndk_path))
- def load_record_file(
- self, record_file: str, report_lib_options: ReportLibOptions,
- sample_filter: Optional[str]):
+ def load_record_file(self, record_file: str, report_lib_options: ReportLibOptions):
lib = ReportLib()
lib.SetRecordFile(record_file)
# If not showing ip for unknown symbols, the percent of the unknown symbol may be
@@ -630,8 +628,6 @@ class RecordData(object):
lib.ShowIpForUnknownSymbol()
if self.binary_cache_path:
lib.SetSymfs(self.binary_cache_path)
- if sample_filter:
- lib.SetSampleFilter(sample_filter)
lib.SetReportOptions(report_lib_options)
self.meta_info = lib.MetaInfo()
self.cmdline = lib.GetRecordCmd()
@@ -983,7 +979,6 @@ def get_args() -> argparse.Namespace:
parser.add_argument('--aggregate-by-thread-name', action='store_true', help="""aggregate
samples by thread name instead of thread id. This is useful for
showing multiple perf.data generated for the same app.""")
- parser.add_sample_filter_options()
parser.add_report_lib_options()
return parser.parse_args()
@@ -1012,7 +1007,7 @@ def main():
# 2. Produce record data.
record_data = RecordData(binary_cache_path, ndk_path, build_addr_hit_map)
for record_file in args.record_file:
- record_data.load_record_file(record_file, args.report_lib_options, args.sample_filter)
+ record_data.load_record_file(record_file, args.report_lib_options)
if args.aggregate_by_thread_name:
record_data.aggregate_by_thread_name()
record_data.limit_percents(args.min_func_percent, args.min_callchain_percent)
diff --git a/simpleperf/scripts/report_sample.py b/simpleperf/scripts/report_sample.py
index d99bbf9e..dc5c4e2b 100755
--- a/simpleperf/scripts/report_sample.py
+++ b/simpleperf/scripts/report_sample.py
@@ -29,8 +29,6 @@ def report_sample(
kallsyms_file: str,
show_tracing_data: bool,
header: bool,
- comm_filter: Set[str],
- sample_filter: Optional[str],
report_lib_options: ReportLibOptions):
""" read record_file, and print each sample"""
lib = ReportLib()
@@ -42,8 +40,6 @@ def report_sample(
lib.SetRecordFile(record_file)
if kallsyms_file is not None:
lib.SetKallsymsFile(kallsyms_file)
- if sample_filter:
- lib.SetSampleFilter(sample_filter)
lib.SetReportOptions(report_lib_options)
if header:
@@ -60,9 +56,6 @@ def report_sample(
if sample is None:
lib.Close()
break
- if comm_filter:
- if sample.thread_comm not in comm_filter:
- continue
event = lib.GetEventOfCurrentSample()
symbol = lib.GetSymbolOfCurrentSample()
callchain = lib.GetCallChainOfCurrentSample()
@@ -95,9 +88,6 @@ def main():
parser.add_argument('--show_tracing_data', action='store_true', help='print tracing data.')
parser.add_argument('--header', action='store_true',
help='Show metadata header, like perf script --header')
- parser.add_argument('--comm', nargs='+', action='append', help="""
- Use samples only in threads with selected names.""")
- parser.add_sample_filter_options()
parser.add_report_lib_options()
args = parser.parse_args()
report_sample(
@@ -106,8 +96,6 @@ def main():
kallsyms_file=args.kallsyms,
show_tracing_data=args.show_tracing_data,
header=args.header,
- comm_filter=set(flatten_arg_list(args.comm)),
- sample_filter=args.sample_filter,
report_lib_options=args.report_lib_options)
diff --git a/simpleperf/scripts/simpleperf_report_lib.py b/simpleperf/scripts/simpleperf_report_lib.py
index 45938882..48b31199 100644
--- a/simpleperf/scripts/simpleperf_report_lib.py
+++ b/simpleperf/scripts/simpleperf_report_lib.py
@@ -307,6 +307,8 @@ class ReportLib(object):
self.ShowArtFrames(True)
if options.trace_offcpu:
self.SetTraceOffCpuMode(options.trace_offcpu)
+ if options.sample_filters:
+ self.SetSampleFilter(options.sample_filters)
def SetLogSeverity(self, log_level: str = 'info'):
""" Set log severity of native lib, can be verbose,debug,info,error,fatal."""
@@ -373,7 +375,7 @@ class ReportLib(object):
res: bool = self._SetTraceOffCpuModeFunc(self.getInstance(), _char_pt(mode))
_check(res, f'Failed to call SetTraceOffCpuMode({mode})')
- def SetSampleFilter(self, filter: str):
+ def SetSampleFilter(self, filters: List[str]):
""" Set options used to filter samples. Available options are:
--exclude-pid pid1,pid2,... Exclude samples for selected processes.
--exclude-tid tid1,tid2,... Exclude samples for selected threads.
@@ -392,8 +394,10 @@ class ReportLib(object):
The filter argument should be a concatenation of options.
"""
- res: bool = self._SetSampleFilterFunc(self.getInstance(), _char_pt(filter))
- _check(res, f'Failed to call SetSampleFilter({filter})')
+ filter_array = (ct.c_char_p * len(filters))()
+ filter_array[:] = [_char_pt(f) for f in filters]
+ res: bool = self._SetSampleFilterFunc(self.getInstance(), filter_array, len(filters))
+ _check(res, f'Failed to call SetSampleFilter({filters})')
def GetNextSample(self) -> Optional[SampleStruct]:
""" Return the next sample. If no more samples, return None. """
diff --git a/simpleperf/scripts/simpleperf_utils.py b/simpleperf/scripts/simpleperf_utils.py
index f11d0a0d..2a7dfd35 100644
--- a/simpleperf/scripts/simpleperf_utils.py
+++ b/simpleperf/scripts/simpleperf_utils.py
@@ -1005,6 +1005,7 @@ class ReportLibOptions:
show_art_frames: bool
trace_offcpu: str
proguard_mapping_files: List[str]
+ sample_filters: List[str]
class BaseArgumentParser(argparse.ArgumentParser):
@@ -1015,7 +1016,9 @@ class BaseArgumentParser(argparse.ArgumentParser):
self.has_report_lib_options = False
def add_report_lib_options(self, group: Optional[Any] = None,
- default_show_art_frames: bool = False):
+ default_show_art_frames: bool = False,
+ sample_filter_group: Optional[Any] = None,
+ sample_filter_with_pid_shortcut: bool = True):
self.has_report_lib_options = True
parser = group if group else self
parser.add_argument(
@@ -1032,8 +1035,9 @@ class BaseArgumentParser(argparse.ArgumentParser):
mixed-on-off-cpu (on-cpu and off-cpu samples using the same event name).
If not set, mixed-on-off-cpu mode is used.
""")
+ self._add_sample_filter_options(sample_filter_group, sample_filter_with_pid_shortcut)
- def add_sample_filter_options(
+ def _add_sample_filter_options(
self, group: Optional[Any] = None, with_pid_shortcut: bool = True):
if not group:
group = self.add_argument_group('Sample filter options')
@@ -1061,7 +1065,8 @@ class BaseArgumentParser(argparse.ArgumentParser):
'--include-process-name', metavar='process_name_regex', nargs='+',
help='only include samples for processes with name containing the regular expression')
group.add_argument(
- '--include-thread-name', metavar='thread_name_regex', nargs='+',
+ '--comm', '--include-thread-name', metavar='thread_name_regex',
+ dest='include_thread_name', nargs='+',
help='only include samples for threads with name containing the regular expression')
group.add_argument(
'--filter-file', metavar='file',
@@ -1070,40 +1075,38 @@ class BaseArgumentParser(argparse.ArgumentParser):
self.has_sample_filter_options = True
self.sample_filter_with_pid_shortcut = with_pid_shortcut
- def _build_sample_filter(self, args: argparse.Namespace) -> Optional[str]:
- """ Convert sample filter options into a sample filter string, which can be passed to
- ReportLib.SetSampleFilter().
- """
+ def _build_sample_filter(self, args: argparse.Namespace) -> List[str]:
+ """ Build sample filters, which can be passed to ReportLib.SetSampleFilter(). """
filters = []
if args.exclude_pid:
- filters.append('--exclude-pid ' + ','.join(str(pid) for pid in args.exclude_pid))
+ filters.extend(['--exclude-pid', ','.join(str(pid) for pid in args.exclude_pid)])
if args.exclude_tid:
- filters.append('--exclude-tid ' + ','.join(str(tid) for tid in args.exclude_tid))
+ filters.extend(['--exclude-tid', ','.join(str(tid) for tid in args.exclude_tid)])
if args.exclude_process_name:
for name in args.exclude_process_name:
- filters.append('--exclude-process-name ' + name)
+ filters.extend(['--exclude-process-name', name])
if args.exclude_thread_name:
for name in args.exclude_thread_name:
- filters.append('--exclude-thread-name ' + name)
+ filters.extend(['--exclude-thread-name', name])
if args.include_pid:
- filters.append('--include-pid ' + ','.join(str(pid) for pid in args.include_pid))
+ filters.extend(['--include-pid', ','.join(str(pid) for pid in args.include_pid)])
if args.include_tid:
- filters.append('--include-tid ' + ','.join(str(tid) for tid in args.include_tid))
+ filters.extend(['--include-tid', ','.join(str(tid) for tid in args.include_tid)])
if self.sample_filter_with_pid_shortcut:
if args.pid:
- filters.append('--include-pid ' + ','.join(str(pid) for pid in args.pid))
+ filters.extend(['--include-pid', ','.join(str(pid) for pid in args.pid)])
if args.tid:
- filters.append('--include-tid ' + ','.join(str(pid) for pid in args.tid))
+ filters.extend(['--include-tid', ','.join(str(pid) for pid in args.tid)])
if args.include_process_name:
for name in args.include_process_name:
- filters.append('--include-process-name ' + name)
+ filters.extend(['--include-process-name', name])
if args.include_thread_name:
for name in args.include_thread_name:
- filters.append('--include-thread-name ' + name)
+ filters.extend(['--include-thread-name', name])
if args.filter_file:
- filters.append('--filter-file ' + args.filter_file)
- return ' '.join(filters)
+ filters.extend(['--filter-file', args.filter_file])
+ return filters
def parse_known_args(self, *args, **kwargs):
self.add_argument(
@@ -1111,12 +1114,11 @@ class BaseArgumentParser(argparse.ArgumentParser):
default='info', help='set log level')
namespace, left_args = super().parse_known_args(*args, **kwargs)
- if self.has_sample_filter_options:
- setattr(namespace, 'sample_filter', self._build_sample_filter(namespace))
-
if self.has_report_lib_options:
+ sample_filters = self._build_sample_filter(namespace)
report_lib_options = ReportLibOptions(
- namespace.show_art_frames, namespace.trace_offcpu, namespace.proguard_mapping_file)
+ namespace.show_art_frames, namespace.trace_offcpu, namespace.proguard_mapping_file,
+ sample_filters)
setattr(namespace, 'report_lib_options', report_lib_options)
if not Log.initialized:
diff --git a/simpleperf/scripts/stackcollapse.py b/simpleperf/scripts/stackcollapse.py
index ee82a0ba..e0e1d86f 100755
--- a/simpleperf/scripts/stackcollapse.py
+++ b/simpleperf/scripts/stackcollapse.py
@@ -43,8 +43,6 @@ def collapse_stacks(
annotate_kernel: bool,
annotate_jit: bool,
include_addrs: bool,
- comm_filter: Set[str],
- sample_filter: Optional[str],
report_lib_options: ReportLibOptions):
"""read record_file, aggregate per-stack and print totals per-stack"""
lib = ReportLib()
@@ -57,8 +55,6 @@ def collapse_stacks(
lib.SetRecordFile(record_file)
if kallsyms_file is not None:
lib.SetKallsymsFile(kallsyms_file)
- if sample_filter:
- lib.SetSampleFilter(sample_filter)
lib.SetReportOptions(report_lib_options)
stacks: DefaultDict[str, int] = defaultdict(int)
@@ -69,9 +65,6 @@ def collapse_stacks(
if sample is None:
lib.Close()
break
- if comm_filter:
- if sample.thread_comm not in comm_filter:
- continue
event = lib.GetEventOfCurrentSample()
symbol = lib.GetSymbolOfCurrentSample()
callchain = lib.GetCallChainOfCurrentSample()
@@ -123,12 +116,10 @@ def main():
parser.add_argument('--addrs', action='store_true',
help='include raw addresses where symbols can\'t be found')
sample_filter_group = parser.add_argument_group('Sample filter options')
- parser.add_sample_filter_options(sample_filter_group, False)
sample_filter_group.add_argument('--event-filter', nargs='?', default='',
help='Event type filter e.g. "cpu-cycles" or "instructions"')
- sample_filter_group.add_argument('--comm', nargs='+', action='append', help="""
- Use samples only in threads with selected names.""")
- parser.add_report_lib_options()
+ parser.add_report_lib_options(sample_filter_group=sample_filter_group,
+ sample_filter_with_pid_shortcut=False)
args = parser.parse_args()
collapse_stacks(
record_file=args.record_file,
@@ -140,8 +131,6 @@ def main():
annotate_kernel=args.kernel,
annotate_jit=args.jit,
include_addrs=args.addrs,
- comm_filter=set(flatten_arg_list(args.comm)),
- sample_filter=args.sample_filter,
report_lib_options=args.report_lib_options)
diff --git a/simpleperf/scripts/test/pprof_proto_generator_test.py b/simpleperf/scripts/test/pprof_proto_generator_test.py
index 8e39d1a7..cbeb8d6a 100644
--- a/simpleperf/scripts/test/pprof_proto_generator_test.py
+++ b/simpleperf/scripts/test/pprof_proto_generator_test.py
@@ -218,7 +218,7 @@ class TestPprofProtoGenerator(TestBase):
# Read recording file.
config = {'ndk_path': None, 'max_chain_length': 1000000,
- 'report_lib_options': ReportLibOptions(False, '', None)}
+ 'report_lib_options': ReportLibOptions(False, '', None, None)}
generator = PprofProfileGenerator(config)
generator.load_record_file(testdata_file)
diff --git a/simpleperf/scripts/test/report_lib_test.py b/simpleperf/scripts/test/report_lib_test.py
index ba7ae466..1447c5ae 100644
--- a/simpleperf/scripts/test/report_lib_test.py
+++ b/simpleperf/scripts/test/report_lib_test.py
@@ -16,7 +16,7 @@
import os
import tempfile
-from typing import Set
+from typing import List, Set
from simpleperf_report_lib import ReportLib
from . test_utils import TestBase, TestHelper
@@ -275,34 +275,39 @@ class TestReportLib(TestBase):
def test_set_sample_filter(self):
""" Test using ReportLib.SetSampleFilter(). """
- def get_threads_for_filter(filter: str) -> Set[int]:
+ def get_threads_for_filter(filters: List[str]) -> Set[int]:
self.report_lib.Close()
self.report_lib = ReportLib()
self.report_lib.SetRecordFile(TestHelper.testdata_path('perf_display_bitmaps.data'))
- self.report_lib.SetSampleFilter(filter)
+ self.report_lib.SetSampleFilter(filters)
threads = set()
while self.report_lib.GetNextSample():
sample = self.report_lib.GetCurrentSample()
threads.add(sample.tid)
return threads
- self.assertNotIn(31850, get_threads_for_filter('--exclude-pid 31850'))
- self.assertIn(31850, get_threads_for_filter('--include-pid 31850'))
- self.assertNotIn(31881, get_threads_for_filter('--exclude-tid 31881'))
- self.assertIn(31881, get_threads_for_filter('--include-tid 31881'))
+ self.assertNotIn(31850, get_threads_for_filter(['--exclude-pid', '31850']))
+ self.assertIn(31850, get_threads_for_filter(['--include-pid', '31850']))
+ self.assertNotIn(31881, get_threads_for_filter(['--exclude-tid', '31881']))
+ self.assertIn(31881, get_threads_for_filter(['--include-tid', '31881']))
self.assertNotIn(31881, get_threads_for_filter(
- '--exclude-process-name com.example.android.displayingbitmaps'))
+ ['--exclude-process-name', 'com.example.android.displayingbitmaps']))
self.assertIn(31881, get_threads_for_filter(
- '--include-process-name com.example.android.displayingbitmaps'))
+ ['--include-process-name', 'com.example.android.displayingbitmaps']))
self.assertNotIn(31850, get_threads_for_filter(
- '--exclude-thread-name com.example.android.displayingbitmaps'))
+ ['--exclude-thread-name', 'com.example.android.displayingbitmaps']))
self.assertIn(31850, get_threads_for_filter(
- '--include-thread-name com.example.android.displayingbitmaps'))
+ ['--include-thread-name', 'com.example.android.displayingbitmaps']))
+
+ # Check that thread name can have space.
+ self.assertNotIn(31856, get_threads_for_filter(
+ ['--exclude-thread-name', 'Jit thread pool']))
+ self.assertIn(31856, get_threads_for_filter(['--include-thread-name', 'Jit thread pool']))
with tempfile.NamedTemporaryFile('w', delete=False) as filter_file:
filter_file.write('GLOBAL_BEGIN 684943449406175\nGLOBAL_END 684943449406176')
filter_file.flush()
- threads = get_threads_for_filter('--filter-file ' + filter_file.name)
+ threads = get_threads_for_filter(['--filter-file', filter_file.name])
self.assertIn(31881, threads)
self.assertNotIn(31850, threads)
os.unlink(filter_file.name)