summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Hansen <markhansen@google.com>2021-10-08 00:34:28 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2021-10-08 00:34:28 +0000
commit0452f9d10fddc5fcffc9b84644567e74cef436de (patch)
tree52d7a9e9f88e711f1bd6708c6434c0a60f8bb2a3
parent6a0fcd9e4c1344433cffd97971ae433fbe304256 (diff)
parentadef0b5112a8b1b36eb05dccfdde4f120607197b (diff)
downloadextras-0452f9d10fddc5fcffc9b84644567e74cef436de.tar.gz
Merge "Add: stackcollapse.py converter to Folded Stacks"
-rw-r--r--simpleperf/doc/scripts_reference.md41
-rw-r--r--simpleperf/scripts/CONTRIBUTING.md11
-rwxr-xr-xsimpleperf/scripts/report_sample.py1
-rwxr-xr-xsimpleperf/scripts/stackcollapse.py146
-rwxr-xr-xsimpleperf/scripts/test/do_test.py2
-rw-r--r--simpleperf/scripts/test/stackcollapse_test.py87
-rw-r--r--simpleperf/testdata/perf_with_jit_symbol.foldedstack10
-rw-r--r--simpleperf/testdata/perf_with_jit_symbol.foldedstack_addrs10
-rw-r--r--simpleperf/testdata/perf_with_jit_symbol.foldedstack_with_pid10
-rw-r--r--simpleperf/testdata/perf_with_jit_symbol.foldedstack_with_tid10
-rw-r--r--simpleperf/testdata/perf_with_trace_offcpu.foldedstack41
-rw-r--r--simpleperf/testdata/perf_with_two_event_types.foldedstack2
-rw-r--r--simpleperf/testdata/perf_with_two_event_types.foldedstack_cpu_clock1
13 files changed, 371 insertions, 1 deletions
diff --git a/simpleperf/doc/scripts_reference.md b/simpleperf/doc/scripts_reference.md
index ee5b413c..6122cc4d 100644
--- a/simpleperf/doc/scripts_reference.md
+++ b/simpleperf/doc/scripts_reference.md
@@ -259,13 +259,54 @@ This format can be imported into:
- [Speedscope](https://github.com/jlfwong/speedscope/wiki/Importing-from-perf-(linux))
```sh
+# Record a profile to perf.data
+$ ./app_profiler.py <args>
+
# Convert perf.data in the current directory to a format used by FlameGraph.
$ ./report_sample.py --symfs binary_cache >out.perf
+
$ git clone https://github.com/brendangregg/FlameGraph.git
$ FlameGraph/stackcollapse-perf.pl out.perf >out.folded
$ FlameGraph/flamegraph.pl out.folded >a.svg
```
+### stackcollapse.py
+
+`stackcollapse.py` converts a profiling data file (`perf.data`) to [Brendan
+Gregg's "Folded Stacks"
+format](https://queue.acm.org/detail.cfm?id=2927301#:~:text=The%20folded%20stack%2Dtrace%20format,trace%2C%20followed%20by%20a%20semicolon).
+
+Folded Stacks are lines of semicolon-delimited stack frames, root to leaf,
+followed by a count of events sampled in that stack, e.g.:
+
+```
+BusyThread;__start_thread;__pthread_start(void*);java.lang.Thread.run 17889729
+```
+
+All similar stacks are aggregated and sample timestamps are unused.
+
+Folded Stacks format is readable by:
+
+- The [FlameGraph](https://github.com/brendangregg/FlameGraph) toolkit
+- [Inferno](https://github.com/jonhoo/inferno) (Rust port of FlameGraph)
+- [Speedscope](https://speedscope.app/)
+
+Example:
+
+```sh
+# Record a profile to perf.data
+$ ./app_profiler.py <args>
+
+# Convert to Folded Stacks format
+$ ./stackcollapse.py --kernel --jit | gzip > profile.folded.gz
+
+# Visualise with FlameGraph with Java Stacks and nanosecond times
+$ git clone https://github.com/brendangregg/FlameGraph.git
+$ gunzip -c profile.folded.gz \
+ | FlameGraph/flamegraph.pl --color=java --countname=ns \
+ > profile.svg
+```
+
## simpleperf_report_lib.py
`simpleperf_report_lib.py` is a Python library used to parse profiling data files generated by the
diff --git a/simpleperf/scripts/CONTRIBUTING.md b/simpleperf/scripts/CONTRIBUTING.md
new file mode 100644
index 00000000..a996c1da
--- /dev/null
+++ b/simpleperf/scripts/CONTRIBUTING.md
@@ -0,0 +1,11 @@
+Simpleperf scripts use 4 spaces for indentation
+
+To format the scripts, use:
+
+```shell
+autopep8 --max-line-length 100 --in-place <script.py>
+```
+
+Changes are normally reviewed on top of the AOSP `master` branch.
+
+New scripts should have documentation in `../doc/scripts_reference.md`.
diff --git a/simpleperf/scripts/report_sample.py b/simpleperf/scripts/report_sample.py
index a49c127f..78f1a9d7 100755
--- a/simpleperf/scripts/report_sample.py
+++ b/simpleperf/scripts/report_sample.py
@@ -18,7 +18,6 @@
"""report_sample.py: report samples in the same format as `perf script`.
"""
-from __future__ import print_function
from simpleperf_report_lib import ReportLib
from simpleperf_utils import BaseArgumentParser, flatten_arg_list
from typing import List, Set
diff --git a/simpleperf/scripts/stackcollapse.py b/simpleperf/scripts/stackcollapse.py
new file mode 100755
index 00000000..52351bc0
--- /dev/null
+++ b/simpleperf/scripts/stackcollapse.py
@@ -0,0 +1,146 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2021 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+"""stackcollapse.py: convert perf.data to Brendan Gregg's "Folded Stacks" format,
+ which can be read by https://github.com/brendangregg/FlameGraph, and many
+ other tools.
+
+ Example:
+ ./app_profiler.py
+ ./stackcollapse.py | ~/FlameGraph/flamegraph.pl --color=java --countname=ns > flamegraph.svg
+"""
+
+from collections import defaultdict
+from simpleperf_report_lib import ReportLib
+from simpleperf_utils import BaseArgumentParser, flatten_arg_list
+from typing import DefaultDict, List, Set
+
+import logging
+import sys
+
+
+def collapse_stacks(
+ record_file: str,
+ symfs_dir: str,
+ kallsyms_file: str,
+ proguard_mapping_file: List[str],
+ event_filter: str,
+ include_pid: bool,
+ include_tid: bool,
+ annotate_kernel: bool,
+ annotate_jit: bool,
+ include_addrs: bool,
+ comm_filter: Set[str]):
+ """read record_file, aggregate per-stack and print totals per-stack"""
+ lib = ReportLib()
+
+ if include_addrs:
+ lib.ShowIpForUnknownSymbol()
+ for file_path in proguard_mapping_file:
+ lib.AddProguardMappingFile(file_path)
+ if symfs_dir is not None:
+ lib.SetSymfs(symfs_dir)
+ if record_file is not None:
+ lib.SetRecordFile(record_file)
+ if kallsyms_file is not None:
+ lib.SetKallsymsFile(kallsyms_file)
+
+ stacks: DefaultDict[str, int] = defaultdict(int)
+ event_defaulted = False
+ event_warning_shown = False
+ while True:
+ sample = lib.GetNextSample()
+ 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()
+ if not event_filter:
+ event_filter = event.name
+ event_defaulted = True
+ elif event.name != event_filter:
+ if event_defaulted and not event_warning_shown:
+ logging.warning(
+ 'Input has multiple event types. Filtering for the first event type seen: %s' % event_filter)
+ event_warning_shown = True
+ continue
+
+ stack = []
+ for i in range(callchain.nr):
+ entry = callchain.entries[i]
+ func = entry.symbol.symbol_name
+ if annotate_kernel and "kallsyms" in entry.symbol.dso_name or ".ko" in entry.symbol.dso_name:
+ func += '_[k]' # kernel
+ if annotate_jit and entry.symbol.dso_name == "[JIT app cache]":
+ func += '_[j]' # jit
+ stack.append(func)
+ if include_tid:
+ stack.append("%s-%d/%d" % (sample.thread_comm, sample.pid, sample.tid))
+ elif include_pid:
+ stack.append("%s-%d" % (sample.thread_comm, sample.pid))
+ else:
+ stack.append(sample.thread_comm)
+ stack.reverse()
+ stacks[";".join(stack)] += sample.period
+
+ for k in sorted(stacks.keys()):
+ print("%s %d" % (k, stacks[k]))
+
+
+def main():
+ parser = BaseArgumentParser(description=__doc__)
+ parser.add_argument('--symfs',
+ help='Set the path to find binaries with symbols and debug info.')
+ 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.')
+ parser.add_argument('--event-filter', nargs='?', default='',
+ help='Event type filter e.g. "cpu-cycles" or "instructions"')
+ parser.add_argument('--pid', action='store_true', help='Include PID with process names')
+ parser.add_argument('--tid', action='store_true', help='Include TID and PID with process names')
+ parser.add_argument('--kernel', action='store_true',
+ help='Annotate kernel functions with a _[k]')
+ parser.add_argument('--jit', action='store_true', help='Annotate JIT functions with a _[j]')
+ parser.add_argument('--addrs', action='store_true',
+ help='include raw addresses where symbols can\'t be found')
+ parser.add_argument(
+ '--proguard-mapping-file', nargs='+',
+ help='Add proguard mapping file to de-obfuscate symbols',
+ default=[])
+ parser.add_argument('--comm', nargs='+', action='append', help="""
+ Use samples only in threads with selected names.""")
+ args = parser.parse_args()
+ collapse_stacks(
+ record_file=args.record_file,
+ symfs_dir=args.symfs,
+ kallsyms_file=args.kallsyms,
+ proguard_mapping_file=args.proguard_mapping_file,
+ event_filter=args.event_filter,
+ include_pid=args.pid,
+ include_tid=args.tid,
+ annotate_kernel=args.kernel,
+ annotate_jit=args.jit,
+ include_addrs=args.addrs,
+ comm_filter=set(flatten_arg_list(args.comm)))
+
+
+if __name__ == '__main__':
+ main()
diff --git a/simpleperf/scripts/test/do_test.py b/simpleperf/scripts/test/do_test.py
index aa447051..201d2519 100755
--- a/simpleperf/scripts/test/do_test.py
+++ b/simpleperf/scripts/test/do_test.py
@@ -58,6 +58,7 @@ from . report_html_test import *
from . report_lib_test import *
from . report_sample_test import *
from . run_simpleperf_on_device_test import *
+from . stackcollapse_test import *
from . tools_test import *
from . test_utils import TestHelper
@@ -132,6 +133,7 @@ def get_test_type(test: str) -> Optional[str]:
'TestReportHtml',
'TestReportLib',
'TestReportSample',
+ 'TestStackCollapse',
'TestTools',
'TestGeckoProfileGenerator'):
return 'host_test'
diff --git a/simpleperf/scripts/test/stackcollapse_test.py b/simpleperf/scripts/test/stackcollapse_test.py
new file mode 100644
index 00000000..2734d4e8
--- /dev/null
+++ b/simpleperf/scripts/test/stackcollapse_test.py
@@ -0,0 +1,87 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2021 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import json
+from pathlib import Path
+
+from . test_utils import TestBase, TestHelper
+
+
+class TestStackCollapse(TestBase):
+
+ def test_jit_annotations(self):
+ got = self.run_cmd([
+ 'stackcollapse.py',
+ '-i', TestHelper.testdata_path('perf_with_jit_symbol.data'),
+ '--jit',
+ ], return_output=True)
+ golden_path = TestHelper.testdata_path('perf_with_jit_symbol.foldedstack')
+ self.assertEqual(got, Path(golden_path).read_text())
+
+ def test_kernel_annotations(self):
+ got = self.run_cmd([
+ 'stackcollapse.py',
+ '-i', TestHelper.testdata_path('perf_with_trace_offcpu.data'),
+ '--kernel',
+ ], return_output=True)
+ golden_path = TestHelper.testdata_path('perf_with_trace_offcpu.foldedstack')
+ self.assertEqual(got, Path(golden_path).read_text())
+
+ def test_with_pid(self):
+ got = self.run_cmd([
+ 'stackcollapse.py',
+ '-i', TestHelper.testdata_path('perf_with_jit_symbol.data'),
+ '--jit',
+ '--pid',
+ ], return_output=True)
+ golden_path = TestHelper.testdata_path('perf_with_jit_symbol.foldedstack_with_pid')
+ self.assertEqual(got, Path(golden_path).read_text())
+
+ def test_with_tid(self):
+ got = self.run_cmd([
+ 'stackcollapse.py',
+ '-i', TestHelper.testdata_path('perf_with_jit_symbol.data'),
+ '--jit',
+ '--tid',
+ ], return_output=True)
+ golden_path = TestHelper.testdata_path('perf_with_jit_symbol.foldedstack_with_tid')
+ self.assertEqual(got, Path(golden_path).read_text())
+
+ def test_two_event_types_chooses_first(self):
+ got = self.run_cmd([
+ 'stackcollapse.py',
+ '-i', TestHelper.testdata_path('perf_with_two_event_types.data'),
+ ], return_output=True)
+ golden_path = TestHelper.testdata_path('perf_with_two_event_types.foldedstack')
+ self.assertEqual(got, Path(golden_path).read_text())
+
+ def test_two_event_types_chooses_with_event_filter(self):
+ got = self.run_cmd([
+ 'stackcollapse.py',
+ '-i', TestHelper.testdata_path('perf_with_two_event_types.data'),
+ '--event-filter', 'cpu-clock',
+ ], return_output=True)
+ golden_path = TestHelper.testdata_path('perf_with_two_event_types.foldedstack_cpu_clock')
+ self.assertEqual(got, Path(golden_path).read_text())
+
+ def test_unknown_symbol_addrs(self):
+ got = self.run_cmd([
+ 'stackcollapse.py',
+ '-i', TestHelper.testdata_path('perf_with_jit_symbol.data'),
+ '--addrs',
+ ], return_output=True)
+ golden_path = TestHelper.testdata_path('perf_with_jit_symbol.foldedstack_addrs')
+ self.assertEqual(got, Path(golden_path).read_text())
diff --git a/simpleperf/testdata/perf_with_jit_symbol.foldedstack b/simpleperf/testdata/perf_with_jit_symbol.foldedstack
new file mode 100644
index 00000000..a2af8474
--- /dev/null
+++ b/simpleperf/testdata/perf_with_jit_symbol.foldedstack
@@ -0,0 +1,10 @@
+BusyThread;__start_thread;__pthread_start(void*);java.lang.Thread.run 17889729
+BusyThread;__start_thread;__pthread_start(void*);java.lang.Thread.run;com.android.simpleperf.debuggable.MainActivity$1.run;java.lang.Thread.sleep_[j];java.lang.Thread.sleep_[j] 317654
+BusyThread;__start_thread;__pthread_start(void*);java.lang.Thread.run;com.android.simpleperf.debuggable.MainActivity$1.run;java.lang.Thread.sleep_[j];java.lang.Thread.sleep_[j];art::Monitor::Wait(art::Thread*, art::ObjPtr<art::mirror::Object>, long, int, bool, art::ThreadState);__set_errno_internal 144598
+BusyThread;__start_thread;__pthread_start(void*);java.lang.Thread.run;com.android.simpleperf.debuggable.MainActivity$1.run;java.lang.Thread.sleep_[j];java.lang.Thread.sleep_[j];art::Monitor::Wait(art::Thread*, art::ObjPtr<art::mirror::Object>, long, int, bool, art::ThreadState);syscall;unknown;unknown 144638
+BusyThread;__start_thread;__pthread_start(void*);java.lang.Thread.run;com.android.simpleperf.debuggable.MainActivity$1.run;java.lang.Thread.sleep_[j];java.lang.Thread.sleep_[j];art::Monitor::Wait(art::Thread*, art::ObjPtr<art::mirror::Object>, long, int, bool, art::ThreadState);syscall;unknown;unknown;unknown;unknown 144761
+BusyThread;__start_thread;__pthread_start(void*);java.lang.Thread.run;com.android.simpleperf.debuggable.MainActivity$1.run;java.lang.Thread.sleep_[j];java.lang.Thread.sleep_[j];art::Monitor::Wait(art::Thread*, art::ObjPtr<art::mirror::Object>, long, int, bool, art::ThreadState);syscall;unknown;unknown;unknown;unknown;unknown 141929
+BusyThread;__start_thread;__pthread_start(void*);java.lang.Thread.run;com.android.simpleperf.debuggable.MainActivity$1.run;java.lang.Thread.sleep_[j];java.lang.Thread.sleep_[j];art::Monitor::Wait(art::Thread*, art::ObjPtr<art::mirror::Object>, long, int, bool, art::ThreadState);syscall;unknown;unknown;unknown;unknown;unknown;unknown 19628
+BusyThread;__start_thread;__pthread_start(void*);java.lang.Thread.run;com.android.simpleperf.debuggable.MainActivity$1.run;java.lang.Thread.sleep_[j];java.lang.Thread.sleep_[j];art::Monitor::Wait(art::Thread*, art::ObjPtr<art::mirror::Object>, long, int, bool, art::ThreadState);unknown;unknown;unknown;unknown;unknown 144665
+BusyThread;__start_thread;__pthread_start(void*);java.lang.Thread.run;com.android.simpleperf.debuggable.MainActivity$1.run;java.lang.Thread.sleep_[j];java.lang.Thread.sleep_[j];unknown;unknown;unknown;unknown;unknown;unknown 148430
+BusyThread;__start_thread;__pthread_start(void*);java.lang.Thread.run;com.android.simpleperf.debuggable.MainActivity$1.run;unknown;unknown;unknown;unknown 131261
diff --git a/simpleperf/testdata/perf_with_jit_symbol.foldedstack_addrs b/simpleperf/testdata/perf_with_jit_symbol.foldedstack_addrs
new file mode 100644
index 00000000..f0167769
--- /dev/null
+++ b/simpleperf/testdata/perf_with_jit_symbol.foldedstack_addrs
@@ -0,0 +1,10 @@
+BusyThread;__start_thread;__pthread_start(void*);java.lang.Thread.run 17889729
+BusyThread;__start_thread;__pthread_start(void*);java.lang.Thread.run;com.android.simpleperf.debuggable.MainActivity$1.run;[kernel.kallsyms][+ffffff93eb483f36];[kernel.kallsyms][+ffffff93eb481f72];[kernel.kallsyms][+ffffff93eb5f1b6a];[kernel.kallsyms][+ffffff93eb5424a6] 131261
+BusyThread;__start_thread;__pthread_start(void*);java.lang.Thread.run;com.android.simpleperf.debuggable.MainActivity$1.run;java.lang.Thread.sleep;java.lang.Thread.sleep 317654
+BusyThread;__start_thread;__pthread_start(void*);java.lang.Thread.run;com.android.simpleperf.debuggable.MainActivity$1.run;java.lang.Thread.sleep;java.lang.Thread.sleep;[kernel.kallsyms][+ffffff93eb483f36];[kernel.kallsyms][+ffffff93eb481f72];[kernel.kallsyms][+ffffff93eb5f1b6a];[kernel.kallsyms][+ffffff93eb5424a6];[kernel.kallsyms][+ffffff93eb482226];[kernel.kallsyms][+ffffff93eb6188c2] 148430
+BusyThread;__start_thread;__pthread_start(void*);java.lang.Thread.run;com.android.simpleperf.debuggable.MainActivity$1.run;java.lang.Thread.sleep;java.lang.Thread.sleep;art::Monitor::Wait(art::Thread*, art::ObjPtr<art::mirror::Object>, long, int, bool, art::ThreadState);[kernel.kallsyms][+ffffff93eb483f36];[kernel.kallsyms][+ffffff93eb481f72];[kernel.kallsyms][+ffffff93eb5f1b6a];[kernel.kallsyms][+ffffff93eb5424a6];[kernel.kallsyms][+ffffff93eb482226] 144665
+BusyThread;__start_thread;__pthread_start(void*);java.lang.Thread.run;com.android.simpleperf.debuggable.MainActivity$1.run;java.lang.Thread.sleep;java.lang.Thread.sleep;art::Monitor::Wait(art::Thread*, art::ObjPtr<art::mirror::Object>, long, int, bool, art::ThreadState);__set_errno_internal 144598
+BusyThread;__start_thread;__pthread_start(void*);java.lang.Thread.run;com.android.simpleperf.debuggable.MainActivity$1.run;java.lang.Thread.sleep;java.lang.Thread.sleep;art::Monitor::Wait(art::Thread*, art::ObjPtr<art::mirror::Object>, long, int, bool, art::ThreadState);syscall;[kernel.kallsyms][+ffffff93eb484126];[kernel.kallsyms][+ffffff93eb502696] 144638
+BusyThread;__start_thread;__pthread_start(void*);java.lang.Thread.run;com.android.simpleperf.debuggable.MainActivity$1.run;java.lang.Thread.sleep;java.lang.Thread.sleep;art::Monitor::Wait(art::Thread*, art::ObjPtr<art::mirror::Object>, long, int, bool, art::ThreadState);syscall;[kernel.kallsyms][+ffffff93eb484156];[kernel.kallsyms][+ffffff93eb64c252];[kernel.kallsyms][+ffffff93eb645bee];[kernel.kallsyms][+ffffff93eb647f66] 144761
+BusyThread;__start_thread;__pthread_start(void*);java.lang.Thread.run;com.android.simpleperf.debuggable.MainActivity$1.run;java.lang.Thread.sleep;java.lang.Thread.sleep;art::Monitor::Wait(art::Thread*, art::ObjPtr<art::mirror::Object>, long, int, bool, art::ThreadState);syscall;[kernel.kallsyms][+ffffff93eb484156];[kernel.kallsyms][+ffffff93eb64c252];[kernel.kallsyms][+ffffff93eb645bee];[kernel.kallsyms][+ffffff93eb647ffa];[kernel.kallsyms][+ffffff93eb64aab2] 141929
+BusyThread;__start_thread;__pthread_start(void*);java.lang.Thread.run;com.android.simpleperf.debuggable.MainActivity$1.run;java.lang.Thread.sleep;java.lang.Thread.sleep;art::Monitor::Wait(art::Thread*, art::ObjPtr<art::mirror::Object>, long, int, bool, art::ThreadState);syscall;[kernel.kallsyms][+ffffff93eb484156];[kernel.kallsyms][+ffffff93eb64c252];[kernel.kallsyms][+ffffff93eb645bee];[kernel.kallsyms][+ffffff93eb647ffa];[kernel.kallsyms][+ffffff93eb64ab86];[kernel.kallsyms][+ffffff93ed05e93e] 19628
diff --git a/simpleperf/testdata/perf_with_jit_symbol.foldedstack_with_pid b/simpleperf/testdata/perf_with_jit_symbol.foldedstack_with_pid
new file mode 100644
index 00000000..a824e7d8
--- /dev/null
+++ b/simpleperf/testdata/perf_with_jit_symbol.foldedstack_with_pid
@@ -0,0 +1,10 @@
+BusyThread-7601;__start_thread;__pthread_start(void*);java.lang.Thread.run 17889729
+BusyThread-7601;__start_thread;__pthread_start(void*);java.lang.Thread.run;com.android.simpleperf.debuggable.MainActivity$1.run;java.lang.Thread.sleep_[j];java.lang.Thread.sleep_[j] 317654
+BusyThread-7601;__start_thread;__pthread_start(void*);java.lang.Thread.run;com.android.simpleperf.debuggable.MainActivity$1.run;java.lang.Thread.sleep_[j];java.lang.Thread.sleep_[j];art::Monitor::Wait(art::Thread*, art::ObjPtr<art::mirror::Object>, long, int, bool, art::ThreadState);__set_errno_internal 144598
+BusyThread-7601;__start_thread;__pthread_start(void*);java.lang.Thread.run;com.android.simpleperf.debuggable.MainActivity$1.run;java.lang.Thread.sleep_[j];java.lang.Thread.sleep_[j];art::Monitor::Wait(art::Thread*, art::ObjPtr<art::mirror::Object>, long, int, bool, art::ThreadState);syscall;unknown;unknown 144638
+BusyThread-7601;__start_thread;__pthread_start(void*);java.lang.Thread.run;com.android.simpleperf.debuggable.MainActivity$1.run;java.lang.Thread.sleep_[j];java.lang.Thread.sleep_[j];art::Monitor::Wait(art::Thread*, art::ObjPtr<art::mirror::Object>, long, int, bool, art::ThreadState);syscall;unknown;unknown;unknown;unknown 144761
+BusyThread-7601;__start_thread;__pthread_start(void*);java.lang.Thread.run;com.android.simpleperf.debuggable.MainActivity$1.run;java.lang.Thread.sleep_[j];java.lang.Thread.sleep_[j];art::Monitor::Wait(art::Thread*, art::ObjPtr<art::mirror::Object>, long, int, bool, art::ThreadState);syscall;unknown;unknown;unknown;unknown;unknown 141929
+BusyThread-7601;__start_thread;__pthread_start(void*);java.lang.Thread.run;com.android.simpleperf.debuggable.MainActivity$1.run;java.lang.Thread.sleep_[j];java.lang.Thread.sleep_[j];art::Monitor::Wait(art::Thread*, art::ObjPtr<art::mirror::Object>, long, int, bool, art::ThreadState);syscall;unknown;unknown;unknown;unknown;unknown;unknown 19628
+BusyThread-7601;__start_thread;__pthread_start(void*);java.lang.Thread.run;com.android.simpleperf.debuggable.MainActivity$1.run;java.lang.Thread.sleep_[j];java.lang.Thread.sleep_[j];art::Monitor::Wait(art::Thread*, art::ObjPtr<art::mirror::Object>, long, int, bool, art::ThreadState);unknown;unknown;unknown;unknown;unknown 144665
+BusyThread-7601;__start_thread;__pthread_start(void*);java.lang.Thread.run;com.android.simpleperf.debuggable.MainActivity$1.run;java.lang.Thread.sleep_[j];java.lang.Thread.sleep_[j];unknown;unknown;unknown;unknown;unknown;unknown 148430
+BusyThread-7601;__start_thread;__pthread_start(void*);java.lang.Thread.run;com.android.simpleperf.debuggable.MainActivity$1.run;unknown;unknown;unknown;unknown 131261
diff --git a/simpleperf/testdata/perf_with_jit_symbol.foldedstack_with_tid b/simpleperf/testdata/perf_with_jit_symbol.foldedstack_with_tid
new file mode 100644
index 00000000..6b640128
--- /dev/null
+++ b/simpleperf/testdata/perf_with_jit_symbol.foldedstack_with_tid
@@ -0,0 +1,10 @@
+BusyThread-7601/7630;__start_thread;__pthread_start(void*);java.lang.Thread.run 17889729
+BusyThread-7601/7630;__start_thread;__pthread_start(void*);java.lang.Thread.run;com.android.simpleperf.debuggable.MainActivity$1.run;java.lang.Thread.sleep_[j];java.lang.Thread.sleep_[j] 317654
+BusyThread-7601/7630;__start_thread;__pthread_start(void*);java.lang.Thread.run;com.android.simpleperf.debuggable.MainActivity$1.run;java.lang.Thread.sleep_[j];java.lang.Thread.sleep_[j];art::Monitor::Wait(art::Thread*, art::ObjPtr<art::mirror::Object>, long, int, bool, art::ThreadState);__set_errno_internal 144598
+BusyThread-7601/7630;__start_thread;__pthread_start(void*);java.lang.Thread.run;com.android.simpleperf.debuggable.MainActivity$1.run;java.lang.Thread.sleep_[j];java.lang.Thread.sleep_[j];art::Monitor::Wait(art::Thread*, art::ObjPtr<art::mirror::Object>, long, int, bool, art::ThreadState);syscall;unknown;unknown 144638
+BusyThread-7601/7630;__start_thread;__pthread_start(void*);java.lang.Thread.run;com.android.simpleperf.debuggable.MainActivity$1.run;java.lang.Thread.sleep_[j];java.lang.Thread.sleep_[j];art::Monitor::Wait(art::Thread*, art::ObjPtr<art::mirror::Object>, long, int, bool, art::ThreadState);syscall;unknown;unknown;unknown;unknown 144761
+BusyThread-7601/7630;__start_thread;__pthread_start(void*);java.lang.Thread.run;com.android.simpleperf.debuggable.MainActivity$1.run;java.lang.Thread.sleep_[j];java.lang.Thread.sleep_[j];art::Monitor::Wait(art::Thread*, art::ObjPtr<art::mirror::Object>, long, int, bool, art::ThreadState);syscall;unknown;unknown;unknown;unknown;unknown 141929
+BusyThread-7601/7630;__start_thread;__pthread_start(void*);java.lang.Thread.run;com.android.simpleperf.debuggable.MainActivity$1.run;java.lang.Thread.sleep_[j];java.lang.Thread.sleep_[j];art::Monitor::Wait(art::Thread*, art::ObjPtr<art::mirror::Object>, long, int, bool, art::ThreadState);syscall;unknown;unknown;unknown;unknown;unknown;unknown 19628
+BusyThread-7601/7630;__start_thread;__pthread_start(void*);java.lang.Thread.run;com.android.simpleperf.debuggable.MainActivity$1.run;java.lang.Thread.sleep_[j];java.lang.Thread.sleep_[j];art::Monitor::Wait(art::Thread*, art::ObjPtr<art::mirror::Object>, long, int, bool, art::ThreadState);unknown;unknown;unknown;unknown;unknown 144665
+BusyThread-7601/7630;__start_thread;__pthread_start(void*);java.lang.Thread.run;com.android.simpleperf.debuggable.MainActivity$1.run;java.lang.Thread.sleep_[j];java.lang.Thread.sleep_[j];unknown;unknown;unknown;unknown;unknown;unknown 148430
+BusyThread-7601/7630;__start_thread;__pthread_start(void*);java.lang.Thread.run;com.android.simpleperf.debuggable.MainActivity$1.run;unknown;unknown;unknown;unknown 131261
diff --git a/simpleperf/testdata/perf_with_trace_offcpu.foldedstack b/simpleperf/testdata/perf_with_trace_offcpu.foldedstack
new file mode 100644
index 00000000..21b55652
--- /dev/null
+++ b/simpleperf/testdata/perf_with_trace_offcpu.foldedstack
@@ -0,0 +1,41 @@
+inplace_sampler;__start_thread;__pthread_start(void*);(anonymous namespace)::CommunicationThread(void*);UnixSocketServer::Create(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, bool);(anonymous namespace)::netdClientSocket(int, int, int);__socket;unknown_[k] 91406
+inplace_sampler;__start_thread;__pthread_start(void*);(anonymous namespace)::CommunicationThread(void*);UnixSocketServer::Create(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, bool);(anonymous namespace)::netdClientSocket(int, int, int);__socket;unknown_[k];unknown_[k];unknown_[k] 6063073
+inplace_sampler;__start_thread;__pthread_start(void*);(anonymous namespace)::CommunicationThread(void*);UnixSocketServer::Create(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, bool);bind;unknown_[k];unknown_[k] 171198
+inplace_sampler;__start_thread;__pthread_start(void*);(anonymous namespace)::CommunicationThread(void*);android::base::LogMessage::~LogMessage();android::base::LogMessage::LogLine(char const*, unsigned int, android::base::LogId, android::base::LogSeverity, char const*);__android_log_buf_print;__android_log_buf_write;__write_to_log_daemon;android_log_clockid 157031
+inplace_sampler;__start_thread;__pthread_start(void*);(anonymous namespace)::CommunicationThread(void*);android::base::LogMessage::~LogMessage();android::base::LogMessage::LogLine(char const*, unsigned int, android::base::LogId, android::base::LogSeverity, char const*);__android_log_buf_print;__android_log_buf_write;__write_to_log_init;__android_log_config_write 146458
+inplace_sampler;__start_thread;__pthread_start(void*);(anonymous namespace)::CommunicationThread(void*);android::base::LogMessage::~LogMessage();android::base::LogMessage::LogLine(char const*, unsigned int, android::base::LogId, android::base::LogSeverity, char const*);__android_log_buf_print;__android_log_buf_write;__write_to_log_init;logdAvailable;___faccessat;unknown_[k];unknown_[k];unknown_[k] 154479
+inplace_sampler;__start_thread;__pthread_start(void*);(anonymous namespace)::CommunicationThread(void*);android::base::LogMessage::~LogMessage();android::base::LogMessage::LogLine(char const*, unsigned int, android::base::LogId, android::base::LogSeverity, char const*);__android_log_buf_print;__android_log_buf_write;__write_to_log_init;logdOpen;(anonymous namespace)::netdClientConnect(int, sockaddr const*, unsigned int);__connect;unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k] 168490
+simpleperf;execvpe;execve;unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k] 3285208
+simpleperf_runt;[linker]_start;[linker]__linker_init;[linker]soinfo::call_constructors();[linker]soinfo::call_constructors();[linker]soinfo::call_constructors();[linker]void call_array<void (*)(int, char**, char**)>(char const*, void (**)(int, char**, char**), unsigned long, bool, char const*);netdClientInit;pthread_once;netdClientInitImpl();dlopen;[linker]__dlopen(char const*, int, void const*);[linker]do_dlopen(char const*, int, android_dlextinfo const*, void const*);[linker]find_libraries(android_namespace_t*, soinfo*, char const* const*, unsigned long, soinfo**, std::__1::vector<soinfo*, std::__1::allocator<soinfo*> >*, unsigned long, int, android_dlextinfo const*, bool, bool, std::__1::unordered_map<soinfo const*, ElfReader, std::__1::hash<soinfo const*>, std::__1::equal_to<soinfo const*>, std::__1::allocator<std::__1::pair<soinfo const* const, ElfReader> > >&, std::__1::vector<android_namespace_t*, std::__1::allocator<android_namespace_t*> >*);[linker]soinfo::link_image(LinkedList<soinfo, SoinfoListAllocator> const&, LinkedList<soinfo, SoinfoListAllocator> const&, android_dlextinfo const*) 156042
+simpleperf_runt;[linker]_start;[linker]__linker_init;[linker]soinfo::call_constructors();[linker]soinfo::call_constructors();[linker]soinfo::call_constructors();[linker]void call_array<void (*)(int, char**, char**)>(char const*, void (**)(int, char**, char**), unsigned long, bool, char const*);netdClientInit;pthread_once;netdClientInitImpl();dlopen;[linker]__dlopen(char const*, int, void const*);[linker]do_dlopen(char const*, int, android_dlextinfo const*, void const*);[linker]find_libraries(android_namespace_t*, soinfo*, char const* const*, unsigned long, soinfo**, std::__1::vector<soinfo*, std::__1::allocator<soinfo*> >*, unsigned long, int, android_dlextinfo const*, bool, bool, std::__1::unordered_map<soinfo const*, ElfReader, std::__1::hash<soinfo const*>, std::__1::equal_to<soinfo const*>, std::__1::allocator<std::__1::pair<soinfo const* const, ElfReader> > >&, std::__1::vector<android_namespace_t*, std::__1::allocator<android_namespace_t*> >*);[linker]soinfo::link_image(LinkedList<soinfo, SoinfoListAllocator> const&, LinkedList<soinfo, SoinfoListAllocator> const&, android_dlextinfo const*);[linker]VersionTracker::init_verneed(soinfo const*);[linker]std::__1::vector<version_info, std::__1::allocator<version_info> >::__append(unsigned long);[linker]operator new(unsigned long);[linker]LinkerSmallObjectAllocator::alloc();[linker]LinkerSmallObjectAllocator::alloc_page();unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k] 203697
+simpleperf_runt;[linker]_start;[linker]__linker_init;[linker]soinfo::call_constructors();[linker]soinfo::call_constructors();[linker]soinfo::call_constructors();[linker]void call_array<void (*)(int, char**, char**)>(char const*, void (**)(int, char**, char**), unsigned long, bool, char const*);netdClientInit;pthread_once;netdClientInitImpl();dlopen;[linker]__dlopen(char const*, int, void const*);[linker]do_dlopen(char const*, int, android_dlextinfo const*, void const*);[linker]find_libraries(android_namespace_t*, soinfo*, char const* const*, unsigned long, soinfo**, std::__1::vector<soinfo*, std::__1::allocator<soinfo*> >*, unsigned long, int, android_dlextinfo const*, bool, bool, std::__1::unordered_map<soinfo const*, ElfReader, std::__1::hash<soinfo const*>, std::__1::equal_to<soinfo const*>, std::__1::allocator<std::__1::pair<soinfo const* const, ElfReader> > >&, std::__1::vector<android_namespace_t*, std::__1::allocator<android_namespace_t*> >*);[linker]soinfo::link_image(LinkedList<soinfo, SoinfoListAllocator> const&, LinkedList<soinfo, SoinfoListAllocator> const&, android_dlextinfo const*);[linker]VersionTracker::init_verneed(soinfo const*);[linker]strcmp;unknown_[k];unknown_[k];unknown_[k] 151823
+simpleperf_runt;[linker]_start;[linker]__linker_init;[linker]soinfo::call_constructors();[linker]soinfo::call_constructors();[linker]soinfo::call_constructors();[linker]void call_array<void (*)(int, char**, char**)>(char const*, void (**)(int, char**, char**), unsigned long, bool, char const*);netdClientInit;pthread_once;netdClientInitImpl();dlopen;[linker]__dlopen(char const*, int, void const*);[linker]do_dlopen(char const*, int, android_dlextinfo const*, void const*);[linker]find_libraries(android_namespace_t*, soinfo*, char const* const*, unsigned long, soinfo**, std::__1::vector<soinfo*, std::__1::allocator<soinfo*> >*, unsigned long, int, android_dlextinfo const*, bool, bool, std::__1::unordered_map<soinfo const*, ElfReader, std::__1::hash<soinfo const*>, std::__1::equal_to<soinfo const*>, std::__1::allocator<std::__1::pair<soinfo const* const, ElfReader> > >&, std::__1::vector<android_namespace_t*, std::__1::allocator<android_namespace_t*> >*);[linker]soinfo::link_image(LinkedList<soinfo, SoinfoListAllocator> const&, LinkedList<soinfo, SoinfoListAllocator> const&, android_dlextinfo const*);[linker]VersionTracker::init_verneed(soinfo const*);[linker]strcmp;unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k] 176250
+simpleperf_runt;[linker]_start;[linker]__linker_init;[linker]soinfo::call_constructors();[linker]soinfo::call_constructors();[linker]soinfo::call_constructors();[linker]void call_array<void (*)(int, char**, char**)>(char const*, void (**)(int, char**, char**), unsigned long, bool, char const*);netdClientInit;pthread_once;netdClientInitImpl();dlopen;[linker]__dlopen(char const*, int, void const*);[linker]do_dlopen(char const*, int, android_dlextinfo const*, void const*);[linker]find_libraries(android_namespace_t*, soinfo*, char const* const*, unsigned long, soinfo**, std::__1::vector<soinfo*, std::__1::allocator<soinfo*> >*, unsigned long, int, android_dlextinfo const*, bool, bool, std::__1::unordered_map<soinfo const*, ElfReader, std::__1::hash<soinfo const*>, std::__1::equal_to<soinfo const*>, std::__1::allocator<std::__1::pair<soinfo const* const, ElfReader> > >&, std::__1::vector<android_namespace_t*, std::__1::allocator<android_namespace_t*> >*);[linker]soinfo::link_image(LinkedList<soinfo, SoinfoListAllocator> const&, LinkedList<soinfo, SoinfoListAllocator> const&, android_dlextinfo const*);[linker]bool soinfo::relocate<plain_reloc_iterator>(VersionTracker const&, plain_reloc_iterator&&, LinkedList<soinfo, SoinfoListAllocator> const&, LinkedList<soinfo, SoinfoListAllocator> const&);unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k] 484688
+simpleperf_runt;[linker]_start;[linker]__linker_init;[linker]soinfo::call_constructors();[linker]soinfo::call_constructors();[linker]soinfo::call_constructors();[linker]void call_array<void (*)(int, char**, char**)>(char const*, void (**)(int, char**, char**), unsigned long, bool, char const*);netdClientInit;pthread_once;netdClientInitImpl();dlopen;[linker]__dlopen(char const*, int, void const*);[linker]do_dlopen(char const*, int, android_dlextinfo const*, void const*);[linker]find_libraries(android_namespace_t*, soinfo*, char const* const*, unsigned long, soinfo**, std::__1::vector<soinfo*, std::__1::allocator<soinfo*> >*, unsigned long, int, android_dlextinfo const*, bool, bool, std::__1::unordered_map<soinfo const*, ElfReader, std::__1::hash<soinfo const*>, std::__1::equal_to<soinfo const*>, std::__1::allocator<std::__1::pair<soinfo const* const, ElfReader> > >&, std::__1::vector<android_namespace_t*, std::__1::allocator<android_namespace_t*> >*);[linker]soinfo::link_image(LinkedList<soinfo, SoinfoListAllocator> const&, LinkedList<soinfo, SoinfoListAllocator> const&, android_dlextinfo const*);[linker]soinfo::protect_relro();[linker]phdr_table_protect_gnu_relro(elf64_phdr const*, unsigned long, unsigned long long);[linker]mprotect;unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k] 187396
+simpleperf_runt;[linker]_start;[linker]__linker_init;[linker]soinfo::call_constructors();[linker]soinfo::call_constructors();[linker]soinfo::call_constructors();[linker]void call_array<void (*)(int, char**, char**)>(char const*, void (**)(int, char**, char**), unsigned long, bool, char const*);netdClientInit;pthread_once;netdClientInitImpl();dlsym;[linker]dlsym_impl(void*, char const*, char const*, void const*) 201302
+simpleperf_runt;[linker]_start;[linker]__linker_init;[linker]soinfo::call_constructors();[linker]soinfo::call_constructors();[linker]void call_array<void (*)(int, char**, char**)>(char const*, void (**)(int, char**, char**), unsigned long, bool, char const*);(anonymous namespace)::InitSampler();pthread_create;clone;__bionic_clone;unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k] 643958
+simpleperf_runt;[linker]_start;[linker]__linker_init;[linker]soinfo::call_constructors();[linker]soinfo::call_constructors();[linker]void call_array<void (*)(int, char**, char**)>(char const*, void (**)(int, char**, char**), unsigned long, bool, char const*);_GLOBAL__sub_I_BitcodeReader.cpp;llvm::cl::Option::addArgument();llvm::ManagedStaticBase::RegisterManagedStatic(void* (*)(), void (*)(void*)) const;unknown_[k];unknown_[k] 194791
+simpleperf_runt;[linker]_start;[linker]__linker_init;[linker]soinfo::call_constructors();[linker]soinfo::call_constructors();[linker]void call_array<void (*)(int, char**, char**)>(char const*, void (**)(int, char**, char**), unsigned long, bool, char const*);_GLOBAL__sub_I_BitcodeReader.cpp;llvm::cl::Option::addArgument();llvm::ManagedStaticBase::RegisterManagedStatic(void* (*)(), void (*)(void*)) const;unknown_[k];unknown_[k];unknown_[k] 398803
+simpleperf_runt;[linker]_start;[linker]__linker_init;[linker]soinfo::call_constructors();[linker]soinfo::call_constructors();[linker]void call_array<void (*)(int, char**, char**)>(char const*, void (**)(int, char**, char**), unsigned long, bool, char const*);_GLOBAL__sub_I_BitcodeReader.cpp;llvm::cl::Option::addArgument();llvm::ManagedStaticBase::RegisterManagedStatic(void* (*)(), void (*)(void*)) const;unknown_[k];unknown_[k];unknown_[k];unknown_[k] 740052
+simpleperf_runt;[linker]_start;[linker]__linker_init;[linker]soinfo::call_constructors();[linker]soinfo::call_constructors();[linker]void call_array<void (*)(int, char**, char**)>(char const*, void (**)(int, char**, char**), unsigned long, bool, char const*);_GLOBAL__sub_I_BitcodeReader.cpp;llvm::cl::Option::addArgument();llvm::ManagedStaticBase::RegisterManagedStatic(void* (*)(), void (*)(void*)) const;unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k] 130834
+simpleperf_runt;[linker]_start;[linker]__linker_init;[linker]soinfo::call_constructors();[linker]soinfo::call_constructors();[linker]void call_array<void (*)(int, char**, char**)>(char const*, void (**)(int, char**, char**), unsigned long, bool, char const*);_GLOBAL__sub_I_BitcodeReader.cpp;llvm::cl::Option::addArgument();llvm::ManagedStaticBase::RegisterManagedStatic(void* (*)(), void (*)(void*)) const;unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k] 1150677
+simpleperf_runt;[linker]_start;[linker]__linker_init;[linker]soinfo::call_constructors();[linker]soinfo::call_constructors();[linker]void call_array<void (*)(int, char**, char**)>(char const*, void (**)(int, char**, char**), unsigned long, bool, char const*);_GLOBAL__sub_I_BitcodeReader.cpp;llvm::cl::Option::addArgument();llvm::ManagedStaticBase::RegisterManagedStatic(void* (*)(), void (*)(void*)) const;unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k] 64739
+simpleperf_runt;[linker]_start;[linker]__linker_init;[linker]soinfo::call_constructors();[linker]soinfo::call_constructors();[linker]void call_array<void (*)(int, char**, char**)>(char const*, void (**)(int, char**, char**), unsigned long, bool, char const*);_GLOBAL__sub_I_BitcodeReader.cpp;llvm::cl::Option::addArgument();llvm::ManagedStaticBase::RegisterManagedStatic(void* (*)(), void (*)(void*)) const;unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k] 199219
+simpleperf_runt;[linker]_start;[linker]__linker_init;[linker]soinfo::call_constructors();[linker]soinfo::call_constructors();[linker]void call_array<void (*)(int, char**, char**)>(char const*, void (**)(int, char**, char**), unsigned long, bool, char const*);_GLOBAL__sub_I_BitcodeReader.cpp;llvm::cl::Option::addArgument();llvm::ManagedStaticBase::RegisterManagedStatic(void* (*)(), void (*)(void*)) const;unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k] 65261
+simpleperf_runt;[linker]_start;[linker]__linker_init;[linker]soinfo::call_constructors();[linker]soinfo::call_constructors();[linker]void call_array<void (*)(int, char**, char**)>(char const*, void (**)(int, char**, char**), unsigned long, bool, char const*);_GLOBAL__sub_I_BitcodeReader.cpp;llvm::cl::Option::addArgument();llvm::ManagedStaticBase::RegisterManagedStatic(void* (*)(), void (*)(void*)) const;unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k] 1280937
+simpleperf_runt;[linker]_start;[linker]__linker_init;[linker]soinfo::call_constructors();[linker]soinfo::call_constructors();[linker]void call_array<void (*)(int, char**, char**)>(char const*, void (**)(int, char**, char**), unsigned long, bool, char const*);_GLOBAL__sub_I_dso.cpp;__cxa_atexit;mprotect 225260
+simpleperf_runt;[linker]_start;[linker]__linker_init;[linker]soinfo::call_constructors();[linker]soinfo::call_constructors();[linker]void call_array<void (*)(int, char**, char**)>(char const*, void (**)(int, char**, char**), unsigned long, bool, char const*);_GLOBAL__sub_I_event_type.cpp;__cxx_global_var_init 228542
+simpleperf_runt;_start_main;__libc_init;main;GlobalFunction() 1046446718
+simpleperf_runt;_start_main;__libc_init;main;GlobalFunction();RunFunction() 43750
+simpleperf_runt;_start_main;__libc_init;main;GlobalFunction();RunFunction();unknown_[k] 69167
+simpleperf_runt;_start_main;__libc_init;main;GlobalFunction();RunFunction();unknown_[k];unknown_[k] 69947
+simpleperf_runt;_start_main;__libc_init;main;GlobalFunction();RunFunction();unknown_[k];unknown_[k];unknown_[k] 24251931
+simpleperf_runt;_start_main;__libc_init;main;GlobalFunction();RunFunction();unknown_[k];unknown_[k];unknown_[k];unknown_[k] 4538646
+simpleperf_runt;_start_main;__libc_init;main;GlobalFunction();RunFunction();unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k] 446563
+simpleperf_runt;_start_main;__libc_init;main;GlobalFunction();RunFunction();unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k] 15373698
+simpleperf_runt;_start_main;__libc_init;main;GlobalFunction();RunFunction();unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k] 269896
+simpleperf_runt;_start_main;__libc_init;main;GlobalFunction();RunFunction();unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k] 538437
+simpleperf_runt;_start_main;__libc_init;main;GlobalFunction();SleepFunction(unsigned long long);nanosleep;unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k] 717231253
+simpleperf_runt;execvpe;execve;unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k] 800678
+simpleperf_runt;execvpe;execve;unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k] 22906770
+simpleperf_runt;std::__1::locale::__global();std::__1::locale::__imp::__imp(unsigned long);unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k];unknown_[k] 193334
diff --git a/simpleperf/testdata/perf_with_two_event_types.foldedstack b/simpleperf/testdata/perf_with_two_event_types.foldedstack
new file mode 100644
index 00000000..b12ef2dc
--- /dev/null
+++ b/simpleperf/testdata/perf_with_two_event_types.foldedstack
@@ -0,0 +1,2 @@
+simpleperf 70372
+sleep 3913545
diff --git a/simpleperf/testdata/perf_with_two_event_types.foldedstack_cpu_clock b/simpleperf/testdata/perf_with_two_event_types.foldedstack_cpu_clock
new file mode 100644
index 00000000..d34ca5a6
--- /dev/null
+++ b/simpleperf/testdata/perf_with_two_event_types.foldedstack_cpu_clock
@@ -0,0 +1 @@
+sleep 500000