summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Hansen <markhansen@google.com>2021-09-28 10:16:24 +1000
committerMark Hansen <markhansen@google.com>2021-09-28 10:21:31 +1000
commitc64f3e93da447522c8e6f14728c204be157f3e40 (patch)
treebed671d40202309c692a935f9dfdf17f81d11519
parenta17ac5b7f65789ac9c3c790bab8e5b3783b582ba (diff)
downloadextras-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-xsimpleperf/scripts/pprof_proto_generator.py15
-rw-r--r--simpleperf/scripts/test/pprof_proto_generator_test.py8
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