diff options
author | Mark Hansen <markhansen@google.com> | 2021-09-28 10:16:24 +1000 |
---|---|---|
committer | Mark Hansen <markhansen@google.com> | 2021-09-28 10:21:31 +1000 |
commit | c64f3e93da447522c8e6f14728c204be157f3e40 (patch) | |
tree | bed671d40202309c692a935f9dfdf17f81d11519 | |
parent | a17ac5b7f65789ac9c3c790bab8e5b3783b582ba (diff) | |
download | extras-c64f3e93da447522c8e6f14728c204be157f3e40.tar.gz |
Group pprof samples by threadpool comm
This is a heuristic, that many threads often live in threadpools
labelled with numbers and a common string. By grouping these
threadpools, we're able to see common work.
Often these threadpools are created with a format string like "DefaultPool%d",
and my heuristic "unmaps" that, kind-of. Hopefully it's clear to the reader of
these labels what is meant.
Here's an example of running it on a Google Maps build, which nicely shows the
difference between the `thread` and new `threadpool` tags:
```
$ pprof pprof.profile
Entering interactive mode (type "help" for commands, "o" for options)
(pprof) tags
thread: Total 103383248686.0
22118435629.0 (21.39%): DefaultPool8
13358985234.0 (12.92%): DefaultPool1
7386956769.0 ( 7.15%): GoogleApiHandle
5410867464.0 ( 5.23%): Primes-1
5307503967.0 ( 5.13%): Binder:14330_3
5151798743.0 ( 4.98%): com.google.android.apps.maps
4790949129.0 ( 4.63%): queued-work-loo
3147004739.0 ( 3.04%): RenderThread
2885251486.0 ( 2.79%): ChromiumNet
2629960939.0 ( 2.54%): GLViewThreadImp
2614501772.0 ( 2.53%): Labeling
2317391011.0 ( 2.24%): LocFreshPool1
2268259602.0 ( 2.19%): MemoryMon
2129146149.0 ( 2.06%): weak-identity-m
1870032894.0 ( 1.81%): Binder:14330_1
1814053100.0 ( 1.75%): Primes-2
1804141068.0 ( 1.75%): DefaultPool6
1724206320.0 ( 1.67%): TilePrepPool2
1611002144.0 ( 1.56%): DefaultPool7
1579754376.0 ( 1.53%): Jit thread pool
1518972491.0 ( 1.47%): TilePrepPool3
1356331492.0 ( 1.31%): DefaultPool3
1210458509.0 ( 1.17%): DefaultPool5
1198135693.0 ( 1.16%): NavState
1126259329.0 ( 1.09%): Location
1008315579.0 ( 0.98%): DefaultPool4
983120929.0 ( 0.95%): TilePrepPool1
814214874.0 ( 0.79%): Timer-0
793766954.0 ( 0.77%): ThreadPoolForeg
344686545.0 ( 0.33%): HeapTaskDaemon
244979090.0 ( 0.24%): DefaultPool2
146047936.0 ( 0.14%): NetworkPool1
126920534.0 ( 0.12%): NetworkPool2
82417870.0 ( 0.08%): OfflineManage
70649177.0 (0.068%): Sensors
68850631.0 (0.067%): NavInternal
66499899.0 (0.064%): NetworkPool4
59950214.0 (0.058%): Primes-nativecr
51125581.0 (0.049%): NetworkPool3
39731570.0 (0.038%): NetworkPool5
29167450.0 (0.028%): ReferenceQueueD
27231566.0 (0.026%): pool-6-thread-1
23984844.0 (0.023%): CronetInit
18201927.0 (0.018%): Binder:14330_4
12020989.0 (0.012%): ClassLoader
11934322.0 (0.012%): SharedPreferenc
8960622.0 (0.0087%): Primes-Jank
5272917.0 (0.0051%): FinalizerDaemon
5145625.0 (0.005%): GAC_Executor[1]
3079896.0 (0.003%): NativeLibLoader
1476511.0 (0.0014%): pool-6-thread-2
1342552.0 (0.0013%): network
1224843.0 (0.0012%): OfflineDynamic
1112971.0 (0.0011%): Binder:14330_2
568698.0 (0.00055%): ThreadPoolServi
264167.0 (0.00026%): pool-6-thread-3
199062.0 (0.00019%): LocFreshPool2
183646.0 (0.00018%): Network File Th
144583.0 (0.00014%): OneGoogle #0
59323.0 (5.7e-05%): glide-active-re
34740.0 (3.4e-05%): Traffic auto-re
threadpool: Total 103383248686.0
42712648745.0 (41.31%): DefaultPool%d
7386956769.0 ( 7.15%): GoogleApiHandle
7224920564.0 ( 6.99%): Primes-%d
7196851759.0 ( 6.96%): Binder:%d_%d
5151798743.0 ( 4.98%): com.google.android.apps.maps
4790949129.0 ( 4.63%): queued-work-loo
4226299740.0 ( 4.09%): TilePrepPool%d
3147004739.0 ( 3.04%): RenderThread
2885251486.0 ( 2.79%): ChromiumNet
2629960939.0 ( 2.54%): GLViewThreadImp
2614501772.0 ( 2.53%): Labeling
2317590073.0 ( 2.24%): LocFreshPool%d
2268259602.0 ( 2.19%): MemoryMon
2129146149.0 ( 2.06%): weak-identity-m
1579754376.0 ( 1.53%): Jit thread pool
1198135693.0 ( 1.16%): NavState
1126259329.0 ( 1.09%): Location
814214874.0 ( 0.79%): Timer-%d
793766954.0 ( 0.77%): ThreadPoolForeg
430325520.0 ( 0.42%): NetworkPool%d
344686545.0 ( 0.33%): HeapTaskDaemon
82417870.0 ( 0.08%): OfflineManage
70649177.0 (0.068%): Sensors
68850631.0 (0.067%): NavInternal
59950214.0 (0.058%): Primes-nativecr
29167450.0 (0.028%): ReferenceQueueD
28972244.0 (0.028%): pool-%d-thread-%d
23984844.0 (0.023%): CronetInit
12020989.0 (0.012%): ClassLoader
11934322.0 (0.012%): SharedPreferenc
8960622.0 (0.0087%): Primes-Jank
5272917.0 (0.0051%): FinalizerDaemon
5145625.0 (0.005%): GAC_Executor[%d]
3079896.0 (0.003%): NativeLibLoader
1342552.0 (0.0013%): network
1224843.0 (0.0012%): OfflineDynamic
568698.0 (0.00055%): ThreadPoolServi
183646.0 (0.00018%): Network File Th
144583.0 (0.00014%): OneGoogle #%d
59323.0 (5.7e-05%): glide-active-re
34740.0 (3.4e-05%): Traffic auto-re
```
BUG=200992206
Test: ran test/test.py -p TestPprofProtoGenerator.\*
Change-Id: I249aed58f753f58215c9bd0e7e2e5b9253baf610
-rwxr-xr-x | simpleperf/scripts/pprof_proto_generator.py | 15 | ||||
-rw-r--r-- | simpleperf/scripts/test/pprof_proto_generator_test.py | 8 |
2 files changed, 20 insertions, 3 deletions
diff --git a/simpleperf/scripts/pprof_proto_generator.py b/simpleperf/scripts/pprof_proto_generator.py index 20f61987..b29634da 100755 --- a/simpleperf/scripts/pprof_proto_generator.py +++ b/simpleperf/scripts/pprof_proto_generator.py @@ -27,6 +27,7 @@ import logging import os import os.path +import re from simpleperf_report_lib import ReportLib from simpleperf_utils import (Addr2Nearestline, BaseArgumentParser, BinaryFinder, extant_dir, @@ -301,6 +302,7 @@ class PprofProfileGenerator(object): self.lib.ShowArtFrames() for file_path in self.config['proguard_mapping_file'] or []: self.lib.AddProguardMappingFile(file_path) + numbers_re = re.compile(r"\d+") # Process all samples in perf.data, aggregate samples. while True: @@ -320,9 +322,16 @@ class PprofProfileGenerator(object): sample = Sample() sample.add_value(sample_type_id, 1) sample.add_value(sample_type_id + 1, report_sample.period) - label = Label(self.get_string_id("thread"), - self.get_string_id(report_sample.thread_comm)) - sample.labels.append(label) + sample.labels.append(Label( + self.get_string_id("thread"), + self.get_string_id(report_sample.thread_comm))) + # Heuristic: threadpools doing similar work are often named as + # name-1, name-2, name-3. Combine threadpools into one label + # "name-%d" if they only differ by a number. + sample.labels.append(Label( + self.get_string_id("threadpool"), + self.get_string_id( + numbers_re.sub("%d", report_sample.thread_comm)))) if self._filter_symbol(symbol): location_id = self.get_location_id(report_sample.ip, symbol) sample.add_location_id(location_id) diff --git a/simpleperf/scripts/test/pprof_proto_generator_test.py b/simpleperf/scripts/test/pprof_proto_generator_test.py index 72089f71..4a8de00b 100644 --- a/simpleperf/scripts/test/pprof_proto_generator_test.py +++ b/simpleperf/scripts/test/pprof_proto_generator_test.py @@ -50,6 +50,14 @@ class TestPprofProtoGenerator(TestBase): self.assertIn(key, self.run_generator(['--pid', '10419', '10416'])) self.assertNotIn(key, self.run_generator(['--pid', '10416'])) + def test_thread_labels(self): + output = self.run_generator() + self.assertIn('label[0] = thread:Binder:10419_1', output) + self.assertIn('label[0] = thread:Binder:10419_2', output) + self.assertIn('label[0] = thread:Binder:10419_3', output) + self.assertIn('label[0] = thread:Binder:10419_4', output) + self.assertIn('label[1] = threadpool:Binder:%d_%d', output) + def test_tid_filter(self): key1 = 'art::ProfileSaver::Run()' # function in thread 10459 key2 = 'PlayScene::DoFrame()' # function in thread 10463 |