Merge "Trace Redaction - Remove comm value from new task events" into main
diff --git a/Android.bp b/Android.bp
index c136ed5..1cf094b 100644
--- a/Android.bp
+++ b/Android.bp
@@ -11435,6 +11435,7 @@
"src/trace_processor/importers/common/flow_tracker.cc",
"src/trace_processor/importers/common/global_args_tracker.cc",
"src/trace_processor/importers/common/jit_cache.cc",
+ "src/trace_processor/importers/common/machine_tracker.cc",
"src/trace_processor/importers/common/mapping_tracker.cc",
"src/trace_processor/importers/common/metadata_tracker.cc",
"src/trace_processor/importers/common/process_tracker.cc",
@@ -11766,6 +11767,7 @@
"src/trace_processor/importers/proto/memory_tracker_snapshot_module.cc",
"src/trace_processor/importers/proto/memory_tracker_snapshot_parser.cc",
"src/trace_processor/importers/proto/metadata_minimal_module.cc",
+ "src/trace_processor/importers/proto/multi_machine_trace_manager.cc",
"src/trace_processor/importers/proto/network_trace_module.cc",
"src/trace_processor/importers/proto/packet_analyzer.cc",
"src/trace_processor/importers/proto/packet_sequence_state_generation.cc",
diff --git a/BUILD b/BUILD
index 2e137b7..2b53c16 100644
--- a/BUILD
+++ b/BUILD
@@ -1477,6 +1477,8 @@
"src/trace_processor/importers/common/global_args_tracker.h",
"src/trace_processor/importers/common/jit_cache.cc",
"src/trace_processor/importers/common/jit_cache.h",
+ "src/trace_processor/importers/common/machine_tracker.cc",
+ "src/trace_processor/importers/common/machine_tracker.h",
"src/trace_processor/importers/common/mapping_tracker.cc",
"src/trace_processor/importers/common/mapping_tracker.h",
"src/trace_processor/importers/common/metadata_tracker.cc",
@@ -1850,6 +1852,8 @@
"src/trace_processor/importers/proto/memory_tracker_snapshot_parser.h",
"src/trace_processor/importers/proto/metadata_minimal_module.cc",
"src/trace_processor/importers/proto/metadata_minimal_module.h",
+ "src/trace_processor/importers/proto/multi_machine_trace_manager.cc",
+ "src/trace_processor/importers/proto/multi_machine_trace_manager.h",
"src/trace_processor/importers/proto/network_trace_module.cc",
"src/trace_processor/importers/proto/network_trace_module.h",
"src/trace_processor/importers/proto/packet_analyzer.cc",
diff --git a/docs/instrumentation/tracing-sdk.md b/docs/instrumentation/tracing-sdk.md
index ea9393d..a9b0831 100644
--- a/docs/instrumentation/tracing-sdk.md
+++ b/docs/instrumentation/tracing-sdk.md
@@ -30,7 +30,7 @@
To start using the Client API, first check out the latest SDK release:
```bash
-git clone https://android.googlesource.com/platform/external/perfetto -b v43.1
+git clone https://android.googlesource.com/platform/external/perfetto -b v44.0
```
The SDK consists of two files, `sdk/perfetto.h` and `sdk/perfetto.cc`. These are
diff --git a/examples/sdk/README.md b/examples/sdk/README.md
index 8c53d85..6e5754e 100644
--- a/examples/sdk/README.md
+++ b/examples/sdk/README.md
@@ -15,7 +15,7 @@
First, check out the latest Perfetto release:
```bash
-git clone https://android.googlesource.com/platform/external/perfetto -b v43.1
+git clone https://android.googlesource.com/platform/external/perfetto -b v44.0
```
Then, build using CMake:
diff --git a/protos/perfetto/trace/ftrace/fastrpc.proto b/protos/perfetto/trace/ftrace/fastrpc.proto
index 2008bae..01ad8f9 100644
--- a/protos/perfetto/trace/ftrace/fastrpc.proto
+++ b/protos/perfetto/trace/ftrace/fastrpc.proto
@@ -10,3 +10,29 @@
optional int64 len = 2;
optional uint64 total_allocated = 3;
}
+message FastrpcDmaFreeFtraceEvent {
+ optional int32 cid = 1;
+ optional uint64 phys = 2;
+ optional uint64 size = 3;
+}
+message FastrpcDmaAllocFtraceEvent {
+ optional int32 cid = 1;
+ optional uint64 phys = 2;
+ optional uint64 size = 3;
+ optional uint64 attr = 4;
+ optional int32 mflags = 5;
+}
+message FastrpcDmaUnmapFtraceEvent {
+ optional int32 cid = 1;
+ optional uint64 phys = 2;
+ optional uint64 size = 3;
+}
+message FastrpcDmaMapFtraceEvent {
+ optional int32 cid = 1;
+ optional int32 fd = 2;
+ optional uint64 phys = 3;
+ optional uint64 size = 4;
+ optional uint64 len = 5;
+ optional uint32 attr = 6;
+ optional int32 mflags = 7;
+}
diff --git a/protos/perfetto/trace/ftrace/ftrace_event.proto b/protos/perfetto/trace/ftrace/ftrace_event.proto
index 5d5bf06..302de2a 100644
--- a/protos/perfetto/trace/ftrace/ftrace_event.proto
+++ b/protos/perfetto/trace/ftrace/ftrace_event.proto
@@ -614,5 +614,9 @@
F2fsBackgroundGcFtraceEvent f2fs_background_gc = 495;
F2fsGcBeginFtraceEvent f2fs_gc_begin = 496;
F2fsGcEndFtraceEvent f2fs_gc_end = 497;
+ FastrpcDmaFreeFtraceEvent fastrpc_dma_free = 498;
+ FastrpcDmaAllocFtraceEvent fastrpc_dma_alloc = 499;
+ FastrpcDmaUnmapFtraceEvent fastrpc_dma_unmap = 500;
+ FastrpcDmaMapFtraceEvent fastrpc_dma_map = 501;
}
}
diff --git a/protos/perfetto/trace/perfetto_trace.proto b/protos/perfetto/trace/perfetto_trace.proto
index 4988bfd..a821823 100644
--- a/protos/perfetto/trace/perfetto_trace.proto
+++ b/protos/perfetto/trace/perfetto_trace.proto
@@ -8339,6 +8339,32 @@
optional int64 len = 2;
optional uint64 total_allocated = 3;
}
+message FastrpcDmaFreeFtraceEvent {
+ optional int32 cid = 1;
+ optional uint64 phys = 2;
+ optional uint64 size = 3;
+}
+message FastrpcDmaAllocFtraceEvent {
+ optional int32 cid = 1;
+ optional uint64 phys = 2;
+ optional uint64 size = 3;
+ optional uint64 attr = 4;
+ optional int32 mflags = 5;
+}
+message FastrpcDmaUnmapFtraceEvent {
+ optional int32 cid = 1;
+ optional uint64 phys = 2;
+ optional uint64 size = 3;
+}
+message FastrpcDmaMapFtraceEvent {
+ optional int32 cid = 1;
+ optional int32 fd = 2;
+ optional uint64 phys = 3;
+ optional uint64 size = 4;
+ optional uint64 len = 5;
+ optional uint32 attr = 6;
+ optional int32 mflags = 7;
+}
// End of protos/perfetto/trace/ftrace/fastrpc.proto
@@ -10685,6 +10711,10 @@
F2fsBackgroundGcFtraceEvent f2fs_background_gc = 495;
F2fsGcBeginFtraceEvent f2fs_gc_begin = 496;
F2fsGcEndFtraceEvent f2fs_gc_end = 497;
+ FastrpcDmaFreeFtraceEvent fastrpc_dma_free = 498;
+ FastrpcDmaAllocFtraceEvent fastrpc_dma_alloc = 499;
+ FastrpcDmaUnmapFtraceEvent fastrpc_dma_unmap = 500;
+ FastrpcDmaMapFtraceEvent fastrpc_dma_map = 501;
}
}
diff --git a/python/perfetto/prebuilts/manifests/trace_processor_shell.py b/python/perfetto/prebuilts/manifests/trace_processor_shell.py
index d71c679..cd0e407 100755
--- a/python/perfetto/prebuilts/manifests/trace_processor_shell.py
+++ b/python/perfetto/prebuilts/manifests/trace_processor_shell.py
@@ -1,15 +1,15 @@
-# This file has been generated by: tools/roll-prebuilts v43.2
+# This file has been generated by: tools/roll-prebuilts v44.0
TRACE_PROCESSOR_SHELL_MANIFEST = [{
'arch':
'mac-amd64',
'file_name':
'trace_processor_shell',
'file_size':
- 8583624,
+ 8879352,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/mac-amd64/trace_processor_shell',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/mac-amd64/trace_processor_shell',
'sha256':
- 'a1c16a74725cefb62406b39538b5d22f56a94e390a0394816d2945793f91f8cf',
+ '8ac591150919d5e3701a3fdb7ce44f2ae9b48a4b27afc2da31b97dba3238c4c8',
'platform':
'darwin',
'machine': ['x86_64']
@@ -19,11 +19,11 @@
'file_name':
'trace_processor_shell',
'file_size':
- 7980232,
+ 8261544,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/mac-arm64/trace_processor_shell',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/mac-arm64/trace_processor_shell',
'sha256':
- '3651654cd462df8a2ec8cb3f7375cee01ccc11861a675b9da0d00aa697efe7b2',
+ '55ef799a383fb460e0167fad68b8f169d6d46bc10285df9db26cecec52dd24f1',
'platform':
'darwin',
'machine': ['arm64']
@@ -33,11 +33,11 @@
'file_name':
'trace_processor_shell',
'file_size':
- 8770200,
+ 9035064,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/linux-amd64/trace_processor_shell',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/linux-amd64/trace_processor_shell',
'sha256':
- '0796a01af496a6b62623fea89b2d34063ade9d156783e1f88949d8b7ab1f76d0',
+ 'd4826f1c2acf0a4caaa167bc089d12a1e6460fcd2847ec8c026933ed73d30540',
'platform':
'linux',
'machine': ['x86_64']
@@ -47,11 +47,11 @@
'file_name':
'trace_processor_shell',
'file_size':
- 6371036,
+ 6581588,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/linux-arm/trace_processor_shell',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/linux-arm/trace_processor_shell',
'sha256':
- 'f4bbef5008de376913c3a95410802d94d8d5715439c3f797be0e4ca8c9bccb1a',
+ '1918aa71521e3daaeedadd9a0760f597c94c3baa803836e442f54c584dc402ac',
'platform':
'linux',
'machine': ['armv6l', 'armv7l', 'armv8l']
@@ -61,11 +61,11 @@
'file_name':
'trace_processor_shell',
'file_size':
- 8425776,
+ 8698104,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/linux-arm64/trace_processor_shell',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/linux-arm64/trace_processor_shell',
'sha256':
- 'f1ff5585a06ad8b9fc1d13dbf8d02f39d2804019ea7e70b740872e0f6826695f',
+ '9b4e77e541bf397bcdb4f51b30b0cea23aea761865c5bebdac424b15beecdf18',
'platform':
'linux',
'machine': ['aarch64']
@@ -75,55 +75,55 @@
'file_name':
'trace_processor_shell',
'file_size':
- 6382140,
+ 6581420,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/android-arm/trace_processor_shell',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/android-arm/trace_processor_shell',
'sha256':
- '989b209a108c7d44e2531bb15a5d57f667c717cf774bb8a4a810f99fda0b958d'
+ 'cdf7d4f0ad38f977f20d52c2d881f5aeac3ad1a9b07032dee32b08ee631ad041'
}, {
'arch':
'android-arm64',
'file_name':
'trace_processor_shell',
'file_size':
- 8340616,
+ 8592256,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/android-arm64/trace_processor_shell',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/android-arm64/trace_processor_shell',
'sha256':
- 'ade7e72990cb97fd74766cd0df50a24cbd547d2f54c26b49d66236c809922645'
+ '8df9e4e01509184fe5d65f79af343384f8e11f90eabebe8075cf779d6d82304d'
}, {
'arch':
'android-x86',
'file_name':
'trace_processor_shell',
'file_size':
- 9170488,
+ 9457000,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/android-x86/trace_processor_shell',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/android-x86/trace_processor_shell',
'sha256':
- '6bd1f74616fd8f620fbf3228f83301844adae08a772b8ac2a64703724a79b516'
+ 'd0404998a661864dfabb440a1227ded43c6e793741675576c863460ce869bead'
}, {
'arch':
'android-x64',
'file_name':
'trace_processor_shell',
'file_size':
- 8591040,
+ 8848144,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/android-x64/trace_processor_shell',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/android-x64/trace_processor_shell',
'sha256':
- '1ccbcb8b2928615cf512cf97eaba395de6f1fc5d70313e884ea3975867f365ea'
+ '8e5a539457f8a50b898a2f2178acd14d7f4076a6a10bbc030a7c2a8cb229b57f'
}, {
'arch':
'windows-amd64',
'file_name':
'trace_processor_shell.exe',
'file_size':
- 8676352,
+ 8951296,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/windows-amd64/trace_processor_shell.exe',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/windows-amd64/trace_processor_shell.exe',
'sha256':
- '9125418fedd96eb0e6f1ddeaf46069a05bdcb910592b059669fc982b4fff3f1b',
+ 'd01a7d0c3bd460a041fdd25cba88163d945ef939f48de3c76cdc554e19321419',
'platform':
'win32',
'machine': ['amd64']
diff --git a/python/perfetto/prebuilts/manifests/tracebox.py b/python/perfetto/prebuilts/manifests/tracebox.py
index 159aa28..22cb347 100755
--- a/python/perfetto/prebuilts/manifests/tracebox.py
+++ b/python/perfetto/prebuilts/manifests/tracebox.py
@@ -1,15 +1,15 @@
-# This file has been generated by: tools/roll-prebuilts v43.2
+# This file has been generated by: tools/roll-prebuilts v44.0
TRACEBOX_MANIFEST = [{
'arch':
'mac-amd64',
'file_name':
'tracebox',
'file_size':
- 1564728,
+ 1548256,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/mac-amd64/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/mac-amd64/tracebox',
'sha256':
- '239736808cbfba5085892e15c145381ea37ddba5df7c8fad97b68d9c04a4d860',
+ '392cb1ae5f11c6a87d15e69fb6576e5c62ae3b1d87a43d68d7fe8bd3cea4fd7e',
'platform':
'darwin',
'machine': ['x86_64']
@@ -19,11 +19,11 @@
'file_name':
'tracebox',
'file_size':
- 1459160,
+ 1459096,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/mac-arm64/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/mac-arm64/tracebox',
'sha256':
- '4af1449dc90e5505bd5f3d638f11b8bf7e5dc82c0290f0085dc0b335ababd143',
+ '0edde5e3d35ef044848eeca5f63da7fa9f96e4bb3cac5e87ba4e2772a09e8f8f',
'platform':
'darwin',
'machine': ['arm64']
@@ -33,11 +33,11 @@
'file_name':
'tracebox',
'file_size':
- 2314424,
+ 2304304,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/linux-amd64/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/linux-amd64/tracebox',
'sha256':
- 'a97a5efdaf475f13f4f5947c03289029253f89d0f44caa64765b00b269551297',
+ 'cd2b3c0fdc7d0a649bbe4103901263927b2f736836ce56fa06467efa5c825472',
'platform':
'linux',
'machine': ['x86_64']
@@ -47,11 +47,11 @@
'file_name':
'tracebox',
'file_size':
- 1418968,
+ 1408648,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/linux-arm/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/linux-arm/tracebox',
'sha256':
- '818390305d15730fadcbd87dc3c8d87a439e040a02b5098f51af15dfff3f0ca0',
+ '51794d99493c04ced26a40a242ddb6a53b1213ee96b0b1af9ba874715656ff06',
'platform':
'linux',
'machine': ['armv6l', 'armv7l', 'armv8l']
@@ -61,11 +61,11 @@
'file_name':
'tracebox',
'file_size':
- 2221176,
+ 2212000,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/linux-arm64/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/linux-arm64/tracebox',
'sha256':
- '5a3cf8c755e08b7a558083a70ad28293baa389e544ebd09806b6a883a5f17952',
+ '7faf03feecf045ed25bfad7cb845621c533ca50b586e722e1bb61aa7fd54cd74',
'platform':
'linux',
'machine': ['aarch64']
@@ -75,42 +75,42 @@
'file_name':
'tracebox',
'file_size':
- 1304280,
+ 1299200,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/android-arm/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/android-arm/tracebox',
'sha256':
- '87bb07c7ac4c58d306975cabad3ed5d4b6fe11a8d617dad30fe7dd25bfdc6736'
+ 'fa78644befc527481dac76b217762cbddb9233cc050c2a31444c78391ed7715c'
}, {
'arch':
'android-arm64',
'file_name':
'tracebox',
'file_size':
- 2076144,
+ 2067768,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/android-arm64/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/android-arm64/tracebox',
'sha256':
- '501b2bb0cba0ecb770e2b568698f89f6b42d083fcca111c872f7a0e95c0cacc5'
+ 'f3167ce57aec78e200675640a683a938bcb206219346427e42f86fdc70923386'
}, {
'arch':
'android-x86',
'file_name':
'tracebox',
'file_size':
- 2253568,
+ 2241784,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/android-x86/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/android-x86/tracebox',
'sha256':
- '28be4f88a9b8f950ebc45a20d4844002f9b3f81ef0230d0a5d9b1627cf89c9a5'
+ '9c9a4b1c498c985c3fbbd9122a9df66bb5275c715c54475d7fbabfec5722d50a'
}, {
'arch':
'android-x64',
'file_name':
'tracebox',
'file_size':
- 2101752,
+ 2092696,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/android-x64/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/android-x64/tracebox',
'sha256':
- '6c08b743b9cb6073a75e2b3dd34098e09e3c8bcace89096dc5b9d0f071b2831a'
+ '96fdc7b584247a2f4fc18d4a4a8e8891ab88693c8bc7a301e8dffb3ec8b96a1d'
}]
diff --git a/python/perfetto/prebuilts/manifests/traceconv.py b/python/perfetto/prebuilts/manifests/traceconv.py
index 85bdfe6..0978c4a 100755
--- a/python/perfetto/prebuilts/manifests/traceconv.py
+++ b/python/perfetto/prebuilts/manifests/traceconv.py
@@ -1,15 +1,15 @@
-# This file has been generated by: tools/roll-prebuilts v43.2
+# This file has been generated by: tools/roll-prebuilts v44.0
TRACECONV_MANIFEST = [{
'arch':
'mac-amd64',
'file_name':
'traceconv',
'file_size':
- 7790424,
+ 8069808,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/mac-amd64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/mac-amd64/traceconv',
'sha256':
- 'c1d9c50c89545b41af88525dc6f3ce508156ed3787ccecae0ff7c8e736c39318',
+ '7d9c0421235c083932408a5a716372dfddc3a87828b2b3b7e30f8d3aa1c5bf43',
'platform':
'darwin',
'machine': ['x86_64']
@@ -19,11 +19,11 @@
'file_name':
'traceconv',
'file_size':
- 7264824,
+ 7529704,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/mac-arm64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/mac-arm64/traceconv',
'sha256':
- 'df5349ae462dbd7c1ca9a1b8a0f09c044a47026d6ad8dc24e6945701d7c61a84',
+ 'bffadacd2a6e44a9f5c7b0beb48f3f5d568433fd9d425cdee5342e7f3c112cbb',
'platform':
'darwin',
'machine': ['arm64']
@@ -33,11 +33,11 @@
'file_name':
'traceconv',
'file_size':
- 7885952,
+ 8152216,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/linux-amd64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/linux-amd64/traceconv',
'sha256':
- 'b2c19364c1fb68e9f5cde610e5d71dd59b9fdf2bada8f7e1eefc319f828f7cb1',
+ 'b1815e29aabb51deff0c68e3e690c96aedfea0796a0292d5f177815d33584995',
'platform':
'linux',
'machine': ['x86_64']
@@ -47,11 +47,11 @@
'file_name':
'traceconv',
'file_size':
- 5919372,
+ 6132076,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/linux-arm/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/linux-arm/traceconv',
'sha256':
- 'b669be326b4b6a024e557e0927f1014fd1ea5d5427e194dc0653f21acac273ee',
+ '2b391081ce9ce45d843584816bc11ba7383b634c88ffa75c7dc927a9632e6d28',
'platform':
'linux',
'machine': ['armv6l', 'armv7l', 'armv8l']
@@ -61,11 +61,11 @@
'file_name':
'traceconv',
'file_size':
- 7588200,
+ 7862696,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/linux-arm64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/linux-arm64/traceconv',
'sha256':
- 'aff1c4751e721733ce85f58048c17971399fe605a81ac300d306c200d6957818',
+ 'd10a598fb6c14926ceb3afb0fc9841a4924c2fedadf9ef981609781ecb8b338b',
'platform':
'linux',
'machine': ['aarch64']
@@ -75,55 +75,55 @@
'file_name':
'traceconv',
'file_size':
- 5931120,
+ 6131288,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/android-arm/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/android-arm/traceconv',
'sha256':
- '826212f658fef744fbaeea66331b6fe7ca0152f69cf63ff2ea218a376d5d41d9'
+ '3cf391f42bb51e47159b2236b1171cd1bd4461f3e4576b00100f590cf7ff8b2b'
}, {
'arch':
'android-arm64',
'file_name':
'traceconv',
'file_size':
- 7546224,
+ 7798968,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/android-arm64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/android-arm64/traceconv',
'sha256':
- '29dd7e93e9182c4413a9f9c1c6a6f643f64e1fe0b9657ab1ea3cec8b0bb360c9'
+ '1b17a740ba86a5e218b69dd981d739173515777ee761f3723446f6e400e9367e'
}, {
'arch':
'android-x86',
'file_name':
'traceconv',
'file_size':
- 8176528,
+ 8464080,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/android-x86/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/android-x86/traceconv',
'sha256':
- '63c2ebe7ed51f9667bcf69d7b9679f6077db5fd8ee9e1be7b786037e2a649fcb'
+ '2dc045a79276e62f71cf40c1e8ee433125785ce32a223ce4c9e5871cacc3940e'
}, {
'arch':
'android-x64',
'file_name':
'traceconv',
'file_size':
- 7767560,
+ 8025896,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/android-x64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/android-x64/traceconv',
'sha256':
- 'bb9350230c2fac5adf9e6fe21937865b6eaafaefc555ae26e68cae9419ad5ee8'
+ '03db509df8e3816b4c4d78d187d42794b37c3d2c830d85feae0f17a5b581ee53'
}, {
'arch':
'windows-amd64',
'file_name':
'traceconv.exe',
'file_size':
- 7645696,
+ 7920128,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/windows-amd64/traceconv.exe',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/windows-amd64/traceconv.exe',
'sha256':
- '0c84b712941e4f63f74e66731745f94aec3cd30d94469e52cdf1143262f063a4',
+ '97b66259d385a5bd482ebb5a21535b67e3836fb0cf7c971bb36d5f5ea00774bd',
'platform':
'win32',
'machine': ['amd64']
diff --git a/src/tools/ftrace_proto_gen/event_list b/src/tools/ftrace_proto_gen/event_list
index db13230..3d5ead4 100644
--- a/src/tools/ftrace_proto_gen/event_list
+++ b/src/tools/ftrace_proto_gen/event_list
@@ -492,3 +492,7 @@
f2fs/f2fs_background_gc
f2fs/f2fs_gc_begin
f2fs/f2fs_gc_end
+fastrpc/fastrpc_dma_free
+fastrpc/fastrpc_dma_alloc
+fastrpc/fastrpc_dma_unmap
+fastrpc/fastrpc_dma_map
diff --git a/src/trace_processor/importers/common/BUILD.gn b/src/trace_processor/importers/common/BUILD.gn
index c3ba78a..43dfb23 100644
--- a/src/trace_processor/importers/common/BUILD.gn
+++ b/src/trace_processor/importers/common/BUILD.gn
@@ -39,6 +39,8 @@
"global_args_tracker.h",
"jit_cache.cc",
"jit_cache.h",
+ "machine_tracker.cc",
+ "machine_tracker.h",
"mapping_tracker.cc",
"mapping_tracker.h",
"metadata_tracker.cc",
diff --git a/src/trace_processor/importers/common/event_tracker.cc b/src/trace_processor/importers/common/event_tracker.cc
index 0ed799b..43cf710 100644
--- a/src/trace_processor/importers/common/event_tracker.cc
+++ b/src/trace_processor/importers/common/event_tracker.cc
@@ -65,7 +65,9 @@
max_timestamp_ = timestamp;
auto* counter_values = context_->storage->mutable_counter_table();
- return counter_values->Insert({timestamp, track_id, value}).id;
+ return counter_values
+ ->Insert({timestamp, track_id, value, {}, context_->machine_id()})
+ .id;
}
std::optional<CounterId> EventTracker::PushCounter(
diff --git a/src/trace_processor/importers/common/machine_tracker.cc b/src/trace_processor/importers/common/machine_tracker.cc
new file mode 100644
index 0000000..26e8d4a
--- /dev/null
+++ b/src/trace_processor/importers/common/machine_tracker.cc
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+#include "src/trace_processor/importers/common/machine_tracker.h"
+#include "src/trace_processor/storage/trace_storage.h"
+
+namespace perfetto::trace_processor {
+
+MachineTracker::MachineTracker(TraceProcessorContext* context,
+ uint32_t raw_machine_id)
+ : context_(context) {
+ auto id =
+ context_->storage->mutable_machine_table()->Insert({raw_machine_id}).id;
+
+ if (raw_machine_id)
+ machine_id_ = id;
+}
+MachineTracker::~MachineTracker() = default;
+
+} // namespace perfetto::trace_processor
diff --git a/src/trace_processor/importers/common/machine_tracker.h b/src/trace_processor/importers/common/machine_tracker.h
new file mode 100644
index 0000000..1909311
--- /dev/null
+++ b/src/trace_processor/importers/common/machine_tracker.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+#ifndef SRC_TRACE_PROCESSOR_IMPORTERS_COMMON_MACHINE_TRACKER_H_
+#define SRC_TRACE_PROCESSOR_IMPORTERS_COMMON_MACHINE_TRACKER_H_
+
+#include <cstdint>
+
+#include "src/trace_processor/types/trace_processor_context.h"
+
+namespace perfetto::trace_processor {
+
+// Tracks information in the machine table.
+class MachineTracker {
+ public:
+ MachineTracker(TraceProcessorContext* contex, uint32_t raw_machine_id);
+ ~MachineTracker();
+
+ std::optional<MachineId> machine_id() const { return machine_id_; }
+
+ private:
+ std::optional<MachineId> machine_id_;
+ TraceProcessorContext* const context_;
+};
+
+} // namespace perfetto::trace_processor
+
+#endif // SRC_TRACE_PROCESSOR_IMPORTERS_COMMON_MACHINE_TRACKER_H_
diff --git a/src/trace_processor/importers/common/process_tracker.cc b/src/trace_processor/importers/common/process_tracker.cc
index 473c48e..910cc25 100644
--- a/src/trace_processor/importers/common/process_tracker.cc
+++ b/src/trace_processor/importers/common/process_tracker.cc
@@ -32,15 +32,25 @@
// tid0/pid0 to utid0/upid0. If other types of traces refer to tid0/pid0,
// then they will get their own non-zero utid/upid, so that those threads are
// still surfaced in embedder UIs.
- tables::ThreadTable::Row thread_row;
- thread_row.tid = 0u;
- thread_row.upid = 0u;
- thread_row.is_main_thread = true;
- context_->storage->mutable_thread_table()->Insert(thread_row);
-
+ //
+ // Note on multi-machine tracing: utid/upid of the swapper process of
+ // secondary machine will not be 0. The ProcessTracker needs to insert to the
+ // thread and process tables to reserve utid and upid.
tables::ProcessTable::Row process_row;
process_row.pid = 0u;
- context_->storage->mutable_process_table()->Insert(process_row);
+ process_row.machine_id = context_->machine_id();
+ auto upid =
+ context_->storage->mutable_process_table()->Insert(process_row).row;
+
+ tables::ThreadTable::Row thread_row;
+ thread_row.tid = 0u;
+ thread_row.upid = upid; // The swapper upid may be != 0 for remote machines.
+ thread_row.is_main_thread = true;
+ thread_row.machine_id = context_->machine_id();
+ auto utid = context_->storage->mutable_thread_table()->Insert(thread_row).row;
+
+ swapper_upid_ = upid;
+ swapper_utid_ = utid;
// An element to match the reserved tid = 0.
thread_name_priorities_.push_back(ThreadNamePriority::kOther);
@@ -53,12 +63,20 @@
tables::ThreadTable::Row row;
row.tid = tid;
row.start_ts = timestamp;
+ row.machine_id = context_->machine_id();
auto* thread_table = context_->storage->mutable_thread_table();
UniqueTid new_utid = thread_table->Insert(row).row;
tids_[tid].emplace_back(new_utid);
- PERFETTO_DCHECK(thread_name_priorities_.size() == new_utid);
- thread_name_priorities_.push_back(ThreadNamePriority::kOther);
+
+ if (PERFETTO_UNLIKELY(thread_name_priorities_.size() <= new_utid)) {
+ // This condition can happen in a multi-machine tracing session:
+ // Machine 1 gets utid 0, 1
+ // Machine 2 gets utid 2, 3
+ // Machine 1 gets utid 4: where thread_name_priorities_.size() == 2.
+ thread_name_priorities_.resize(new_utid + 1);
+ }
+ thread_name_priorities_[new_utid] = ThreadNamePriority::kOther;
return new_utid;
}
@@ -107,7 +125,8 @@
// Ensure that the tid matches the tid we were looking for.
PERFETTO_DCHECK(threads->tid()[utid] == tid);
-
+ // Ensure that the thread's machine ID matches the context's machine ID.
+ PERFETTO_DCHECK(threads->machine_id()[utid] == context_->machine_id());
// If the thread is being tracked by the process tracker, it should not be
// known to have ended.
PERFETTO_DCHECK(!threads->end_ts()[utid].has_value());
@@ -135,6 +154,13 @@
return;
auto* thread_table = context_->storage->mutable_thread_table();
+ if (PERFETTO_UNLIKELY(thread_name_priorities_.size() <= utid)) {
+ // This condition can happen in a multi-machine tracing session:
+ // Machine 1 gets utid 0, 1
+ // Machine 2 gets utid 2, 3
+ // Machine 1 gets utid 4: where thread_name_priorities_.size() == 2.
+ thread_name_priorities_.resize(utid + 1);
+ }
if (priority >= thread_name_priorities_[utid]) {
thread_table->mutable_name()->Set(utid, thread_name_id);
thread_name_priorities_[utid] = priority;
@@ -214,6 +240,8 @@
// If no matching thread was found, create a new one.
UniqueTid utid = opt_utid ? *opt_utid : StartNewThread(std::nullopt, tid);
PERFETTO_DCHECK(thread_table->tid()[utid] == tid);
+ // Ensure that the thread's machine ID matches the context's machine ID.
+ PERFETTO_DCHECK(thread_table->machine_id()[utid] == context_->machine_id());
// Find matching process or create new one.
if (!thread_table->upid()[utid].has_value()) {
@@ -383,6 +411,7 @@
tables::ProcessTable::Row row;
row.pid = pid;
+ row.machine_id = context_->machine_id();
UniquePid upid = process_table->Insert(row).row;
*it_and_ins.first = upid; // Update the newly inserted hashmap entry.
@@ -507,11 +536,13 @@
}
void ProcessTracker::SetPidZeroIsUpidZeroIdleProcess() {
- // Create a mapping from (t|p)id 0 -> u(t|p)id 0 for the idle process.
- tids_.Insert(0, std::vector<UniqueTid>{0});
- pids_.Insert(0, UniquePid{0});
-
auto swapper_id = context_->storage->InternString("swapper");
+
+ // Create a mapping from (t|p)id 0 -> u(t|p)id for the idle process.
+ tids_.Insert(0, std::vector<UniqueTid>{swapper_utid_});
+ pids_.Insert(0, swapper_upid_);
+
+ // Use null StringId for the swapper process/thread.
UpdateThreadName(0, swapper_id, ThreadNamePriority::kTraceProcessorConstant);
}
diff --git a/src/trace_processor/importers/common/process_tracker.h b/src/trace_processor/importers/common/process_tracker.h
index df648c2..3808f99 100644
--- a/src/trace_processor/importers/common/process_tracker.h
+++ b/src/trace_processor/importers/common/process_tracker.h
@@ -189,6 +189,10 @@
uint32_t tid,
std::vector<uint32_t> nstid);
+ // The UniqueTid of the swapper thread, is 0 for the default machine and is
+ // > 0 for remote machines.
+ UniqueTid swapper_utid() const { return swapper_utid_; }
+
private:
// Returns the utid of a thread having |tid| and |pid| as the parent process.
// pid == std::nullopt matches all processes.
@@ -253,6 +257,9 @@
// Keeps track pid-namespaced processes, keyed by root-level pids.
std::unordered_map<uint32_t /* pid (aka tgid) */, NamespacedProcess>
namespaced_processes_;
+
+ UniquePid swapper_upid_ = 0;
+ UniqueTid swapper_utid_ = 0;
};
} // namespace trace_processor
diff --git a/src/trace_processor/importers/common/sched_event_tracker.h b/src/trace_processor/importers/common/sched_event_tracker.h
index 3eba6ae..12aa4c0 100644
--- a/src/trace_processor/importers/common/sched_event_tracker.h
+++ b/src/trace_processor/importers/common/sched_event_tracker.h
@@ -45,8 +45,9 @@
// just switched to. Set the duration to -1, to indicate that the event is
// not finished. Duration will be updated later after event finish.
auto* sched = context_->storage->mutable_sched_slice_table();
- auto row_and_id = sched->Insert(
- {ts, /* duration */ -1, cpu, next_utid, kNullStringId, next_prio});
+ auto row_and_id =
+ sched->Insert({ts, /* duration */ -1, cpu, next_utid, kNullStringId,
+ next_prio, context_->machine_id()});
SchedId sched_id = row_and_id.id;
return *sched->id().IndexOf(sched_id);
}
diff --git a/src/trace_processor/importers/common/thread_state_tracker.cc b/src/trace_processor/importers/common/thread_state_tracker.cc
index 9c3ee3c..37d26d1 100644
--- a/src/trace_processor/importers/common/thread_state_tracker.cc
+++ b/src/trace_processor/importers/common/thread_state_tracker.cc
@@ -15,14 +15,17 @@
*/
#include "src/trace_processor/importers/common/thread_state_tracker.h"
+#include <cstdint>
#include <optional>
+#include "src/trace_processor/importers/common/process_tracker.h"
namespace perfetto {
namespace trace_processor {
-ThreadStateTracker::ThreadStateTracker(TraceStorage* storage)
- : storage_(storage),
- running_string_id_(storage->InternString("Running")),
- runnable_string_id_(storage->InternString("R")) {}
+ThreadStateTracker::ThreadStateTracker(TraceProcessorContext* context)
+ : storage_(context->storage.get()),
+ context_(context),
+ running_string_id_(storage_->InternString("Running")),
+ runnable_string_id_(storage_->InternString("R")) {}
ThreadStateTracker::~ThreadStateTracker() = default;
void ThreadStateTracker::PushSchedSwitchEvent(int64_t event_ts,
@@ -124,9 +127,9 @@
std::optional<uint16_t> cpu,
std::optional<UniqueTid> waker_utid,
std::optional<uint16_t> common_flags) {
- // Ignore utid 0 because it corresponds to the swapper thread which doesn't
- // make sense to insert.
- if (utid == 0)
+ // Ignore the swapper utid because it corresponds to the swapper thread which
+ // doesn't make sense to insert.
+ if (utid == context_->process_tracker->swapper_utid())
return;
// Insert row with unfinished state
@@ -137,6 +140,7 @@
row.dur = -1;
row.utid = utid;
row.state = state;
+ row.machine_id = context_->machine_id();
if (common_flags.has_value()) {
row.irq_context = CommonFlagsToIrqContext(*common_flags);
}
diff --git a/src/trace_processor/importers/common/thread_state_tracker.h b/src/trace_processor/importers/common/thread_state_tracker.h
index 2b7206b..9a78ada 100644
--- a/src/trace_processor/importers/common/thread_state_tracker.h
+++ b/src/trace_processor/importers/common/thread_state_tracker.h
@@ -28,14 +28,13 @@
// waking events and blocking reasons.
class ThreadStateTracker : public Destructible {
public:
- explicit ThreadStateTracker(TraceStorage*);
+ explicit ThreadStateTracker(TraceProcessorContext*);
ThreadStateTracker(const ThreadStateTracker&) = delete;
ThreadStateTracker& operator=(const ThreadStateTracker&) = delete;
~ThreadStateTracker() override;
static ThreadStateTracker* GetOrCreate(TraceProcessorContext* context) {
if (!context->thread_state_tracker) {
- context->thread_state_tracker.reset(
- new ThreadStateTracker(context->storage.get()));
+ context->thread_state_tracker.reset(new ThreadStateTracker(context));
}
return static_cast<ThreadStateTracker*>(
context->thread_state_tracker.get());
@@ -90,6 +89,7 @@
}
TraceStorage* const storage_;
+ TraceProcessorContext* const context_;
// Strings
StringId running_string_id_;
diff --git a/src/trace_processor/importers/common/thread_state_tracker_unittest.cc b/src/trace_processor/importers/common/thread_state_tracker_unittest.cc
index ea6794a..153b02b 100644
--- a/src/trace_processor/importers/common/thread_state_tracker_unittest.cc
+++ b/src/trace_processor/importers/common/thread_state_tracker_unittest.cc
@@ -20,6 +20,7 @@
#include "src/trace_processor/importers/common/args_tracker.h"
#include "src/trace_processor/importers/common/global_args_tracker.h"
+#include "src/trace_processor/importers/common/process_tracker.h"
#include "src/trace_processor/types/trace_processor_context.h"
#include "test/gtest_and_gmock.h"
@@ -41,10 +42,11 @@
public:
ThreadStateTrackerUnittest() {
context_.storage.reset(new TraceStorage());
+ context_.process_tracker.reset(new ProcessTracker(&context_));
context_.global_args_tracker.reset(
new GlobalArgsTracker(context_.storage.get()));
context_.args_tracker.reset(new ArgsTracker(&context_));
- tracker_.reset(new ThreadStateTracker(context_.storage.get()));
+ tracker_.reset(new ThreadStateTracker(&context_));
}
StringId StringIdOf(const char* s) {
diff --git a/src/trace_processor/importers/common/track_tracker.cc b/src/trace_processor/importers/common/track_tracker.cc
index 2163b80..ca5ffbd 100644
--- a/src/trace_processor/importers/common/track_tracker.cc
+++ b/src/trace_processor/importers/common/track_tracker.cc
@@ -70,6 +70,7 @@
tables::ThreadTrackTable::Row row;
row.utid = utid;
+ row.machine_id = context_->machine_id();
auto id = context_->storage->mutable_thread_track_table()->Insert(row).id;
thread_tracks_[utid] = id;
return id;
@@ -82,6 +83,7 @@
tables::ProcessTrackTable::Row row;
row.upid = upid;
+ row.machine_id = context_->machine_id();
auto id = context_->storage->mutable_process_track_table()->Insert(row).id;
process_tracks_[upid] = id;
return id;
@@ -102,6 +104,7 @@
tables::CpuTrackTable::Row row(name);
row.cpu = cpu;
+ row.machine_id = context_->machine_id();
auto id = context_->storage->mutable_cpu_track_table()->Insert(row).id;
cpu_tracks_[std::make_pair(name, cpu)] = id;
@@ -115,7 +118,9 @@
if (it != gpu_tracks_.end())
return it->second;
- auto id = context_->storage->mutable_gpu_track_table()->Insert(row).id;
+ auto row_copy = row;
+ row_copy.machine_id = context_->machine_id();
+ auto id = context_->storage->mutable_gpu_track_table()->Insert(row_copy).id;
gpu_tracks_[tuple] = id;
return id;
}
@@ -163,6 +168,7 @@
// the ID's scope is global.
tables::ProcessTrackTable::Row track(name);
track.upid = upid;
+ track.machine_id = context_->machine_id();
TrackId id =
context_->storage->mutable_process_track_table()->Insert(track).id;
chrome_tracks_[tuple] = id;
@@ -179,6 +185,7 @@
TrackId TrackTracker::CreateGlobalAsyncTrack(StringId name, StringId source) {
tables::TrackTable::Row row(name);
+ row.machine_id = context_->machine_id();
auto id = context_->storage->mutable_track_table()->Insert(row).id;
if (!source.is_null()) {
context_->args_tracker->AddArgsTo(id).AddArg(source_key_,
@@ -192,6 +199,7 @@
StringId source) {
tables::ProcessTrackTable::Row row(name);
row.upid = upid;
+ row.machine_id = context_->machine_id();
auto id = context_->storage->mutable_process_track_table()->Insert(row).id;
if (!source.is_null()) {
context_->args_tracker->AddArgsTo(id).AddArg(source_key_,
@@ -207,6 +215,7 @@
tables::ProcessTrackTable::Row row;
row.upid = upid;
+ row.machine_id = context_->machine_id();
auto id = context_->storage->mutable_process_track_table()->Insert(row).id;
chrome_process_instant_tracks_[upid] = id;
@@ -218,8 +227,10 @@
TrackId TrackTracker::GetOrCreateLegacyChromeGlobalInstantTrack() {
if (!chrome_global_instant_track_id_) {
+ tables::TrackTable::Row row;
+ row.machine_id = context_->machine_id();
chrome_global_instant_track_id_ =
- context_->storage->mutable_track_table()->Insert({}).id;
+ context_->storage->mutable_track_table()->Insert(row).id;
context_->args_tracker->AddArgsTo(*chrome_global_instant_track_id_)
.AddArg(source_key_, Variadic::String(chrome_source_));
@@ -233,6 +244,7 @@
}
tables::TrackTable::Row row;
row.name = context_->storage->InternString("Trace Triggers");
+ row.machine_id = context_->machine_id();
trigger_track_id_ = context_->storage->mutable_track_table()->Insert(row).id;
return *trigger_track_id_;
}
@@ -251,6 +263,7 @@
row.parent_id = InternTrackForGroup(group);
row.unit = unit;
row.description = description;
+ row.machine_id = context_->machine_id();
TrackId track =
context_->storage->mutable_counter_track_table()->Insert(row).id;
global_counter_tracks_by_name_[name] = track;
@@ -269,6 +282,7 @@
tables::CpuCounterTrackTable::Row row(name);
row.cpu = cpu;
+ row.machine_id = context_->machine_id();
TrackId track =
context_->storage->mutable_cpu_counter_track_table()->Insert(row).id;
@@ -284,6 +298,7 @@
tables::ThreadCounterTrackTable::Row row(name);
row.utid = utid;
+ row.machine_id = context_->machine_id();
TrackId track =
context_->storage->mutable_thread_counter_track_table()->Insert(row).id;
@@ -304,6 +319,7 @@
row.upid = upid;
row.unit = unit;
row.description = description;
+ row.machine_id = context_->machine_id();
TrackId track =
context_->storage->mutable_process_counter_track_table()->Insert(row).id;
@@ -319,6 +335,7 @@
tables::IrqCounterTrackTable::Row row(name);
row.irq = irq;
+ row.machine_id = context_->machine_id();
TrackId track =
context_->storage->mutable_irq_counter_track_table()->Insert(row).id;
@@ -335,6 +352,7 @@
tables::SoftirqCounterTrackTable::Row row(name);
row.softirq = softirq;
+ row.machine_id = context_->machine_id();
TrackId track =
context_->storage->mutable_softirq_counter_track_table()->Insert(row).id;
@@ -364,6 +382,7 @@
row.consumer_id = consumer_id;
row.consumer_type = consumer_type;
row.ordinal = ordinal;
+ row.machine_id = context_->machine_id();
TrackId track =
context_->storage->mutable_energy_counter_track_table()->Insert(row).id;
energy_counter_tracks_[std::make_pair(name, consumer_id)] = track;
@@ -381,6 +400,7 @@
tables::EnergyPerUidCounterTrackTable::Row row(name);
row.consumer_id = consumer_id;
row.uid = uid;
+ row.machine_id = context_->machine_id();
TrackId track =
context_->storage->mutable_energy_per_uid_counter_track_table()
->Insert(row)
@@ -410,6 +430,7 @@
row.gpu_id = gpu_id;
row.description = description;
row.unit = unit;
+ row.machine_id = context_->machine_id();
return context_->storage->mutable_gpu_counter_track_table()->Insert(row).id;
}
@@ -422,6 +443,7 @@
row.perf_session_id = perf_session_id;
row.cpu = cpu;
row.is_timebase = is_timebase;
+ row.machine_id = context_->machine_id();
return context_->storage->mutable_perf_counter_track_table()->Insert(row).id;
}
@@ -433,7 +455,9 @@
}
StringId id = context_->storage->InternString(GetNameForGroup(group));
- TrackId track_id = context_->storage->mutable_track_table()->Insert({id}).id;
+ tables::TrackTable::Row row{id};
+ row.machine_id = context_->machine_id();
+ TrackId track_id = context_->storage->mutable_track_table()->Insert(row).id;
group_track_ids_[group_idx] = track_id;
return track_id;
}
diff --git a/src/trace_processor/importers/ftrace/ftrace_parser.cc b/src/trace_processor/importers/ftrace/ftrace_parser.cc
index b648907..4390a71 100644
--- a/src/trace_processor/importers/ftrace/ftrace_parser.cc
+++ b/src/trace_processor/importers/ftrace/ftrace_parser.cc
@@ -1264,9 +1264,10 @@
protos::pbzero::GenericFtraceEvent::Decoder evt(blob.data, blob.size);
StringId event_id = context_->storage->InternString(evt.event_name());
UniqueTid utid = context_->process_tracker->GetOrCreateThread(tid);
- RawId id = context_->storage->mutable_ftrace_event_table()
- ->Insert({ts, event_id, cpu, utid})
- .id;
+ RawId id =
+ context_->storage->mutable_ftrace_event_table()
+ ->Insert({ts, event_id, cpu, utid, {}, {}, context_->machine_id()})
+ .id;
auto inserter = context_->args_tracker->AddArgsTo(id);
for (auto it = evt.field(); it; ++it) {
@@ -1305,10 +1306,15 @@
FtraceMessageDescriptor* m = GetMessageDescriptorForId(ftrace_id);
const auto& message_strings = ftrace_message_strings_[ftrace_id];
UniqueTid utid = context_->process_tracker->GetOrCreateThread(tid);
- RawId id =
- context_->storage->mutable_ftrace_event_table()
- ->Insert({timestamp, message_strings.message_name_id, cpu, utid})
- .id;
+ RawId id = context_->storage->mutable_ftrace_event_table()
+ ->Insert({timestamp,
+ message_strings.message_name_id,
+ cpu,
+ utid,
+ {},
+ {},
+ context_->machine_id()})
+ .id;
auto inserter = context_->args_tracker->AddArgsTo(id);
for (auto fld = decoder.ReadField(); fld.valid(); fld = decoder.ReadField()) {
diff --git a/src/trace_processor/importers/ftrace/ftrace_sched_event_tracker.cc b/src/trace_processor/importers/ftrace/ftrace_sched_event_tracker.cc
index 1a4f5d7..2c0a962 100644
--- a/src/trace_processor/importers/ftrace/ftrace_sched_event_tracker.cc
+++ b/src/trace_processor/importers/ftrace/ftrace_sched_event_tracker.cc
@@ -241,6 +241,7 @@
row.cpu = cpu;
row.utid = curr_utid;
row.common_flags = common_flags;
+ row.machine_id = context_->machine_id();
// Add an entry to the raw table.
RawId id = context_->storage->mutable_ftrace_event_table()->Insert(row).id;
@@ -281,7 +282,13 @@
// Push the raw event - this is done as the raw ftrace event codepath does
// not insert sched_switch.
RawId id = context_->storage->mutable_ftrace_event_table()
- ->Insert({ts, sched_switch_id_, cpu, prev_utid})
+ ->Insert({ts,
+ sched_switch_id_,
+ cpu,
+ prev_utid,
+ {},
+ {},
+ context_->machine_id()})
.id;
// Note: this ordering is important. The events should be pushed in the same
diff --git a/src/trace_processor/importers/ftrace/ftrace_tokenizer.cc b/src/trace_processor/importers/ftrace/ftrace_tokenizer.cc
index 9d678d1..cf38ac2 100644
--- a/src/trace_processor/importers/ftrace/ftrace_tokenizer.cc
+++ b/src/trace_processor/importers/ftrace/ftrace_tokenizer.cc
@@ -21,6 +21,7 @@
#include "perfetto/protozero/proto_decoder.h"
#include "perfetto/protozero/proto_utils.h"
#include "perfetto/trace_processor/basic_types.h"
+#include "src/trace_processor/importers/common/machine_tracker.h"
#include "src/trace_processor/importers/common/metadata_tracker.h"
#include "src/trace_processor/importers/proto/packet_sequence_state.h"
#include "src/trace_processor/sorter/trace_sorter.h"
@@ -280,7 +281,8 @@
}
context_->sorter->PushFtraceEvent(cpu, *timestamp, std::move(event),
- state->current_generation());
+ state->current_generation(),
+ context_->machine_id());
}
PERFETTO_ALWAYS_INLINE
@@ -340,7 +342,8 @@
DlogWithLimit(timestamp.status());
return;
}
- context_->sorter->PushInlineFtraceEvent(cpu, *timestamp, event);
+ context_->sorter->PushInlineFtraceEvent(cpu, *timestamp, event,
+ context_->machine_id());
}
// Check that all packed buffers were decoded correctly, and fully.
@@ -396,7 +399,8 @@
DlogWithLimit(timestamp.status());
return;
}
- context_->sorter->PushInlineFtraceEvent(cpu, *timestamp, event);
+ context_->sorter->PushInlineFtraceEvent(cpu, *timestamp, event,
+ context_->machine_id());
}
// Check that all packed buffers were decoded correctly, and fully.
@@ -461,7 +465,8 @@
}
context_->sorter->PushFtraceEvent(cpu, *timestamp, std::move(event),
- state->current_generation());
+ state->current_generation(),
+ context_->machine_id());
}
} // namespace trace_processor
diff --git a/src/trace_processor/importers/ftrace/gpu_work_period_tracker.cc b/src/trace_processor/importers/ftrace/gpu_work_period_tracker.cc
index 07e60a4..86db07b 100644
--- a/src/trace_processor/importers/ftrace/gpu_work_period_tracker.cc
+++ b/src/trace_processor/importers/ftrace/gpu_work_period_tracker.cc
@@ -40,6 +40,7 @@
tables::GpuWorkPeriodTrackTable::Row track(gpu_work_period_id_);
track.uid = static_cast<int32_t>(evt.uid());
track.gpu_id = evt.gpu_id();
+ track.machine_id = context_->machine_id();
TrackId track_id = context_->track_tracker->InternGpuWorkPeriodTrack(track);
const int64_t duration =
diff --git a/src/trace_processor/importers/proto/BUILD.gn b/src/trace_processor/importers/proto/BUILD.gn
index 03b0399..0f2f53a 100644
--- a/src/trace_processor/importers/proto/BUILD.gn
+++ b/src/trace_processor/importers/proto/BUILD.gn
@@ -34,6 +34,8 @@
"memory_tracker_snapshot_parser.h",
"metadata_minimal_module.cc",
"metadata_minimal_module.h",
+ "multi_machine_trace_manager.cc",
+ "multi_machine_trace_manager.h",
"network_trace_module.cc",
"network_trace_module.h",
"packet_analyzer.cc",
diff --git a/src/trace_processor/importers/proto/additional_modules.cc b/src/trace_processor/importers/proto/additional_modules.cc
index 6bd58ee..83b13e5 100644
--- a/src/trace_processor/importers/proto/additional_modules.cc
+++ b/src/trace_processor/importers/proto/additional_modules.cc
@@ -22,6 +22,7 @@
#include "src/trace_processor/importers/proto/graphics_event_module.h"
#include "src/trace_processor/importers/proto/heap_graph_module.h"
#include "src/trace_processor/importers/proto/metadata_module.h"
+#include "src/trace_processor/importers/proto/multi_machine_trace_manager.h"
#include "src/trace_processor/importers/proto/network_trace_module.h"
#include "src/trace_processor/importers/proto/statsd_module.h"
#include "src/trace_processor/importers/proto/system_probes_module.h"
@@ -51,6 +52,11 @@
context->modules.emplace_back(new FtraceModuleImpl(context));
context->ftrace_module =
static_cast<FtraceModule*>(context->modules.back().get());
+
+ if (context->multi_machine_trace_manager) {
+ context->multi_machine_trace_manager->EnableAdditionalModules(
+ RegisterAdditionalModules);
+ }
}
} // namespace trace_processor
diff --git a/src/trace_processor/importers/proto/android_camera_event_module.cc b/src/trace_processor/importers/proto/android_camera_event_module.cc
index 1fdddd1..5c7722a 100644
--- a/src/trace_processor/importers/proto/android_camera_event_module.cc
+++ b/src/trace_processor/importers/proto/android_camera_event_module.cc
@@ -20,6 +20,7 @@
#include "protos/perfetto/trace/android/camera_event.pbzero.h"
#include "protos/perfetto/trace/trace_packet.pbzero.h"
#include "src/trace_processor/importers/common/async_track_set_tracker.h"
+#include "src/trace_processor/importers/common/machine_tracker.h"
#include "src/trace_processor/importers/common/parser_types.h"
#include "src/trace_processor/importers/common/slice_tracker.h"
#include "src/trace_processor/importers/common/track_tracker.h"
@@ -54,7 +55,7 @@
decoder.android_camera_frame_event());
context_->sorter->PushTracePacket(
android_camera_frame_event.request_processing_started_ns(),
- state->current_generation(), std::move(*packet));
+ state->current_generation(), std::move(*packet), context_->machine_id());
return ModuleResult::Handled();
}
diff --git a/src/trace_processor/importers/proto/android_probes_module.cc b/src/trace_processor/importers/proto/android_probes_module.cc
index d26b6ef..02dcfe7 100644
--- a/src/trace_processor/importers/proto/android_probes_module.cc
+++ b/src/trace_processor/importers/proto/android_probes_module.cc
@@ -19,6 +19,7 @@
#include "perfetto/base/build_config.h"
#include "perfetto/ext/base/string_writer.h"
#include "perfetto/protozero/scattered_heap_buffer.h"
+#include "src/trace_processor/importers/common/machine_tracker.h"
#include "src/trace_processor/importers/common/track_tracker.h"
#include "src/trace_processor/importers/proto/android_probes_parser.h"
#include "src/trace_processor/importers/proto/android_probes_tracker.h"
@@ -193,7 +194,8 @@
std::vector<uint8_t> vec = data_packet.SerializeAsArray();
TraceBlob blob = TraceBlob::CopyFrom(vec.data(), vec.size());
context_->sorter->PushTracePacket(actual_ts, state->current_generation(),
- TraceBlobView(std::move(blob)));
+ TraceBlobView(std::move(blob)),
+ context_->machine_id());
}
return ModuleResult::Handled();
diff --git a/src/trace_processor/importers/proto/multi_machine_trace_manager.cc b/src/trace_processor/importers/proto/multi_machine_trace_manager.cc
new file mode 100644
index 0000000..e91dcee
--- /dev/null
+++ b/src/trace_processor/importers/proto/multi_machine_trace_manager.cc
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+#include "src/trace_processor/importers/proto/multi_machine_trace_manager.h"
+#include <memory>
+
+#include "src/trace_processor/importers/common/args_translation_table.h"
+#include "src/trace_processor/importers/common/async_track_set_tracker.h"
+#include "src/trace_processor/importers/common/clock_converter.h"
+#include "src/trace_processor/importers/common/clock_tracker.h"
+#include "src/trace_processor/importers/common/event_tracker.h"
+#include "src/trace_processor/importers/common/flow_tracker.h"
+#include "src/trace_processor/importers/common/machine_tracker.h"
+#include "src/trace_processor/importers/common/mapping_tracker.h"
+#include "src/trace_processor/importers/common/process_tracker.h"
+#include "src/trace_processor/importers/common/sched_event_tracker.h"
+#include "src/trace_processor/importers/common/slice_tracker.h"
+#include "src/trace_processor/importers/common/stack_profile_tracker.h"
+#include "src/trace_processor/importers/common/track_tracker.h"
+#include "src/trace_processor/importers/proto/default_modules.h"
+#include "src/trace_processor/importers/proto/perf_sample_tracker.h"
+#include "src/trace_processor/importers/proto/proto_importer_module.h"
+#include "src/trace_processor/importers/proto/proto_trace_parser.h"
+#include "src/trace_processor/importers/proto/proto_trace_reader.h"
+#include "src/trace_processor/sorter/trace_sorter.h"
+#include "src/trace_processor/types/trace_processor_context.h"
+
+namespace perfetto {
+namespace trace_processor {
+
+MultiMachineTraceManager::MultiMachineTraceManager(
+ TraceProcessorContext* default_context)
+ : default_context_(default_context) {
+ PERFETTO_DCHECK(default_context && !default_context_->machine_id());
+}
+MultiMachineTraceManager::~MultiMachineTraceManager() = default;
+
+std::unique_ptr<TraceProcessorContext> MultiMachineTraceManager::CreateContext(
+ RawMachineId raw_machine_id) {
+ TraceProcessorContext::InitArgs args{
+ default_context_->config, default_context_->storage, raw_machine_id};
+ auto ctx = std::make_unique<TraceProcessorContext>(args);
+
+ // Register default and additional modules (if enabled).
+ RegisterDefaultModules(ctx.get());
+ // Register addtional modules through the registered function pointer.
+ if (additional_modules_factory_)
+ additional_modules_factory_(ctx.get());
+
+ return ctx;
+}
+
+void MultiMachineTraceManager::EnableAdditionalModules(
+ ProtoImporterModuleFactory factory) {
+ additional_modules_factory_ = factory;
+}
+
+ProtoTraceReader* MultiMachineTraceManager::GetOrCreateReader(
+ RawMachineId raw_machine_id) {
+ auto* remote_ctx = remote_machine_contexts_.Find(raw_machine_id);
+ if (remote_ctx)
+ return remote_ctx->reader.get();
+
+ auto context = CreateContext(raw_machine_id);
+ // Share the sorter, but enable for the parser.
+ context->sorter = default_context_->sorter;
+ context->sorter->AddMachine(
+ context->machine_id(), std::make_unique<ProtoTraceParser>(context.get()));
+ context->process_tracker->SetPidZeroIsUpidZeroIdleProcess();
+
+ auto new_reader = std::make_unique<ProtoTraceReader>(context.get());
+ remote_machine_contexts_[raw_machine_id] =
+ RemoteMachineContext{std::move(context), std::move(new_reader)};
+ return remote_machine_contexts_[raw_machine_id].reader.get();
+}
+
+} // namespace trace_processor
+} // namespace perfetto
diff --git a/src/trace_processor/importers/proto/multi_machine_trace_manager.h b/src/trace_processor/importers/proto/multi_machine_trace_manager.h
new file mode 100644
index 0000000..0184d85
--- /dev/null
+++ b/src/trace_processor/importers/proto/multi_machine_trace_manager.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+#ifndef SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_MULTI_MACHINE_TRACE_MANAGER_H_
+#define SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_MULTI_MACHINE_TRACE_MANAGER_H_
+
+#include <memory>
+#include <vector>
+
+#include "perfetto/ext/base/flat_hash_map.h"
+#include "src/trace_processor/storage/trace_storage.h"
+#include "src/trace_processor/types/trace_processor_context.h"
+
+namespace perfetto {
+namespace trace_processor {
+
+class TraceProcessorContext;
+class ProtoTraceReader;
+
+// This class provides the get-or-create function for ProtoTraceReader to
+// support multi-machine tracing. When the default ProtoTraceReader instance
+// decodes a trace packet with a non-default machine ID:
+//
+// packet {
+// ftrace_events {
+// }
+// machine_id: 1001
+// }
+//
+// An object graph rooted from a new ProtoTraceReader is created for the
+// machine:
+//
+// ProtoTraceReader -> TraceProcessorContext (with a non-null machine_id).
+// +--> TraceProcessorStorage (shared with the default
+// instance)
+// |--> TraceSorter (shared with the default instance)
+// |--> TrackTracker (created for machine 1001)
+// |--> ProcessTracker (created for machine 1001)
+// |--> ... other data members rooted from
+// TraceProcessorContext
+//
+// and the new ProtoTraceReader is used to parse all trace packet with the same
+// machine ID. The context is used to insert the machine ID into the sqlite
+// tables. for query in the trace processor or from the UI frontend.
+class MultiMachineTraceManager {
+ public:
+ // RawMachineId is the value of 'machine_id' in trace packets.
+ using RawMachineId = uint32_t;
+
+ explicit MultiMachineTraceManager(TraceProcessorContext* default_context);
+ ~MultiMachineTraceManager();
+
+ // Get or create an instance of ProtoTraceReader for parsing the trace packets
+ // with the RawMachineId from the trace packet.
+ ProtoTraceReader* GetOrCreateReader(RawMachineId);
+
+ using ProtoImporterModuleFactory = void (*)(TraceProcessorContext*);
+ void EnableAdditionalModules(ProtoImporterModuleFactory);
+
+ private:
+ struct RemoteMachineContext {
+ std::unique_ptr<TraceProcessorContext> context;
+ std::unique_ptr<ProtoTraceReader> reader;
+ };
+
+ std::unique_ptr<TraceProcessorContext> CreateContext(RawMachineId);
+
+ // The default TraceProcessorContext instance.
+ TraceProcessorContext* default_context_;
+ // Owns contexts for remote machines.
+ base::FlatHashMap<RawMachineId, RemoteMachineContext>
+ remote_machine_contexts_;
+
+ ProtoImporterModuleFactory additional_modules_factory_ = nullptr;
+};
+
+} // namespace trace_processor
+} // namespace perfetto
+
+#endif // SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_MULTI_MACHINE_TRACE_MANAGER_H_
diff --git a/src/trace_processor/importers/proto/profile_module.cc b/src/trace_processor/importers/proto/profile_module.cc
index f8e2711..c194107 100644
--- a/src/trace_processor/importers/proto/profile_module.cc
+++ b/src/trace_processor/importers/proto/profile_module.cc
@@ -139,8 +139,9 @@
sequence_state->IncrementAndGetTrackEventTimeNs(*timestamp_it * 1000);
}
- context_->sorter->PushTracePacket(
- packet_ts, sequence_state->current_generation(), std::move(*packet));
+ context_->sorter->PushTracePacket(packet_ts,
+ sequence_state->current_generation(),
+ std::move(*packet), context_->machine_id());
return ModuleResult::Handled();
}
diff --git a/src/trace_processor/importers/proto/proto_trace_parser.cc b/src/trace_processor/importers/proto/proto_trace_parser.cc
index b23a513..4043ec6 100644
--- a/src/trace_processor/importers/proto/proto_trace_parser.cc
+++ b/src/trace_processor/importers/proto/proto_trace_parser.cc
@@ -30,6 +30,7 @@
#include "src/trace_processor/importers/common/args_tracker.h"
#include "src/trace_processor/importers/common/event_tracker.h"
+#include "src/trace_processor/importers/common/machine_tracker.h"
#include "src/trace_processor/importers/common/metadata_tracker.h"
#include "src/trace_processor/importers/common/parser_types.h"
#include "src/trace_processor/importers/common/process_tracker.h"
@@ -255,7 +256,8 @@
ArgsTracker args(context_);
if (bundle.has_metadata()) {
RawId id = storage->mutable_raw_table()
- ->Insert({ts, raw_chrome_metadata_event_id_, 0, 0})
+ ->Insert({ts, raw_chrome_metadata_event_id_, 0, 0, 0, 0,
+ context_->machine_id()})
.id;
auto inserter = args.AddArgsTo(id);
@@ -301,10 +303,10 @@
}
if (bundle.has_legacy_ftrace_output()) {
- RawId id =
- storage->mutable_raw_table()
- ->Insert({ts, raw_chrome_legacy_system_trace_event_id_, 0, 0})
- .id;
+ RawId id = storage->mutable_raw_table()
+ ->Insert({ts, raw_chrome_legacy_system_trace_event_id_, 0, 0,
+ 0, 0, context_->machine_id()})
+ .id;
std::string data;
for (auto it = bundle.legacy_ftrace_output(); it; ++it) {
@@ -322,10 +324,10 @@
protos::pbzero::ChromeLegacyJsonTrace::USER_TRACE) {
continue;
}
- RawId id =
- storage->mutable_raw_table()
- ->Insert({ts, raw_chrome_legacy_user_trace_event_id_, 0, 0})
- .id;
+ RawId id = storage->mutable_raw_table()
+ ->Insert({ts, raw_chrome_legacy_user_trace_event_id_, 0, 0,
+ 0, 0, context_->machine_id()})
+ .id;
Variadic value =
Variadic::String(storage->InternString(legacy_trace.data()));
args.AddArgsTo(id).AddArg(data_name_id_, value);
diff --git a/src/trace_processor/importers/proto/proto_trace_reader.cc b/src/trace_processor/importers/proto/proto_trace_reader.cc
index 12e044b..972acf3 100644
--- a/src/trace_processor/importers/proto/proto_trace_reader.cc
+++ b/src/trace_processor/importers/proto/proto_trace_reader.cc
@@ -25,9 +25,11 @@
#include "perfetto/ext/base/utils.h"
#include "perfetto/protozero/proto_decoder.h"
#include "perfetto/protozero/proto_utils.h"
+#include "perfetto/public/compiler.h"
#include "perfetto/trace_processor/status.h"
#include "src/trace_processor/importers/common/clock_tracker.h"
#include "src/trace_processor/importers/common/event_tracker.h"
+#include "src/trace_processor/importers/common/machine_tracker.h"
#include "src/trace_processor/importers/common/metadata_tracker.h"
#include "src/trace_processor/importers/common/track_tracker.h"
#include "src/trace_processor/importers/ftrace/ftrace_module.h"
@@ -86,6 +88,21 @@
// Any compressed packets should have been handled by the tokenizer.
PERFETTO_CHECK(!decoder.has_compressed_packets());
+ // When the trace packet is emitted from a remote machine: parse the packet
+ // using a different ProtoTraceReader instance. The packet will be parsed
+ // in the context of the remote machine.
+ if (PERFETTO_UNLIKELY(decoder.has_machine_id())) {
+ if (!context_->machine_id()) {
+ // Default context: switch to another reader instance to parse the packet.
+ PERFETTO_DCHECK(context_->multi_machine_trace_manager);
+ auto* reader = context_->multi_machine_trace_manager->GetOrCreateReader(
+ decoder.machine_id());
+ return reader->ParsePacket(std::move(packet));
+ }
+ }
+ // Assert that the packet is parsed using the right instance of reader.
+ PERFETTO_DCHECK(decoder.has_machine_id() == !!context_->machine_id());
+
const uint32_t seq_id = decoder.trusted_packet_sequence_id();
auto* state = GetIncrementalStateForPacketSequence(seq_id);
@@ -239,7 +256,7 @@
// Use parent data and length because we want to parse this again
// later to get the exact type of the packet.
context_->sorter->PushTracePacket(timestamp, state->current_generation(),
- std::move(packet));
+ std::move(packet), context_->machine_id());
return util::OkStatus();
}
@@ -407,6 +424,7 @@
clock_timestamp.timestamp * clock_timestamp.clock.unit_multiplier_ns;
row.clock_name = GetBuiltinClockNameOrNull(clock_timestamp.clock.id);
row.snapshot_id = *snapshot_id;
+ row.machine_id = context_->machine_id();
context_->storage->mutable_clock_snapshot_table()->Insert(row);
}
diff --git a/src/trace_processor/importers/proto/proto_trace_reader.h b/src/trace_processor/importers/proto/proto_trace_reader.h
index 8afc40c..1243b97 100644
--- a/src/trace_processor/importers/proto/proto_trace_reader.h
+++ b/src/trace_processor/importers/proto/proto_trace_reader.h
@@ -22,6 +22,7 @@
#include <memory>
#include "src/trace_processor/importers/common/chunked_trace_reader.h"
+#include "src/trace_processor/importers/proto/multi_machine_trace_manager.h"
#include "src/trace_processor/importers/proto/proto_incremental_state.h"
#include "src/trace_processor/importers/proto/proto_trace_tokenizer.h"
#include "src/trace_processor/storage/trace_storage.h"
diff --git a/src/trace_processor/importers/proto/statsd_module.cc b/src/trace_processor/importers/proto/statsd_module.cc
index 49a7300..2f9d3cd 100644
--- a/src/trace_processor/importers/proto/statsd_module.cc
+++ b/src/trace_processor/importers/proto/statsd_module.cc
@@ -20,6 +20,7 @@
#include "protos/perfetto/trace/statsd/statsd_atom.pbzero.h"
#include "protos/perfetto/trace/trace_packet.pbzero.h"
#include "src/trace_processor/importers/common/async_track_set_tracker.h"
+#include "src/trace_processor/importers/common/machine_tracker.h"
#include "src/trace_processor/importers/common/slice_tracker.h"
#include "src/trace_processor/importers/common/track_tracker.h"
#include "src/trace_processor/importers/proto/packet_sequence_state.h"
@@ -245,9 +246,9 @@
std::vector<uint8_t> vec = forged.SerializeAsArray();
TraceBlob blob = TraceBlob::CopyFrom(vec.data(), vec.size());
- context_->sorter->PushTracePacket(atom_timestamp,
- state->current_generation(),
- TraceBlobView(std::move(blob)));
+ context_->sorter->PushTracePacket(
+ atom_timestamp, state->current_generation(),
+ TraceBlobView(std::move(blob)), context_->machine_id());
}
return ModuleResult::Handled();
diff --git a/src/trace_processor/importers/proto/system_probes_parser.cc b/src/trace_processor/importers/proto/system_probes_parser.cc
index 8812674..5b878ed 100644
--- a/src/trace_processor/importers/proto/system_probes_parser.cc
+++ b/src/trace_processor/importers/proto/system_probes_parser.cc
@@ -761,6 +761,7 @@
cluster_id++;
}
cpu_row.cluster_id = cluster_id;
+ cpu_row.machine_id = context_->machine_id();
last_cpu_freqs = freqs;
tables::CpuTable::Id cpu_row_id =
@@ -771,6 +772,7 @@
tables::CpuFreqTable::Row cpu_freq_row;
cpu_freq_row.cpu_id = cpu_row_id;
cpu_freq_row.freq = freq;
+ cpu_freq_row.machine_id = context_->machine_id();
context_->storage->mutable_cpu_freq_table()->Insert(cpu_freq_row);
}
}
diff --git a/src/trace_processor/importers/proto/track_event_parser.cc b/src/trace_processor/importers/proto/track_event_parser.cc
index cdf2c45..cb80844 100644
--- a/src/trace_processor/importers/proto/track_event_parser.cc
+++ b/src/trace_processor/importers/proto/track_event_parser.cc
@@ -28,6 +28,7 @@
#include "src/trace_processor/importers/common/args_translation_table.h"
#include "src/trace_processor/importers/common/event_tracker.h"
#include "src/trace_processor/importers/common/flow_tracker.h"
+#include "src/trace_processor/importers/common/machine_tracker.h"
#include "src/trace_processor/importers/common/process_tracker.h"
#include "src/trace_processor/importers/common/track_tracker.h"
#include "src/trace_processor/importers/json/json_utils.h"
@@ -1122,7 +1123,8 @@
return util::ErrStatus("raw legacy event without thread association");
RawId id = storage_->mutable_raw_table()
- ->Insert({ts_, parser_->raw_legacy_event_id_, 0, *utid_})
+ ->Insert({ts_, parser_->raw_legacy_event_id_, 0, *utid_, 0,
+ 0, context_->machine_id()})
.id;
auto inserter = context_->args_tracker->AddArgsTo(id);
diff --git a/src/trace_processor/importers/proto/track_event_tokenizer.cc b/src/trace_processor/importers/proto/track_event_tokenizer.cc
index 6b655f4..7f20742 100644
--- a/src/trace_processor/importers/proto/track_event_tokenizer.cc
+++ b/src/trace_processor/importers/proto/track_event_tokenizer.cc
@@ -19,6 +19,7 @@
#include "perfetto/base/logging.h"
#include "perfetto/trace_processor/trace_blob_view.h"
#include "src/trace_processor/importers/common/clock_tracker.h"
+#include "src/trace_processor/importers/common/machine_tracker.h"
#include "src/trace_processor/importers/common/metadata_tracker.h"
#include "src/trace_processor/importers/common/process_tracker.h"
#include "src/trace_processor/importers/common/track_tracker.h"
@@ -370,7 +371,8 @@
return;
}
- context_->sorter->PushTrackEventPacket(timestamp, std::move(data));
+ context_->sorter->PushTrackEventPacket(timestamp, std::move(data),
+ context_->machine_id());
}
template <typename T>
diff --git a/src/trace_processor/importers/proto/track_event_tracker.cc b/src/trace_processor/importers/proto/track_event_tracker.cc
index ad78346..56e081d 100644
--- a/src/trace_processor/importers/proto/track_event_tracker.cc
+++ b/src/trace_processor/importers/proto/track_event_tracker.cc
@@ -20,6 +20,7 @@
#include "src/trace_processor/importers/common/args_translation_table.h"
#include "src/trace_processor/importers/common/process_tracker.h"
#include "src/trace_processor/importers/common/track_tracker.h"
+#include "src/trace_processor/tables/track_tables_py.h"
namespace perfetto {
namespace trace_processor {
@@ -163,6 +164,7 @@
TrackId TrackEventTracker::InsertThreadTrack(UniqueTid utid) {
tables::ThreadTrackTable::Row row;
row.utid = utid;
+ row.machine_id = context_->machine_id();
auto* thread_tracks = context_->storage->mutable_thread_track_table();
return thread_tracks->Insert(row).id;
}
@@ -283,6 +285,7 @@
if (track.is_counter()) {
tables::ThreadCounterTrackTable::Row row;
row.utid = track.utid();
+ row.machine_id = context_->machine_id();
auto* thread_counter_tracks =
context_->storage->mutable_thread_counter_track_table();
@@ -295,6 +298,7 @@
if (track.is_counter()) {
tables::ProcessCounterTrackTable::Row row;
row.upid = track.upid();
+ row.machine_id = context_->machine_id();
auto* process_counter_tracks =
context_->storage->mutable_process_counter_track_table();
@@ -303,14 +307,20 @@
tables::ProcessTrackTable::Row row;
row.upid = track.upid();
+ row.machine_id = context_->machine_id();
auto* process_tracks = context_->storage->mutable_process_track_table();
return process_tracks->Insert(row).id;
}
case ResolvedDescriptorTrack::Scope::kGlobal: {
- if (track.is_counter())
- return context_->storage->mutable_counter_track_table()->Insert({}).id;
- return context_->storage->mutable_track_table()->Insert({}).id;
+ if (track.is_counter()) {
+ tables::CounterTrackTable::Row row;
+ row.machine_id = context_->machine_id();
+ return context_->storage->mutable_counter_track_table()->Insert(row).id;
+ }
+ tables::TrackTable::Row row;
+ row.machine_id = context_->machine_id();
+ return context_->storage->mutable_track_table()->Insert(row).id;
}
}
PERFETTO_FATAL("For GCC");
diff --git a/src/trace_processor/sorter/trace_sorter.cc b/src/trace_processor/sorter/trace_sorter.cc
index 0a09224..b937e2e 100644
--- a/src/trace_processor/sorter/trace_sorter.cc
+++ b/src/trace_processor/sorter/trace_sorter.cc
@@ -31,9 +31,8 @@
TraceSorter::TraceSorter(TraceProcessorContext* context,
std::unique_ptr<TraceParser> parser,
SortingMode sorting_mode)
- : context_(context),
- parser_(std::move(parser)),
- sorting_mode_(sorting_mode) {
+ : context_(context), sorting_mode_(sorting_mode) {
+ AddMachine(context_->machine_id(), std::move(parser));
const char* env = getenv("TRACE_PROCESSOR_SORT_ONLY");
bypass_next_stage_for_testing_ = env && !strcmp(env, "1");
if (bypass_next_stage_for_testing_)
@@ -44,9 +43,11 @@
// If trace processor encountered a fatal error, it's possible for some events
// to have been pushed without evicting them by pushing to the next stage. Do
// that now.
- for (auto& queue : queues_) {
- for (const auto& event : queue.events_) {
- ExtractAndDiscardTokenizedObject(event);
+ for (auto& sorter_data : sorter_data_by_machine_) {
+ for (auto& queue : sorter_data.queues) {
+ for (const auto& event : queue.events_) {
+ ExtractAndDiscardTokenizedObject(event);
+ }
}
}
}
@@ -98,6 +99,7 @@
BumpAllocator::AllocId limit_alloc_id) {
constexpr int64_t kTsMax = std::numeric_limits<int64_t>::max();
for (;;) {
+ size_t min_machine_idx = 0;
size_t min_queue_idx = 0; // The index of the queue with the min(ts).
// The top-2 min(ts) among all queues.
@@ -107,25 +109,30 @@
// This loop identifies the queue which starts with the earliest event and
// also remembers the earliest event of the 2nd queue (in min_queue_ts[1]).
bool all_queues_empty = true;
- for (size_t i = 0; i < queues_.size(); i++) {
- auto& queue = queues_[i];
- if (queue.events_.empty())
- continue;
- all_queues_empty = false;
+ for (size_t m = 0; m < sorter_data_by_machine_.size(); m++) {
+ TraceSorterData& sorter_data = sorter_data_by_machine_[m];
+ for (size_t i = 0; i < sorter_data.queues.size(); i++) {
+ auto& queue = sorter_data.queues[i];
+ if (queue.events_.empty())
+ continue;
+ all_queues_empty = false;
- PERFETTO_DCHECK(queue.max_ts_ <= append_max_ts_);
- if (queue.min_ts_ < min_queue_ts[0]) {
- min_queue_ts[1] = min_queue_ts[0];
- min_queue_ts[0] = queue.min_ts_;
- min_queue_idx = i;
- } else if (queue.min_ts_ < min_queue_ts[1]) {
- min_queue_ts[1] = queue.min_ts_;
+ PERFETTO_DCHECK(queue.max_ts_ <= append_max_ts_);
+ if (queue.min_ts_ < min_queue_ts[0]) {
+ min_queue_ts[1] = min_queue_ts[0];
+ min_queue_ts[0] = queue.min_ts_;
+ min_queue_idx = i;
+ min_machine_idx = m;
+ } else if (queue.min_ts_ < min_queue_ts[1]) {
+ min_queue_ts[1] = queue.min_ts_;
+ }
}
}
if (all_queues_empty)
break;
- Queue& queue = queues_[min_queue_idx];
+ auto& sorter_data = sorter_data_by_machine_[min_machine_idx];
+ auto& queue = sorter_data.queues[min_queue_idx];
auto& events = queue.events_;
if (queue.needs_sorting())
queue.Sort();
@@ -148,7 +155,7 @@
}
++num_extracted;
- MaybeExtractEvent(min_queue_idx, event);
+ MaybeExtractEvent(min_machine_idx, min_queue_idx, event);
} // for (event: events)
// The earliest event cannot be extracted without going past the limit.
@@ -174,32 +181,33 @@
} // for(;;)
}
-void TraceSorter::ParseTracePacket(const TimestampedEvent& event) {
+void TraceSorter::ParseTracePacket(TraceParser* parser,
+ const TimestampedEvent& event) {
TraceTokenBuffer::Id id = GetTokenBufferId(event);
switch (static_cast<TimestampedEvent::Type>(event.event_type)) {
case TimestampedEvent::Type::kTraceBlobView:
- parser_->ParseTraceBlobView(event.ts,
- token_buffer_.Extract<TraceBlobView>(id));
+ parser->ParseTraceBlobView(event.ts,
+ token_buffer_.Extract<TraceBlobView>(id));
return;
case TimestampedEvent::Type::kTracePacket:
- parser_->ParseTracePacket(event.ts,
- token_buffer_.Extract<TracePacketData>(id));
+ parser->ParseTracePacket(event.ts,
+ token_buffer_.Extract<TracePacketData>(id));
return;
case TimestampedEvent::Type::kTrackEvent:
- parser_->ParseTrackEvent(event.ts,
- token_buffer_.Extract<TrackEventData>(id));
+ parser->ParseTrackEvent(event.ts,
+ token_buffer_.Extract<TrackEventData>(id));
return;
case TimestampedEvent::Type::kFuchsiaRecord:
- parser_->ParseFuchsiaRecord(event.ts,
- token_buffer_.Extract<FuchsiaRecord>(id));
+ parser->ParseFuchsiaRecord(event.ts,
+ token_buffer_.Extract<FuchsiaRecord>(id));
return;
case TimestampedEvent::Type::kJsonValue:
- parser_->ParseJsonPacket(
+ parser->ParseJsonPacket(
event.ts, std::move(token_buffer_.Extract<JsonEvent>(id).value));
return;
case TimestampedEvent::Type::kSystraceLine:
- parser_->ParseSystraceLine(event.ts,
- token_buffer_.Extract<SystraceLine>(id));
+ parser->ParseSystraceLine(event.ts,
+ token_buffer_.Extract<SystraceLine>(id));
return;
case TimestampedEvent::Type::kInlineSchedSwitch:
case TimestampedEvent::Type::kInlineSchedWaking:
@@ -210,7 +218,8 @@
PERFETTO_FATAL("For GCC");
}
-void TraceSorter::ParseEtwPacket(uint32_t /*cpu*/,
+void TraceSorter::ParseEtwPacket(TraceParser* /*parser*/,
+ uint32_t /*cpu*/,
const TimestampedEvent& event) {
switch (static_cast<TimestampedEvent::Type>(event.event_type)) {
case TimestampedEvent::Type::kEtwEvent:
@@ -229,21 +238,22 @@
PERFETTO_FATAL("For GCC");
}
-void TraceSorter::ParseFtracePacket(uint32_t cpu,
+void TraceSorter::ParseFtracePacket(TraceParser* parser,
+ uint32_t cpu,
const TimestampedEvent& event) {
TraceTokenBuffer::Id id = GetTokenBufferId(event);
switch (static_cast<TimestampedEvent::Type>(event.event_type)) {
case TimestampedEvent::Type::kInlineSchedSwitch:
- parser_->ParseInlineSchedSwitch(
+ parser->ParseInlineSchedSwitch(
cpu, event.ts, token_buffer_.Extract<InlineSchedSwitch>(id));
return;
case TimestampedEvent::Type::kInlineSchedWaking:
- parser_->ParseInlineSchedWaking(
+ parser->ParseInlineSchedWaking(
cpu, event.ts, token_buffer_.Extract<InlineSchedWaking>(id));
return;
case TimestampedEvent::Type::kFtraceEvent:
- parser_->ParseFtraceEvent(cpu, event.ts,
- token_buffer_.Extract<TracePacketData>(id));
+ parser->ParseFtraceEvent(cpu, event.ts,
+ token_buffer_.Extract<TracePacketData>(id));
return;
case TimestampedEvent::Type::kEtwEvent:
case TimestampedEvent::Type::kTrackEvent:
@@ -295,8 +305,10 @@
PERFETTO_FATAL("For GCC");
}
-void TraceSorter::MaybeExtractEvent(size_t queue_idx,
+void TraceSorter::MaybeExtractEvent(size_t min_machine_idx,
+ size_t queue_idx,
const TimestampedEvent& event) {
+ auto* parser = sorter_data_by_machine_[min_machine_idx].parser.get();
int64_t timestamp = event.ts;
if (timestamp < latest_pushed_event_ts_)
context_->storage->IncrementStats(stats::sorter_push_event_out_of_order);
@@ -311,16 +323,16 @@
}
if (queue_idx == 0) {
- ParseTracePacket(event);
+ ParseTracePacket(parser, event);
} else {
// Ftrace queues start at offset 1. So queues_[1] = cpu[0] and so on.
uint32_t cpu = static_cast<uint32_t>(queue_idx - 1);
auto event_type = static_cast<TimestampedEvent::Type>(event.event_type);
if (event_type == TimestampedEvent::Type::kEtwEvent) {
- ParseEtwPacket(static_cast<uint32_t>(cpu), event);
+ ParseEtwPacket(parser, static_cast<uint32_t>(cpu), event);
} else {
- ParseFtracePacket(cpu, event);
+ ParseFtracePacket(parser, cpu, event);
}
}
}
diff --git a/src/trace_processor/sorter/trace_sorter.h b/src/trace_processor/sorter/trace_sorter.h
index fc4bac8..56fd0a1 100644
--- a/src/trace_processor/sorter/trace_sorter.h
+++ b/src/trace_processor/sorter/trace_sorter.h
@@ -19,11 +19,13 @@
#include <algorithm>
#include <memory>
+#include <optional>
#include <utility>
#include <vector>
#include "perfetto/ext/base/circular_queue.h"
#include "perfetto/ext/base/utils.h"
+#include "perfetto/public/compiler.h"
#include "perfetto/trace_processor/basic_types.h"
#include "perfetto/trace_processor/trace_blob_view.h"
#include "src/trace_processor/importers/common/parser_types.h"
@@ -95,21 +97,37 @@
SortingMode);
~TraceSorter();
- inline void PushTraceBlobView(int64_t timestamp, TraceBlobView tbv) {
+ inline void AddMachine(std::optional<MachineId> machine_id,
+ std::unique_ptr<TraceParser> parser) {
+ sorter_data_by_machine_.emplace_back(machine_id, std::move(parser));
+ }
+
+ inline void PushTraceBlobView(
+ int64_t timestamp,
+ TraceBlobView tbv,
+ std::optional<MachineId> machine_id = std::nullopt) {
TraceTokenBuffer::Id id = token_buffer_.Append(std::move(tbv));
- AppendNonFtraceEvent(timestamp, TimestampedEvent::Type::kTraceBlobView, id);
+ AppendNonFtraceEvent(timestamp, TimestampedEvent::Type::kTraceBlobView, id,
+ machine_id);
}
- inline void PushTracePacket(int64_t timestamp, TracePacketData data) {
+ inline void PushTracePacket(
+ int64_t timestamp,
+ TracePacketData data,
+ std::optional<MachineId> machine_id = std::nullopt) {
TraceTokenBuffer::Id id = token_buffer_.Append(std::move(data));
- AppendNonFtraceEvent(timestamp, TimestampedEvent::Type::kTracePacket, id);
+ AppendNonFtraceEvent(timestamp, TimestampedEvent::Type::kTracePacket, id,
+ machine_id);
}
- inline void PushTracePacket(int64_t timestamp,
- RefPtr<PacketSequenceStateGeneration> state,
- TraceBlobView tbv) {
+ inline void PushTracePacket(
+ int64_t timestamp,
+ RefPtr<PacketSequenceStateGeneration> state,
+ TraceBlobView tbv,
+ std::optional<MachineId> machine_id = std::nullopt) {
PushTracePacket(timestamp,
- TracePacketData{std::move(tbv), std::move(state)});
+ TracePacketData{std::move(tbv), std::move(state)},
+ machine_id);
}
inline void PushJsonValue(int64_t timestamp, std::string json_value) {
@@ -130,37 +148,45 @@
TimestampedEvent::Type::kSystraceLine, id);
}
- inline void PushTrackEventPacket(int64_t timestamp,
- TrackEventData track_event) {
+ inline void PushTrackEventPacket(
+ int64_t timestamp,
+ TrackEventData track_event,
+ std::optional<MachineId> machine_id = std::nullopt) {
TraceTokenBuffer::Id id = token_buffer_.Append(std::move(track_event));
- AppendNonFtraceEvent(timestamp, TimestampedEvent::Type::kTrackEvent, id);
+ AppendNonFtraceEvent(timestamp, TimestampedEvent::Type::kTrackEvent, id,
+ machine_id);
}
inline void PushEtwEvent(uint32_t cpu,
int64_t timestamp,
TraceBlobView tbv,
- RefPtr<PacketSequenceStateGeneration> state) {
+ RefPtr<PacketSequenceStateGeneration> state,
+ std::optional<MachineId> machine_id = std::nullopt) {
TraceTokenBuffer::Id id =
token_buffer_.Append(TracePacketData{std::move(tbv), std::move(state)});
- auto* queue = GetQueue(cpu + 1);
+ auto* queue = GetQueue(cpu + 1, machine_id);
queue->Append(timestamp, TimestampedEvent::Type::kEtwEvent, id);
UpdateAppendMaxTs(queue);
}
- inline void PushFtraceEvent(uint32_t cpu,
- int64_t timestamp,
- TraceBlobView tbv,
- RefPtr<PacketSequenceStateGeneration> state) {
+ inline void PushFtraceEvent(
+ uint32_t cpu,
+ int64_t timestamp,
+ TraceBlobView tbv,
+ RefPtr<PacketSequenceStateGeneration> state,
+ std::optional<MachineId> machine_id = std::nullopt) {
TraceTokenBuffer::Id id =
token_buffer_.Append(TracePacketData{std::move(tbv), std::move(state)});
- auto* queue = GetQueue(cpu + 1);
+ auto* queue = GetQueue(cpu + 1, machine_id);
queue->Append(timestamp, TimestampedEvent::Type::kFtraceEvent, id);
UpdateAppendMaxTs(queue);
}
- inline void PushInlineFtraceEvent(uint32_t cpu,
- int64_t timestamp,
- InlineSchedSwitch inline_sched_switch) {
+ inline void PushInlineFtraceEvent(
+ uint32_t cpu,
+ int64_t timestamp,
+ InlineSchedSwitch inline_sched_switch,
+ std::optional<MachineId> machine_id = std::nullopt) {
// TODO(rsavitski): if a trace has a mix of normal & "compact" events
// (being pushed through this function), the ftrace batches will no longer
// be fully sorted by timestamp. In such situations, we will have to sort
@@ -170,17 +196,19 @@
// // instead.
TraceTokenBuffer::Id id =
token_buffer_.Append(std::move(inline_sched_switch));
- auto* queue = GetQueue(cpu + 1);
+ auto* queue = GetQueue(cpu + 1, machine_id);
queue->Append(timestamp, TimestampedEvent::Type::kInlineSchedSwitch, id);
UpdateAppendMaxTs(queue);
}
- inline void PushInlineFtraceEvent(uint32_t cpu,
- int64_t timestamp,
- InlineSchedWaking inline_sched_waking) {
+ inline void PushInlineFtraceEvent(
+ uint32_t cpu,
+ int64_t timestamp,
+ InlineSchedWaking inline_sched_waking,
+ std::optional<MachineId> machine_id = std::nullopt) {
TraceTokenBuffer::Id id =
token_buffer_.Append(std::move(inline_sched_waking));
- auto* queue = GetQueue(cpu + 1);
+ auto* queue = GetQueue(cpu + 1, machine_id);
queue->Append(timestamp, TimestampedEvent::Type::kInlineSchedWaking, id);
UpdateAppendMaxTs(queue);
}
@@ -188,10 +216,12 @@
void ExtractEventsForced() {
BumpAllocator::AllocId end_id = token_buffer_.PastTheEndAllocId();
SortAndExtractEventsUntilAllocId(end_id);
- for (const auto& queue : queues_) {
- PERFETTO_DCHECK(queue.events_.empty());
+ for (auto& sorter_data : sorter_data_by_machine_) {
+ for (const auto& queue : sorter_data.queues) {
+ PERFETTO_DCHECK(queue.events_.empty());
+ }
+ sorter_data.queues.clear();
}
- queues_.clear();
alloc_id_for_extraction_ = end_id;
flushes_since_extraction_ = 0;
@@ -319,16 +349,34 @@
void SortAndExtractEventsUntilAllocId(BumpAllocator::AllocId alloc_id);
- inline Queue* GetQueue(size_t index) {
- if (PERFETTO_UNLIKELY(index >= queues_.size()))
- queues_.resize(index + 1);
- return &queues_[index];
+ inline Queue* GetQueue(size_t index,
+ std::optional<MachineId> machine_id = std::nullopt) {
+ // sorter_data_by_machine_[0] corresponds to the default machine.
+ PERFETTO_DCHECK(sorter_data_by_machine_[0].machine_id == std::nullopt);
+ auto* queues = &sorter_data_by_machine_[0].queues;
+
+ // Find the TraceSorterData instance when |machine_id| is not nullopt.
+ if (PERFETTO_UNLIKELY(!!machine_id)) {
+ auto it = std::find_if(sorter_data_by_machine_.begin() + 1,
+ sorter_data_by_machine_.end(),
+ [machine_id](const TraceSorterData& item) {
+ return item.machine_id == machine_id;
+ });
+ PERFETTO_DCHECK(it != sorter_data_by_machine_.end());
+ queues = &it->queues;
+ }
+
+ if (PERFETTO_UNLIKELY(index >= queues->size()))
+ queues->resize(index + 1);
+ return &queues->at(index);
}
- inline void AppendNonFtraceEvent(int64_t ts,
- TimestampedEvent::Type event_type,
- TraceTokenBuffer::Id id) {
- Queue* queue = GetQueue(0);
+ inline void AppendNonFtraceEvent(
+ int64_t ts,
+ TimestampedEvent::Type event_type,
+ TraceTokenBuffer::Id id,
+ std::optional<MachineId> machine_id = std::nullopt) {
+ Queue* queue = GetQueue(0, machine_id);
queue->Append(ts, event_type, id);
UpdateAppendMaxTs(queue);
}
@@ -337,19 +385,33 @@
append_max_ts_ = std::max(append_max_ts_, queue->max_ts_);
}
- void ParseTracePacket(const TimestampedEvent&);
- void ParseFtracePacket(uint32_t cpu, const TimestampedEvent&);
- void ParseEtwPacket(uint32_t cpu, const TimestampedEvent&);
+ void ParseTracePacket(TraceParser*, const TimestampedEvent&);
+ void ParseFtracePacket(TraceParser*, uint32_t cpu, const TimestampedEvent&);
+ void ParseEtwPacket(TraceParser*, uint32_t cpu, const TimestampedEvent&);
- void MaybeExtractEvent(size_t queue_idx, const TimestampedEvent&);
+ void MaybeExtractEvent(size_t machine_idx,
+ size_t queue_idx,
+ const TimestampedEvent&);
void ExtractAndDiscardTokenizedObject(const TimestampedEvent& event);
TraceTokenBuffer::Id GetTokenBufferId(const TimestampedEvent& event) {
return TraceTokenBuffer::Id{event.alloc_id()};
}
+ struct TraceSorterData {
+ TraceSorterData(std::optional<MachineId> _machine_id,
+ std::unique_ptr<TraceParser> _parser)
+ : machine_id(_machine_id), parser(std::move(_parser)) {}
+ std::optional<MachineId> machine_id;
+ std::unique_ptr<TraceParser> parser;
+ // queues_[0] is the general (non-ftrace) queue.
+ // queues_[1] is the ftrace queue for CPU(0).
+ // queues_[x] is the ftrace queue for CPU(x - 1).
+ std::vector<Queue> queues;
+ };
+ std::vector<TraceSorterData> sorter_data_by_machine_;
+
TraceProcessorContext* context_ = nullptr;
- std::unique_ptr<TraceParser> parser_;
// Whether we should ignore incremental extraction and just wait for
// forced extractionn at the end of the trace.
@@ -368,11 +430,6 @@
// extraction.
uint32_t flushes_since_extraction_ = 0;
- // queues_[0] is the general (non-ftrace) queue.
- // queues_[1] is the ftrace queue for CPU(0).
- // queues_[x] is the ftrace queue for CPU(x - 1).
- std::vector<Queue> queues_;
-
// max(e.ts for e appended to the sorter)
int64_t append_max_ts_ = 0;
diff --git a/src/trace_processor/sorter/trace_sorter_unittest.cc b/src/trace_processor/sorter/trace_sorter_unittest.cc
index 791e21a..8f7e73d 100644
--- a/src/trace_processor/sorter/trace_sorter_unittest.cc
+++ b/src/trace_processor/sorter/trace_sorter_unittest.cc
@@ -38,20 +38,26 @@
using ::testing::MockFunction;
using ::testing::NiceMock;
+constexpr std::optional<MachineId> kNullMachineId = std::nullopt;
+
class MockTraceParser : public ProtoTraceParser {
public:
- MockTraceParser(TraceProcessorContext* context) : ProtoTraceParser(context) {}
+ explicit MockTraceParser(TraceProcessorContext* context)
+ : ProtoTraceParser(context), machine_id_(context->machine_id()) {}
- MOCK_METHOD(
- void,
- MOCK_ParseFtracePacket,
- (uint32_t cpu, int64_t timestamp, const uint8_t* data, size_t length));
+ MOCK_METHOD(void,
+ MOCK_ParseFtracePacket,
+ (uint32_t cpu,
+ int64_t timestamp,
+ const uint8_t* data,
+ size_t length,
+ std::optional<MachineId>));
void ParseFtraceEvent(uint32_t cpu,
int64_t timestamp,
TracePacketData data) override {
MOCK_ParseFtracePacket(cpu, timestamp, data.packet.data(),
- data.packet.length());
+ data.packet.length(), machine_id_);
}
MOCK_METHOD(void,
@@ -64,6 +70,8 @@
TraceBlobView& tbv = data.packet;
MOCK_ParseTracePacket(ts, tbv.data(), tbv.length());
}
+
+ std::optional<MachineId> machine_id_;
};
class MockTraceStorage : public TraceStorage {
@@ -100,7 +108,8 @@
TEST_F(TraceSorterTest, TestFtrace) {
PacketSequenceState state(&context_);
TraceBlobView view = test_buffer_.slice_off(0, 1);
- EXPECT_CALL(*parser_, MOCK_ParseFtracePacket(0, 1000, view.data(), 1));
+ EXPECT_CALL(*parser_,
+ MOCK_ParseFtracePacket(0, 1000, view.data(), 1, kNullMachineId));
context_.sorter->PushFtraceEvent(0 /*cpu*/, 1000 /*timestamp*/,
std::move(view), state.current_generation());
context_.sorter->ExtractEventsForced();
@@ -124,10 +133,12 @@
InSequence s;
- EXPECT_CALL(*parser_, MOCK_ParseFtracePacket(0, 1000, view_1.data(), 1));
+ EXPECT_CALL(*parser_, MOCK_ParseFtracePacket(0, 1000, view_1.data(), 1,
+ kNullMachineId));
EXPECT_CALL(*parser_, MOCK_ParseTracePacket(1001, view_2.data(), 2));
EXPECT_CALL(*parser_, MOCK_ParseTracePacket(1100, view_3.data(), 3));
- EXPECT_CALL(*parser_, MOCK_ParseFtracePacket(2, 1200, view_4.data(), 4));
+ EXPECT_CALL(*parser_, MOCK_ParseFtracePacket(2, 1200, view_4.data(), 4,
+ kNullMachineId));
context_.sorter->PushFtraceEvent(2 /*cpu*/, 1200 /*timestamp*/,
std::move(view_4),
@@ -280,9 +291,10 @@
std::minstd_rand0 rnd_engine(0);
std::map<int64_t /*ts*/, std::vector<uint32_t /*cpu*/>> expectations;
- EXPECT_CALL(*parser_, MOCK_ParseFtracePacket(_, _, _, _))
+ EXPECT_CALL(*parser_, MOCK_ParseFtracePacket(_, _, _, _, _))
.WillRepeatedly(Invoke([&expectations](uint32_t cpu, int64_t timestamp,
- const uint8_t*, size_t) {
+ const uint8_t*, size_t,
+ std::optional<MachineId>) {
EXPECT_EQ(expectations.begin()->first, timestamp);
auto& cpus = expectations.begin()->second;
bool cpu_found = false;
@@ -318,6 +330,115 @@
EXPECT_TRUE(expectations.empty());
}
+// An generalized version of MultiQueueSorting with multiple machines.
+TEST_F(TraceSorterTest, MultiMachineSorting) {
+ PacketSequenceState state(&context_);
+ std::minstd_rand0 rnd_engine(0);
+
+ struct ExpectedMachineAndCpu {
+ std::optional<MachineId> machine_id;
+ uint32_t cpu;
+
+ bool operator==(const ExpectedMachineAndCpu& other) const {
+ return std::tie(machine_id, cpu) == std::tie(other.machine_id, other.cpu);
+ }
+ bool operator!=(const ExpectedMachineAndCpu& other) const {
+ return !operator==(other);
+ }
+ };
+ std::map<int64_t /*ts*/, std::vector<ExpectedMachineAndCpu>> expectations;
+
+ // The total number of machines (including the default one).
+ constexpr size_t num_machines = 5;
+ std::vector<MockTraceParser*> extra_parsers;
+ std::vector<std::unique_ptr<TraceProcessorContext>> extra_contexts;
+ // Set up extra machines and add to the sorter.
+ // MachineIdValue are 1..(num_machines-1).
+ for (auto i = 1u; i < num_machines; i++) {
+ TraceProcessorContext::InitArgs args{context_.config, context_.storage, i};
+ auto ctx = std::make_unique<TraceProcessorContext>(args);
+ auto parser = std::make_unique<MockTraceParser>(ctx.get());
+ extra_parsers.push_back(parser.get());
+
+ extra_contexts.push_back(std::move(ctx));
+ context_.sorter->AddMachine(extra_contexts.back()->machine_id(),
+ std::move(parser));
+ }
+
+ // Set up the expectation for the default machine.
+ EXPECT_CALL(*parser_, MOCK_ParseFtracePacket(_, _, _, _, _))
+ .WillRepeatedly(Invoke([&expectations](uint32_t cpu, int64_t timestamp,
+ const uint8_t*, size_t,
+ std::optional<MachineId>) {
+ EXPECT_EQ(expectations.begin()->first, timestamp);
+ auto& machines_and_cpus = expectations.begin()->second;
+ bool found = false;
+ for (auto it = machines_and_cpus.begin(); it < machines_and_cpus.end();
+ it++) {
+ // The default machine is called machine ID == std::nullopt.
+ if (*it != ExpectedMachineAndCpu{kNullMachineId, cpu})
+ continue;
+ found = true;
+ machines_and_cpus.erase(it);
+ break;
+ }
+ if (machines_and_cpus.empty())
+ expectations.erase(expectations.begin());
+ EXPECT_TRUE(found);
+ }));
+ // Set up expectations for remote machines.
+ for (auto* parser : extra_parsers) {
+ EXPECT_CALL(*parser, MOCK_ParseFtracePacket(_, _, _, _, _))
+ .WillRepeatedly(Invoke(
+ [&expectations](uint32_t cpu, int64_t timestamp, const uint8_t*,
+ size_t, std::optional<MachineId> machine_id) {
+ EXPECT_TRUE(machine_id.has_value());
+ EXPECT_EQ(expectations.begin()->first, timestamp);
+ auto& machines_and_cpus = expectations.begin()->second;
+ bool found = false;
+ for (auto it = machines_and_cpus.begin();
+ it < machines_and_cpus.end(); it++) {
+ // Remote machines are called with non-null machine_id.
+ if (*it != ExpectedMachineAndCpu{machine_id, cpu})
+ continue;
+ found = true;
+ machines_and_cpus.erase(it);
+ break;
+ }
+ if (machines_and_cpus.empty())
+ expectations.erase(expectations.begin());
+ EXPECT_TRUE(found);
+ }));
+ }
+
+ // Allocate a 1000 byte trace blob (per-machine) and push one byte chunks to
+ // be sorted with random timestamps.
+ constexpr size_t alloc_size = 1000;
+ TraceBlobView tbv(TraceBlob::Allocate(alloc_size * num_machines));
+ for (size_t m = 0; m < num_machines; m++) {
+ // TraceProcessorContext::machine_id is nullopt for the default machine or a
+ // monotonic counter starting from 1. 0 is a reserved value that isn't used.
+ std::optional<MachineId> machine;
+ if (m)
+ machine = extra_contexts[m - 1]->machine_id();
+
+ for (uint16_t i = 0; i < alloc_size; i++) {
+ int64_t ts = abs(static_cast<int64_t>(rnd_engine()));
+ uint8_t num_cpus = rnd_engine() % 3;
+ for (uint8_t j = 0; j < num_cpus; j++) {
+ uint32_t cpu = static_cast<uint32_t>(rnd_engine() % 32);
+ expectations[ts].push_back(ExpectedMachineAndCpu{machine, cpu});
+ context_.sorter->PushFtraceEvent(cpu, ts,
+ tbv.slice_off(m * alloc_size + i, 1),
+ state.current_generation(), machine);
+ }
+ }
+ }
+
+ context_.sorter->ExtractEventsForced();
+ EXPECT_TRUE(expectations.empty());
+}
+
} // namespace
} // namespace trace_processor
} // namespace perfetto
diff --git a/src/trace_processor/storage/trace_storage.h b/src/trace_processor/storage/trace_storage.h
index c2158d7..21b6090 100644
--- a/src/trace_processor/storage/trace_storage.h
+++ b/src/trace_processor/storage/trace_storage.h
@@ -541,6 +541,9 @@
return &ftrace_event_table_;
}
+ const tables::MachineTable& machine_table() const { return machine_table_; }
+ tables::MachineTable* mutable_machine_table() { return &machine_table_; }
+
const tables::CpuTable& cpu_table() const { return cpu_table_; }
tables::CpuTable* mutable_cpu_table() { return &cpu_table_; }
@@ -1046,6 +1049,8 @@
tables::RawTable raw_table_{&string_pool_};
tables::FtraceEventTable ftrace_event_table_{&string_pool_, &raw_table_};
+ tables::MachineTable machine_table_{&string_pool_};
+
tables::CpuTable cpu_table_{&string_pool_};
tables::CpuFreqTable cpu_freq_table_{&string_pool_};
diff --git a/src/trace_processor/tables/counter_tables.py b/src/trace_processor/tables/counter_tables.py
index e882452..3a9e062 100644
--- a/src/trace_processor/tables/counter_tables.py
+++ b/src/trace_processor/tables/counter_tables.py
@@ -23,6 +23,7 @@
from python.generators.trace_processor_table.public import CppTableId
from python.generators.trace_processor_table.public import CppUint32
+from src.trace_processor.tables.metadata_tables import MACHINE_TABLE
from src.trace_processor.tables.track_tables import COUNTER_TRACK_TABLE
COUNTER_TABLE = Table(
@@ -34,15 +35,25 @@
C('track_id', CppTableId(COUNTER_TRACK_TABLE)),
C('value', CppDouble()),
C('arg_set_id', CppOptional(CppUint32())),
+ C('machine_id', CppOptional(CppTableId(MACHINE_TABLE))),
],
tabledoc=TableDoc(
doc='''''',
group='Events',
columns={
- 'ts': '''''',
- 'track_id': '''''',
- 'value': '''''',
- 'arg_set_id': '''''',
+ 'ts':
+ '''''',
+ 'track_id':
+ '''''',
+ 'value':
+ '''''',
+ 'arg_set_id':
+ '''''',
+ 'machine_id':
+ '''
+ Machine identifier, non-null for counters from a remote
+ machine.
+ ''',
}))
# Keep this list sorted.
diff --git a/src/trace_processor/tables/metadata_tables.py b/src/trace_processor/tables/metadata_tables.py
index d620b6c..0d91d8d 100644
--- a/src/trace_processor/tables/metadata_tables.py
+++ b/src/trace_processor/tables/metadata_tables.py
@@ -28,6 +28,26 @@
from python.generators.trace_processor_table.public import CppSelfTableId
from python.generators.trace_processor_table.public import WrappingSqlView
+MACHINE_TABLE = Table(
+ python_module=__file__,
+ class_name='MachineTable',
+ sql_name='machine',
+ columns=[
+ C('raw_id', CppUint32()),
+ ],
+ tabledoc=TableDoc(
+ doc='''
+ Contains raw machine_id of trace packets emitted from remote machines.
+ ''',
+ group='Metadata',
+ columns={
+ 'raw_id':
+ '''
+ Raw machine identifier in the trace packet, non-zero for
+ remote machines.
+ '''
+ }))
+
PROCESS_TABLE = Table(
python_module=__file__,
class_name='ProcessTable',
@@ -43,6 +63,7 @@
C('android_appid', CppOptional(CppUint32())),
C('cmdline', CppOptional(CppString())),
C('arg_set_id', CppUint32()),
+ C('machine_id', CppOptional(CppTableId(MACHINE_TABLE))),
],
wrapping_sql_view=WrappingSqlView(view_name='process',),
tabledoc=TableDoc(
@@ -98,6 +119,11 @@
'arg_set_id':
ColumnDoc(
'Extra args for this process.', joinable='args.arg_set_id'),
+ 'machine_id':
+ '''
+ Machine identifier, non-null for processes on a remote
+ machine.
+ ''',
}))
THREAD_TABLE = Table(
@@ -112,6 +138,7 @@
C('end_ts', CppOptional(CppInt64())),
C('upid', CppOptional(CppTableId(PROCESS_TABLE))),
C('is_main_thread', CppOptional(CppUint32())),
+ C('machine_id', CppOptional(CppTableId(MACHINE_TABLE))),
],
wrapping_sql_view=WrappingSqlView(view_name='thread',),
tabledoc=TableDoc(
@@ -157,7 +184,11 @@
'''
Boolean indicating if this thread is the main thread
in the process.
+ ''',
+ 'machine_id':
'''
+ Machine identifier, non-null for threads on a remote machine.
+ ''',
}))
RAW_TABLE = Table(
@@ -170,7 +201,8 @@
C('cpu', CppUint32()),
C('utid', CppTableId(THREAD_TABLE)),
C('arg_set_id', CppUint32()),
- C('common_flags', CppUint32())
+ C('common_flags', CppUint32()),
+ C('machine_id', CppOptional(CppTableId(MACHINE_TABLE))),
],
tabledoc=TableDoc(
doc='''
@@ -196,7 +228,15 @@
'utid':
'The thread this event was emitted on.',
'common_flags':
- 'Ftrace event flags for this event. Currently only emitted for sched_waking events.'
+ '''
+ Ftrace event flags for this event. Currently only emitted for
+ sched_waking events.
+ ''',
+ 'machine_id':
+ '''
+ Machine identifier, non-null for raw events on a remote
+ machine.
+ ''',
}))
FTRACE_EVENT_TABLE = Table(
@@ -324,6 +364,7 @@
columns=[
C('cluster_id', CppUint32()),
C('processor', CppString()),
+ C('machine_id', CppOptional(CppTableId(MACHINE_TABLE))),
],
tabledoc=TableDoc(
doc='''
@@ -335,7 +376,11 @@
'''the cluster id is shared by CPUs in
the same cluster''',
'processor':
- '''a string describing this core'''
+ '''a string describing this core''',
+ 'machine_id':
+ '''
+ Machine identifier, non-null for CPUs on a remote machine.
+ ''',
}))
CPU_FREQ_TABLE = Table(
@@ -345,11 +390,18 @@
columns=[
C('cpu_id', CppTableId(CPU_TABLE)),
C('freq', CppUint32()),
+ C('machine_id', CppOptional(CppTableId(MACHINE_TABLE))),
],
tabledoc=TableDoc(
- doc='''''', group='Misc', columns={
+ doc='''''',
+ group='Misc',
+ columns={
'cpu_id': '''''',
- 'freq': ''''''
+ 'freq': '''''',
+ 'machine_id':
+ '''
+ Machine identifier, non-null for CPUs on a remote machine.
+ ''',
}))
CLOCK_SNAPSHOT_TABLE = Table(
@@ -362,6 +414,7 @@
C('clock_name', CppOptional(CppString())),
C('clock_value', CppInt64()),
C('snapshot_id', CppUint32()),
+ C('machine_id', CppOptional(CppTableId(MACHINE_TABLE))),
],
tabledoc=TableDoc(
doc='''
@@ -382,7 +435,12 @@
'clock_value':
'''timestamp of the snapshot in clock time.''',
'snapshot_id':
- '''the index of this snapshot (only useful for debugging)'''
+ '''the index of this snapshot (only useful for debugging)''',
+ 'machine_id':
+ '''
+ Machine identifier, non-null for clock snapshots on a remote
+ machine.
+ ''',
}))
# Keep this list sorted.
@@ -398,4 +456,5 @@
RAW_TABLE,
THREAD_TABLE,
FTRACE_EVENT_TABLE,
+ MACHINE_TABLE,
]
diff --git a/src/trace_processor/tables/sched_tables.py b/src/trace_processor/tables/sched_tables.py
index 0af8014..4ef4de8 100644
--- a/src/trace_processor/tables/sched_tables.py
+++ b/src/trace_processor/tables/sched_tables.py
@@ -27,6 +27,8 @@
from python.generators.trace_processor_table.public import TableDoc
from python.generators.trace_processor_table.public import WrappingSqlView
+from src.trace_processor.tables.metadata_tables import MACHINE_TABLE
+
SCHED_SLICE_TABLE = Table(
python_module=__file__,
class_name='SchedSliceTable',
@@ -38,6 +40,7 @@
C('utid', CppUint32()),
C('end_state', CppString()),
C('priority', CppInt32()),
+ C('machine_id', CppOptional(CppTableId(MACHINE_TABLE))),
],
tabledoc=TableDoc(
doc='''
@@ -70,7 +73,12 @@
cleanup).
''',
'priority':
- '''The kernel priority that the thread ran at.'''
+ '''The kernel priority that the thread ran at.''',
+ 'machine_id':
+ '''
+ Machine identifier, non-null for scheduling slices on a remote
+ machine.
+ ''',
}))
SPURIOUS_SCHED_WAKEUP_TABLE = Table(
@@ -122,6 +130,7 @@
C('waker_utid', CppOptional(CppUint32())),
C('waker_id', CppOptional(CppSelfTableId())),
C('irq_context', CppOptional(CppUint32())),
+ C('machine_id', CppOptional(CppTableId(MACHINE_TABLE))),
],
tabledoc=TableDoc(
doc='''
@@ -160,7 +169,11 @@
'waker_id':
'''
The unique thread state id which caused a wakeup of this thread.
+ ''',
+ 'machine_id':
'''
+ Machine identifier, non-null for threads on a remote machine.
+ ''',
}))
# Keep this list sorted.
diff --git a/src/trace_processor/tables/table_destructors.cc b/src/trace_processor/tables/table_destructors.cc
index 826316c..eade18c 100644
--- a/src/trace_processor/tables/table_destructors.cc
+++ b/src/trace_processor/tables/table_destructors.cc
@@ -60,6 +60,7 @@
ProcessTable::~ProcessTable() = default;
FiledescriptorTable::~FiledescriptorTable() = default;
ClockSnapshotTable::~ClockSnapshotTable() = default;
+MachineTable::~MachineTable() = default;
// profiler_tables_py.h
StackProfileMappingTable::~StackProfileMappingTable() = default;
diff --git a/src/trace_processor/tables/track_tables.py b/src/trace_processor/tables/track_tables.py
index cfdc59d..4d7bc93 100644
--- a/src/trace_processor/tables/track_tables.py
+++ b/src/trace_processor/tables/track_tables.py
@@ -22,8 +22,11 @@
from python.generators.trace_processor_table.public import TableDoc
from python.generators.trace_processor_table.public import ColumnDoc
from python.generators.trace_processor_table.public import CppSelfTableId
+from python.generators.trace_processor_table.public import CppTableId
from python.generators.trace_processor_table.public import CppUint32
+from src.trace_processor.tables.metadata_tables import MACHINE_TABLE
+
TRACK_TABLE = Table(
python_module=__file__,
class_name="TrackTable",
@@ -32,6 +35,7 @@
C("name", CppString()),
C("parent_id", CppOptional(CppSelfTableId())),
C("source_arg_set_id", CppOptional(CppUint32())),
+ C('machine_id', CppOptional(CppTableId(MACHINE_TABLE))),
],
tabledoc=TableDoc(
doc='''
@@ -60,6 +64,10 @@
track orginated from atrace, Chrome tracepoints etc.
''',
joinable='args.arg_set_id'),
+ 'machine_id':
+ '''
+ Machine identifier, non-null for tracks on a remote machine.
+ ''',
}))
PROCESS_TRACK_TABLE = Table(
diff --git a/src/trace_processor/trace_processor_context.cc b/src/trace_processor/trace_processor_context.cc
index 2ee7b3d..c861f63 100644
--- a/src/trace_processor/trace_processor_context.cc
+++ b/src/trace_processor/trace_processor_context.cc
@@ -15,6 +15,7 @@
*/
#include "src/trace_processor/types/trace_processor_context.h"
+#include <optional>
#include "src/trace_processor/forwarding_trace_parser.h"
#include "src/trace_processor/importers/common/args_tracker.h"
@@ -27,6 +28,7 @@
#include "src/trace_processor/importers/common/event_tracker.h"
#include "src/trace_processor/importers/common/flow_tracker.h"
#include "src/trace_processor/importers/common/global_args_tracker.h"
+#include "src/trace_processor/importers/common/machine_tracker.h"
#include "src/trace_processor/importers/common/mapping_tracker.h"
#include "src/trace_processor/importers/common/metadata_tracker.h"
#include "src/trace_processor/importers/common/process_tracker.h"
@@ -36,9 +38,12 @@
#include "src/trace_processor/importers/common/stack_profile_tracker.h"
#include "src/trace_processor/importers/common/track_tracker.h"
#include "src/trace_processor/importers/ftrace/ftrace_module.h"
+#include "src/trace_processor/importers/proto/chrome_track_event.descriptor.h"
+#include "src/trace_processor/importers/proto/multi_machine_trace_manager.h"
#include "src/trace_processor/importers/proto/perf_sample_tracker.h"
#include "src/trace_processor/importers/proto/proto_importer_module.h"
#include "src/trace_processor/importers/proto/proto_trace_parser.h"
+#include "src/trace_processor/importers/proto/track_event.descriptor.h"
#include "src/trace_processor/importers/proto/track_event_module.h"
#include "src/trace_processor/sorter/trace_sorter.h"
#include "src/trace_processor/types/destructible.h"
@@ -46,8 +51,59 @@
namespace perfetto {
namespace trace_processor {
+TraceProcessorContext::TraceProcessorContext(const InitArgs& args)
+ : config(args.config), storage(args.storage) {
+ // Init the trackers.
+ machine_tracker.reset(new MachineTracker(this, args.raw_machine_id));
+ if (!machine_id()) {
+ multi_machine_trace_manager.reset(new MultiMachineTraceManager(this));
+ }
+ track_tracker.reset(new TrackTracker(this));
+ async_track_set_tracker.reset(new AsyncTrackSetTracker(this));
+ args_tracker.reset(new ArgsTracker(this));
+ args_translation_table.reset(new ArgsTranslationTable(storage.get()));
+ slice_tracker.reset(new SliceTracker(this));
+ slice_translation_table.reset(new SliceTranslationTable(storage.get()));
+ flow_tracker.reset(new FlowTracker(this));
+ event_tracker.reset(new EventTracker(this));
+ sched_event_tracker.reset(new SchedEventTracker(this));
+ process_tracker.reset(new ProcessTracker(this));
+ clock_tracker.reset(new ClockTracker(this));
+ clock_converter.reset(new ClockConverter(this));
+ mapping_tracker.reset(new MappingTracker(this));
+ perf_sample_tracker.reset(new PerfSampleTracker(this));
+ stack_profile_tracker.reset(new StackProfileTracker(this));
+ metadata_tracker.reset(new MetadataTracker(storage.get()));
+ global_args_tracker.reset(new GlobalArgsTracker(storage.get()));
+ {
+ descriptor_pool_.reset(new DescriptorPool());
+ auto status = descriptor_pool_->AddFromFileDescriptorSet(
+ kTrackEventDescriptor.data(), kTrackEventDescriptor.size());
+
+ PERFETTO_DCHECK(status.ok());
+
+ status = descriptor_pool_->AddFromFileDescriptorSet(
+ kChromeTrackEventDescriptor.data(), kChromeTrackEventDescriptor.size());
+
+ PERFETTO_DCHECK(status.ok());
+ }
+
+ slice_tracker->SetOnSliceBeginCallback(
+ [this](TrackId track_id, SliceId slice_id) {
+ flow_tracker->ClosePendingEventsOnTrack(track_id, slice_id);
+ });
+}
+
TraceProcessorContext::TraceProcessorContext() = default;
TraceProcessorContext::~TraceProcessorContext() = default;
+std::optional<MachineId> TraceProcessorContext::machine_id() const {
+ if (!machine_tracker) {
+ // Doesn't require that |machine_tracker| is initialzed, e.g. in unit tests.
+ return std::nullopt;
+ }
+ return machine_tracker->machine_id();
+}
+
} // namespace trace_processor
} // namespace perfetto
diff --git a/src/trace_processor/trace_processor_storage_impl.cc b/src/trace_processor/trace_processor_storage_impl.cc
index b0c7a15..b6cc299 100644
--- a/src/trace_processor/trace_processor_storage_impl.cc
+++ b/src/trace_processor/trace_processor_storage_impl.cc
@@ -26,6 +26,7 @@
#include "src/trace_processor/importers/common/clock_tracker.h"
#include "src/trace_processor/importers/common/event_tracker.h"
#include "src/trace_processor/importers/common/flow_tracker.h"
+#include "src/trace_processor/importers/common/machine_tracker.h"
#include "src/trace_processor/importers/common/mapping_tracker.h"
#include "src/trace_processor/importers/common/metadata_tracker.h"
#include "src/trace_processor/importers/common/process_tracker.h"
@@ -47,48 +48,8 @@
namespace perfetto {
namespace trace_processor {
-TraceProcessorStorageImpl::TraceProcessorStorageImpl(const Config& cfg) {
- context_.config = cfg;
-
- context_.storage.reset(new TraceStorage(context_.config));
- context_.track_tracker.reset(new TrackTracker(&context_));
- context_.async_track_set_tracker.reset(new AsyncTrackSetTracker(&context_));
- context_.args_tracker.reset(new ArgsTracker(&context_));
- context_.args_translation_table.reset(
- new ArgsTranslationTable(context_.storage.get()));
- context_.slice_tracker.reset(new SliceTracker(&context_));
- context_.slice_translation_table.reset(
- new SliceTranslationTable(context_.storage.get()));
- context_.flow_tracker.reset(new FlowTracker(&context_));
- context_.event_tracker.reset(new EventTracker(&context_));
- context_.sched_event_tracker.reset(new SchedEventTracker(&context_));
- context_.process_tracker.reset(new ProcessTracker(&context_));
- context_.clock_tracker.reset(new ClockTracker(&context_));
- context_.clock_converter.reset(new ClockConverter(&context_));
- context_.mapping_tracker.reset(new MappingTracker(&context_));
- context_.perf_sample_tracker.reset(new PerfSampleTracker(&context_));
- context_.stack_profile_tracker.reset(new StackProfileTracker(&context_));
- context_.metadata_tracker.reset(new MetadataTracker(context_.storage.get()));
- context_.global_args_tracker.reset(
- new GlobalArgsTracker(context_.storage.get()));
- {
- context_.descriptor_pool_.reset(new DescriptorPool());
- auto status = context_.descriptor_pool_->AddFromFileDescriptorSet(
- kTrackEventDescriptor.data(), kTrackEventDescriptor.size());
-
- PERFETTO_DCHECK(status.ok());
-
- status = context_.descriptor_pool_->AddFromFileDescriptorSet(
- kChromeTrackEventDescriptor.data(), kChromeTrackEventDescriptor.size());
-
- PERFETTO_DCHECK(status.ok());
- }
-
- context_.slice_tracker->SetOnSliceBeginCallback(
- [this](TrackId track_id, SliceId slice_id) {
- context_.flow_tracker->ClosePendingEventsOnTrack(track_id, slice_id);
- });
-
+TraceProcessorStorageImpl::TraceProcessorStorageImpl(const Config& cfg)
+ : context_({cfg, std::make_shared<TraceStorage>(cfg)}) {
RegisterDefaultModules(&context_);
}
@@ -163,6 +124,8 @@
context.system_info_tracker = std::move(context_.system_info_tracker);
context_ = std::move(context);
+
+ // TODO(chinglinyu): also need to destroy secondary contextes.
}
} // namespace trace_processor
diff --git a/src/trace_processor/types/BUILD.gn b/src/trace_processor/types/BUILD.gn
index 0605ea1..6b66c53 100644
--- a/src/trace_processor/types/BUILD.gn
+++ b/src/trace_processor/types/BUILD.gn
@@ -31,6 +31,7 @@
"../../../include/perfetto/ext/base",
"../../../include/perfetto/trace_processor",
"../containers",
+ "../tables:tables_python",
]
}
diff --git a/src/trace_processor/types/trace_processor_context.h b/src/trace_processor/types/trace_processor_context.h
index 164df00..af2837f 100644
--- a/src/trace_processor/types/trace_processor_context.h
+++ b/src/trace_processor/types/trace_processor_context.h
@@ -21,6 +21,7 @@
#include <vector>
#include "perfetto/trace_processor/basic_types.h"
+#include "src/trace_processor/tables/metadata_tables_py.h"
#include "src/trace_processor/types/destructible.h"
namespace perfetto {
@@ -55,8 +56,10 @@
class StackProfileTracker;
class HeapGraphTracker;
class PerfSampleTracker;
+class MachineTracker;
class MappingTracker;
class MetadataTracker;
+class MultiMachineTraceManager;
class PacketAnalyzer;
class ProtoImporterModule;
class TrackEventModule;
@@ -71,8 +74,17 @@
class TrackTracker;
class DescriptorPool;
+using MachineId = tables::MachineTable::Id;
+
class TraceProcessorContext {
public:
+ struct InitArgs {
+ Config config;
+ std::shared_ptr<TraceStorage> storage;
+ uint32_t raw_machine_id = 0;
+ };
+ explicit TraceProcessorContext(const InitArgs&);
+ // The default constructor is used in testing.
TraceProcessorContext();
~TraceProcessorContext();
@@ -81,10 +93,14 @@
Config config;
- std::unique_ptr<TraceStorage> storage;
+ // |storage| is shared among multiple contexts in multi-machine tracing.
+ std::shared_ptr<TraceStorage> storage;
std::unique_ptr<ChunkedTraceReader> chunk_reader;
- std::unique_ptr<TraceSorter> sorter;
+
+ // The sorter is used to sort trace data by timestamp and is shared among
+ // multiple machines.
+ std::shared_ptr<TraceSorter> sorter;
// Keep the global tracker before the args tracker as we access the global
// tracker in the destructor of the args tracker. Also keep it before other
@@ -104,6 +120,7 @@
std::unique_ptr<ClockTracker> clock_tracker;
std::unique_ptr<ClockConverter> clock_converter;
std::unique_ptr<MappingTracker> mapping_tracker;
+ std::unique_ptr<MachineTracker> machine_tracker;
std::unique_ptr<PerfSampleTracker> perf_sample_tracker;
std::unique_ptr<StackProfileTracker> stack_profile_tracker;
std::unique_ptr<MetadataTracker> metadata_tracker;
@@ -171,6 +188,11 @@
bool uuid_found_in_trace = false;
TraceType trace_type = kUnknownTraceType;
+
+ std::optional<MachineId> machine_id() const;
+
+ // Manages the contexts for reading trace data emitted from remote machines.
+ std::unique_ptr<MultiMachineTraceManager> multi_machine_trace_manager;
};
} // namespace trace_processor
diff --git a/src/traced/probes/ftrace/atrace_wrapper.cc b/src/traced/probes/ftrace/atrace_wrapper.cc
index 7254325..1a64544 100644
--- a/src/traced/probes/ftrace/atrace_wrapper.cc
+++ b/src/traced/probes/ftrace/atrace_wrapper.cc
@@ -38,9 +38,6 @@
namespace {
-RunAtraceFunction g_run_atrace_for_testing = nullptr;
-std::optional<bool> g_is_old_atrace_for_testing{};
-
#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
// Args should include "atrace" for argv[0].
bool ExecvAtrace(const std::vector<std::string>& args,
@@ -174,25 +171,23 @@
} // namespace
-bool RunAtrace(const std::vector<std::string>& args,
- std::string* atrace_errors) {
- if (g_run_atrace_for_testing)
- return g_run_atrace_for_testing(args, atrace_errors);
+AtraceWrapper::~AtraceWrapper() = default;
+
+AtraceWrapperImpl::~AtraceWrapperImpl() = default;
+
+bool AtraceWrapperImpl::RunAtrace(const std::vector<std::string>& args,
+ std::string* atrace_errors) {
#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
return ExecvAtrace(args, atrace_errors);
#else
+ base::ignore_result(args);
+ base::ignore_result(atrace_errors);
PERFETTO_LOG("Atrace only supported on Android.");
return false;
#endif
}
-void SetRunAtraceForTesting(RunAtraceFunction f) {
- g_run_atrace_for_testing = f;
-}
-
-bool IsOldAtrace() {
- if (g_is_old_atrace_for_testing.has_value())
- return *g_is_old_atrace_for_testing;
+bool AtraceWrapperImpl::IsOldAtrace() {
#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) && \
!PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD)
// Sideloaded case. We could be sideloaded on a modern device or an older one.
@@ -207,12 +202,4 @@
#endif
}
-void SetIsOldAtraceForTesting(bool value) {
- g_is_old_atrace_for_testing = value;
-}
-
-void ClearIsOldAtraceForTesting() {
- g_is_old_atrace_for_testing.reset();
-}
-
} // namespace perfetto
diff --git a/src/traced/probes/ftrace/atrace_wrapper.h b/src/traced/probes/ftrace/atrace_wrapper.h
index 29847aa..5c6a148 100644
--- a/src/traced/probes/ftrace/atrace_wrapper.h
+++ b/src/traced/probes/ftrace/atrace_wrapper.h
@@ -18,27 +18,30 @@
#define SRC_TRACED_PROBES_FTRACE_ATRACE_WRAPPER_H_
#include <string>
-#include <type_traits>
#include <vector>
namespace perfetto {
-using RunAtraceFunction =
- std::add_pointer<bool(const std::vector<std::string>& /*args*/,
- std::string* /*atrace_errors*/)>::type;
+class AtraceWrapper {
+ public:
+ virtual ~AtraceWrapper();
+ // When we are sideloaded on an old version of Android (pre P), we cannot use
+ // atrace --only_userspace because that option doesn't exist. In that case we:
+ // - Just use atrace --async_start/stop, which will cause atrace to also
+ // poke at ftrace.
+ // - Suppress the checks for "somebody else enabled ftrace unexpectedly".
+ virtual bool IsOldAtrace() = 0;
+ virtual bool RunAtrace(const std::vector<std::string>& args,
+ std::string* atrace_errors) = 0;
+};
-// When we are sideloaded on an old version of Android (pre P), we cannot use
-// atrace --only_userspace because that option doesn't exist. In that case we:
-// - Just use atrace --async_start/stop, which will cause atrace to also
-// poke at ftrace.
-// - Suppress the checks for "somebody else enabled ftrace unexpectedly".
-bool IsOldAtrace();
-void SetIsOldAtraceForTesting(bool);
-void ClearIsOldAtraceForTesting();
-
-bool RunAtrace(const std::vector<std::string>& args,
- std::string* atrace_errors);
-void SetRunAtraceForTesting(RunAtraceFunction);
+class AtraceWrapperImpl : public AtraceWrapper {
+ public:
+ ~AtraceWrapperImpl() override;
+ bool IsOldAtrace() override;
+ bool RunAtrace(const std::vector<std::string>& args,
+ std::string* atrace_errors) override;
+};
} // namespace perfetto
diff --git a/src/traced/probes/ftrace/event_info.cc b/src/traced/probes/ftrace/event_info.cc
index e472d06..e11184b 100644
--- a/src/traced/probes/ftrace/event_info.cc
+++ b/src/traced/probes/ftrace/event_info.cc
@@ -4758,6 +4758,88 @@
kUnsetFtraceId,
347,
kUnsetSize},
+ {"fastrpc_dma_free",
+ "fastrpc",
+ {
+ {kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
+ "cid", 1, ProtoSchemaType::kInt32,
+ TranslationStrategy::kInvalidTranslationStrategy},
+ {kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
+ "phys", 2, ProtoSchemaType::kUint64,
+ TranslationStrategy::kInvalidTranslationStrategy},
+ {kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
+ "size", 3, ProtoSchemaType::kUint64,
+ TranslationStrategy::kInvalidTranslationStrategy},
+ },
+ kUnsetFtraceId,
+ 498,
+ kUnsetSize},
+ {"fastrpc_dma_alloc",
+ "fastrpc",
+ {
+ {kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
+ "cid", 1, ProtoSchemaType::kInt32,
+ TranslationStrategy::kInvalidTranslationStrategy},
+ {kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
+ "phys", 2, ProtoSchemaType::kUint64,
+ TranslationStrategy::kInvalidTranslationStrategy},
+ {kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
+ "size", 3, ProtoSchemaType::kUint64,
+ TranslationStrategy::kInvalidTranslationStrategy},
+ {kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
+ "attr", 4, ProtoSchemaType::kUint64,
+ TranslationStrategy::kInvalidTranslationStrategy},
+ {kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
+ "mflags", 5, ProtoSchemaType::kInt32,
+ TranslationStrategy::kInvalidTranslationStrategy},
+ },
+ kUnsetFtraceId,
+ 499,
+ kUnsetSize},
+ {"fastrpc_dma_unmap",
+ "fastrpc",
+ {
+ {kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
+ "cid", 1, ProtoSchemaType::kInt32,
+ TranslationStrategy::kInvalidTranslationStrategy},
+ {kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
+ "phys", 2, ProtoSchemaType::kUint64,
+ TranslationStrategy::kInvalidTranslationStrategy},
+ {kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
+ "size", 3, ProtoSchemaType::kUint64,
+ TranslationStrategy::kInvalidTranslationStrategy},
+ },
+ kUnsetFtraceId,
+ 500,
+ kUnsetSize},
+ {"fastrpc_dma_map",
+ "fastrpc",
+ {
+ {kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
+ "cid", 1, ProtoSchemaType::kInt32,
+ TranslationStrategy::kInvalidTranslationStrategy},
+ {kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
+ "fd", 2, ProtoSchemaType::kInt32,
+ TranslationStrategy::kInvalidTranslationStrategy},
+ {kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
+ "phys", 3, ProtoSchemaType::kUint64,
+ TranslationStrategy::kInvalidTranslationStrategy},
+ {kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
+ "size", 4, ProtoSchemaType::kUint64,
+ TranslationStrategy::kInvalidTranslationStrategy},
+ {kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
+ "len", 5, ProtoSchemaType::kUint64,
+ TranslationStrategy::kInvalidTranslationStrategy},
+ {kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
+ "attr", 6, ProtoSchemaType::kUint32,
+ TranslationStrategy::kInvalidTranslationStrategy},
+ {kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
+ "mflags", 7, ProtoSchemaType::kInt32,
+ TranslationStrategy::kInvalidTranslationStrategy},
+ },
+ kUnsetFtraceId,
+ 501,
+ kUnsetSize},
{"fence_init",
"fence",
{
@@ -7515,22 +7597,16 @@
"panel",
{
{kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
- "pid", 1, ProtoSchemaType::kInt32,
+ "type", 1, ProtoSchemaType::kUint32,
TranslationStrategy::kInvalidTranslationStrategy},
{kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
- "trace_name", 2, ProtoSchemaType::kString,
+ "pid", 2, ProtoSchemaType::kInt32,
TranslationStrategy::kInvalidTranslationStrategy},
{kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
- "trace_begin", 3, ProtoSchemaType::kUint32,
+ "name", 3, ProtoSchemaType::kString,
TranslationStrategy::kInvalidTranslationStrategy},
{kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
- "name", 4, ProtoSchemaType::kString,
- TranslationStrategy::kInvalidTranslationStrategy},
- {kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
- "type", 5, ProtoSchemaType::kUint32,
- TranslationStrategy::kInvalidTranslationStrategy},
- {kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
- "value", 6, ProtoSchemaType::kInt32,
+ "value", 4, ProtoSchemaType::kInt32,
TranslationStrategy::kInvalidTranslationStrategy},
},
kUnsetFtraceId,
@@ -7540,55 +7616,55 @@
"perf_trace_counters",
{
{kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
- "old_pid", 1, ProtoSchemaType::kInt32,
+ "prev_comm", 1, ProtoSchemaType::kString,
TranslationStrategy::kInvalidTranslationStrategy},
{kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
- "new_pid", 2, ProtoSchemaType::kInt32,
+ "prev_pid", 2, ProtoSchemaType::kInt32,
TranslationStrategy::kInvalidTranslationStrategy},
{kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
- "cctr", 3, ProtoSchemaType::kUint32,
+ "cyc", 3, ProtoSchemaType::kUint32,
TranslationStrategy::kInvalidTranslationStrategy},
{kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
- "ctr0", 4, ProtoSchemaType::kUint32,
+ "inst", 4, ProtoSchemaType::kUint32,
TranslationStrategy::kInvalidTranslationStrategy},
{kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
- "ctr1", 5, ProtoSchemaType::kUint32,
+ "stallbm", 5, ProtoSchemaType::kUint32,
TranslationStrategy::kInvalidTranslationStrategy},
{kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
- "ctr2", 6, ProtoSchemaType::kUint32,
+ "l3dm", 6, ProtoSchemaType::kUint32,
TranslationStrategy::kInvalidTranslationStrategy},
{kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
- "ctr3", 7, ProtoSchemaType::kUint32,
+ "old_pid", 7, ProtoSchemaType::kInt32,
TranslationStrategy::kInvalidTranslationStrategy},
{kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
- "lctr0", 8, ProtoSchemaType::kUint32,
+ "new_pid", 8, ProtoSchemaType::kInt32,
TranslationStrategy::kInvalidTranslationStrategy},
{kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
- "lctr1", 9, ProtoSchemaType::kUint32,
+ "cctr", 9, ProtoSchemaType::kUint32,
TranslationStrategy::kInvalidTranslationStrategy},
{kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
- "ctr4", 10, ProtoSchemaType::kUint32,
+ "ctr0", 10, ProtoSchemaType::kUint32,
TranslationStrategy::kInvalidTranslationStrategy},
{kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
- "ctr5", 11, ProtoSchemaType::kUint32,
+ "ctr1", 11, ProtoSchemaType::kUint32,
TranslationStrategy::kInvalidTranslationStrategy},
{kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
- "prev_comm", 12, ProtoSchemaType::kString,
+ "ctr2", 12, ProtoSchemaType::kUint32,
TranslationStrategy::kInvalidTranslationStrategy},
{kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
- "prev_pid", 13, ProtoSchemaType::kInt32,
+ "ctr3", 13, ProtoSchemaType::kUint32,
TranslationStrategy::kInvalidTranslationStrategy},
{kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
- "cyc", 14, ProtoSchemaType::kUint32,
+ "lctr0", 14, ProtoSchemaType::kUint32,
TranslationStrategy::kInvalidTranslationStrategy},
{kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
- "inst", 15, ProtoSchemaType::kUint32,
+ "lctr1", 15, ProtoSchemaType::kUint32,
TranslationStrategy::kInvalidTranslationStrategy},
{kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
- "stallbm", 16, ProtoSchemaType::kUint32,
+ "ctr4", 16, ProtoSchemaType::kUint32,
TranslationStrategy::kInvalidTranslationStrategy},
{kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
- "l3dm", 17, ProtoSchemaType::kUint32,
+ "ctr5", 17, ProtoSchemaType::kUint32,
TranslationStrategy::kInvalidTranslationStrategy},
},
kUnsetFtraceId,
diff --git a/src/traced/probes/ftrace/ftrace_config_muxer.cc b/src/traced/probes/ftrace/ftrace_config_muxer.cc
index 3e2b9ab..e4d8a19 100644
--- a/src/traced/probes/ftrace/ftrace_config_muxer.cc
+++ b/src/traced/probes/ftrace/ftrace_config_muxer.cc
@@ -579,11 +579,13 @@
FtraceConfigMuxer::FtraceConfigMuxer(
FtraceProcfs* ftrace,
+ AtraceWrapper* atrace_wrapper,
ProtoTranslationTable* table,
SyscallTable syscalls,
std::map<std::string, std::vector<GroupAndName>> vendor_events,
bool secondary_instance)
: ftrace_(ftrace),
+ atrace_wrapper_(atrace_wrapper),
table_(table),
syscalls_(std::move(syscalls)),
current_state_(),
@@ -654,7 +656,7 @@
"atrace_apps options as they affect global state");
return false;
}
- if (IsOldAtrace() && !ds_configs_.empty()) {
+ if (atrace_wrapper_->IsOldAtrace() && !ds_configs_.empty()) {
PERFETTO_ELOG(
"Concurrent atrace sessions are not supported before Android P, "
"bailing out.");
@@ -1040,7 +1042,6 @@
}
}
-// static
bool FtraceConfigMuxer::StartAtrace(const std::vector<std::string>& apps,
const std::vector<std::string>& categories,
std::string* atrace_errors) {
@@ -1049,7 +1050,7 @@
std::vector<std::string> args;
args.push_back("atrace"); // argv0 for exec()
args.push_back("--async_start");
- if (!IsOldAtrace())
+ if (!atrace_wrapper_->IsOldAtrace())
args.push_back("--only_userspace");
for (const auto& category : categories)
@@ -1066,7 +1067,7 @@
args.push_back(arg);
}
- bool result = RunAtrace(args, atrace_errors);
+ bool result = atrace_wrapper_->RunAtrace(args, atrace_errors);
PERFETTO_DLOG("...done (%s)", result ? "success" : "fail");
return result;
}
@@ -1077,9 +1078,9 @@
PERFETTO_DLOG("Stop atrace...");
std::vector<std::string> args{"atrace", "--async_stop"};
- if (!IsOldAtrace())
+ if (!atrace_wrapper_->IsOldAtrace())
args.push_back("--only_userspace");
- if (RunAtrace(args, /*atrace_errors=*/nullptr)) {
+ if (atrace_wrapper_->RunAtrace(args, /*atrace_errors=*/nullptr)) {
current_state_.atrace_categories.clear();
current_state_.atrace_apps.clear();
current_state_.atrace_on = false;
diff --git a/src/traced/probes/ftrace/ftrace_config_muxer.h b/src/traced/probes/ftrace/ftrace_config_muxer.h
index e11efb0..4c3f10b 100644
--- a/src/traced/probes/ftrace/ftrace_config_muxer.h
+++ b/src/traced/probes/ftrace/ftrace_config_muxer.h
@@ -22,6 +22,7 @@
#include <set>
#include "src/kernel_utils/syscall_table.h"
+#include "src/traced/probes/ftrace/atrace_wrapper.h"
#include "src/traced/probes/ftrace/compact_sched.h"
#include "src/traced/probes/ftrace/ftrace_config_utils.h"
#include "src/traced/probes/ftrace/ftrace_print_filter.h"
@@ -106,6 +107,7 @@
// should outlive this instance.
FtraceConfigMuxer(
FtraceProcfs* ftrace,
+ AtraceWrapper* atrace_wrapper,
ProtoTranslationTable* table,
SyscallTable syscalls,
std::map<std::string, std::vector<GroupAndName>> vendor_events,
@@ -174,10 +176,6 @@
const SyscallTable& syscalls);
private:
- static bool StartAtrace(const std::vector<std::string>& apps,
- const std::vector<std::string>& categories,
- std::string* atrace_errors);
-
struct FtraceState {
EventFilter ftrace_events;
std::set<size_t> syscall_filter; // syscall ids or kAllSyscallsId
@@ -198,6 +196,9 @@
void SetupBufferSize(const FtraceConfig& request);
bool UpdateBufferPercent();
void UpdateAtrace(const FtraceConfig& request, std::string* atrace_errors);
+ bool StartAtrace(const std::vector<std::string>& apps,
+ const std::vector<std::string>& categories,
+ std::string* atrace_errors);
void DisableAtrace();
// This processes the config to get the exact events.
@@ -226,6 +227,7 @@
bool SetSyscallEventFilter(const EventFilter& extra_syscalls);
FtraceProcfs* ftrace_;
+ AtraceWrapper* atrace_wrapper_;
ProtoTranslationTable* table_;
SyscallTable syscalls_;
diff --git a/src/traced/probes/ftrace/ftrace_config_muxer_unittest.cc b/src/traced/probes/ftrace/ftrace_config_muxer_unittest.cc
index 3ef5635..513d851 100644
--- a/src/traced/probes/ftrace/ftrace_config_muxer_unittest.cc
+++ b/src/traced/probes/ftrace/ftrace_config_muxer_unittest.cc
@@ -93,19 +93,10 @@
(const, override));
};
-struct MockRunAtrace {
- MockRunAtrace() {
- static MockRunAtrace* instance;
- instance = this;
- SetRunAtraceForTesting(
- [](const std::vector<std::string>& args, std::string* atrace_errors) {
- return instance->RunAtrace(args, atrace_errors);
- });
- }
-
- ~MockRunAtrace() { SetRunAtraceForTesting(nullptr); }
-
+class MockAtraceWrapper : public AtraceWrapper {
+ public:
MOCK_METHOD(bool, RunAtrace, (const std::vector<std::string>&, std::string*));
+ MOCK_METHOD(bool, IsOldAtrace, ());
};
class MockProtoTranslationTable : public ProtoTranslationTable {
@@ -131,22 +122,66 @@
(const, override));
};
+TEST(ComputeCpuBufferSizeInPagesTest, DifferentCases) {
+ constexpr auto test = ComputeCpuBufferSizeInPages;
+ auto KbToPages = [](uint64_t kb) {
+ return kb * 1024 / base::GetSysPageSize();
+ };
+ auto kMaxBufSizePages = KbToPages(64 * 1024);
+ int64_t kNoRamInfo = 0;
+ bool kExactSize = false;
+ bool kLowerBoundSize = true;
+ int64_t kLowRamPages =
+ static_cast<int64_t>(KbToPages(3 * (1ULL << 20) + 512 * (1ULL << 10)));
+ int64_t kHighRamPages =
+ static_cast<int64_t>(KbToPages(7 * (1ULL << 20) + 512 * (1ULL << 10)));
+
+ // No buffer size given: good default.
+ EXPECT_EQ(test(0, kExactSize, kNoRamInfo), KbToPages(2048));
+ // Default depends on device ram size.
+ EXPECT_EQ(test(0, kExactSize, kLowRamPages), KbToPages(2048));
+ EXPECT_EQ(test(0, kExactSize, kHighRamPages), KbToPages(8192));
+
+ // buffer_size_lower_bound lets us choose a higher default than given.
+ // default > requested:
+ EXPECT_EQ(test(4096, kExactSize, kHighRamPages), KbToPages(4096));
+ EXPECT_EQ(test(4096, kLowerBoundSize, kHighRamPages), KbToPages(8192));
+ // requested > default:
+ EXPECT_EQ(test(4096, kExactSize, kLowRamPages), KbToPages(4096));
+ EXPECT_EQ(test(4096, kLowerBoundSize, kLowRamPages), KbToPages(4096));
+ // requested > default:
+ EXPECT_EQ(test(16384, kExactSize, kHighRamPages), KbToPages(16384));
+ EXPECT_EQ(test(16384, kLowerBoundSize, kHighRamPages), KbToPages(16384));
+
+ // Buffer size given way too big: good default.
+ EXPECT_EQ(test(10 * (1ULL << 20), kExactSize, kNoRamInfo), kMaxBufSizePages);
+ EXPECT_EQ(test(512 * 1024, kExactSize, kNoRamInfo), kMaxBufSizePages);
+
+ // Your size ends up with less than 1 page per cpu -> 1 page.
+ EXPECT_EQ(test(3, kExactSize, kNoRamInfo), 1u);
+ // You picked a good size -> your size rounded to nearest page.
+ EXPECT_EQ(test(42, kExactSize, kNoRamInfo), KbToPages(42));
+
+ // Sysconf returning an error is ok.
+ EXPECT_EQ(test(0, kExactSize, -1), KbToPages(2048));
+ EXPECT_EQ(test(4096, kExactSize, -1), KbToPages(4096));
+}
+
+// Base fixture that provides some dependencies but doesn't construct a
+// FtraceConfigMuxer.
class FtraceConfigMuxerTest : public ::testing::Test {
protected:
- void SetUp() override {
- // Don't probe for older SDK levels, that would relax the atrace-related
- // checks on older versions of Android (But some tests here test those).
- // We want the unittests to behave consistently (as if we were on a post P
- // device) regardless of the Android versions they run on.
- SetIsOldAtraceForTesting(false);
+ FtraceConfigMuxerTest() {
+ ON_CALL(atrace_wrapper_, RunAtrace).WillByDefault(Return(true));
+ ON_CALL(atrace_wrapper_, IsOldAtrace).WillByDefault(Return(false));
}
- void TearDown() override { ClearIsOldAtraceForTesting(); }
+
std::unique_ptr<MockProtoTranslationTable> GetMockTable() {
std::vector<Field> common_fields;
std::vector<Event> events;
return std::unique_ptr<MockProtoTranslationTable>(
new MockProtoTranslationTable(
- &table_procfs_, events, std::move(common_fields),
+ &ftrace_, events, std::move(common_fields),
ProtoTranslationTable::DefaultPageHeaderSpecForTesting(),
InvalidCompactSchedEventFormatForTesting()));
}
@@ -225,956 +260,25 @@
}
return std::unique_ptr<ProtoTranslationTable>(new ProtoTranslationTable(
- &table_procfs_, events, std::move(common_fields),
+ &ftrace_, events, std::move(common_fields),
ProtoTranslationTable::DefaultPageHeaderSpecForTesting(),
compact_format, PrintkMap()));
}
- NiceMock<MockFtraceProcfs> table_procfs_;
- std::unique_ptr<ProtoTranslationTable> table_ = CreateFakeTable();
+ NiceMock<MockFtraceProcfs> ftrace_;
+ NiceMock<MockAtraceWrapper> atrace_wrapper_;
};
-TEST_F(FtraceConfigMuxerTest, ComputeCpuBufferSizeInPages) {
- constexpr auto test = ComputeCpuBufferSizeInPages;
- auto KbToPages = [](uint64_t kb) {
- return kb * 1024 / base::GetSysPageSize();
- };
- auto kMaxBufSizePages = KbToPages(64 * 1024);
- int64_t kNoRamInfo = 0;
- bool kExactSize = false;
- bool kLowerBoundSize = true;
- int64_t kLowRamPages =
- static_cast<int64_t>(KbToPages(3 * (1ULL << 20) + 512 * (1ULL << 10)));
- int64_t kHighRamPages =
- static_cast<int64_t>(KbToPages(7 * (1ULL << 20) + 512 * (1ULL << 10)));
-
- // No buffer size given: good default.
- EXPECT_EQ(test(0, kExactSize, kNoRamInfo), KbToPages(2048));
- // Default depends on device ram size.
- EXPECT_EQ(test(0, kExactSize, kLowRamPages), KbToPages(2048));
- EXPECT_EQ(test(0, kExactSize, kHighRamPages), KbToPages(8192));
-
- // buffer_size_lower_bound lets us choose a higher default than given.
- // default > requested:
- EXPECT_EQ(test(4096, kExactSize, kHighRamPages), KbToPages(4096));
- EXPECT_EQ(test(4096, kLowerBoundSize, kHighRamPages), KbToPages(8192));
- // requested > default:
- EXPECT_EQ(test(4096, kExactSize, kLowRamPages), KbToPages(4096));
- EXPECT_EQ(test(4096, kLowerBoundSize, kLowRamPages), KbToPages(4096));
- // requested > default:
- EXPECT_EQ(test(16384, kExactSize, kHighRamPages), KbToPages(16384));
- EXPECT_EQ(test(16384, kLowerBoundSize, kHighRamPages), KbToPages(16384));
-
- // Buffer size given way too big: good default.
- EXPECT_EQ(test(10 * (1ULL << 20), kExactSize, kNoRamInfo), kMaxBufSizePages);
- EXPECT_EQ(test(512 * 1024, kExactSize, kNoRamInfo), kMaxBufSizePages);
-
- // Your size ends up with less than 1 page per cpu -> 1 page.
- EXPECT_EQ(test(3, kExactSize, kNoRamInfo), 1u);
- // You picked a good size -> your size rounded to nearest page.
- EXPECT_EQ(test(42, kExactSize, kNoRamInfo), KbToPages(42));
-
- // Sysconf returning an error is ok.
- EXPECT_EQ(test(0, kExactSize, -1), KbToPages(2048));
- EXPECT_EQ(test(4096, kExactSize, -1), KbToPages(4096));
-}
-
-TEST_F(FtraceConfigMuxerTest, GenericSyscallFiltering) {
+TEST_F(FtraceConfigMuxerTest, SecondaryInstanceDoNotSupportAtrace) {
auto fake_table = CreateFakeTable();
- NiceMock<MockFtraceProcfs> ftrace;
-
- FtraceConfig config = CreateFtraceConfig({"raw_syscalls/sys_enter"});
- *config.add_syscall_events() = "sys_open";
- *config.add_syscall_events() = "sys_read";
-
- FtraceConfigMuxer model(&ftrace, fake_table.get(), GetSyscallTable(), {});
-
- ON_CALL(ftrace, ReadFileIntoString("/root/trace_clock"))
- .WillByDefault(Return("[local] global boot"));
- EXPECT_CALL(ftrace, ReadFileIntoString("/root/trace_clock"))
- .Times(AnyNumber());
- EXPECT_CALL(ftrace, ReadFileIntoString("/root/current_tracer"))
- .WillOnce(Return("nop"));
- EXPECT_CALL(ftrace, ReadOneCharFromFile("/root/tracing_on"))
- .WillOnce(Return('1'));
- EXPECT_CALL(ftrace, WriteToFile(_, _)).WillRepeatedly(Return(true));
- EXPECT_CALL(ftrace, WriteToFile("/root/events/raw_syscalls/sys_enter/filter",
- "id == 0 || id == 1"));
- EXPECT_CALL(ftrace, WriteToFile("/root/events/raw_syscalls/sys_exit/filter",
- "id == 0 || id == 1"));
-
- FtraceConfigId id = 37;
- ASSERT_TRUE(model.SetupConfig(id, config));
- ASSERT_TRUE(model.ActivateConfig(id));
-
- const std::set<size_t>& filter = model.GetSyscallFilterForTesting();
- ASSERT_THAT(filter, UnorderedElementsAre(0, 1));
-}
-
-TEST_F(FtraceConfigMuxerTest, UnknownSyscallFilter) {
- auto fake_table = CreateFakeTable();
- NiceMock<MockFtraceProcfs> ftrace;
- FtraceConfigMuxer model(&ftrace, fake_table.get(), GetSyscallTable(), {});
-
- FtraceConfig config = CreateFtraceConfig({"raw_syscalls/sys_enter"});
- config.add_syscall_events("sys_open");
- config.add_syscall_events("sys_not_a_call");
-
- ON_CALL(ftrace, ReadFileIntoString("/root/trace_clock"))
- .WillByDefault(Return("[local] global boot"));
- EXPECT_CALL(ftrace, ReadFileIntoString("/root/trace_clock"))
- .Times(AnyNumber());
- EXPECT_CALL(ftrace, ReadFileIntoString("/root/current_tracer"))
- .WillOnce(Return("nop"));
- EXPECT_CALL(ftrace, ReadOneCharFromFile("/root/tracing_on"))
- .WillOnce(Return('1'));
-
- // Unknown syscall is ignored.
- ASSERT_TRUE(model.SetupConfig(/*id = */ 73, config));
- ASSERT_THAT(model.GetSyscallFilterForTesting(), UnorderedElementsAre(0));
-}
-
-TEST_F(FtraceConfigMuxerTest, SyscallFilterMuxing) {
- auto fake_table = CreateFakeTable();
- NiceMock<MockFtraceProcfs> ftrace;
- FtraceConfigMuxer model(&ftrace, fake_table.get(), GetSyscallTable(), {});
-
- FtraceConfig empty_config = CreateFtraceConfig({});
-
- FtraceConfig syscall_config = empty_config;
- syscall_config.add_ftrace_events("raw_syscalls/sys_enter");
-
- FtraceConfig syscall_open_config = syscall_config;
- syscall_open_config.add_syscall_events("sys_open");
-
- FtraceConfig syscall_read_config = syscall_config;
- syscall_read_config.add_syscall_events("sys_read");
-
- ON_CALL(ftrace, ReadFileIntoString("/root/current_tracer"))
- .WillByDefault(Return("nop"));
-
- // Expect no filter for non-syscall config.
- ASSERT_TRUE(model.SetupConfig(/* id= */ 179239, empty_config));
- ASSERT_THAT(model.GetSyscallFilterForTesting(), UnorderedElementsAre());
-
- // Expect no filter for syscall config with no specified events.
- FtraceConfigId syscall_id = 73;
- ASSERT_TRUE(model.SetupConfig(syscall_id, syscall_config));
- ASSERT_THAT(model.GetSyscallFilterForTesting(), UnorderedElementsAre());
-
- // Still expect no filter to satisfy this and the above.
- FtraceConfigId syscall_open_id = 101;
- ASSERT_TRUE(model.SetupConfig(syscall_open_id, syscall_open_config));
- ASSERT_THAT(model.GetSyscallFilterForTesting(), UnorderedElementsAre());
-
- // After removing the generic syscall trace, only the one with filter is left.
- ASSERT_TRUE(model.RemoveConfig(syscall_id));
- ASSERT_THAT(model.GetSyscallFilterForTesting(), UnorderedElementsAre(0));
-
- // With sys_read and sys_open traced separately, filter includes both.
- FtraceConfigId syscall_read_id = 57;
- ASSERT_TRUE(model.SetupConfig(syscall_read_id, syscall_read_config));
- ASSERT_THAT(model.GetSyscallFilterForTesting(), UnorderedElementsAre(0, 1));
-
- // After removing configs with filters, filter is reset to empty.
- ASSERT_TRUE(model.RemoveConfig(syscall_open_id));
- ASSERT_TRUE(model.RemoveConfig(syscall_read_id));
- ASSERT_THAT(model.GetSyscallFilterForTesting(), UnorderedElementsAre());
-}
-
-TEST_F(FtraceConfigMuxerTest, AddGenericEvent) {
- auto mock_table = GetMockTable();
- MockFtraceProcfs ftrace;
-
- FtraceConfig config = CreateFtraceConfig({"power/cpu_frequency"});
-
- FtraceConfigMuxer model(&ftrace, mock_table.get(), GetSyscallTable(), {});
-
- EXPECT_CALL(ftrace, ReadFileIntoString("/root/current_tracer"))
- .WillOnce(Return("nop"));
- EXPECT_CALL(ftrace, ReadOneCharFromFile("/root/tracing_on"))
- .WillOnce(Return('1'));
- EXPECT_CALL(ftrace, WriteToFile("/root/tracing_on", "0"));
- EXPECT_CALL(ftrace, WriteToFile("/root/events/enable", "0"));
- EXPECT_CALL(ftrace, ClearFile("/root/trace"));
- EXPECT_CALL(ftrace, ClearFile(MatchesRegex("/root/per_cpu/cpu[0-9]/trace")));
- ON_CALL(ftrace, ReadFileIntoString("/root/trace_clock"))
- .WillByDefault(Return("[local] global boot"));
- EXPECT_CALL(ftrace, ReadFileIntoString("/root/trace_clock"))
- .Times(AnyNumber());
- EXPECT_CALL(ftrace, WriteToFile("/root/buffer_size_kb", _));
- EXPECT_CALL(ftrace, WriteToFile("/root/trace_clock", "boot"));
- EXPECT_CALL(ftrace,
- WriteToFile("/root/events/power/cpu_frequency/enable", "1"));
- EXPECT_CALL(*mock_table, GetEvent(GroupAndName("power", "cpu_frequency")))
- .Times(AnyNumber());
-
- static constexpr int kExpectedEventId = 77;
- Event event_to_return;
- event_to_return.name = "cpu_frequency";
- event_to_return.group = "power";
- event_to_return.ftrace_event_id = kExpectedEventId;
- ON_CALL(*mock_table, GetOrCreateEvent(GroupAndName("power", "cpu_frequency")))
- .WillByDefault(Return(&event_to_return));
- EXPECT_CALL(*mock_table,
- GetOrCreateEvent(GroupAndName("power", "cpu_frequency")));
-
- FtraceConfigId id = 7;
- ASSERT_TRUE(model.SetupConfig(id, config));
-
- EXPECT_CALL(ftrace, WriteToFile("/root/tracing_on", "1"));
- ASSERT_TRUE(model.ActivateConfig(id));
-
- const FtraceDataSourceConfig* ds_config = model.GetDataSourceConfig(id);
- ASSERT_TRUE(ds_config);
- ASSERT_THAT(ds_config->event_filter.GetEnabledEvents(),
- ElementsAreArray({kExpectedEventId}));
-
- const EventFilter* central_filter = model.GetCentralEventFilterForTesting();
- ASSERT_THAT(central_filter->GetEnabledEvents(),
- ElementsAreArray({kExpectedEventId}));
-}
-
-TEST_F(FtraceConfigMuxerTest, AddSameNameEvents) {
- auto mock_table = GetMockTable();
- NiceMock<MockFtraceProcfs> ftrace;
-
- FtraceConfig config = CreateFtraceConfig({"group_one/foo", "group_two/foo"});
-
- FtraceConfigMuxer model(&ftrace, mock_table.get(), GetSyscallTable(), {});
-
- static constexpr int kEventId1 = 1;
- Event event1;
- event1.name = "foo";
- event1.group = "group_one";
- event1.ftrace_event_id = kEventId1;
- ON_CALL(*mock_table, GetOrCreateEvent(GroupAndName("group_one", "foo")))
- .WillByDefault(Return(&event1));
- EXPECT_CALL(*mock_table, GetOrCreateEvent(GroupAndName("group_one", "foo")));
-
- static constexpr int kEventId2 = 2;
- Event event2;
- event2.name = "foo";
- event2.group = "group_two";
- event2.ftrace_event_id = kEventId2;
- ON_CALL(*mock_table, GetOrCreateEvent(GroupAndName("group_two", "foo")))
- .WillByDefault(Return(&event2));
- EXPECT_CALL(*mock_table, GetOrCreateEvent(GroupAndName("group_two", "foo")));
-
- ON_CALL(ftrace, ReadFileIntoString("/root/current_tracer"))
- .WillByDefault(Return("nop"));
- ON_CALL(ftrace, ReadFileIntoString("/root/events/enable"))
- .WillByDefault(Return("0"));
-
- FtraceConfigId id = 5;
- ASSERT_TRUE(model.SetupConfig(id, config));
- ASSERT_TRUE(model.ActivateConfig(id));
-
- const FtraceDataSourceConfig* ds_config = model.GetDataSourceConfig(id);
- ASSERT_THAT(ds_config->event_filter.GetEnabledEvents(),
- ElementsAreArray({kEventId1, kEventId2}));
-
- const EventFilter* central_filter = model.GetCentralEventFilterForTesting();
- ASSERT_THAT(central_filter->GetEnabledEvents(),
- ElementsAreArray({kEventId1, kEventId2}));
-}
-
-TEST_F(FtraceConfigMuxerTest, AddAllEvents) {
- auto mock_table = GetMockTable();
- MockFtraceProcfs ftrace;
-
- FtraceConfig config = CreateFtraceConfig({"sched/*"});
-
- EXPECT_CALL(ftrace, ReadFileIntoString("/root/current_tracer"))
- .WillOnce(Return("nop"));
- EXPECT_CALL(ftrace, ReadOneCharFromFile("/root/tracing_on"))
- .WillOnce(Return('1'));
- EXPECT_CALL(ftrace, WriteToFile("/root/tracing_on", "0"));
- EXPECT_CALL(ftrace, WriteToFile("/root/events/enable", "0"));
- EXPECT_CALL(ftrace, ClearFile("/root/trace"));
- EXPECT_CALL(ftrace, ClearFile(MatchesRegex("/root/per_cpu/cpu[0-9]/trace")));
- ON_CALL(ftrace, ReadFileIntoString("/root/trace_clock"))
- .WillByDefault(Return("[local] global boot"));
- EXPECT_CALL(ftrace, ReadFileIntoString("/root/trace_clock"))
- .Times(AnyNumber());
- EXPECT_CALL(ftrace, WriteToFile("/root/buffer_size_kb", _));
- EXPECT_CALL(ftrace, WriteToFile("/root/trace_clock", "boot"));
- EXPECT_CALL(ftrace,
- WriteToFile("/root/events/sched/sched_switch/enable", "1"));
- EXPECT_CALL(ftrace,
- WriteToFile("/root/events/sched/sched_new_event/enable", "1"));
-
- FtraceConfigMuxer model(&ftrace, mock_table.get(), GetSyscallTable(), {});
- std::set<std::string> n = {"sched_switch", "sched_new_event"};
- ON_CALL(ftrace, GetEventNamesForGroup("events/sched"))
- .WillByDefault(Return(n));
- EXPECT_CALL(ftrace, GetEventNamesForGroup("events/sched")).Times(1);
-
- // Non-generic event.
- static constexpr int kSchedSwitchEventId = 1;
- Event sched_switch = {"sched_switch", "sched", {}, 0, 0, 0};
- sched_switch.ftrace_event_id = kSchedSwitchEventId;
- ON_CALL(*mock_table, GetOrCreateEvent(GroupAndName("sched", "sched_switch")))
- .WillByDefault(Return(&sched_switch));
- EXPECT_CALL(*mock_table,
- GetOrCreateEvent(GroupAndName("sched", "sched_switch")))
- .Times(AnyNumber());
-
- // Generic event.
- static constexpr int kGenericEventId = 2;
- Event event_to_return;
- event_to_return.name = "sched_new_event";
- event_to_return.group = "sched";
- event_to_return.ftrace_event_id = kGenericEventId;
- ON_CALL(*mock_table,
- GetOrCreateEvent(GroupAndName("sched", "sched_new_event")))
- .WillByDefault(Return(&event_to_return));
- EXPECT_CALL(*mock_table,
- GetOrCreateEvent(GroupAndName("sched", "sched_new_event")));
-
- FtraceConfigId id = 13;
- ASSERT_TRUE(model.SetupConfig(id, config));
- ASSERT_TRUE(id);
-
- EXPECT_CALL(ftrace, WriteToFile("/root/tracing_on", "1"));
- ASSERT_TRUE(model.ActivateConfig(id));
-
- const FtraceDataSourceConfig* ds_config = model.GetDataSourceConfig(id);
- ASSERT_TRUE(ds_config);
- ASSERT_THAT(ds_config->event_filter.GetEnabledEvents(),
- ElementsAreArray({kSchedSwitchEventId, kGenericEventId}));
-
- const EventFilter* central_filter = model.GetCentralEventFilterForTesting();
- ASSERT_THAT(central_filter->GetEnabledEvents(),
- ElementsAreArray({kSchedSwitchEventId, kGenericEventId}));
-}
-
-TEST_F(FtraceConfigMuxerTest, TwoWildcardGroups) {
- auto mock_table = GetMockTable();
- NiceMock<MockFtraceProcfs> ftrace;
-
- FtraceConfig config = CreateFtraceConfig({"group_one/*", "group_two/*"});
-
- FtraceConfigMuxer model(&ftrace, mock_table.get(), GetSyscallTable(), {});
-
- std::set<std::string> event_names = {"foo"};
- ON_CALL(ftrace, GetEventNamesForGroup("events/group_one"))
- .WillByDefault(Return(event_names));
- EXPECT_CALL(ftrace, GetEventNamesForGroup("events/group_one"))
- .Times(AnyNumber());
-
- ON_CALL(ftrace, GetEventNamesForGroup("events/group_two"))
- .WillByDefault(Return(event_names));
- EXPECT_CALL(ftrace, GetEventNamesForGroup("events/group_two"))
- .Times(AnyNumber());
-
- static constexpr int kEventId1 = 1;
- Event event1;
- event1.name = "foo";
- event1.group = "group_one";
- event1.ftrace_event_id = kEventId1;
- ON_CALL(*mock_table, GetOrCreateEvent(GroupAndName("group_one", "foo")))
- .WillByDefault(Return(&event1));
- EXPECT_CALL(*mock_table, GetOrCreateEvent(GroupAndName("group_one", "foo")));
-
- static constexpr int kEventId2 = 2;
- Event event2;
- event2.name = "foo";
- event2.group = "group_two";
- event2.ftrace_event_id = kEventId2;
- ON_CALL(*mock_table, GetOrCreateEvent(GroupAndName("group_two", "foo")))
- .WillByDefault(Return(&event2));
- EXPECT_CALL(*mock_table, GetOrCreateEvent(GroupAndName("group_two", "foo")));
-
- ON_CALL(ftrace, ReadFileIntoString("/root/current_tracer"))
- .WillByDefault(Return("nop"));
- ON_CALL(ftrace, ReadFileIntoString("/root/events/enable"))
- .WillByDefault(Return("0"));
-
- FtraceConfigId id = 23;
- ASSERT_TRUE(model.SetupConfig(id, config));
- ASSERT_TRUE(model.ActivateConfig(id));
-
- const FtraceDataSourceConfig* ds_config = model.GetDataSourceConfig(id);
- ASSERT_TRUE(ds_config);
- ASSERT_THAT(ds_config->event_filter.GetEnabledEvents(),
- ElementsAreArray({kEventId1, kEventId2}));
-
- const EventFilter* central_filter = model.GetCentralEventFilterForTesting();
- ASSERT_THAT(central_filter->GetEnabledEvents(),
- ElementsAreArray({kEventId1, kEventId2}));
-}
-
-TEST_F(FtraceConfigMuxerTest, TurnFtraceOnOff) {
- MockFtraceProcfs ftrace;
-
- FtraceConfig config = CreateFtraceConfig({"sched_switch", "foo"});
-
- FtraceConfigMuxer model(&ftrace, table_.get(), GetSyscallTable(), {});
-
- EXPECT_CALL(ftrace, ReadFileIntoString("/root/current_tracer"))
- .WillOnce(Return("nop"));
- EXPECT_CALL(ftrace, ReadOneCharFromFile("/root/tracing_on"))
- .WillOnce(Return('1'));
- EXPECT_CALL(ftrace, WriteToFile("/root/tracing_on", "0"));
- EXPECT_CALL(ftrace, WriteToFile("/root/events/enable", "0"));
- EXPECT_CALL(ftrace, ClearFile("/root/trace"));
- EXPECT_CALL(ftrace, ClearFile(MatchesRegex("/root/per_cpu/cpu[0-9]/trace")));
- ON_CALL(ftrace, ReadFileIntoString("/root/trace_clock"))
- .WillByDefault(Return("[local] global boot"));
- EXPECT_CALL(ftrace, ReadFileIntoString("/root/trace_clock"))
- .Times(AnyNumber());
- EXPECT_CALL(ftrace, WriteToFile("/root/buffer_size_kb", _));
- EXPECT_CALL(ftrace, WriteToFile("/root/trace_clock", "boot"));
- EXPECT_CALL(ftrace,
- WriteToFile("/root/events/sched/sched_switch/enable", "1"));
-
- FtraceConfigId id = 97;
- ASSERT_TRUE(model.SetupConfig(id, config));
-
- EXPECT_CALL(ftrace, WriteToFile("/root/tracing_on", "1"));
- ASSERT_TRUE(model.ActivateConfig(id));
-
- const FtraceDataSourceConfig* ds_config = model.GetDataSourceConfig(id);
- ASSERT_TRUE(ds_config);
- ASSERT_THAT(ds_config->event_filter.GetEnabledEvents(),
- ElementsAreArray({kFakeSchedSwitchEventId}));
-
- const EventFilter* central_filter = model.GetCentralEventFilterForTesting();
- ASSERT_THAT(central_filter->GetEnabledEvents(),
- ElementsAreArray({kFakeSchedSwitchEventId}));
-
- ASSERT_TRUE(testing::Mock::VerifyAndClearExpectations(&ftrace));
- EXPECT_CALL(ftrace, NumberOfCpus()).Times(AnyNumber());
- EXPECT_CALL(ftrace, WriteToFile("/root/buffer_percent", _))
- .WillRepeatedly(Return(true));
-
- EXPECT_CALL(ftrace,
- WriteToFile("/root/events/sched/sched_switch/enable", "0"));
- EXPECT_CALL(ftrace, WriteToFile("/root/tracing_on", "0"));
- EXPECT_CALL(ftrace, WriteToFile("/root/buffer_size_kb", PageSizeKb()));
- EXPECT_CALL(ftrace, WriteToFile("/root/events/enable", "0"));
- EXPECT_CALL(ftrace, ClearFile("/root/trace"));
- EXPECT_CALL(ftrace, ClearFile(MatchesRegex("/root/per_cpu/cpu[0-9]/trace")));
- EXPECT_CALL(ftrace, WriteToFile("/root/tracing_on", "1"));
-
- ASSERT_TRUE(model.RemoveConfig(id));
-}
-
-TEST_F(FtraceConfigMuxerTest, FtraceIsAlreadyOn) {
- MockFtraceProcfs ftrace;
-
- FtraceConfig config = CreateFtraceConfig({"sched/sched_switch"});
-
- FtraceConfigMuxer model(&ftrace, table_.get(), GetSyscallTable(), {});
-
- // If someone is using ftrace already don't stomp on what they are doing.
- EXPECT_CALL(ftrace, ReadFileIntoString("/root/current_tracer"))
- .WillOnce(Return("function"));
- ASSERT_FALSE(model.SetupConfig(/* id= */ 123, config));
-}
-
-TEST_F(FtraceConfigMuxerTest, Atrace) {
- NiceMock<MockFtraceProcfs> ftrace;
- MockRunAtrace atrace;
+ FtraceConfigMuxer model(&ftrace_, &atrace_wrapper_, fake_table.get(),
+ GetSyscallTable(), {},
+ /* secondary_instance= */ true);
FtraceConfig config = CreateFtraceConfig({"sched/sched_switch"});
*config.add_atrace_categories() = "sched";
- FtraceConfigMuxer model(&ftrace, table_.get(), GetSyscallTable(), {});
-
- ON_CALL(ftrace, ReadFileIntoString("/root/current_tracer"))
- .WillByDefault(Return("nop"));
- ON_CALL(ftrace, ReadFileIntoString("/root/events/enable"))
- .WillByDefault(Return("0"));
- EXPECT_CALL(atrace, RunAtrace(ElementsAreArray({"atrace", "--async_start",
- "--only_userspace", "sched"}),
- _))
- .WillOnce(Return(true));
-
- FtraceConfigId id = 57;
- ASSERT_TRUE(model.SetupConfig(id, config));
-
- // "ftrace" group events are always enabled, and therefore the "print" event
- // will show up in the per data source event filter (as we want to record it),
- // but not the central filter (as we're not enabling/disabling it).
- const FtraceDataSourceConfig* ds_config = model.GetDataSourceConfig(id);
- ASSERT_TRUE(ds_config);
- EXPECT_THAT(ds_config->event_filter.GetEnabledEvents(),
- Contains(kFakeSchedSwitchEventId));
- EXPECT_THAT(ds_config->event_filter.GetEnabledEvents(),
- Contains(kFakePrintEventId));
-
- const EventFilter* central_filter = model.GetCentralEventFilterForTesting();
- EXPECT_THAT(central_filter->GetEnabledEvents(),
- Contains(kFakeSchedSwitchEventId));
-
- EXPECT_CALL(
- atrace,
- RunAtrace(
- ElementsAreArray({"atrace", "--async_stop", "--only_userspace"}), _))
- .WillOnce(Return(true));
- ASSERT_TRUE(model.RemoveConfig(id));
-}
-
-TEST_F(FtraceConfigMuxerTest, AtraceTwoApps) {
- NiceMock<MockFtraceProcfs> ftrace;
- MockRunAtrace atrace;
-
- FtraceConfig config = CreateFtraceConfig({});
- *config.add_atrace_apps() = "com.google.android.gms.persistent";
- *config.add_atrace_apps() = "com.google.android.gms";
-
- FtraceConfigMuxer model(&ftrace, table_.get(), GetSyscallTable(), {});
-
- ON_CALL(ftrace, ReadFileIntoString("/root/current_tracer"))
- .WillByDefault(Return("nop"));
- ON_CALL(ftrace, ReadFileIntoString("/root/events/enable"))
- .WillByDefault(Return("0"));
- EXPECT_CALL(
- atrace,
- RunAtrace(
- ElementsAreArray(
- {"atrace", "--async_start", "--only_userspace", "-a",
- "com.google.android.gms,com.google.android.gms.persistent"}),
- _))
- .WillOnce(Return(true));
-
- FtraceConfigId id = 97;
- ASSERT_TRUE(model.SetupConfig(id, config));
-
- const FtraceDataSourceConfig* ds_config = model.GetDataSourceConfig(id);
- ASSERT_TRUE(ds_config);
- ASSERT_THAT(ds_config->event_filter.GetEnabledEvents(),
- Contains(kFakePrintEventId));
-
- EXPECT_CALL(
- atrace,
- RunAtrace(
- ElementsAreArray({"atrace", "--async_stop", "--only_userspace"}), _))
- .WillOnce(Return(true));
- ASSERT_TRUE(model.RemoveConfig(id));
-}
-
-TEST_F(FtraceConfigMuxerTest, AtraceMultipleConfigs) {
- NiceMock<MockFtraceProcfs> ftrace;
- MockRunAtrace atrace;
-
- FtraceConfig config_a = CreateFtraceConfig({});
- *config_a.add_atrace_apps() = "app_a";
- *config_a.add_atrace_categories() = "cat_a";
-
- FtraceConfig config_b = CreateFtraceConfig({});
- *config_b.add_atrace_apps() = "app_b";
- *config_b.add_atrace_categories() = "cat_b";
-
- FtraceConfig config_c = CreateFtraceConfig({});
- *config_c.add_atrace_apps() = "app_c";
- *config_c.add_atrace_categories() = "cat_c";
-
- FtraceConfigMuxer model(&ftrace, table_.get(), GetSyscallTable(), {});
-
- ON_CALL(ftrace, ReadFileIntoString("/root/current_tracer"))
- .WillByDefault(Return("nop"));
- ON_CALL(ftrace, ReadFileIntoString("/root/events/enable"))
- .WillByDefault(Return("0"));
- EXPECT_CALL(atrace, RunAtrace(ElementsAreArray({"atrace", "--async_start",
- "--only_userspace", "cat_a",
- "-a", "app_a"}),
- _))
- .WillOnce(Return(true));
- FtraceConfigId id_a = 3;
- ASSERT_TRUE(model.SetupConfig(id_a, config_a));
-
- EXPECT_CALL(
- atrace,
- RunAtrace(ElementsAreArray({"atrace", "--async_start", "--only_userspace",
- "cat_a", "cat_b", "-a", "app_a,app_b"}),
- _))
- .WillOnce(Return(true));
- FtraceConfigId id_b = 13;
- ASSERT_TRUE(model.SetupConfig(id_b, config_b));
-
- EXPECT_CALL(atrace,
- RunAtrace(ElementsAreArray({"atrace", "--async_start",
- "--only_userspace", "cat_a", "cat_b",
- "cat_c", "-a", "app_a,app_b,app_c"}),
- _))
- .WillOnce(Return(true));
- FtraceConfigId id_c = 23;
- ASSERT_TRUE(model.SetupConfig(id_c, config_c));
-
- EXPECT_CALL(
- atrace,
- RunAtrace(ElementsAreArray({"atrace", "--async_start", "--only_userspace",
- "cat_a", "cat_c", "-a", "app_a,app_c"}),
- _))
- .WillOnce(Return(true));
- ASSERT_TRUE(model.RemoveConfig(id_b));
-
- EXPECT_CALL(atrace, RunAtrace(ElementsAreArray({"atrace", "--async_start",
- "--only_userspace", "cat_c",
- "-a", "app_c"}),
- _))
- .WillOnce(Return(true));
- ASSERT_TRUE(model.RemoveConfig(id_a));
-
- EXPECT_CALL(
- atrace,
- RunAtrace(
- ElementsAreArray({"atrace", "--async_stop", "--only_userspace"}), _))
- .WillOnce(Return(true));
- ASSERT_TRUE(model.RemoveConfig(id_c));
-}
-
-TEST_F(FtraceConfigMuxerTest, AtraceFailedConfig) {
- NiceMock<MockFtraceProcfs> ftrace;
- MockRunAtrace atrace;
-
- FtraceConfig config_a = CreateFtraceConfig({});
- *config_a.add_atrace_apps() = "app_1";
- *config_a.add_atrace_apps() = "app_2";
- *config_a.add_atrace_categories() = "cat_1";
- *config_a.add_atrace_categories() = "cat_2";
-
- FtraceConfig config_b = CreateFtraceConfig({});
- *config_b.add_atrace_apps() = "app_fail";
- *config_b.add_atrace_categories() = "cat_fail";
-
- FtraceConfig config_c = CreateFtraceConfig({});
- *config_c.add_atrace_apps() = "app_1";
- *config_c.add_atrace_apps() = "app_3";
- *config_c.add_atrace_categories() = "cat_1";
- *config_c.add_atrace_categories() = "cat_3";
-
- FtraceConfigMuxer model(&ftrace, table_.get(), GetSyscallTable(), {});
-
- ON_CALL(ftrace, ReadFileIntoString("/root/current_tracer"))
- .WillByDefault(Return("nop"));
- ON_CALL(ftrace, ReadFileIntoString("/root/events/enable"))
- .WillByDefault(Return("0"));
- EXPECT_CALL(
- atrace,
- RunAtrace(ElementsAreArray({"atrace", "--async_start", "--only_userspace",
- "cat_1", "cat_2", "-a", "app_1,app_2"}),
- _))
- .WillOnce(Return(true));
- FtraceConfigId id_a = 7;
- ASSERT_TRUE(model.SetupConfig(id_a, config_a));
-
- EXPECT_CALL(atrace, RunAtrace(ElementsAreArray({"atrace", "--async_start",
- "--only_userspace", "cat_1",
- "cat_2", "cat_fail", "-a",
- "app_1,app_2,app_fail"}),
- _))
- .WillOnce(Return(false));
- FtraceConfigId id_b = 17;
- ASSERT_TRUE(model.SetupConfig(id_b, config_b));
-
- EXPECT_CALL(atrace,
- RunAtrace(ElementsAreArray({"atrace", "--async_start",
- "--only_userspace", "cat_1", "cat_2",
- "cat_3", "-a", "app_1,app_2,app_3"}),
- _))
- .WillOnce(Return(true));
- FtraceConfigId id_c = 47;
- ASSERT_TRUE(model.SetupConfig(id_c, config_c));
-
- EXPECT_CALL(
- atrace,
- RunAtrace(ElementsAreArray({"atrace", "--async_start", "--only_userspace",
- "cat_1", "cat_2", "-a", "app_1,app_2"}),
- _))
- .WillOnce(Return(true));
- ASSERT_TRUE(model.RemoveConfig(id_c));
-
- // Removing the config we failed to enable doesn't change the atrace state
- // so we don't expect a call here.
- ASSERT_TRUE(model.RemoveConfig(id_b));
-
- EXPECT_CALL(
- atrace,
- RunAtrace(
- ElementsAreArray({"atrace", "--async_stop", "--only_userspace"}), _))
- .WillOnce(Return(true));
- ASSERT_TRUE(model.RemoveConfig(id_a));
-}
-
-TEST_F(FtraceConfigMuxerTest, AtraceDuplicateConfigs) {
- NiceMock<MockFtraceProcfs> ftrace;
- MockRunAtrace atrace;
-
- FtraceConfig config_a = CreateFtraceConfig({});
- *config_a.add_atrace_apps() = "app_1";
- *config_a.add_atrace_categories() = "cat_1";
-
- FtraceConfig config_b = CreateFtraceConfig({});
- *config_b.add_atrace_apps() = "app_1";
- *config_b.add_atrace_categories() = "cat_1";
-
- FtraceConfigMuxer model(&ftrace, table_.get(), GetSyscallTable(), {});
-
- ON_CALL(ftrace, ReadFileIntoString("/root/current_tracer"))
- .WillByDefault(Return("nop"));
- ON_CALL(ftrace, ReadFileIntoString("/root/events/enable"))
- .WillByDefault(Return("0"));
- EXPECT_CALL(atrace, RunAtrace(ElementsAreArray({"atrace", "--async_start",
- "--only_userspace", "cat_1",
- "-a", "app_1"}),
- _))
- .WillOnce(Return(true));
- FtraceConfigId id_a = 19;
- ASSERT_TRUE(model.SetupConfig(id_a, config_a));
-
- FtraceConfigId id_b = 29;
- ASSERT_TRUE(model.SetupConfig(id_b, config_b));
-
- ASSERT_TRUE(model.RemoveConfig(id_a));
-
- EXPECT_CALL(
- atrace,
- RunAtrace(
- ElementsAreArray({"atrace", "--async_stop", "--only_userspace"}), _))
- .WillOnce(Return(true));
- ASSERT_TRUE(model.RemoveConfig(id_b));
-}
-
-TEST_F(FtraceConfigMuxerTest, AtraceAndFtraceConfigs) {
- NiceMock<MockFtraceProcfs> ftrace;
- MockRunAtrace atrace;
-
- FtraceConfig config_a = CreateFtraceConfig({"sched/sched_cpu_hotplug"});
-
- FtraceConfig config_b = CreateFtraceConfig({"sched/sched_switch"});
- *config_b.add_atrace_categories() = "b";
-
- FtraceConfig config_c = CreateFtraceConfig({"sched/sched_switch"});
-
- FtraceConfig config_d = CreateFtraceConfig({"sched/sched_cpu_hotplug"});
- *config_d.add_atrace_categories() = "d";
-
- FtraceConfigMuxer model(&ftrace, table_.get(), GetSyscallTable(), {});
-
- ON_CALL(ftrace, ReadFileIntoString("/root/current_tracer"))
- .WillByDefault(Return("nop"));
- ON_CALL(ftrace, ReadFileIntoString("/root/events/enable"))
- .WillByDefault(Return("0"));
- FtraceConfigId id_a = 179;
- ASSERT_TRUE(model.SetupConfig(id_a, config_a));
-
- EXPECT_CALL(atrace, RunAtrace(ElementsAreArray({"atrace", "--async_start",
- "--only_userspace", "b"}),
- _))
- .WillOnce(Return(true));
- FtraceConfigId id_b = 239;
- ASSERT_TRUE(model.SetupConfig(id_b, config_b));
-
- FtraceConfigId id_c = 101;
- ASSERT_TRUE(model.SetupConfig(id_c, config_c));
-
- EXPECT_CALL(atrace,
- RunAtrace(ElementsAreArray({"atrace", "--async_start",
- "--only_userspace", "b", "d"}),
- _))
- .WillOnce(Return(true));
- FtraceConfigId id_d = 47;
- ASSERT_TRUE(model.SetupConfig(id_d, config_d));
-
- EXPECT_CALL(atrace, RunAtrace(ElementsAreArray({"atrace", "--async_start",
- "--only_userspace", "b"}),
- _))
- .WillOnce(Return(true));
- ASSERT_TRUE(model.RemoveConfig(id_d));
-
- ASSERT_TRUE(model.RemoveConfig(id_c));
-
- EXPECT_CALL(
- atrace,
- RunAtrace(
- ElementsAreArray({"atrace", "--async_stop", "--only_userspace"}), _))
- .WillOnce(Return(true));
- ASSERT_TRUE(model.RemoveConfig(id_b));
-
- ASSERT_TRUE(model.RemoveConfig(id_a));
-}
-
-TEST_F(FtraceConfigMuxerTest, AtraceErrorsPropagated) {
- NiceMock<MockFtraceProcfs> ftrace;
- MockRunAtrace atrace;
-
- FtraceConfig config = CreateFtraceConfig({});
- *config.add_atrace_categories() = "cat_1";
- *config.add_atrace_categories() = "cat_2";
-
- ON_CALL(ftrace, ReadFileIntoString("/root/current_tracer"))
- .WillByDefault(Return("nop"));
- ON_CALL(ftrace, ReadFileIntoString("/root/events/enable"))
- .WillByDefault(Return("0"));
-
- FtraceConfigMuxer model(&ftrace, table_.get(), GetSyscallTable(), {});
-
- EXPECT_CALL(atrace, RunAtrace(ElementsAreArray({"atrace", "--async_start",
- "--only_userspace", "cat_1",
- "cat_2"}),
- _))
- .WillOnce(Invoke([](const std::vector<std::string>&, std::string* err) {
- EXPECT_NE(err, nullptr);
- if (err)
- err->append("foo\nbar\n");
- return true;
- }));
-
- FtraceSetupErrors errors{};
- FtraceConfigId id_a = 23;
- ASSERT_TRUE(model.SetupConfig(id_a, config, &errors));
- EXPECT_EQ(errors.atrace_errors, "foo\nbar\n");
-}
-
-TEST_F(FtraceConfigMuxerTest, SetupClockForTesting) {
- MockFtraceProcfs ftrace;
- FtraceConfig config;
-
- FtraceConfigMuxer model(&ftrace, table_.get(), GetSyscallTable(), {});
- namespace pb0 = protos::pbzero;
-
- EXPECT_CALL(ftrace, ReadFileIntoString("/root/trace_clock"))
- .Times(AnyNumber());
-
- ON_CALL(ftrace, ReadFileIntoString("/root/trace_clock"))
- .WillByDefault(Return("[local] global boot"));
- EXPECT_CALL(ftrace, WriteToFile("/root/trace_clock", "boot"));
- model.SetupClockForTesting(config);
- // unspecified = boot.
- EXPECT_EQ(model.ftrace_clock(),
- static_cast<int>(pb0::FTRACE_CLOCK_UNSPECIFIED));
-
- ON_CALL(ftrace, ReadFileIntoString("/root/trace_clock"))
- .WillByDefault(Return("[local] global"));
- EXPECT_CALL(ftrace, WriteToFile("/root/trace_clock", "global"));
- model.SetupClockForTesting(config);
- EXPECT_EQ(model.ftrace_clock(), static_cast<int>(pb0::FTRACE_CLOCK_GLOBAL));
-
- ON_CALL(ftrace, ReadFileIntoString("/root/trace_clock"))
- .WillByDefault(Return(""));
- model.SetupClockForTesting(config);
- EXPECT_EQ(model.ftrace_clock(), static_cast<int>(pb0::FTRACE_CLOCK_UNKNOWN));
-
- ON_CALL(ftrace, ReadFileIntoString("/root/trace_clock"))
- .WillByDefault(Return("local [global]"));
- model.SetupClockForTesting(config);
- EXPECT_EQ(model.ftrace_clock(), static_cast<int>(pb0::FTRACE_CLOCK_GLOBAL));
-}
-
-TEST_F(FtraceConfigMuxerTest, GetFtraceEvents) {
- MockFtraceProcfs ftrace;
- FtraceConfigMuxer model(&ftrace, table_.get(), GetSyscallTable(), {});
-
- FtraceConfig config = CreateFtraceConfig({"sched/sched_switch"});
- std::set<GroupAndName> events =
- model.GetFtraceEventsForTesting(config, table_.get());
-
- EXPECT_THAT(events, Contains(GroupAndName("sched", "sched_switch")));
- EXPECT_THAT(events, Not(Contains(GroupAndName("ftrace", "print"))));
-}
-
-TEST_F(FtraceConfigMuxerTest, GetFtraceEventsAtrace) {
- MockFtraceProcfs ftrace;
- FtraceConfigMuxer model(&ftrace, table_.get(), GetSyscallTable(), {});
-
- FtraceConfig config = CreateFtraceConfig({});
- *config.add_atrace_categories() = "sched";
- std::set<GroupAndName> events =
- model.GetFtraceEventsForTesting(config, table_.get());
-
- EXPECT_THAT(events, Contains(GroupAndName("sched", "sched_switch")));
- EXPECT_THAT(events, Contains(GroupAndName("sched", "sched_cpu_hotplug")));
- EXPECT_THAT(events, Contains(GroupAndName("ftrace", "print")));
-}
-
-TEST_F(FtraceConfigMuxerTest, GetFtraceEventsAtraceCategories) {
- MockFtraceProcfs ftrace;
- FtraceConfigMuxer model(&ftrace, table_.get(), GetSyscallTable(), {});
-
- FtraceConfig config = CreateFtraceConfig({});
- *config.add_atrace_categories() = "sched";
- *config.add_atrace_categories() = "memreclaim";
- std::set<GroupAndName> events =
- model.GetFtraceEventsForTesting(config, table_.get());
-
- EXPECT_THAT(events, Contains(GroupAndName("sched", "sched_switch")));
- EXPECT_THAT(events, Contains(GroupAndName("sched", "sched_cpu_hotplug")));
- EXPECT_THAT(events, Contains(GroupAndName("cgroup", "cgroup_mkdir")));
- EXPECT_THAT(events, Contains(GroupAndName("vmscan",
- "mm_vmscan_direct_reclaim_begin")));
- EXPECT_THAT(events,
- Contains(GroupAndName("lowmemorykiller", "lowmemory_kill")));
- EXPECT_THAT(events, Contains(GroupAndName("ftrace", "print")));
-}
-
-// Tests the enabling fallback logic that tries to use the "set_event" interface
-// if writing the individual xxx/enable file fails.
-TEST_F(FtraceConfigMuxerTest, FallbackOnSetEvent) {
- MockFtraceProcfs ftrace;
- FtraceConfig config =
- CreateFtraceConfig({"sched/sched_switch", "cgroup/cgroup_mkdir"});
- FtraceConfigMuxer model(&ftrace, table_.get(), GetSyscallTable(), {});
- EXPECT_CALL(ftrace, WriteToFile("/root/buffer_percent", _))
- .WillRepeatedly(Return(true));
-
- EXPECT_CALL(ftrace, ReadFileIntoString("/root/current_tracer"))
- .WillOnce(Return("nop"));
- EXPECT_CALL(ftrace, ReadOneCharFromFile("/root/tracing_on"))
- .WillOnce(Return('1'));
- EXPECT_CALL(ftrace, WriteToFile("/root/tracing_on", "0"));
- EXPECT_CALL(ftrace, WriteToFile("/root/events/enable", "0"));
- EXPECT_CALL(ftrace, ClearFile("/root/trace"));
- EXPECT_CALL(ftrace, ClearFile(MatchesRegex("/root/per_cpu/cpu[0-9]/trace")));
- ON_CALL(ftrace, ReadFileIntoString("/root/trace_clock"))
- .WillByDefault(Return("[local] global boot"));
- EXPECT_CALL(ftrace, ReadFileIntoString("/root/trace_clock"))
- .Times(AnyNumber());
- EXPECT_CALL(ftrace, WriteToFile("/root/buffer_size_kb", _));
- EXPECT_CALL(ftrace, WriteToFile("/root/trace_clock", "boot"));
- EXPECT_CALL(ftrace,
- WriteToFile("/root/events/sched/sched_switch/enable", "1"));
- EXPECT_CALL(ftrace,
- WriteToFile("/root/events/cgroup/cgroup_mkdir/enable", "1"))
- .WillOnce(Return(false));
- EXPECT_CALL(ftrace, AppendToFile("/root/set_event", "cgroup:cgroup_mkdir"))
- .WillOnce(Return(true));
- FtraceConfigId id = 97;
- ASSERT_TRUE(model.SetupConfig(id, config));
-
- EXPECT_CALL(ftrace, WriteToFile("/root/tracing_on", "1"));
- ASSERT_TRUE(model.ActivateConfig(id));
-
- const FtraceDataSourceConfig* ds_config = model.GetDataSourceConfig(id);
- ASSERT_TRUE(ds_config);
- EXPECT_THAT(ds_config->event_filter.GetEnabledEvents(),
- Contains(kFakeSchedSwitchEventId));
- EXPECT_THAT(ds_config->event_filter.GetEnabledEvents(),
- Contains(kCgroupMkdirEventId));
-
- const EventFilter* central_filter = model.GetCentralEventFilterForTesting();
- EXPECT_THAT(central_filter->GetEnabledEvents(),
- Contains(kFakeSchedSwitchEventId));
- EXPECT_THAT(central_filter->GetEnabledEvents(),
- Contains(kCgroupMkdirEventId));
-
- EXPECT_CALL(ftrace,
- WriteToFile("/root/events/sched/sched_switch/enable", "0"));
- EXPECT_CALL(ftrace,
- WriteToFile("/root/events/cgroup/cgroup_mkdir/enable", "0"))
- .WillOnce(Return(false));
- EXPECT_CALL(ftrace, AppendToFile("/root/set_event", "!cgroup:cgroup_mkdir"))
- .WillOnce(Return(true));
- EXPECT_CALL(ftrace, WriteToFile("/root/tracing_on", "0"));
- EXPECT_CALL(ftrace, WriteToFile("/root/buffer_size_kb", PageSizeKb()));
- EXPECT_CALL(ftrace, WriteToFile("/root/events/enable", "0"));
- EXPECT_CALL(ftrace, ClearFile("/root/trace"));
- EXPECT_CALL(ftrace, ClearFile(MatchesRegex("/root/per_cpu/cpu[0-9]/trace")));
- EXPECT_CALL(ftrace, WriteToFile("/root/tracing_on", "1"));
- ASSERT_TRUE(model.RemoveConfig(id));
+ ASSERT_FALSE(model.SetupConfig(/* id= */ 73, config));
}
TEST_F(FtraceConfigMuxerTest, CompactSchedConfig) {
@@ -1185,13 +289,14 @@
auto valid_compact_format = CompactSchedEventFormat{
/*format_valid=*/true, format_with_id, CompactSchedWakingFormat{}};
- NiceMock<MockFtraceProcfs> ftrace;
- table_ = CreateFakeTable(valid_compact_format);
- FtraceConfigMuxer muxer(&ftrace, table_.get(), GetSyscallTable(), {});
+ std::unique_ptr<ProtoTranslationTable> table =
+ CreateFakeTable(valid_compact_format);
+ FtraceConfigMuxer muxer(&ftrace_, &atrace_wrapper_, table.get(),
+ GetSyscallTable(), {});
- ON_CALL(ftrace, ReadFileIntoString("/root/current_tracer"))
+ ON_CALL(ftrace_, ReadFileIntoString("/root/current_tracer"))
.WillByDefault(Return("nop"));
- ON_CALL(ftrace, ReadFileIntoString("/root/events/enable"))
+ ON_CALL(ftrace_, ReadFileIntoString("/root/events/enable"))
.WillByDefault(Return("0"));
{
@@ -1246,38 +351,659 @@
}
}
-TEST_F(FtraceConfigMuxerTest, CompactSchedConfigWithInvalidFormat) {
- NiceMock<MockFtraceProcfs> ftrace;
- FtraceConfigMuxer model(&ftrace, table_.get(), GetSyscallTable(), {});
+// Fixture that constructs a FtraceConfigMuxer with a fake
+// ProtoTranslationTable.
+class FtraceConfigMuxerFakeTableTest : public FtraceConfigMuxerTest {
+ protected:
+ std::unique_ptr<ProtoTranslationTable> table_ = CreateFakeTable();
+ FtraceConfigMuxer model_ = FtraceConfigMuxer(&ftrace_,
+ &atrace_wrapper_,
+ table_.get(),
+ GetSyscallTable(),
+ {});
+};
+TEST_F(FtraceConfigMuxerFakeTableTest, GenericSyscallFiltering) {
+ FtraceConfig config = CreateFtraceConfig({"raw_syscalls/sys_enter"});
+ *config.add_syscall_events() = "sys_open";
+ *config.add_syscall_events() = "sys_read";
+
+ ON_CALL(ftrace_, ReadFileIntoString("/root/trace_clock"))
+ .WillByDefault(Return("[local] global boot"));
+ EXPECT_CALL(ftrace_, ReadFileIntoString("/root/trace_clock"))
+ .Times(AnyNumber());
+ EXPECT_CALL(ftrace_, ReadFileIntoString("/root/current_tracer"))
+ .WillOnce(Return("nop"));
+ EXPECT_CALL(ftrace_, ReadOneCharFromFile("/root/tracing_on"))
+ .WillOnce(Return('1'));
+ EXPECT_CALL(ftrace_, WriteToFile(_, _)).WillRepeatedly(Return(true));
+ EXPECT_CALL(ftrace_, WriteToFile("/root/events/raw_syscalls/sys_enter/filter",
+ "id == 0 || id == 1"));
+ EXPECT_CALL(ftrace_, WriteToFile("/root/events/raw_syscalls/sys_exit/filter",
+ "id == 0 || id == 1"));
+
+ FtraceConfigId id = 37;
+ ASSERT_TRUE(model_.SetupConfig(id, config));
+ ASSERT_TRUE(model_.ActivateConfig(id));
+
+ const std::set<size_t>& filter = model_.GetSyscallFilterForTesting();
+ ASSERT_THAT(filter, UnorderedElementsAre(0, 1));
+}
+
+TEST_F(FtraceConfigMuxerFakeTableTest, UnknownSyscallFilter) {
+ FtraceConfig config = CreateFtraceConfig({"raw_syscalls/sys_enter"});
+ config.add_syscall_events("sys_open");
+ config.add_syscall_events("sys_not_a_call");
+
+ ON_CALL(ftrace_, ReadFileIntoString("/root/trace_clock"))
+ .WillByDefault(Return("[local] global boot"));
+ EXPECT_CALL(ftrace_, ReadFileIntoString("/root/trace_clock"))
+ .Times(AnyNumber());
+ EXPECT_CALL(ftrace_, ReadFileIntoString("/root/current_tracer"))
+ .WillOnce(Return("nop"));
+ EXPECT_CALL(ftrace_, ReadOneCharFromFile("/root/tracing_on"))
+ .WillOnce(Return('1'));
+
+ // Unknown syscall is ignored.
+ ASSERT_TRUE(model_.SetupConfig(/*id = */ 73, config));
+ ASSERT_THAT(model_.GetSyscallFilterForTesting(), UnorderedElementsAre(0));
+}
+
+TEST_F(FtraceConfigMuxerFakeTableTest, SyscallFilterMuxing) {
+ FtraceConfig empty_config = CreateFtraceConfig({});
+
+ FtraceConfig syscall_config = empty_config;
+ syscall_config.add_ftrace_events("raw_syscalls/sys_enter");
+
+ FtraceConfig syscall_open_config = syscall_config;
+ syscall_open_config.add_syscall_events("sys_open");
+
+ FtraceConfig syscall_read_config = syscall_config;
+ syscall_read_config.add_syscall_events("sys_read");
+
+ ON_CALL(ftrace_, ReadFileIntoString("/root/current_tracer"))
+ .WillByDefault(Return("nop"));
+
+ // Expect no filter for non-syscall config.
+ ASSERT_TRUE(model_.SetupConfig(/* id= */ 179239, empty_config));
+ ASSERT_THAT(model_.GetSyscallFilterForTesting(), UnorderedElementsAre());
+
+ // Expect no filter for syscall config with no specified events.
+ FtraceConfigId syscall_id = 73;
+ ASSERT_TRUE(model_.SetupConfig(syscall_id, syscall_config));
+ ASSERT_THAT(model_.GetSyscallFilterForTesting(), UnorderedElementsAre());
+
+ // Still expect no filter to satisfy this and the above.
+ FtraceConfigId syscall_open_id = 101;
+ ASSERT_TRUE(model_.SetupConfig(syscall_open_id, syscall_open_config));
+ ASSERT_THAT(model_.GetSyscallFilterForTesting(), UnorderedElementsAre());
+
+ // After removing the generic syscall trace, only the one with filter is left.
+ ASSERT_TRUE(model_.RemoveConfig(syscall_id));
+ ASSERT_THAT(model_.GetSyscallFilterForTesting(), UnorderedElementsAre(0));
+
+ // With sys_read and sys_open traced separately, filter includes both.
+ FtraceConfigId syscall_read_id = 57;
+ ASSERT_TRUE(model_.SetupConfig(syscall_read_id, syscall_read_config));
+ ASSERT_THAT(model_.GetSyscallFilterForTesting(), UnorderedElementsAre(0, 1));
+
+ // After removing configs with filters, filter is reset to empty.
+ ASSERT_TRUE(model_.RemoveConfig(syscall_open_id));
+ ASSERT_TRUE(model_.RemoveConfig(syscall_read_id));
+ ASSERT_THAT(model_.GetSyscallFilterForTesting(), UnorderedElementsAre());
+}
+
+TEST_F(FtraceConfigMuxerFakeTableTest, TurnFtraceOnOff) {
+ FtraceConfig config = CreateFtraceConfig({"sched_switch", "foo"});
+
+ EXPECT_CALL(ftrace_, ReadFileIntoString("/root/current_tracer"))
+ .WillOnce(Return("nop"));
+ EXPECT_CALL(ftrace_, ReadOneCharFromFile("/root/tracing_on"))
+ .WillOnce(Return('1'));
+ EXPECT_CALL(ftrace_, WriteToFile("/root/tracing_on", "0"));
+ EXPECT_CALL(ftrace_, WriteToFile("/root/events/enable", "0"));
+ EXPECT_CALL(ftrace_, ClearFile("/root/trace"));
+ EXPECT_CALL(ftrace_, ClearFile(MatchesRegex("/root/per_cpu/cpu[0-9]/trace")));
+ ON_CALL(ftrace_, ReadFileIntoString("/root/trace_clock"))
+ .WillByDefault(Return("[local] global boot"));
+ EXPECT_CALL(ftrace_, ReadFileIntoString("/root/trace_clock"))
+ .Times(AnyNumber());
+ EXPECT_CALL(ftrace_, WriteToFile("/root/buffer_size_kb", _));
+ EXPECT_CALL(ftrace_, WriteToFile("/root/trace_clock", "boot"));
+ EXPECT_CALL(ftrace_,
+ WriteToFile("/root/events/sched/sched_switch/enable", "1"));
+
+ FtraceConfigId id = 97;
+ ASSERT_TRUE(model_.SetupConfig(id, config));
+
+ EXPECT_CALL(ftrace_, WriteToFile("/root/tracing_on", "1"));
+ ASSERT_TRUE(model_.ActivateConfig(id));
+
+ const FtraceDataSourceConfig* ds_config = model_.GetDataSourceConfig(id);
+ ASSERT_TRUE(ds_config);
+ ASSERT_THAT(ds_config->event_filter.GetEnabledEvents(),
+ ElementsAreArray({kFakeSchedSwitchEventId}));
+
+ const EventFilter* central_filter = model_.GetCentralEventFilterForTesting();
+ ASSERT_THAT(central_filter->GetEnabledEvents(),
+ ElementsAreArray({kFakeSchedSwitchEventId}));
+
+ ASSERT_TRUE(testing::Mock::VerifyAndClearExpectations(&ftrace_));
+ EXPECT_CALL(ftrace_, NumberOfCpus()).Times(AnyNumber());
+ EXPECT_CALL(ftrace_, WriteToFile("/root/buffer_percent", _))
+ .WillRepeatedly(Return(true));
+
+ EXPECT_CALL(ftrace_,
+ WriteToFile("/root/events/sched/sched_switch/enable", "0"));
+ EXPECT_CALL(ftrace_, WriteToFile("/root/tracing_on", "0"));
+ EXPECT_CALL(ftrace_, WriteToFile("/root/buffer_size_kb", PageSizeKb()));
+ EXPECT_CALL(ftrace_, WriteToFile("/root/events/enable", "0"));
+ EXPECT_CALL(ftrace_, ClearFile("/root/trace"));
+ EXPECT_CALL(ftrace_, ClearFile(MatchesRegex("/root/per_cpu/cpu[0-9]/trace")));
+ EXPECT_CALL(ftrace_, WriteToFile("/root/tracing_on", "1"));
+
+ ASSERT_TRUE(model_.RemoveConfig(id));
+}
+
+TEST_F(FtraceConfigMuxerFakeTableTest, FtraceIsAlreadyOn) {
+ FtraceConfig config = CreateFtraceConfig({"sched/sched_switch"});
+
+ // If someone is using ftrace already don't stomp on what they are doing.
+ EXPECT_CALL(ftrace_, ReadFileIntoString("/root/current_tracer"))
+ .WillOnce(Return("function"));
+ ASSERT_FALSE(model_.SetupConfig(/* id= */ 123, config));
+}
+
+TEST_F(FtraceConfigMuxerFakeTableTest, Atrace) {
+ FtraceConfig config = CreateFtraceConfig({"sched/sched_switch"});
+ *config.add_atrace_categories() = "sched";
+
+ ON_CALL(ftrace_, ReadFileIntoString("/root/current_tracer"))
+ .WillByDefault(Return("nop"));
+ ON_CALL(ftrace_, ReadFileIntoString("/root/events/enable"))
+ .WillByDefault(Return("0"));
+ EXPECT_CALL(atrace_wrapper_,
+ RunAtrace(ElementsAreArray({"atrace", "--async_start",
+ "--only_userspace", "sched"}),
+ _))
+ .WillOnce(Return(true));
+
+ FtraceConfigId id = 57;
+ ASSERT_TRUE(model_.SetupConfig(id, config));
+
+ // "ftrace" group events are always enabled, and therefore the "print" event
+ // will show up in the per data source event filter (as we want to record it),
+ // but not the central filter (as we're not enabling/disabling it).
+ const FtraceDataSourceConfig* ds_config = model_.GetDataSourceConfig(id);
+ ASSERT_TRUE(ds_config);
+ EXPECT_THAT(ds_config->event_filter.GetEnabledEvents(),
+ Contains(kFakeSchedSwitchEventId));
+ EXPECT_THAT(ds_config->event_filter.GetEnabledEvents(),
+ Contains(kFakePrintEventId));
+
+ const EventFilter* central_filter = model_.GetCentralEventFilterForTesting();
+ EXPECT_THAT(central_filter->GetEnabledEvents(),
+ Contains(kFakeSchedSwitchEventId));
+
+ EXPECT_CALL(
+ atrace_wrapper_,
+ RunAtrace(
+ ElementsAreArray({"atrace", "--async_stop", "--only_userspace"}), _))
+ .WillOnce(Return(true));
+ ASSERT_TRUE(model_.RemoveConfig(id));
+}
+
+TEST_F(FtraceConfigMuxerFakeTableTest, AtraceTwoApps) {
+ FtraceConfig config = CreateFtraceConfig({});
+ *config.add_atrace_apps() = "com.google.android.gms.persistent";
+ *config.add_atrace_apps() = "com.google.android.gms";
+
+ ON_CALL(ftrace_, ReadFileIntoString("/root/current_tracer"))
+ .WillByDefault(Return("nop"));
+ ON_CALL(ftrace_, ReadFileIntoString("/root/events/enable"))
+ .WillByDefault(Return("0"));
+ EXPECT_CALL(
+ atrace_wrapper_,
+ RunAtrace(
+ ElementsAreArray(
+ {"atrace", "--async_start", "--only_userspace", "-a",
+ "com.google.android.gms,com.google.android.gms.persistent"}),
+ _))
+ .WillOnce(Return(true));
+
+ FtraceConfigId id = 97;
+ ASSERT_TRUE(model_.SetupConfig(id, config));
+
+ const FtraceDataSourceConfig* ds_config = model_.GetDataSourceConfig(id);
+ ASSERT_TRUE(ds_config);
+ ASSERT_THAT(ds_config->event_filter.GetEnabledEvents(),
+ Contains(kFakePrintEventId));
+
+ EXPECT_CALL(
+ atrace_wrapper_,
+ RunAtrace(
+ ElementsAreArray({"atrace", "--async_stop", "--only_userspace"}), _))
+ .WillOnce(Return(true));
+ ASSERT_TRUE(model_.RemoveConfig(id));
+}
+
+TEST_F(FtraceConfigMuxerFakeTableTest, AtraceMultipleConfigs) {
+ FtraceConfig config_a = CreateFtraceConfig({});
+ *config_a.add_atrace_apps() = "app_a";
+ *config_a.add_atrace_categories() = "cat_a";
+
+ FtraceConfig config_b = CreateFtraceConfig({});
+ *config_b.add_atrace_apps() = "app_b";
+ *config_b.add_atrace_categories() = "cat_b";
+
+ FtraceConfig config_c = CreateFtraceConfig({});
+ *config_c.add_atrace_apps() = "app_c";
+ *config_c.add_atrace_categories() = "cat_c";
+
+ ON_CALL(ftrace_, ReadFileIntoString("/root/current_tracer"))
+ .WillByDefault(Return("nop"));
+ ON_CALL(ftrace_, ReadFileIntoString("/root/events/enable"))
+ .WillByDefault(Return("0"));
+ EXPECT_CALL(
+ atrace_wrapper_,
+ RunAtrace(ElementsAreArray({"atrace", "--async_start", "--only_userspace",
+ "cat_a", "-a", "app_a"}),
+ _))
+ .WillOnce(Return(true));
+ FtraceConfigId id_a = 3;
+ ASSERT_TRUE(model_.SetupConfig(id_a, config_a));
+
+ EXPECT_CALL(
+ atrace_wrapper_,
+ RunAtrace(ElementsAreArray({"atrace", "--async_start", "--only_userspace",
+ "cat_a", "cat_b", "-a", "app_a,app_b"}),
+ _))
+ .WillOnce(Return(true));
+ FtraceConfigId id_b = 13;
+ ASSERT_TRUE(model_.SetupConfig(id_b, config_b));
+
+ EXPECT_CALL(atrace_wrapper_,
+ RunAtrace(ElementsAreArray({"atrace", "--async_start",
+ "--only_userspace", "cat_a", "cat_b",
+ "cat_c", "-a", "app_a,app_b,app_c"}),
+ _))
+ .WillOnce(Return(true));
+ FtraceConfigId id_c = 23;
+ ASSERT_TRUE(model_.SetupConfig(id_c, config_c));
+
+ EXPECT_CALL(
+ atrace_wrapper_,
+ RunAtrace(ElementsAreArray({"atrace", "--async_start", "--only_userspace",
+ "cat_a", "cat_c", "-a", "app_a,app_c"}),
+ _))
+ .WillOnce(Return(true));
+ ASSERT_TRUE(model_.RemoveConfig(id_b));
+
+ EXPECT_CALL(
+ atrace_wrapper_,
+ RunAtrace(ElementsAreArray({"atrace", "--async_start", "--only_userspace",
+ "cat_c", "-a", "app_c"}),
+ _))
+ .WillOnce(Return(true));
+ ASSERT_TRUE(model_.RemoveConfig(id_a));
+
+ EXPECT_CALL(
+ atrace_wrapper_,
+ RunAtrace(
+ ElementsAreArray({"atrace", "--async_stop", "--only_userspace"}), _))
+ .WillOnce(Return(true));
+ ASSERT_TRUE(model_.RemoveConfig(id_c));
+}
+
+TEST_F(FtraceConfigMuxerFakeTableTest, AtraceFailedConfig) {
+ FtraceConfig config_a = CreateFtraceConfig({});
+ *config_a.add_atrace_apps() = "app_1";
+ *config_a.add_atrace_apps() = "app_2";
+ *config_a.add_atrace_categories() = "cat_1";
+ *config_a.add_atrace_categories() = "cat_2";
+
+ FtraceConfig config_b = CreateFtraceConfig({});
+ *config_b.add_atrace_apps() = "app_fail";
+ *config_b.add_atrace_categories() = "cat_fail";
+
+ FtraceConfig config_c = CreateFtraceConfig({});
+ *config_c.add_atrace_apps() = "app_1";
+ *config_c.add_atrace_apps() = "app_3";
+ *config_c.add_atrace_categories() = "cat_1";
+ *config_c.add_atrace_categories() = "cat_3";
+
+ ON_CALL(ftrace_, ReadFileIntoString("/root/current_tracer"))
+ .WillByDefault(Return("nop"));
+ ON_CALL(ftrace_, ReadFileIntoString("/root/events/enable"))
+ .WillByDefault(Return("0"));
+ EXPECT_CALL(
+ atrace_wrapper_,
+ RunAtrace(ElementsAreArray({"atrace", "--async_start", "--only_userspace",
+ "cat_1", "cat_2", "-a", "app_1,app_2"}),
+ _))
+ .WillOnce(Return(true));
+ FtraceConfigId id_a = 7;
+ ASSERT_TRUE(model_.SetupConfig(id_a, config_a));
+
+ EXPECT_CALL(
+ atrace_wrapper_,
+ RunAtrace(ElementsAreArray({"atrace", "--async_start", "--only_userspace",
+ "cat_1", "cat_2", "cat_fail", "-a",
+ "app_1,app_2,app_fail"}),
+ _))
+ .WillOnce(Return(false));
+ FtraceConfigId id_b = 17;
+ ASSERT_TRUE(model_.SetupConfig(id_b, config_b));
+
+ EXPECT_CALL(atrace_wrapper_,
+ RunAtrace(ElementsAreArray({"atrace", "--async_start",
+ "--only_userspace", "cat_1", "cat_2",
+ "cat_3", "-a", "app_1,app_2,app_3"}),
+ _))
+ .WillOnce(Return(true));
+ FtraceConfigId id_c = 47;
+ ASSERT_TRUE(model_.SetupConfig(id_c, config_c));
+
+ EXPECT_CALL(
+ atrace_wrapper_,
+ RunAtrace(ElementsAreArray({"atrace", "--async_start", "--only_userspace",
+ "cat_1", "cat_2", "-a", "app_1,app_2"}),
+ _))
+ .WillOnce(Return(true));
+ ASSERT_TRUE(model_.RemoveConfig(id_c));
+
+ // Removing the config we failed to enable doesn't change the atrace state
+ // so we don't expect a call here.
+ ASSERT_TRUE(model_.RemoveConfig(id_b));
+
+ EXPECT_CALL(
+ atrace_wrapper_,
+ RunAtrace(
+ ElementsAreArray({"atrace", "--async_stop", "--only_userspace"}), _))
+ .WillOnce(Return(true));
+ ASSERT_TRUE(model_.RemoveConfig(id_a));
+}
+
+TEST_F(FtraceConfigMuxerFakeTableTest, AtraceDuplicateConfigs) {
+ FtraceConfig config_a = CreateFtraceConfig({});
+ *config_a.add_atrace_apps() = "app_1";
+ *config_a.add_atrace_categories() = "cat_1";
+
+ FtraceConfig config_b = CreateFtraceConfig({});
+ *config_b.add_atrace_apps() = "app_1";
+ *config_b.add_atrace_categories() = "cat_1";
+
+ ON_CALL(ftrace_, ReadFileIntoString("/root/current_tracer"))
+ .WillByDefault(Return("nop"));
+ ON_CALL(ftrace_, ReadFileIntoString("/root/events/enable"))
+ .WillByDefault(Return("0"));
+ EXPECT_CALL(
+ atrace_wrapper_,
+ RunAtrace(ElementsAreArray({"atrace", "--async_start", "--only_userspace",
+ "cat_1", "-a", "app_1"}),
+ _))
+ .WillOnce(Return(true));
+ FtraceConfigId id_a = 19;
+ ASSERT_TRUE(model_.SetupConfig(id_a, config_a));
+
+ FtraceConfigId id_b = 29;
+ ASSERT_TRUE(model_.SetupConfig(id_b, config_b));
+
+ ASSERT_TRUE(model_.RemoveConfig(id_a));
+
+ EXPECT_CALL(
+ atrace_wrapper_,
+ RunAtrace(
+ ElementsAreArray({"atrace", "--async_stop", "--only_userspace"}), _))
+ .WillOnce(Return(true));
+ ASSERT_TRUE(model_.RemoveConfig(id_b));
+}
+
+TEST_F(FtraceConfigMuxerFakeTableTest, AtraceAndFtraceConfigs) {
+ FtraceConfig config_a = CreateFtraceConfig({"sched/sched_cpu_hotplug"});
+
+ FtraceConfig config_b = CreateFtraceConfig({"sched/sched_switch"});
+ *config_b.add_atrace_categories() = "b";
+
+ FtraceConfig config_c = CreateFtraceConfig({"sched/sched_switch"});
+
+ FtraceConfig config_d = CreateFtraceConfig({"sched/sched_cpu_hotplug"});
+ *config_d.add_atrace_categories() = "d";
+
+ ON_CALL(ftrace_, ReadFileIntoString("/root/current_tracer"))
+ .WillByDefault(Return("nop"));
+ ON_CALL(ftrace_, ReadFileIntoString("/root/events/enable"))
+ .WillByDefault(Return("0"));
+ FtraceConfigId id_a = 179;
+ ASSERT_TRUE(model_.SetupConfig(id_a, config_a));
+
+ EXPECT_CALL(atrace_wrapper_,
+ RunAtrace(ElementsAreArray({"atrace", "--async_start",
+ "--only_userspace", "b"}),
+ _))
+ .WillOnce(Return(true));
+ FtraceConfigId id_b = 239;
+ ASSERT_TRUE(model_.SetupConfig(id_b, config_b));
+
+ FtraceConfigId id_c = 101;
+ ASSERT_TRUE(model_.SetupConfig(id_c, config_c));
+
+ EXPECT_CALL(atrace_wrapper_,
+ RunAtrace(ElementsAreArray({"atrace", "--async_start",
+ "--only_userspace", "b", "d"}),
+ _))
+ .WillOnce(Return(true));
+ FtraceConfigId id_d = 47;
+ ASSERT_TRUE(model_.SetupConfig(id_d, config_d));
+
+ EXPECT_CALL(atrace_wrapper_,
+ RunAtrace(ElementsAreArray({"atrace", "--async_start",
+ "--only_userspace", "b"}),
+ _))
+ .WillOnce(Return(true));
+ ASSERT_TRUE(model_.RemoveConfig(id_d));
+
+ ASSERT_TRUE(model_.RemoveConfig(id_c));
+
+ EXPECT_CALL(
+ atrace_wrapper_,
+ RunAtrace(
+ ElementsAreArray({"atrace", "--async_stop", "--only_userspace"}), _))
+ .WillOnce(Return(true));
+ ASSERT_TRUE(model_.RemoveConfig(id_b));
+
+ ASSERT_TRUE(model_.RemoveConfig(id_a));
+}
+
+TEST_F(FtraceConfigMuxerFakeTableTest, AtraceErrorsPropagated) {
+ FtraceConfig config = CreateFtraceConfig({});
+ *config.add_atrace_categories() = "cat_1";
+ *config.add_atrace_categories() = "cat_2";
+
+ ON_CALL(ftrace_, ReadFileIntoString("/root/current_tracer"))
+ .WillByDefault(Return("nop"));
+ ON_CALL(ftrace_, ReadFileIntoString("/root/events/enable"))
+ .WillByDefault(Return("0"));
+
+ EXPECT_CALL(
+ atrace_wrapper_,
+ RunAtrace(ElementsAreArray({"atrace", "--async_start", "--only_userspace",
+ "cat_1", "cat_2"}),
+ _))
+ .WillOnce(Invoke([](const std::vector<std::string>&, std::string* err) {
+ EXPECT_NE(err, nullptr);
+ if (err)
+ err->append("foo\nbar\n");
+ return true;
+ }));
+
+ FtraceSetupErrors errors{};
+ FtraceConfigId id_a = 23;
+ ASSERT_TRUE(model_.SetupConfig(id_a, config, &errors));
+ EXPECT_EQ(errors.atrace_errors, "foo\nbar\n");
+}
+
+TEST_F(FtraceConfigMuxerFakeTableTest, SetupClockForTesting) {
+ FtraceConfig config;
+
+ namespace pb0 = protos::pbzero;
+
+ EXPECT_CALL(ftrace_, ReadFileIntoString("/root/trace_clock"))
+ .Times(AnyNumber());
+
+ ON_CALL(ftrace_, ReadFileIntoString("/root/trace_clock"))
+ .WillByDefault(Return("[local] global boot"));
+ EXPECT_CALL(ftrace_, WriteToFile("/root/trace_clock", "boot"));
+ model_.SetupClockForTesting(config);
+ // unspecified = boot.
+ EXPECT_EQ(model_.ftrace_clock(),
+ static_cast<int>(pb0::FTRACE_CLOCK_UNSPECIFIED));
+
+ ON_CALL(ftrace_, ReadFileIntoString("/root/trace_clock"))
+ .WillByDefault(Return("[local] global"));
+ EXPECT_CALL(ftrace_, WriteToFile("/root/trace_clock", "global"));
+ model_.SetupClockForTesting(config);
+ EXPECT_EQ(model_.ftrace_clock(), static_cast<int>(pb0::FTRACE_CLOCK_GLOBAL));
+
+ ON_CALL(ftrace_, ReadFileIntoString("/root/trace_clock"))
+ .WillByDefault(Return(""));
+ model_.SetupClockForTesting(config);
+ EXPECT_EQ(model_.ftrace_clock(), static_cast<int>(pb0::FTRACE_CLOCK_UNKNOWN));
+
+ ON_CALL(ftrace_, ReadFileIntoString("/root/trace_clock"))
+ .WillByDefault(Return("local [global]"));
+ model_.SetupClockForTesting(config);
+ EXPECT_EQ(model_.ftrace_clock(), static_cast<int>(pb0::FTRACE_CLOCK_GLOBAL));
+}
+
+TEST_F(FtraceConfigMuxerFakeTableTest, GetFtraceEvents) {
+ FtraceConfig config = CreateFtraceConfig({"sched/sched_switch"});
+ std::set<GroupAndName> events =
+ model_.GetFtraceEventsForTesting(config, table_.get());
+
+ EXPECT_THAT(events, Contains(GroupAndName("sched", "sched_switch")));
+ EXPECT_THAT(events, Not(Contains(GroupAndName("ftrace", "print"))));
+}
+
+TEST_F(FtraceConfigMuxerFakeTableTest, GetFtraceEventsAtrace) {
+ FtraceConfig config = CreateFtraceConfig({});
+ *config.add_atrace_categories() = "sched";
+ std::set<GroupAndName> events =
+ model_.GetFtraceEventsForTesting(config, table_.get());
+
+ EXPECT_THAT(events, Contains(GroupAndName("sched", "sched_switch")));
+ EXPECT_THAT(events, Contains(GroupAndName("sched", "sched_cpu_hotplug")));
+ EXPECT_THAT(events, Contains(GroupAndName("ftrace", "print")));
+}
+
+TEST_F(FtraceConfigMuxerFakeTableTest, GetFtraceEventsAtraceCategories) {
+ FtraceConfig config = CreateFtraceConfig({});
+ *config.add_atrace_categories() = "sched";
+ *config.add_atrace_categories() = "memreclaim";
+ std::set<GroupAndName> events =
+ model_.GetFtraceEventsForTesting(config, table_.get());
+
+ EXPECT_THAT(events, Contains(GroupAndName("sched", "sched_switch")));
+ EXPECT_THAT(events, Contains(GroupAndName("sched", "sched_cpu_hotplug")));
+ EXPECT_THAT(events, Contains(GroupAndName("cgroup", "cgroup_mkdir")));
+ EXPECT_THAT(events, Contains(GroupAndName("vmscan",
+ "mm_vmscan_direct_reclaim_begin")));
+ EXPECT_THAT(events,
+ Contains(GroupAndName("lowmemorykiller", "lowmemory_kill")));
+ EXPECT_THAT(events, Contains(GroupAndName("ftrace", "print")));
+}
+
+// Tests the enabling fallback logic that tries to use the "set_event" interface
+// if writing the individual xxx/enable file fails.
+TEST_F(FtraceConfigMuxerFakeTableTest, FallbackOnSetEvent) {
+ FtraceConfig config =
+ CreateFtraceConfig({"sched/sched_switch", "cgroup/cgroup_mkdir"});
+
+ EXPECT_CALL(ftrace_, WriteToFile("/root/buffer_percent", _))
+ .WillRepeatedly(Return(true));
+
+ EXPECT_CALL(ftrace_, ReadFileIntoString("/root/current_tracer"))
+ .WillOnce(Return("nop"));
+ EXPECT_CALL(ftrace_, ReadOneCharFromFile("/root/tracing_on"))
+ .WillOnce(Return('1'));
+ EXPECT_CALL(ftrace_, WriteToFile("/root/tracing_on", "0"));
+ EXPECT_CALL(ftrace_, WriteToFile("/root/events/enable", "0"));
+ EXPECT_CALL(ftrace_, ClearFile("/root/trace"));
+ EXPECT_CALL(ftrace_, ClearFile(MatchesRegex("/root/per_cpu/cpu[0-9]/trace")));
+ ON_CALL(ftrace_, ReadFileIntoString("/root/trace_clock"))
+ .WillByDefault(Return("[local] global boot"));
+ EXPECT_CALL(ftrace_, ReadFileIntoString("/root/trace_clock"))
+ .Times(AnyNumber());
+ EXPECT_CALL(ftrace_, WriteToFile("/root/buffer_size_kb", _));
+ EXPECT_CALL(ftrace_, WriteToFile("/root/trace_clock", "boot"));
+ EXPECT_CALL(ftrace_,
+ WriteToFile("/root/events/sched/sched_switch/enable", "1"));
+ EXPECT_CALL(ftrace_,
+ WriteToFile("/root/events/cgroup/cgroup_mkdir/enable", "1"))
+ .WillOnce(Return(false));
+ EXPECT_CALL(ftrace_, AppendToFile("/root/set_event", "cgroup:cgroup_mkdir"))
+ .WillOnce(Return(true));
+ FtraceConfigId id = 97;
+ ASSERT_TRUE(model_.SetupConfig(id, config));
+
+ EXPECT_CALL(ftrace_, WriteToFile("/root/tracing_on", "1"));
+ ASSERT_TRUE(model_.ActivateConfig(id));
+
+ const FtraceDataSourceConfig* ds_config = model_.GetDataSourceConfig(id);
+ ASSERT_TRUE(ds_config);
+ EXPECT_THAT(ds_config->event_filter.GetEnabledEvents(),
+ Contains(kFakeSchedSwitchEventId));
+ EXPECT_THAT(ds_config->event_filter.GetEnabledEvents(),
+ Contains(kCgroupMkdirEventId));
+
+ const EventFilter* central_filter = model_.GetCentralEventFilterForTesting();
+ EXPECT_THAT(central_filter->GetEnabledEvents(),
+ Contains(kFakeSchedSwitchEventId));
+ EXPECT_THAT(central_filter->GetEnabledEvents(),
+ Contains(kCgroupMkdirEventId));
+
+ EXPECT_CALL(ftrace_,
+ WriteToFile("/root/events/sched/sched_switch/enable", "0"));
+ EXPECT_CALL(ftrace_,
+ WriteToFile("/root/events/cgroup/cgroup_mkdir/enable", "0"))
+ .WillOnce(Return(false));
+ EXPECT_CALL(ftrace_, AppendToFile("/root/set_event", "!cgroup:cgroup_mkdir"))
+ .WillOnce(Return(true));
+ EXPECT_CALL(ftrace_, WriteToFile("/root/tracing_on", "0"));
+ EXPECT_CALL(ftrace_, WriteToFile("/root/buffer_size_kb", PageSizeKb()));
+ EXPECT_CALL(ftrace_, WriteToFile("/root/events/enable", "0"));
+ EXPECT_CALL(ftrace_, ClearFile("/root/trace"));
+ EXPECT_CALL(ftrace_, ClearFile(MatchesRegex("/root/per_cpu/cpu[0-9]/trace")));
+ EXPECT_CALL(ftrace_, WriteToFile("/root/tracing_on", "1"));
+ ASSERT_TRUE(model_.RemoveConfig(id));
+}
+
+TEST_F(FtraceConfigMuxerFakeTableTest, CompactSchedConfigWithInvalidFormat) {
// Request compact encoding.
FtraceConfig config = CreateFtraceConfig({"sched/sched_switch"});
config.mutable_compact_sched()->set_enabled(true);
- ON_CALL(ftrace, ReadFileIntoString("/root/current_tracer"))
+ ON_CALL(ftrace_, ReadFileIntoString("/root/current_tracer"))
.WillByDefault(Return("nop"));
- ON_CALL(ftrace, ReadFileIntoString("/root/events/enable"))
+ ON_CALL(ftrace_, ReadFileIntoString("/root/events/enable"))
.WillByDefault(Return("0"));
FtraceConfigId id = 67;
- ASSERT_TRUE(model.SetupConfig(id, config));
+ ASSERT_TRUE(model_.SetupConfig(id, config));
// The translation table says that the scheduling events' format didn't match
// compile-time assumptions, so we won't enable compact events even if
// requested.
- const FtraceDataSourceConfig* ds_config = model.GetDataSourceConfig(id);
+ const FtraceDataSourceConfig* ds_config = model_.GetDataSourceConfig(id);
ASSERT_TRUE(ds_config);
EXPECT_THAT(ds_config->event_filter.GetEnabledEvents(),
Contains(kFakeSchedSwitchEventId));
EXPECT_FALSE(ds_config->compact_sched.enabled);
}
-TEST_F(FtraceConfigMuxerTest, SkipGenericEventsOption) {
- NiceMock<MockFtraceProcfs> ftrace;
- FtraceConfigMuxer model(&ftrace, table_.get(), GetSyscallTable(), {});
-
+TEST_F(FtraceConfigMuxerFakeTableTest, SkipGenericEventsOption) {
static constexpr int kFtraceGenericEventId = 42;
- ON_CALL(table_procfs_, ReadEventFormat("sched", "generic"))
+ ON_CALL(ftrace_, ReadEventFormat("sched", "generic"))
.WillByDefault(Return(R"(name: generic
ID: 42
format:
@@ -1297,15 +1023,15 @@
CreateFtraceConfig({"sched/sched_switch", "sched/generic"});
config_with_disable.set_disable_generic_events(true);
- ON_CALL(ftrace, ReadFileIntoString("/root/current_tracer"))
+ ON_CALL(ftrace_, ReadFileIntoString("/root/current_tracer"))
.WillByDefault(Return("nop"));
- ON_CALL(ftrace, ReadFileIntoString("/root/events/enable"))
+ ON_CALL(ftrace_, ReadFileIntoString("/root/events/enable"))
.WillByDefault(Return("0"));
{
FtraceConfigId id = 123;
- ASSERT_TRUE(model.SetupConfig(id, config_default));
- const FtraceDataSourceConfig* ds_config = model.GetDataSourceConfig(id);
+ ASSERT_TRUE(model_.SetupConfig(id, config_default));
+ const FtraceDataSourceConfig* ds_config = model_.GetDataSourceConfig(id);
ASSERT_TRUE(ds_config);
// Both events enabled for the data source by default.
EXPECT_THAT(
@@ -1314,8 +1040,8 @@
}
{
FtraceConfigId id = 321;
- ASSERT_TRUE(model.SetupConfig(id, config_with_disable));
- const FtraceDataSourceConfig* ds_config = model.GetDataSourceConfig(id);
+ ASSERT_TRUE(model_.SetupConfig(id, config_with_disable));
+ const FtraceDataSourceConfig* ds_config = model_.GetDataSourceConfig(id);
ASSERT_TRUE(ds_config);
// Only the statically known event is enabled.
EXPECT_THAT(ds_config->event_filter.GetEnabledEvents(),
@@ -1323,11 +1049,7 @@
}
}
-TEST_F(FtraceConfigMuxerTest, Funcgraph) {
- auto fake_table = CreateFakeTable();
- NiceMock<MockFtraceProcfs> ftrace;
- FtraceConfigMuxer model(&ftrace, fake_table.get(), GetSyscallTable(), {});
-
+TEST_F(FtraceConfigMuxerFakeTableTest, Funcgraph) {
FtraceConfig config;
config.set_enable_function_graph(true);
*config.add_function_filters() = "sched*";
@@ -1336,76 +1058,276 @@
*config.add_function_graph_roots() = "sched*";
*config.add_function_graph_roots() = "*mm_fault";
- ON_CALL(ftrace, ReadFileIntoString("/root/current_tracer"))
+ ON_CALL(ftrace_, ReadFileIntoString("/root/current_tracer"))
.WillByDefault(Return("nop"));
- EXPECT_CALL(ftrace, WriteToFile(_, _)).WillRepeatedly(Return(true));
+ EXPECT_CALL(ftrace_, WriteToFile(_, _)).WillRepeatedly(Return(true));
- EXPECT_CALL(ftrace, ClearFile("/root/trace"));
- EXPECT_CALL(ftrace, ClearFile(MatchesRegex("/root/per_cpu/cpu[0-9]/trace")));
+ EXPECT_CALL(ftrace_, ClearFile("/root/trace"));
+ EXPECT_CALL(ftrace_, ClearFile(MatchesRegex("/root/per_cpu/cpu[0-9]/trace")));
// Set up config, assert that the tracefs writes happened:
- EXPECT_CALL(ftrace, ClearFile("/root/set_ftrace_filter"));
- EXPECT_CALL(ftrace, ClearFile("/root/set_graph_function"));
- EXPECT_CALL(ftrace, AppendToFile("/root/set_ftrace_filter",
- "sched*\nhandle_mm_fault"))
+ EXPECT_CALL(ftrace_, ClearFile("/root/set_ftrace_filter"));
+ EXPECT_CALL(ftrace_, ClearFile("/root/set_graph_function"));
+ EXPECT_CALL(ftrace_, AppendToFile("/root/set_ftrace_filter",
+ "sched*\nhandle_mm_fault"))
.WillOnce(Return(true));
- EXPECT_CALL(ftrace,
+ EXPECT_CALL(ftrace_,
AppendToFile("/root/set_graph_function", "sched*\n*mm_fault"))
.WillOnce(Return(true));
- EXPECT_CALL(ftrace, WriteToFile("/root/current_tracer", "function_graph"))
+ EXPECT_CALL(ftrace_, WriteToFile("/root/current_tracer", "function_graph"))
.WillOnce(Return(true));
FtraceConfigId id = 43;
- ASSERT_TRUE(model.SetupConfig(id, config));
- ASSERT_TRUE(testing::Mock::VerifyAndClearExpectations(&ftrace));
+ ASSERT_TRUE(model_.SetupConfig(id, config));
+ ASSERT_TRUE(testing::Mock::VerifyAndClearExpectations(&ftrace_));
// Toggle config on and off, tracer won't be reset yet:
- ASSERT_TRUE(model.ActivateConfig(id));
- ASSERT_TRUE(model.RemoveConfig(id));
- ASSERT_TRUE(testing::Mock::VerifyAndClearExpectations(&ftrace));
+ ASSERT_TRUE(model_.ActivateConfig(id));
+ ASSERT_TRUE(model_.RemoveConfig(id));
+ ASSERT_TRUE(testing::Mock::VerifyAndClearExpectations(&ftrace_));
// Emulate ftrace_controller's call to ResetCurrentTracer (see impl comments
// for why RemoveConfig is insufficient).
- EXPECT_CALL(ftrace, ClearFile("/root/set_ftrace_filter"));
- EXPECT_CALL(ftrace, ClearFile("/root/set_graph_function"));
- EXPECT_CALL(ftrace, WriteToFile("/root/current_tracer", "nop"))
+ EXPECT_CALL(ftrace_, ClearFile("/root/set_ftrace_filter"));
+ EXPECT_CALL(ftrace_, ClearFile("/root/set_graph_function"));
+ EXPECT_CALL(ftrace_, WriteToFile("/root/current_tracer", "nop"))
.WillOnce(Return(true));
- ASSERT_TRUE(model.ResetCurrentTracer());
- ASSERT_TRUE(testing::Mock::VerifyAndClearExpectations(&ftrace));
+ ASSERT_TRUE(model_.ResetCurrentTracer());
+ ASSERT_TRUE(testing::Mock::VerifyAndClearExpectations(&ftrace_));
}
-TEST_F(FtraceConfigMuxerTest, SecondaryInstanceDoNotSupportAtrace) {
- auto fake_table = CreateFakeTable();
- NiceMock<MockFtraceProcfs> ftrace;
- FtraceConfigMuxer model(&ftrace, fake_table.get(), GetSyscallTable(), {},
- /* secondary_instance= */ true);
-
- FtraceConfig config = CreateFtraceConfig({"sched/sched_switch"});
- *config.add_atrace_categories() = "sched";
-
- ASSERT_FALSE(model.SetupConfig(/* id= */ 73, config));
-}
-
-TEST_F(FtraceConfigMuxerTest, PreserveFtraceBufferNotSetBufferSizeKb) {
- auto fake_table = CreateFakeTable();
- NiceMock<MockFtraceProcfs> ftrace;
- FtraceConfigMuxer model(&ftrace, fake_table.get(), GetSyscallTable(), {},
- /* secondary_instance= */ false);
-
+TEST_F(FtraceConfigMuxerFakeTableTest, PreserveFtraceBufferNotSetBufferSizeKb) {
FtraceConfig config = CreateFtraceConfig({"sched/sched_switch"});
config.set_preserve_ftrace_buffer(true);
- EXPECT_CALL(ftrace, ReadOneCharFromFile("/root/tracing_on"))
+ EXPECT_CALL(ftrace_, ReadOneCharFromFile("/root/tracing_on"))
.WillOnce(Return('1'));
- ON_CALL(ftrace, ReadFileIntoString("/root/trace_clock"))
+ ON_CALL(ftrace_, ReadFileIntoString("/root/trace_clock"))
.WillByDefault(Return("[local] global boot"));
- EXPECT_CALL(ftrace, ReadFileIntoString("/root/trace_clock"))
+ EXPECT_CALL(ftrace_, ReadFileIntoString("/root/trace_clock"))
.Times(AnyNumber());
- EXPECT_CALL(ftrace, WriteToFile("/root/buffer_size_kb", _)).Times(0);
- EXPECT_CALL(ftrace,
+ EXPECT_CALL(ftrace_, WriteToFile("/root/buffer_size_kb", _)).Times(0);
+ EXPECT_CALL(ftrace_,
WriteToFile("/root/events/sched/sched_switch/enable", "1"));
FtraceConfigId id = 44;
- ASSERT_TRUE(model.SetupConfig(id, config));
+ ASSERT_TRUE(model_.SetupConfig(id, config));
+}
+
+// Fixture that constructs a FtraceConfigMuxer with a mock
+// ProtoTranslationTable.
+class FtraceConfigMuxerMockTableTest : public FtraceConfigMuxerTest {
+ protected:
+ std::unique_ptr<MockProtoTranslationTable> mock_table_ = GetMockTable();
+ FtraceConfigMuxer model_ = FtraceConfigMuxer(&ftrace_,
+ &atrace_wrapper_,
+ mock_table_.get(),
+ GetSyscallTable(),
+ {});
+};
+
+TEST_F(FtraceConfigMuxerMockTableTest, AddGenericEvent) {
+ FtraceConfig config = CreateFtraceConfig({"power/cpu_frequency"});
+
+ EXPECT_CALL(ftrace_, ReadFileIntoString("/root/current_tracer"))
+ .WillOnce(Return("nop"));
+ EXPECT_CALL(ftrace_, ReadOneCharFromFile("/root/tracing_on"))
+ .WillOnce(Return('1'));
+ EXPECT_CALL(ftrace_, WriteToFile("/root/tracing_on", "0"));
+ EXPECT_CALL(ftrace_, WriteToFile("/root/events/enable", "0"));
+ EXPECT_CALL(ftrace_, ClearFile("/root/trace"));
+ EXPECT_CALL(ftrace_, ClearFile(MatchesRegex("/root/per_cpu/cpu[0-9]/trace")));
+ ON_CALL(ftrace_, ReadFileIntoString("/root/trace_clock"))
+ .WillByDefault(Return("[local] global boot"));
+ EXPECT_CALL(ftrace_, ReadFileIntoString("/root/trace_clock"))
+ .Times(AnyNumber());
+ EXPECT_CALL(ftrace_, WriteToFile("/root/buffer_size_kb", _));
+ EXPECT_CALL(ftrace_, WriteToFile("/root/trace_clock", "boot"));
+ EXPECT_CALL(ftrace_,
+ WriteToFile("/root/events/power/cpu_frequency/enable", "1"));
+ EXPECT_CALL(*mock_table_, GetEvent(GroupAndName("power", "cpu_frequency")))
+ .Times(AnyNumber());
+
+ static constexpr int kExpectedEventId = 77;
+ Event event_to_return;
+ event_to_return.name = "cpu_frequency";
+ event_to_return.group = "power";
+ event_to_return.ftrace_event_id = kExpectedEventId;
+ ON_CALL(*mock_table_,
+ GetOrCreateEvent(GroupAndName("power", "cpu_frequency")))
+ .WillByDefault(Return(&event_to_return));
+ EXPECT_CALL(*mock_table_,
+ GetOrCreateEvent(GroupAndName("power", "cpu_frequency")));
+
+ FtraceConfigId id = 7;
+ ASSERT_TRUE(model_.SetupConfig(id, config));
+
+ EXPECT_CALL(ftrace_, WriteToFile("/root/tracing_on", "1"));
+ ASSERT_TRUE(model_.ActivateConfig(id));
+
+ const FtraceDataSourceConfig* ds_config = model_.GetDataSourceConfig(id);
+ ASSERT_TRUE(ds_config);
+ ASSERT_THAT(ds_config->event_filter.GetEnabledEvents(),
+ ElementsAreArray({kExpectedEventId}));
+
+ const EventFilter* central_filter = model_.GetCentralEventFilterForTesting();
+ ASSERT_THAT(central_filter->GetEnabledEvents(),
+ ElementsAreArray({kExpectedEventId}));
+}
+
+TEST_F(FtraceConfigMuxerMockTableTest, AddAllEvents) {
+ FtraceConfig config = CreateFtraceConfig({"sched/*"});
+
+ EXPECT_CALL(ftrace_, ReadFileIntoString("/root/current_tracer"))
+ .WillOnce(Return("nop"));
+ EXPECT_CALL(ftrace_, ReadOneCharFromFile("/root/tracing_on"))
+ .WillOnce(Return('1'));
+ EXPECT_CALL(ftrace_, WriteToFile("/root/tracing_on", "0"));
+ EXPECT_CALL(ftrace_, WriteToFile("/root/events/enable", "0"));
+ EXPECT_CALL(ftrace_, ClearFile("/root/trace"));
+ EXPECT_CALL(ftrace_, ClearFile(MatchesRegex("/root/per_cpu/cpu[0-9]/trace")));
+ ON_CALL(ftrace_, ReadFileIntoString("/root/trace_clock"))
+ .WillByDefault(Return("[local] global boot"));
+ EXPECT_CALL(ftrace_, ReadFileIntoString("/root/trace_clock"))
+ .Times(AnyNumber());
+ EXPECT_CALL(ftrace_, WriteToFile("/root/buffer_size_kb", _));
+ EXPECT_CALL(ftrace_, WriteToFile("/root/trace_clock", "boot"));
+ EXPECT_CALL(ftrace_,
+ WriteToFile("/root/events/sched/sched_switch/enable", "1"));
+ EXPECT_CALL(ftrace_,
+ WriteToFile("/root/events/sched/sched_new_event/enable", "1"));
+
+ std::set<std::string> n = {"sched_switch", "sched_new_event"};
+ ON_CALL(ftrace_, GetEventNamesForGroup("events/sched"))
+ .WillByDefault(Return(n));
+ EXPECT_CALL(ftrace_, GetEventNamesForGroup("events/sched")).Times(1);
+
+ // Non-generic event.
+ static constexpr int kSchedSwitchEventId = 1;
+ Event sched_switch = {"sched_switch", "sched", {}, 0, 0, 0};
+ sched_switch.ftrace_event_id = kSchedSwitchEventId;
+ ON_CALL(*mock_table_, GetOrCreateEvent(GroupAndName("sched", "sched_switch")))
+ .WillByDefault(Return(&sched_switch));
+ EXPECT_CALL(*mock_table_,
+ GetOrCreateEvent(GroupAndName("sched", "sched_switch")))
+ .Times(AnyNumber());
+
+ // Generic event.
+ static constexpr int kGenericEventId = 2;
+ Event event_to_return;
+ event_to_return.name = "sched_new_event";
+ event_to_return.group = "sched";
+ event_to_return.ftrace_event_id = kGenericEventId;
+ ON_CALL(*mock_table_,
+ GetOrCreateEvent(GroupAndName("sched", "sched_new_event")))
+ .WillByDefault(Return(&event_to_return));
+ EXPECT_CALL(*mock_table_,
+ GetOrCreateEvent(GroupAndName("sched", "sched_new_event")));
+
+ FtraceConfigId id = 13;
+ ASSERT_TRUE(model_.SetupConfig(id, config));
+ ASSERT_TRUE(id);
+
+ EXPECT_CALL(ftrace_, WriteToFile("/root/tracing_on", "1"));
+ ASSERT_TRUE(model_.ActivateConfig(id));
+
+ const FtraceDataSourceConfig* ds_config = model_.GetDataSourceConfig(id);
+ ASSERT_TRUE(ds_config);
+ ASSERT_THAT(ds_config->event_filter.GetEnabledEvents(),
+ ElementsAreArray({kSchedSwitchEventId, kGenericEventId}));
+
+ const EventFilter* central_filter = model_.GetCentralEventFilterForTesting();
+ ASSERT_THAT(central_filter->GetEnabledEvents(),
+ ElementsAreArray({kSchedSwitchEventId, kGenericEventId}));
+}
+
+TEST_F(FtraceConfigMuxerMockTableTest, TwoWildcardGroups) {
+ FtraceConfig config = CreateFtraceConfig({"group_one/*", "group_two/*"});
+
+ std::set<std::string> event_names = {"foo"};
+ ON_CALL(ftrace_, GetEventNamesForGroup("events/group_one"))
+ .WillByDefault(Return(event_names));
+ EXPECT_CALL(ftrace_, GetEventNamesForGroup("events/group_one"))
+ .Times(AnyNumber());
+
+ ON_CALL(ftrace_, GetEventNamesForGroup("events/group_two"))
+ .WillByDefault(Return(event_names));
+ EXPECT_CALL(ftrace_, GetEventNamesForGroup("events/group_two"))
+ .Times(AnyNumber());
+
+ static constexpr int kEventId1 = 1;
+ Event event1;
+ event1.name = "foo";
+ event1.group = "group_one";
+ event1.ftrace_event_id = kEventId1;
+ ON_CALL(*mock_table_, GetOrCreateEvent(GroupAndName("group_one", "foo")))
+ .WillByDefault(Return(&event1));
+ EXPECT_CALL(*mock_table_, GetOrCreateEvent(GroupAndName("group_one", "foo")));
+
+ static constexpr int kEventId2 = 2;
+ Event event2;
+ event2.name = "foo";
+ event2.group = "group_two";
+ event2.ftrace_event_id = kEventId2;
+ ON_CALL(*mock_table_, GetOrCreateEvent(GroupAndName("group_two", "foo")))
+ .WillByDefault(Return(&event2));
+ EXPECT_CALL(*mock_table_, GetOrCreateEvent(GroupAndName("group_two", "foo")));
+
+ ON_CALL(ftrace_, ReadFileIntoString("/root/current_tracer"))
+ .WillByDefault(Return("nop"));
+ ON_CALL(ftrace_, ReadFileIntoString("/root/events/enable"))
+ .WillByDefault(Return("0"));
+
+ FtraceConfigId id = 23;
+ ASSERT_TRUE(model_.SetupConfig(id, config));
+ ASSERT_TRUE(model_.ActivateConfig(id));
+
+ const FtraceDataSourceConfig* ds_config = model_.GetDataSourceConfig(id);
+ ASSERT_TRUE(ds_config);
+ ASSERT_THAT(ds_config->event_filter.GetEnabledEvents(),
+ ElementsAreArray({kEventId1, kEventId2}));
+
+ const EventFilter* central_filter = model_.GetCentralEventFilterForTesting();
+ ASSERT_THAT(central_filter->GetEnabledEvents(),
+ ElementsAreArray({kEventId1, kEventId2}));
+}
+
+TEST_F(FtraceConfigMuxerMockTableTest, AddSameNameEvents) {
+ FtraceConfig config = CreateFtraceConfig({"group_one/foo", "group_two/foo"});
+
+ static constexpr int kEventId1 = 1;
+ Event event1;
+ event1.name = "foo";
+ event1.group = "group_one";
+ event1.ftrace_event_id = kEventId1;
+ ON_CALL(*mock_table_, GetOrCreateEvent(GroupAndName("group_one", "foo")))
+ .WillByDefault(Return(&event1));
+ EXPECT_CALL(*mock_table_, GetOrCreateEvent(GroupAndName("group_one", "foo")));
+
+ static constexpr int kEventId2 = 2;
+ Event event2;
+ event2.name = "foo";
+ event2.group = "group_two";
+ event2.ftrace_event_id = kEventId2;
+ ON_CALL(*mock_table_, GetOrCreateEvent(GroupAndName("group_two", "foo")))
+ .WillByDefault(Return(&event2));
+ EXPECT_CALL(*mock_table_, GetOrCreateEvent(GroupAndName("group_two", "foo")));
+
+ ON_CALL(ftrace_, ReadFileIntoString("/root/current_tracer"))
+ .WillByDefault(Return("nop"));
+ ON_CALL(ftrace_, ReadFileIntoString("/root/events/enable"))
+ .WillByDefault(Return("0"));
+
+ FtraceConfigId id = 5;
+ ASSERT_TRUE(model_.SetupConfig(id, config));
+ ASSERT_TRUE(model_.ActivateConfig(id));
+
+ const FtraceDataSourceConfig* ds_config = model_.GetDataSourceConfig(id);
+ ASSERT_THAT(ds_config->event_filter.GetEnabledEvents(),
+ ElementsAreArray({kEventId1, kEventId2}));
+
+ const EventFilter* central_filter = model_.GetCentralEventFilterForTesting();
+ ASSERT_THAT(central_filter->GetEnabledEvents(),
+ ElementsAreArray({kEventId1, kEventId2}));
}
} // namespace
diff --git a/src/traced/probes/ftrace/ftrace_controller.cc b/src/traced/probes/ftrace/ftrace_controller.cc
index ad924fa..750629d 100644
--- a/src/traced/probes/ftrace/ftrace_controller.cc
+++ b/src/traced/probes/ftrace/ftrace_controller.cc
@@ -179,25 +179,31 @@
if (!table)
return nullptr;
+ auto atrace_wrapper = std::make_unique<AtraceWrapperImpl>();
+
std::map<std::string, std::vector<GroupAndName>> vendor_evts =
GetAtraceVendorEvents(ftrace_procfs.get());
SyscallTable syscalls = SyscallTable::FromCurrentArch();
auto muxer = std::make_unique<FtraceConfigMuxer>(
- ftrace_procfs.get(), table.get(), std::move(syscalls), vendor_evts);
- return std::unique_ptr<FtraceController>(
- new FtraceController(std::move(ftrace_procfs), std::move(table),
- std::move(muxer), runner, observer));
+ ftrace_procfs.get(), atrace_wrapper.get(), table.get(),
+ std::move(syscalls), vendor_evts);
+ return std::unique_ptr<FtraceController>(new FtraceController(
+ std::move(ftrace_procfs), std::move(table), std::move(atrace_wrapper),
+ std::move(muxer), runner, observer));
}
-FtraceController::FtraceController(std::unique_ptr<FtraceProcfs> ftrace_procfs,
- std::unique_ptr<ProtoTranslationTable> table,
- std::unique_ptr<FtraceConfigMuxer> muxer,
- base::TaskRunner* task_runner,
- Observer* observer)
+FtraceController::FtraceController(
+ std::unique_ptr<FtraceProcfs> ftrace_procfs,
+ std::unique_ptr<ProtoTranslationTable> table,
+ std::unique_ptr<AtraceWrapper> atrace_wrapper,
+ std::unique_ptr<FtraceConfigMuxer> muxer,
+ base::TaskRunner* task_runner,
+ Observer* observer)
: task_runner_(task_runner),
observer_(observer),
+ atrace_wrapper_(std::move(atrace_wrapper)),
primary_(std::move(ftrace_procfs), std::move(table), std::move(muxer)),
weak_factory_(this) {}
@@ -816,7 +822,8 @@
auto syscalls = SyscallTable::FromCurrentArch();
auto muxer = std::make_unique<FtraceConfigMuxer>(
- ftrace_procfs.get(), table.get(), std::move(syscalls), vendor_evts,
+ ftrace_procfs.get(), atrace_wrapper_.get(), table.get(),
+ std::move(syscalls), vendor_evts,
/* secondary_instance= */ true);
return std::make_unique<FtraceInstanceState>(
std::move(ftrace_procfs), std::move(table), std::move(muxer));
diff --git a/src/traced/probes/ftrace/ftrace_controller.h b/src/traced/probes/ftrace/ftrace_controller.h
index 1e7c575..a858dfe 100644
--- a/src/traced/probes/ftrace/ftrace_controller.h
+++ b/src/traced/probes/ftrace/ftrace_controller.h
@@ -29,6 +29,7 @@
#include "perfetto/ext/base/weak_ptr.h"
#include "perfetto/ext/tracing/core/basic_types.h"
#include "src/kallsyms/lazy_kernel_symbolizer.h"
+#include "src/traced/probes/ftrace/atrace_wrapper.h"
#include "src/traced/probes/ftrace/cpu_reader.h"
#include "src/traced/probes/ftrace/ftrace_config_utils.h"
@@ -99,6 +100,7 @@
FtraceController(std::unique_ptr<FtraceProcfs>,
std::unique_ptr<ProtoTranslationTable>,
+ std::unique_ptr<AtraceWrapper>,
std::unique_ptr<FtraceConfigMuxer>,
base::TaskRunner*,
Observer*);
@@ -123,6 +125,8 @@
virtual uint64_t NowMs() const;
+ AtraceWrapper* atrace_wrapper() const { return atrace_wrapper_.get(); }
+
private:
friend class TestFtraceController;
enum class PollSupport { kUntested, kSupported, kUnsupported };
@@ -168,6 +172,7 @@
bool retain_ksyms_on_stop_ = false;
PollSupport buffer_watermark_support_ = PollSupport::kUntested;
std::set<FtraceDataSource*> data_sources_;
+ std::unique_ptr<AtraceWrapper> atrace_wrapper_;
// Default tracefs instance (normally /sys/kernel/tracing) is valid for as
// long as the controller is valid.
// Secondary instances (i.e. /sys/kernel/tracing/instances/...) are created
diff --git a/src/traced/probes/ftrace/ftrace_controller_unittest.cc b/src/traced/probes/ftrace/ftrace_controller_unittest.cc
index 28ca2d4..1a3538e 100644
--- a/src/traced/probes/ftrace/ftrace_controller_unittest.cc
+++ b/src/traced/probes/ftrace/ftrace_controller_unittest.cc
@@ -102,9 +102,10 @@
}
std::unique_ptr<FtraceConfigMuxer> FakeMuxer(FtraceProcfs* ftrace,
+ AtraceWrapper* atrace_wrapper,
ProtoTranslationTable* table) {
return std::unique_ptr<FtraceConfigMuxer>(new FtraceConfigMuxer(
- ftrace, table, SyscallTable(Architecture::kUnknown), {}));
+ ftrace, atrace_wrapper, table, SyscallTable(Architecture::kUnknown), {}));
}
class MockFtraceProcfs : public FtraceProcfs {
@@ -201,6 +202,12 @@
std::string current_tracer_ = "nop";
};
+class MockAtraceWrapper : public AtraceWrapper {
+ public:
+ MOCK_METHOD(bool, RunAtrace, (const std::vector<std::string>&, std::string*));
+ MOCK_METHOD(bool, IsOldAtrace, ());
+};
+
} // namespace
class TestFtraceController : public FtraceController,
@@ -208,11 +215,13 @@
public:
TestFtraceController(std::unique_ptr<MockFtraceProcfs> ftrace_procfs,
std::unique_ptr<Table> table,
+ std::unique_ptr<AtraceWrapper> atrace_wrapper,
std::unique_ptr<FtraceConfigMuxer> muxer,
std::unique_ptr<MockTaskRunner> runner,
MockFtraceProcfs* raw_procfs)
: FtraceController(std::move(ftrace_procfs),
std::move(table),
+ std::move(atrace_wrapper),
std::move(muxer),
runner.get(),
/*observer=*/this),
@@ -256,7 +265,7 @@
PERFETTO_CHECK(ftrace_procfs);
auto table = FakeTable(ftrace_procfs.get());
- auto muxer = FakeMuxer(ftrace_procfs.get(), table.get());
+ auto muxer = FakeMuxer(ftrace_procfs.get(), atrace_wrapper(), table.get());
return std::unique_ptr<FtraceController::FtraceInstanceState>(
new FtraceController::FtraceInstanceState(
std::move(ftrace_procfs), std::move(table), std::move(muxer)));
@@ -289,14 +298,17 @@
new MockFtraceProcfs("/root/", cpu_count));
}
+ std::unique_ptr<AtraceWrapper> atrace_wrapper;
+
auto table = FakeTable(ftrace_procfs.get());
- auto muxer = FakeMuxer(ftrace_procfs.get(), table.get());
+ auto muxer =
+ FakeMuxer(ftrace_procfs.get(), atrace_wrapper.get(), table.get());
MockFtraceProcfs* raw_procfs = ftrace_procfs.get();
return std::unique_ptr<TestFtraceController>(new TestFtraceController(
- std::move(ftrace_procfs), std::move(table), std::move(muxer),
- std::move(runner), raw_procfs));
+ std::move(ftrace_procfs), std::move(table), std::move(atrace_wrapper),
+ std::move(muxer), std::move(runner), raw_procfs));
}
} // namespace
diff --git a/src/traced/probes/ftrace/test/data/synthetic/events/fastrpc/fastrpc_dma_alloc/format b/src/traced/probes/ftrace/test/data/synthetic/events/fastrpc/fastrpc_dma_alloc/format
new file mode 100644
index 0000000..77172a3
--- /dev/null
+++ b/src/traced/probes/ftrace/test/data/synthetic/events/fastrpc/fastrpc_dma_alloc/format
@@ -0,0 +1,15 @@
+name: fastrpc_dma_alloc
+ID: 1353
+format:
+ field:unsigned short common_type; offset:0; size:2; signed:0;
+ field:unsigned char common_flags; offset:2; size:1; signed:0;
+ field:unsigned char common_preempt_count; offset:3; size:1; signed:0;
+ field:int common_pid; offset:4; size:4; signed:1;
+
+ field:int cid; offset:8; size:4; signed:1;
+ field:u64 phys; offset:16; size:8; signed:0;
+ field:size_t size; offset:24; size:8; signed:0;
+ field:unsigned long attr; offset:32; size:8; signed:0;
+ field:int mflags; offset:40; size:4; signed:1;
+
+print fmt: "cid %d, phys 0x%llx, size %zu, attr 0x%lx, flags 0x%x", REC->cid, REC->phys, REC->size, REC->attr, REC->mflags
diff --git a/src/traced/probes/ftrace/test/data/synthetic/events/fastrpc/fastrpc_dma_free/format b/src/traced/probes/ftrace/test/data/synthetic/events/fastrpc/fastrpc_dma_free/format
new file mode 100644
index 0000000..44d6e76
--- /dev/null
+++ b/src/traced/probes/ftrace/test/data/synthetic/events/fastrpc/fastrpc_dma_free/format
@@ -0,0 +1,13 @@
+name: fastrpc_dma_free
+ID: 1354
+format:
+ field:unsigned short common_type; offset:0; size:2; signed:0;
+ field:unsigned char common_flags; offset:2; size:1; signed:0;
+ field:unsigned char common_preempt_count; offset:3; size:1; signed:0;
+ field:int common_pid; offset:4; size:4; signed:1;
+
+ field:int cid; offset:8; size:4; signed:1;
+ field:u64 phys; offset:16; size:8; signed:0;
+ field:size_t size; offset:24; size:8; signed:0;
+
+print fmt: "cid %d, phys 0x%llx, size %zu", REC->cid, REC->phys, REC->size
diff --git a/src/traced/probes/ftrace/test/data/synthetic/events/fastrpc/fastrpc_dma_map/format b/src/traced/probes/ftrace/test/data/synthetic/events/fastrpc/fastrpc_dma_map/format
new file mode 100644
index 0000000..6576a1f
--- /dev/null
+++ b/src/traced/probes/ftrace/test/data/synthetic/events/fastrpc/fastrpc_dma_map/format
@@ -0,0 +1,17 @@
+name: fastrpc_dma_map
+ID: 1351
+format:
+ field:unsigned short common_type; offset:0; size:2; signed:0;
+ field:unsigned char common_flags; offset:2; size:1; signed:0;
+ field:unsigned char common_preempt_count; offset:3; size:1; signed:0;
+ field:int common_pid; offset:4; size:4; signed:1;
+
+ field:int cid; offset:8; size:4; signed:1;
+ field:int fd; offset:12; size:4; signed:1;
+ field:u64 phys; offset:16; size:8; signed:0;
+ field:size_t size; offset:24; size:8; signed:0;
+ field:size_t len; offset:32; size:8; signed:0;
+ field:unsigned int attr; offset:40; size:4; signed:0;
+ field:int mflags; offset:44; size:4; signed:1;
+
+print fmt: "cid %d, fd %d, phys 0x%llx, size %zu (len %zu), attr 0x%x, flags 0x%x", REC->cid, REC->fd, REC->phys, REC->size, REC->len, REC->attr, REC->mflags
diff --git a/src/traced/probes/ftrace/test/data/synthetic/events/fastrpc/fastrpc_dma_unmap/format b/src/traced/probes/ftrace/test/data/synthetic/events/fastrpc/fastrpc_dma_unmap/format
new file mode 100644
index 0000000..028495c
--- /dev/null
+++ b/src/traced/probes/ftrace/test/data/synthetic/events/fastrpc/fastrpc_dma_unmap/format
@@ -0,0 +1,13 @@
+name: fastrpc_dma_unmap
+ID: 1352
+format:
+ field:unsigned short common_type; offset:0; size:2; signed:0;
+ field:unsigned char common_flags; offset:2; size:1; signed:0;
+ field:unsigned char common_preempt_count; offset:3; size:1; signed:0;
+ field:int common_pid; offset:4; size:4; signed:1;
+
+ field:int cid; offset:8; size:4; signed:1;
+ field:u64 phys; offset:16; size:8; signed:0;
+ field:size_t size; offset:24; size:8; signed:0;
+
+print fmt: "cid %d, phys 0x%llx, size %zu", REC->cid, REC->phys, REC->size
diff --git a/src/tracing/test/api_integrationtest.cc b/src/tracing/test/api_integrationtest.cc
index ba0d010..b71f0b8 100644
--- a/src/tracing/test/api_integrationtest.cc
+++ b/src/tracing/test/api_integrationtest.cc
@@ -4930,15 +4930,23 @@
// Check that clock snapshots are monotonic and don't contain timestamps from
// trace events with explicit timestamps.
- std::unordered_map<uint64_t, uint64_t> last_clock_ts;
+ struct LastTs {
+ uint64_t ts = 0;
+ uint64_t seq_id = 0;
+ };
+ std::unordered_map<uint64_t, LastTs> last_clock_ts;
for (const auto& packet : trace.packet()) {
if (packet.has_clock_snapshot()) {
for (auto& clock : packet.clock_snapshot().clocks()) {
if (!clock.is_incremental()) {
uint64_t ts = clock.timestamp();
uint64_t id = clock.clock_id();
- EXPECT_LE(last_clock_ts[id], ts);
- last_clock_ts[id] = ts;
+ EXPECT_LE(last_clock_ts[id].ts, ts)
+ << "This sequence:" << packet.trusted_packet_sequence_id()
+ << " prev sequence:" << last_clock_ts[id].seq_id
+ << " clock_id:" << id;
+ last_clock_ts[id].ts = ts;
+ last_clock_ts[id].seq_id = packet.trusted_packet_sequence_id();
}
}
diff --git a/test/data/ui-screenshots/ui-android_trace_30s_expand_camera.png.sha256 b/test/data/ui-screenshots/ui-android_trace_30s_expand_camera.png.sha256
index e82ef5c..a359061 100644
--- a/test/data/ui-screenshots/ui-android_trace_30s_expand_camera.png.sha256
+++ b/test/data/ui-screenshots/ui-android_trace_30s_expand_camera.png.sha256
@@ -1 +1 @@
-c40361fe7a34f3506e0b84d585ea15eb07d111bf0fa49d3976f40738e3448c7a
\ No newline at end of file
+4b4bd13cbae5710efda25c6e2495c7ec5614d348701b9fec1fd554d5b1c61064
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-android_trace_30s_load.png.sha256 b/test/data/ui-screenshots/ui-android_trace_30s_load.png.sha256
index 260ea4f..02b1315 100644
--- a/test/data/ui-screenshots/ui-android_trace_30s_load.png.sha256
+++ b/test/data/ui-screenshots/ui-android_trace_30s_load.png.sha256
@@ -1 +1 @@
-0954283d6fc7beb554ffbaee5afe354aed896a7eeefe2475e14c1ad64327a6f7
\ No newline at end of file
+687a6fc2a478b048bdcbbbfe6231cf3b33463068c8100659a5be0220f41d07fb
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-chrome_missing_track_names_load.png.sha256 b/test/data/ui-screenshots/ui-chrome_missing_track_names_load.png.sha256
index 880b363..ce2d330 100644
--- a/test/data/ui-screenshots/ui-chrome_missing_track_names_load.png.sha256
+++ b/test/data/ui-screenshots/ui-chrome_missing_track_names_load.png.sha256
@@ -1 +1 @@
-8d0cb7b3d4794c4f036fb851dd8a4726e7e6c90f15657b86c06a1fabe2c7984c
\ No newline at end of file
+ce747a5d7a1547aaa238bef8aa7b241d3e16cdc38dd34ef165e57aecb6659a92
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-chrome_rendering_desktop_expand_browser_proc.png.sha256 b/test/data/ui-screenshots/ui-chrome_rendering_desktop_expand_browser_proc.png.sha256
index e327bd1..905ad76 100644
--- a/test/data/ui-screenshots/ui-chrome_rendering_desktop_expand_browser_proc.png.sha256
+++ b/test/data/ui-screenshots/ui-chrome_rendering_desktop_expand_browser_proc.png.sha256
@@ -1 +1 @@
-9e84ad0881a56d3731066604e973b6297dee7b9a602e6b35013560fd0bc8fd39
\ No newline at end of file
+c1fa13737c59bf1eeaa997037ca99117625b4d7956496702734317555ff5a2bc
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-chrome_rendering_desktop_load.png.sha256 b/test/data/ui-screenshots/ui-chrome_rendering_desktop_load.png.sha256
index 1d3de51..de5d8b4 100644
--- a/test/data/ui-screenshots/ui-chrome_rendering_desktop_load.png.sha256
+++ b/test/data/ui-screenshots/ui-chrome_rendering_desktop_load.png.sha256
@@ -1 +1 @@
-eb92c26c12d039aac315e3514bc24ebfcf392914309b28bc83a172127fe60250
\ No newline at end of file
+b1cbf99aeee1bab2eabe0d1495697970535ef350f3d6e6d177ed21d469f3b11e
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-chrome_rendering_desktop_select_slice_with_flows.png.sha256 b/test/data/ui-screenshots/ui-chrome_rendering_desktop_select_slice_with_flows.png.sha256
index 11dfc47..0843823 100644
--- a/test/data/ui-screenshots/ui-chrome_rendering_desktop_select_slice_with_flows.png.sha256
+++ b/test/data/ui-screenshots/ui-chrome_rendering_desktop_select_slice_with_flows.png.sha256
@@ -1 +1 @@
-1d80ba6fc24a1db8252e24e0d4250787bf7da4f6f3f7efe4e71b63a2b42c6e23
\ No newline at end of file
+562482bc25d7a2d34b30d6003d100207e7f1eb0a48ea4549445a340e34a2e3b4
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_navigate_open_trace_from_url.png.sha256 b/test/data/ui-screenshots/ui-routing_navigate_open_trace_from_url.png.sha256
index 97c82b1..24ab368 100644
--- a/test/data/ui-screenshots/ui-routing_navigate_open_trace_from_url.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_navigate_open_trace_from_url.png.sha256
@@ -1 +1 @@
-46d1d64e852be22cb86a7eb6868aea3007ce04c663e9667ae55b71d5a0fad6b7
\ No newline at end of file
+f9b1725cd859b6cccf34d171e8b2e9d87b44a4fc241e9f577ccfde2ae3cc5216
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_open_invalid_trace_from_blank_page.png.sha256 b/test/data/ui-screenshots/ui-routing_open_invalid_trace_from_blank_page.png.sha256
index f60a4ff..fa3e082 100644
--- a/test/data/ui-screenshots/ui-routing_open_invalid_trace_from_blank_page.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_open_invalid_trace_from_blank_page.png.sha256
@@ -1 +1 @@
-cd2fafc00d2f2ab761a7c17a0bdc9e606e3996fe20c17ff7e0b61a0e11c55199
\ No newline at end of file
+82b386830bbfc6287b893331ecffcb1058634868a1bd43cce240b09297f060c7
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_access_subpage_then_go_back.png.sha256 b/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_access_subpage_then_go_back.png.sha256
index c417604..7b76fd1 100644
--- a/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_access_subpage_then_go_back.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_access_subpage_then_go_back.png.sha256
@@ -1 +1 @@
-049301241729848f47474868766daf513e7f739efddbfc3dc3f96200f9b63bc6
\ No newline at end of file
+431b27cc6333c21aac4bf681ab9d7f06e096f340f7913f1c1e3a943d4c4f0111
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_open_first_trace_from_url.png.sha256 b/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_open_first_trace_from_url.png.sha256
index 97c82b1..24ab368 100644
--- a/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_open_first_trace_from_url.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_open_first_trace_from_url.png.sha256
@@ -1 +1 @@
-46d1d64e852be22cb86a7eb6868aea3007ce04c663e9667ae55b71d5a0fad6b7
\ No newline at end of file
+f9b1725cd859b6cccf34d171e8b2e9d87b44a4fc241e9f577ccfde2ae3cc5216
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_open_second_trace_from_url.png.sha256 b/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_open_second_trace_from_url.png.sha256
index c417604..7b76fd1 100644
--- a/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_open_second_trace_from_url.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_open_second_trace_from_url.png.sha256
@@ -1 +1 @@
-049301241729848f47474868766daf513e7f739efddbfc3dc3f96200f9b63bc6
\ No newline at end of file
+431b27cc6333c21aac4bf681ab9d7f06e096f340f7913f1c1e3a943d4c4f0111
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_start_from_no_trace_go_back_to_first_trace.png.sha256 b/test/data/ui-screenshots/ui-routing_start_from_no_trace_go_back_to_first_trace.png.sha256
index c417604..7b76fd1 100644
--- a/test/data/ui-screenshots/ui-routing_start_from_no_trace_go_back_to_first_trace.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_start_from_no_trace_go_back_to_first_trace.png.sha256
@@ -1 +1 @@
-049301241729848f47474868766daf513e7f739efddbfc3dc3f96200f9b63bc6
\ No newline at end of file
+431b27cc6333c21aac4bf681ab9d7f06e096f340f7913f1c1e3a943d4c4f0111
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_start_from_no_trace_open_invalid_trace.png.sha256 b/test/data/ui-screenshots/ui-routing_start_from_no_trace_open_invalid_trace.png.sha256
index c69fd14..a902763 100644
--- a/test/data/ui-screenshots/ui-routing_start_from_no_trace_open_invalid_trace.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_start_from_no_trace_open_invalid_trace.png.sha256
@@ -1 +1 @@
-4b0c253d17c45c7e787e7b9cc484a9c0af38bcf77a92645266f15879af92d8e2
\ No newline at end of file
+eeb0625eb5286e0ca40b5d308608714ae7da0ca67d6bf07fac314a6639b5ddb5
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_start_from_no_trace_open_second_trace.png.sha256 b/test/data/ui-screenshots/ui-routing_start_from_no_trace_open_second_trace.png.sha256
index 97c82b1..24ab368 100644
--- a/test/data/ui-screenshots/ui-routing_start_from_no_trace_open_second_trace.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_start_from_no_trace_open_second_trace.png.sha256
@@ -1 +1 @@
-46d1d64e852be22cb86a7eb6868aea3007ce04c663e9667ae55b71d5a0fad6b7
\ No newline at end of file
+f9b1725cd859b6cccf34d171e8b2e9d87b44a4fc241e9f577ccfde2ae3cc5216
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_start_from_no_trace_open_trace_.png.sha256 b/test/data/ui-screenshots/ui-routing_start_from_no_trace_open_trace_.png.sha256
index c417604..7b76fd1 100644
--- a/test/data/ui-screenshots/ui-routing_start_from_no_trace_open_trace_.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_start_from_no_trace_open_trace_.png.sha256
@@ -1 +1 @@
-049301241729848f47474868766daf513e7f739efddbfc3dc3f96200f9b63bc6
\ No newline at end of file
+431b27cc6333c21aac4bf681ab9d7f06e096f340f7913f1c1e3a943d4c4f0111
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_start_from_no_trace_refresh.png.sha256 b/test/data/ui-screenshots/ui-routing_start_from_no_trace_refresh.png.sha256
index c417604..7b76fd1 100644
--- a/test/data/ui-screenshots/ui-routing_start_from_no_trace_refresh.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_start_from_no_trace_refresh.png.sha256
@@ -1 +1 @@
-049301241729848f47474868766daf513e7f739efddbfc3dc3f96200f9b63bc6
\ No newline at end of file
+431b27cc6333c21aac4bf681ab9d7f06e096f340f7913f1c1e3a943d4c4f0111
\ No newline at end of file
diff --git a/test/trace_processor/diff_tests/syntax/table_tests.py b/test/trace_processor/diff_tests/syntax/table_tests.py
index 0125c72..2eba2b0 100644
--- a/test/trace_processor/diff_tests/syntax/table_tests.py
+++ b/test/trace_processor/diff_tests/syntax/table_tests.py
@@ -78,6 +78,7 @@
3,"perfetto_table_info","track_id","uint32",0,0
4,"perfetto_table_info","value","double",0,0
5,"perfetto_table_info","arg_set_id","uint32",1,0
+ 6,"perfetto_table_info","machine_id","uint32",1,0
"""))
def test_perfetto_table_info_runtime_table(self):
diff --git a/test/trace_processor/diff_tests/tables/tests_sched.py b/test/trace_processor/diff_tests/tables/tests_sched.py
index c2ad002..306b8e8 100644
--- a/test/trace_processor/diff_tests/tables/tests_sched.py
+++ b/test/trace_processor/diff_tests/tables/tests_sched.py
@@ -124,7 +124,8 @@
return DiffTestBlueprint(
trace=DataPath('sched_wakeup_trace.atr'),
query="""
- SELECT * FROM raw WHERE common_flags != 0 ORDER BY ts LIMIT 10
+ SELECT id, type, ts, name, cpu, utid, arg_set_id, common_flags
+ FROM raw WHERE common_flags != 0 ORDER BY ts LIMIT 10
""",
out=Csv("""
"id","type","ts","name","cpu","utid","arg_set_id","common_flags"
diff --git a/tools/cpu_profile b/tools/cpu_profile
index 9d84d12..17f0996 100755
--- a/tools/cpu_profile
+++ b/tools/cpu_profile
@@ -37,18 +37,18 @@
# ----- Amalgamator: begin of python/perfetto/prebuilts/manifests/traceconv.py
-# This file has been generated by: tools/roll-prebuilts v43.2
+# This file has been generated by: tools/roll-prebuilts v44.0
TRACECONV_MANIFEST = [{
'arch':
'mac-amd64',
'file_name':
'traceconv',
'file_size':
- 7790424,
+ 8069808,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/mac-amd64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/mac-amd64/traceconv',
'sha256':
- 'c1d9c50c89545b41af88525dc6f3ce508156ed3787ccecae0ff7c8e736c39318',
+ '7d9c0421235c083932408a5a716372dfddc3a87828b2b3b7e30f8d3aa1c5bf43',
'platform':
'darwin',
'machine': ['x86_64']
@@ -58,11 +58,11 @@
'file_name':
'traceconv',
'file_size':
- 7264824,
+ 7529704,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/mac-arm64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/mac-arm64/traceconv',
'sha256':
- 'df5349ae462dbd7c1ca9a1b8a0f09c044a47026d6ad8dc24e6945701d7c61a84',
+ 'bffadacd2a6e44a9f5c7b0beb48f3f5d568433fd9d425cdee5342e7f3c112cbb',
'platform':
'darwin',
'machine': ['arm64']
@@ -72,11 +72,11 @@
'file_name':
'traceconv',
'file_size':
- 7885952,
+ 8152216,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/linux-amd64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/linux-amd64/traceconv',
'sha256':
- 'b2c19364c1fb68e9f5cde610e5d71dd59b9fdf2bada8f7e1eefc319f828f7cb1',
+ 'b1815e29aabb51deff0c68e3e690c96aedfea0796a0292d5f177815d33584995',
'platform':
'linux',
'machine': ['x86_64']
@@ -86,11 +86,11 @@
'file_name':
'traceconv',
'file_size':
- 5919372,
+ 6132076,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/linux-arm/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/linux-arm/traceconv',
'sha256':
- 'b669be326b4b6a024e557e0927f1014fd1ea5d5427e194dc0653f21acac273ee',
+ '2b391081ce9ce45d843584816bc11ba7383b634c88ffa75c7dc927a9632e6d28',
'platform':
'linux',
'machine': ['armv6l', 'armv7l', 'armv8l']
@@ -100,11 +100,11 @@
'file_name':
'traceconv',
'file_size':
- 7588200,
+ 7862696,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/linux-arm64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/linux-arm64/traceconv',
'sha256':
- 'aff1c4751e721733ce85f58048c17971399fe605a81ac300d306c200d6957818',
+ 'd10a598fb6c14926ceb3afb0fc9841a4924c2fedadf9ef981609781ecb8b338b',
'platform':
'linux',
'machine': ['aarch64']
@@ -114,55 +114,55 @@
'file_name':
'traceconv',
'file_size':
- 5931120,
+ 6131288,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/android-arm/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/android-arm/traceconv',
'sha256':
- '826212f658fef744fbaeea66331b6fe7ca0152f69cf63ff2ea218a376d5d41d9'
+ '3cf391f42bb51e47159b2236b1171cd1bd4461f3e4576b00100f590cf7ff8b2b'
}, {
'arch':
'android-arm64',
'file_name':
'traceconv',
'file_size':
- 7546224,
+ 7798968,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/android-arm64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/android-arm64/traceconv',
'sha256':
- '29dd7e93e9182c4413a9f9c1c6a6f643f64e1fe0b9657ab1ea3cec8b0bb360c9'
+ '1b17a740ba86a5e218b69dd981d739173515777ee761f3723446f6e400e9367e'
}, {
'arch':
'android-x86',
'file_name':
'traceconv',
'file_size':
- 8176528,
+ 8464080,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/android-x86/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/android-x86/traceconv',
'sha256':
- '63c2ebe7ed51f9667bcf69d7b9679f6077db5fd8ee9e1be7b786037e2a649fcb'
+ '2dc045a79276e62f71cf40c1e8ee433125785ce32a223ce4c9e5871cacc3940e'
}, {
'arch':
'android-x64',
'file_name':
'traceconv',
'file_size':
- 7767560,
+ 8025896,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/android-x64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/android-x64/traceconv',
'sha256':
- 'bb9350230c2fac5adf9e6fe21937865b6eaafaefc555ae26e68cae9419ad5ee8'
+ '03db509df8e3816b4c4d78d187d42794b37c3d2c830d85feae0f17a5b581ee53'
}, {
'arch':
'windows-amd64',
'file_name':
'traceconv.exe',
'file_size':
- 7645696,
+ 7920128,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/windows-amd64/traceconv.exe',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/windows-amd64/traceconv.exe',
'sha256':
- '0c84b712941e4f63f74e66731745f94aec3cd30d94469e52cdf1143262f063a4',
+ '97b66259d385a5bd482ebb5a21535b67e3836fb0cf7c971bb36d5f5ea00774bd',
'platform':
'win32',
'machine': ['amd64']
diff --git a/tools/heap_profile b/tools/heap_profile
index 39249bb..700cfeb 100755
--- a/tools/heap_profile
+++ b/tools/heap_profile
@@ -34,18 +34,18 @@
# ----- Amalgamator: begin of python/perfetto/prebuilts/manifests/traceconv.py
-# This file has been generated by: tools/roll-prebuilts v43.2
+# This file has been generated by: tools/roll-prebuilts v44.0
TRACECONV_MANIFEST = [{
'arch':
'mac-amd64',
'file_name':
'traceconv',
'file_size':
- 7790424,
+ 8069808,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/mac-amd64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/mac-amd64/traceconv',
'sha256':
- 'c1d9c50c89545b41af88525dc6f3ce508156ed3787ccecae0ff7c8e736c39318',
+ '7d9c0421235c083932408a5a716372dfddc3a87828b2b3b7e30f8d3aa1c5bf43',
'platform':
'darwin',
'machine': ['x86_64']
@@ -55,11 +55,11 @@
'file_name':
'traceconv',
'file_size':
- 7264824,
+ 7529704,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/mac-arm64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/mac-arm64/traceconv',
'sha256':
- 'df5349ae462dbd7c1ca9a1b8a0f09c044a47026d6ad8dc24e6945701d7c61a84',
+ 'bffadacd2a6e44a9f5c7b0beb48f3f5d568433fd9d425cdee5342e7f3c112cbb',
'platform':
'darwin',
'machine': ['arm64']
@@ -69,11 +69,11 @@
'file_name':
'traceconv',
'file_size':
- 7885952,
+ 8152216,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/linux-amd64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/linux-amd64/traceconv',
'sha256':
- 'b2c19364c1fb68e9f5cde610e5d71dd59b9fdf2bada8f7e1eefc319f828f7cb1',
+ 'b1815e29aabb51deff0c68e3e690c96aedfea0796a0292d5f177815d33584995',
'platform':
'linux',
'machine': ['x86_64']
@@ -83,11 +83,11 @@
'file_name':
'traceconv',
'file_size':
- 5919372,
+ 6132076,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/linux-arm/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/linux-arm/traceconv',
'sha256':
- 'b669be326b4b6a024e557e0927f1014fd1ea5d5427e194dc0653f21acac273ee',
+ '2b391081ce9ce45d843584816bc11ba7383b634c88ffa75c7dc927a9632e6d28',
'platform':
'linux',
'machine': ['armv6l', 'armv7l', 'armv8l']
@@ -97,11 +97,11 @@
'file_name':
'traceconv',
'file_size':
- 7588200,
+ 7862696,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/linux-arm64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/linux-arm64/traceconv',
'sha256':
- 'aff1c4751e721733ce85f58048c17971399fe605a81ac300d306c200d6957818',
+ 'd10a598fb6c14926ceb3afb0fc9841a4924c2fedadf9ef981609781ecb8b338b',
'platform':
'linux',
'machine': ['aarch64']
@@ -111,55 +111,55 @@
'file_name':
'traceconv',
'file_size':
- 5931120,
+ 6131288,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/android-arm/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/android-arm/traceconv',
'sha256':
- '826212f658fef744fbaeea66331b6fe7ca0152f69cf63ff2ea218a376d5d41d9'
+ '3cf391f42bb51e47159b2236b1171cd1bd4461f3e4576b00100f590cf7ff8b2b'
}, {
'arch':
'android-arm64',
'file_name':
'traceconv',
'file_size':
- 7546224,
+ 7798968,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/android-arm64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/android-arm64/traceconv',
'sha256':
- '29dd7e93e9182c4413a9f9c1c6a6f643f64e1fe0b9657ab1ea3cec8b0bb360c9'
+ '1b17a740ba86a5e218b69dd981d739173515777ee761f3723446f6e400e9367e'
}, {
'arch':
'android-x86',
'file_name':
'traceconv',
'file_size':
- 8176528,
+ 8464080,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/android-x86/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/android-x86/traceconv',
'sha256':
- '63c2ebe7ed51f9667bcf69d7b9679f6077db5fd8ee9e1be7b786037e2a649fcb'
+ '2dc045a79276e62f71cf40c1e8ee433125785ce32a223ce4c9e5871cacc3940e'
}, {
'arch':
'android-x64',
'file_name':
'traceconv',
'file_size':
- 7767560,
+ 8025896,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/android-x64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/android-x64/traceconv',
'sha256':
- 'bb9350230c2fac5adf9e6fe21937865b6eaafaefc555ae26e68cae9419ad5ee8'
+ '03db509df8e3816b4c4d78d187d42794b37c3d2c830d85feae0f17a5b581ee53'
}, {
'arch':
'windows-amd64',
'file_name':
'traceconv.exe',
'file_size':
- 7645696,
+ 7920128,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/windows-amd64/traceconv.exe',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/windows-amd64/traceconv.exe',
'sha256':
- '0c84b712941e4f63f74e66731745f94aec3cd30d94469e52cdf1143262f063a4',
+ '97b66259d385a5bd482ebb5a21535b67e3836fb0cf7c971bb36d5f5ea00774bd',
'platform':
'win32',
'machine': ['amd64']
diff --git a/tools/record_android_trace b/tools/record_android_trace
index f77222b..ceb0808 100755
--- a/tools/record_android_trace
+++ b/tools/record_android_trace
@@ -33,18 +33,18 @@
# ----- Amalgamator: begin of python/perfetto/prebuilts/manifests/tracebox.py
-# This file has been generated by: tools/roll-prebuilts v43.2
+# This file has been generated by: tools/roll-prebuilts v44.0
TRACEBOX_MANIFEST = [{
'arch':
'mac-amd64',
'file_name':
'tracebox',
'file_size':
- 1564728,
+ 1548256,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/mac-amd64/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/mac-amd64/tracebox',
'sha256':
- '239736808cbfba5085892e15c145381ea37ddba5df7c8fad97b68d9c04a4d860',
+ '392cb1ae5f11c6a87d15e69fb6576e5c62ae3b1d87a43d68d7fe8bd3cea4fd7e',
'platform':
'darwin',
'machine': ['x86_64']
@@ -54,11 +54,11 @@
'file_name':
'tracebox',
'file_size':
- 1459160,
+ 1459096,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/mac-arm64/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/mac-arm64/tracebox',
'sha256':
- '4af1449dc90e5505bd5f3d638f11b8bf7e5dc82c0290f0085dc0b335ababd143',
+ '0edde5e3d35ef044848eeca5f63da7fa9f96e4bb3cac5e87ba4e2772a09e8f8f',
'platform':
'darwin',
'machine': ['arm64']
@@ -68,11 +68,11 @@
'file_name':
'tracebox',
'file_size':
- 2314424,
+ 2304304,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/linux-amd64/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/linux-amd64/tracebox',
'sha256':
- 'a97a5efdaf475f13f4f5947c03289029253f89d0f44caa64765b00b269551297',
+ 'cd2b3c0fdc7d0a649bbe4103901263927b2f736836ce56fa06467efa5c825472',
'platform':
'linux',
'machine': ['x86_64']
@@ -82,11 +82,11 @@
'file_name':
'tracebox',
'file_size':
- 1418968,
+ 1408648,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/linux-arm/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/linux-arm/tracebox',
'sha256':
- '818390305d15730fadcbd87dc3c8d87a439e040a02b5098f51af15dfff3f0ca0',
+ '51794d99493c04ced26a40a242ddb6a53b1213ee96b0b1af9ba874715656ff06',
'platform':
'linux',
'machine': ['armv6l', 'armv7l', 'armv8l']
@@ -96,11 +96,11 @@
'file_name':
'tracebox',
'file_size':
- 2221176,
+ 2212000,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/linux-arm64/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/linux-arm64/tracebox',
'sha256':
- '5a3cf8c755e08b7a558083a70ad28293baa389e544ebd09806b6a883a5f17952',
+ '7faf03feecf045ed25bfad7cb845621c533ca50b586e722e1bb61aa7fd54cd74',
'platform':
'linux',
'machine': ['aarch64']
@@ -110,44 +110,44 @@
'file_name':
'tracebox',
'file_size':
- 1304280,
+ 1299200,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/android-arm/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/android-arm/tracebox',
'sha256':
- '87bb07c7ac4c58d306975cabad3ed5d4b6fe11a8d617dad30fe7dd25bfdc6736'
+ 'fa78644befc527481dac76b217762cbddb9233cc050c2a31444c78391ed7715c'
}, {
'arch':
'android-arm64',
'file_name':
'tracebox',
'file_size':
- 2076144,
+ 2067768,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/android-arm64/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/android-arm64/tracebox',
'sha256':
- '501b2bb0cba0ecb770e2b568698f89f6b42d083fcca111c872f7a0e95c0cacc5'
+ 'f3167ce57aec78e200675640a683a938bcb206219346427e42f86fdc70923386'
}, {
'arch':
'android-x86',
'file_name':
'tracebox',
'file_size':
- 2253568,
+ 2241784,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/android-x86/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/android-x86/tracebox',
'sha256':
- '28be4f88a9b8f950ebc45a20d4844002f9b3f81ef0230d0a5d9b1627cf89c9a5'
+ '9c9a4b1c498c985c3fbbd9122a9df66bb5275c715c54475d7fbabfec5722d50a'
}, {
'arch':
'android-x64',
'file_name':
'tracebox',
'file_size':
- 2101752,
+ 2092696,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/android-x64/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/android-x64/tracebox',
'sha256':
- '6c08b743b9cb6073a75e2b3dd34098e09e3c8bcace89096dc5b9d0f071b2831a'
+ '96fdc7b584247a2f4fc18d4a4a8e8891ab88693c8bc7a301e8dffb3ec8b96a1d'
}]
# ----- Amalgamator: end of python/perfetto/prebuilts/manifests/tracebox.py
diff --git a/tools/trace_processor b/tools/trace_processor
index ba2a38b..0917f54 100755
--- a/tools/trace_processor
+++ b/tools/trace_processor
@@ -30,18 +30,18 @@
# ----- Amalgamator: begin of python/perfetto/prebuilts/manifests/trace_processor_shell.py
-# This file has been generated by: tools/roll-prebuilts v43.2
+# This file has been generated by: tools/roll-prebuilts v44.0
TRACE_PROCESSOR_SHELL_MANIFEST = [{
'arch':
'mac-amd64',
'file_name':
'trace_processor_shell',
'file_size':
- 8583624,
+ 8879352,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/mac-amd64/trace_processor_shell',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/mac-amd64/trace_processor_shell',
'sha256':
- 'a1c16a74725cefb62406b39538b5d22f56a94e390a0394816d2945793f91f8cf',
+ '8ac591150919d5e3701a3fdb7ce44f2ae9b48a4b27afc2da31b97dba3238c4c8',
'platform':
'darwin',
'machine': ['x86_64']
@@ -51,11 +51,11 @@
'file_name':
'trace_processor_shell',
'file_size':
- 7980232,
+ 8261544,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/mac-arm64/trace_processor_shell',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/mac-arm64/trace_processor_shell',
'sha256':
- '3651654cd462df8a2ec8cb3f7375cee01ccc11861a675b9da0d00aa697efe7b2',
+ '55ef799a383fb460e0167fad68b8f169d6d46bc10285df9db26cecec52dd24f1',
'platform':
'darwin',
'machine': ['arm64']
@@ -65,11 +65,11 @@
'file_name':
'trace_processor_shell',
'file_size':
- 8770200,
+ 9035064,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/linux-amd64/trace_processor_shell',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/linux-amd64/trace_processor_shell',
'sha256':
- '0796a01af496a6b62623fea89b2d34063ade9d156783e1f88949d8b7ab1f76d0',
+ 'd4826f1c2acf0a4caaa167bc089d12a1e6460fcd2847ec8c026933ed73d30540',
'platform':
'linux',
'machine': ['x86_64']
@@ -79,11 +79,11 @@
'file_name':
'trace_processor_shell',
'file_size':
- 6371036,
+ 6581588,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/linux-arm/trace_processor_shell',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/linux-arm/trace_processor_shell',
'sha256':
- 'f4bbef5008de376913c3a95410802d94d8d5715439c3f797be0e4ca8c9bccb1a',
+ '1918aa71521e3daaeedadd9a0760f597c94c3baa803836e442f54c584dc402ac',
'platform':
'linux',
'machine': ['armv6l', 'armv7l', 'armv8l']
@@ -93,11 +93,11 @@
'file_name':
'trace_processor_shell',
'file_size':
- 8425776,
+ 8698104,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/linux-arm64/trace_processor_shell',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/linux-arm64/trace_processor_shell',
'sha256':
- 'f1ff5585a06ad8b9fc1d13dbf8d02f39d2804019ea7e70b740872e0f6826695f',
+ '9b4e77e541bf397bcdb4f51b30b0cea23aea761865c5bebdac424b15beecdf18',
'platform':
'linux',
'machine': ['aarch64']
@@ -107,55 +107,55 @@
'file_name':
'trace_processor_shell',
'file_size':
- 6382140,
+ 6581420,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/android-arm/trace_processor_shell',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/android-arm/trace_processor_shell',
'sha256':
- '989b209a108c7d44e2531bb15a5d57f667c717cf774bb8a4a810f99fda0b958d'
+ 'cdf7d4f0ad38f977f20d52c2d881f5aeac3ad1a9b07032dee32b08ee631ad041'
}, {
'arch':
'android-arm64',
'file_name':
'trace_processor_shell',
'file_size':
- 8340616,
+ 8592256,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/android-arm64/trace_processor_shell',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/android-arm64/trace_processor_shell',
'sha256':
- 'ade7e72990cb97fd74766cd0df50a24cbd547d2f54c26b49d66236c809922645'
+ '8df9e4e01509184fe5d65f79af343384f8e11f90eabebe8075cf779d6d82304d'
}, {
'arch':
'android-x86',
'file_name':
'trace_processor_shell',
'file_size':
- 9170488,
+ 9457000,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/android-x86/trace_processor_shell',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/android-x86/trace_processor_shell',
'sha256':
- '6bd1f74616fd8f620fbf3228f83301844adae08a772b8ac2a64703724a79b516'
+ 'd0404998a661864dfabb440a1227ded43c6e793741675576c863460ce869bead'
}, {
'arch':
'android-x64',
'file_name':
'trace_processor_shell',
'file_size':
- 8591040,
+ 8848144,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/android-x64/trace_processor_shell',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/android-x64/trace_processor_shell',
'sha256':
- '1ccbcb8b2928615cf512cf97eaba395de6f1fc5d70313e884ea3975867f365ea'
+ '8e5a539457f8a50b898a2f2178acd14d7f4076a6a10bbc030a7c2a8cb229b57f'
}, {
'arch':
'windows-amd64',
'file_name':
'trace_processor_shell.exe',
'file_size':
- 8676352,
+ 8951296,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/windows-amd64/trace_processor_shell.exe',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/windows-amd64/trace_processor_shell.exe',
'sha256':
- '9125418fedd96eb0e6f1ddeaf46069a05bdcb910592b059669fc982b4fff3f1b',
+ 'd01a7d0c3bd460a041fdd25cba88163d945ef939f48de3c76cdc554e19321419',
'platform':
'win32',
'machine': ['amd64']
diff --git a/tools/tracebox b/tools/tracebox
index 496fe43..a9a89e6 100755
--- a/tools/tracebox
+++ b/tools/tracebox
@@ -30,18 +30,18 @@
# ----- Amalgamator: begin of python/perfetto/prebuilts/manifests/tracebox.py
-# This file has been generated by: tools/roll-prebuilts v43.2
+# This file has been generated by: tools/roll-prebuilts v44.0
TRACEBOX_MANIFEST = [{
'arch':
'mac-amd64',
'file_name':
'tracebox',
'file_size':
- 1564728,
+ 1548256,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/mac-amd64/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/mac-amd64/tracebox',
'sha256':
- '239736808cbfba5085892e15c145381ea37ddba5df7c8fad97b68d9c04a4d860',
+ '392cb1ae5f11c6a87d15e69fb6576e5c62ae3b1d87a43d68d7fe8bd3cea4fd7e',
'platform':
'darwin',
'machine': ['x86_64']
@@ -51,11 +51,11 @@
'file_name':
'tracebox',
'file_size':
- 1459160,
+ 1459096,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/mac-arm64/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/mac-arm64/tracebox',
'sha256':
- '4af1449dc90e5505bd5f3d638f11b8bf7e5dc82c0290f0085dc0b335ababd143',
+ '0edde5e3d35ef044848eeca5f63da7fa9f96e4bb3cac5e87ba4e2772a09e8f8f',
'platform':
'darwin',
'machine': ['arm64']
@@ -65,11 +65,11 @@
'file_name':
'tracebox',
'file_size':
- 2314424,
+ 2304304,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/linux-amd64/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/linux-amd64/tracebox',
'sha256':
- 'a97a5efdaf475f13f4f5947c03289029253f89d0f44caa64765b00b269551297',
+ 'cd2b3c0fdc7d0a649bbe4103901263927b2f736836ce56fa06467efa5c825472',
'platform':
'linux',
'machine': ['x86_64']
@@ -79,11 +79,11 @@
'file_name':
'tracebox',
'file_size':
- 1418968,
+ 1408648,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/linux-arm/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/linux-arm/tracebox',
'sha256':
- '818390305d15730fadcbd87dc3c8d87a439e040a02b5098f51af15dfff3f0ca0',
+ '51794d99493c04ced26a40a242ddb6a53b1213ee96b0b1af9ba874715656ff06',
'platform':
'linux',
'machine': ['armv6l', 'armv7l', 'armv8l']
@@ -93,11 +93,11 @@
'file_name':
'tracebox',
'file_size':
- 2221176,
+ 2212000,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/linux-arm64/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/linux-arm64/tracebox',
'sha256':
- '5a3cf8c755e08b7a558083a70ad28293baa389e544ebd09806b6a883a5f17952',
+ '7faf03feecf045ed25bfad7cb845621c533ca50b586e722e1bb61aa7fd54cd74',
'platform':
'linux',
'machine': ['aarch64']
@@ -107,44 +107,44 @@
'file_name':
'tracebox',
'file_size':
- 1304280,
+ 1299200,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/android-arm/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/android-arm/tracebox',
'sha256':
- '87bb07c7ac4c58d306975cabad3ed5d4b6fe11a8d617dad30fe7dd25bfdc6736'
+ 'fa78644befc527481dac76b217762cbddb9233cc050c2a31444c78391ed7715c'
}, {
'arch':
'android-arm64',
'file_name':
'tracebox',
'file_size':
- 2076144,
+ 2067768,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/android-arm64/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/android-arm64/tracebox',
'sha256':
- '501b2bb0cba0ecb770e2b568698f89f6b42d083fcca111c872f7a0e95c0cacc5'
+ 'f3167ce57aec78e200675640a683a938bcb206219346427e42f86fdc70923386'
}, {
'arch':
'android-x86',
'file_name':
'tracebox',
'file_size':
- 2253568,
+ 2241784,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/android-x86/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/android-x86/tracebox',
'sha256':
- '28be4f88a9b8f950ebc45a20d4844002f9b3f81ef0230d0a5d9b1627cf89c9a5'
+ '9c9a4b1c498c985c3fbbd9122a9df66bb5275c715c54475d7fbabfec5722d50a'
}, {
'arch':
'android-x64',
'file_name':
'tracebox',
'file_size':
- 2101752,
+ 2092696,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/android-x64/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/android-x64/tracebox',
'sha256':
- '6c08b743b9cb6073a75e2b3dd34098e09e3c8bcace89096dc5b9d0f071b2831a'
+ '96fdc7b584247a2f4fc18d4a4a8e8891ab88693c8bc7a301e8dffb3ec8b96a1d'
}]
# ----- Amalgamator: end of python/perfetto/prebuilts/manifests/tracebox.py
diff --git a/tools/traceconv b/tools/traceconv
index dba29fa..8ba7114 100755
--- a/tools/traceconv
+++ b/tools/traceconv
@@ -30,18 +30,18 @@
# ----- Amalgamator: begin of python/perfetto/prebuilts/manifests/traceconv.py
-# This file has been generated by: tools/roll-prebuilts v43.2
+# This file has been generated by: tools/roll-prebuilts v44.0
TRACECONV_MANIFEST = [{
'arch':
'mac-amd64',
'file_name':
'traceconv',
'file_size':
- 7790424,
+ 8069808,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/mac-amd64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/mac-amd64/traceconv',
'sha256':
- 'c1d9c50c89545b41af88525dc6f3ce508156ed3787ccecae0ff7c8e736c39318',
+ '7d9c0421235c083932408a5a716372dfddc3a87828b2b3b7e30f8d3aa1c5bf43',
'platform':
'darwin',
'machine': ['x86_64']
@@ -51,11 +51,11 @@
'file_name':
'traceconv',
'file_size':
- 7264824,
+ 7529704,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/mac-arm64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/mac-arm64/traceconv',
'sha256':
- 'df5349ae462dbd7c1ca9a1b8a0f09c044a47026d6ad8dc24e6945701d7c61a84',
+ 'bffadacd2a6e44a9f5c7b0beb48f3f5d568433fd9d425cdee5342e7f3c112cbb',
'platform':
'darwin',
'machine': ['arm64']
@@ -65,11 +65,11 @@
'file_name':
'traceconv',
'file_size':
- 7885952,
+ 8152216,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/linux-amd64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/linux-amd64/traceconv',
'sha256':
- 'b2c19364c1fb68e9f5cde610e5d71dd59b9fdf2bada8f7e1eefc319f828f7cb1',
+ 'b1815e29aabb51deff0c68e3e690c96aedfea0796a0292d5f177815d33584995',
'platform':
'linux',
'machine': ['x86_64']
@@ -79,11 +79,11 @@
'file_name':
'traceconv',
'file_size':
- 5919372,
+ 6132076,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/linux-arm/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/linux-arm/traceconv',
'sha256':
- 'b669be326b4b6a024e557e0927f1014fd1ea5d5427e194dc0653f21acac273ee',
+ '2b391081ce9ce45d843584816bc11ba7383b634c88ffa75c7dc927a9632e6d28',
'platform':
'linux',
'machine': ['armv6l', 'armv7l', 'armv8l']
@@ -93,11 +93,11 @@
'file_name':
'traceconv',
'file_size':
- 7588200,
+ 7862696,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/linux-arm64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/linux-arm64/traceconv',
'sha256':
- 'aff1c4751e721733ce85f58048c17971399fe605a81ac300d306c200d6957818',
+ 'd10a598fb6c14926ceb3afb0fc9841a4924c2fedadf9ef981609781ecb8b338b',
'platform':
'linux',
'machine': ['aarch64']
@@ -107,55 +107,55 @@
'file_name':
'traceconv',
'file_size':
- 5931120,
+ 6131288,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/android-arm/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/android-arm/traceconv',
'sha256':
- '826212f658fef744fbaeea66331b6fe7ca0152f69cf63ff2ea218a376d5d41d9'
+ '3cf391f42bb51e47159b2236b1171cd1bd4461f3e4576b00100f590cf7ff8b2b'
}, {
'arch':
'android-arm64',
'file_name':
'traceconv',
'file_size':
- 7546224,
+ 7798968,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/android-arm64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/android-arm64/traceconv',
'sha256':
- '29dd7e93e9182c4413a9f9c1c6a6f643f64e1fe0b9657ab1ea3cec8b0bb360c9'
+ '1b17a740ba86a5e218b69dd981d739173515777ee761f3723446f6e400e9367e'
}, {
'arch':
'android-x86',
'file_name':
'traceconv',
'file_size':
- 8176528,
+ 8464080,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/android-x86/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/android-x86/traceconv',
'sha256':
- '63c2ebe7ed51f9667bcf69d7b9679f6077db5fd8ee9e1be7b786037e2a649fcb'
+ '2dc045a79276e62f71cf40c1e8ee433125785ce32a223ce4c9e5871cacc3940e'
}, {
'arch':
'android-x64',
'file_name':
'traceconv',
'file_size':
- 7767560,
+ 8025896,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/android-x64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/android-x64/traceconv',
'sha256':
- 'bb9350230c2fac5adf9e6fe21937865b6eaafaefc555ae26e68cae9419ad5ee8'
+ '03db509df8e3816b4c4d78d187d42794b37c3d2c830d85feae0f17a5b581ee53'
}, {
'arch':
'windows-amd64',
'file_name':
'traceconv.exe',
'file_size':
- 7645696,
+ 7920128,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v43.2/windows-amd64/traceconv.exe',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v44.0/windows-amd64/traceconv.exe',
'sha256':
- '0c84b712941e4f63f74e66731745f94aec3cd30d94469e52cdf1143262f063a4',
+ '97b66259d385a5bd482ebb5a21535b67e3836fb0cf7c971bb36d5f5ea00774bd',
'platform':
'win32',
'machine': ['amd64']
diff --git a/ui/src/assets/track_panel.scss b/ui/src/assets/track_panel.scss
index 5025959..747014d 100644
--- a/ui/src/assets/track_panel.scss
+++ b/ui/src/assets/track_panel.scss
@@ -44,6 +44,7 @@
display: grid;
grid-template-columns: auto 1fr;
grid-template-rows: 1fr 0;
+ container-type: size;
&::after {
display: block;
@@ -56,15 +57,28 @@
.track-shell {
@include transition();
- padding-left: 10px;
- display: grid;
cursor: grab;
- grid-template-areas: "title buttons";
- grid-template-columns: 1fr auto;
- align-items: center;
width: var(--track-shell-width);
border-right: 1px solid #c7d0db;
- overflow: hidden;
+
+ .track-menubar {
+ position: sticky;
+ top: 0;
+ display: grid;
+ padding-block: 6px;
+ padding-left: 10px;
+ padding-right: 2px;
+ grid-template-areas: "title buttons";
+ grid-template-columns: 1fr auto;
+ }
+
+ .pf-visible-on-hover {
+ visibility: hidden;
+ }
+
+ &:hover .pf-visible-on-hover {
+ visibility: visible;
+ }
&.drag {
background-color: #eee;
@@ -99,33 +113,9 @@
display: flex;
height: 100%;
align-items: center;
- }
- .track-button {
- @include transition();
- color: rgb(60, 86, 136);
- cursor: pointer;
- width: 22px;
font-size: 18px;
- visibility: hidden;
}
- .track-button.show {
- visibility: visible;
- }
- .track-button.full-height {
- display: flex;
- height: 100%;
- align-items: center;
- justify-content: center;
-
- &:hover {
- background-color: #ebeef9;
- }
- }
-
- &:hover .track-button {
- visibility: visible;
- }
&.flash {
background-color: #ffe263;
}
@@ -137,6 +127,12 @@
grid-template-columns: auto 1fr;
grid-template-rows: 1fr;
height: 40px;
+
+ .shell {
+ border-right: 1px solid transparent;
+ padding-right: 2px;
+ }
+
&::after {
display: block;
content: "";
@@ -168,10 +164,10 @@
}
}
.shell {
- padding: 4px 4px;
+ padding-left: 10px;
display: grid;
- grid-template-areas: "fold-button title buttons check";
- grid-template-columns: 28px 1fr auto 20px;
+ grid-template-areas: "fold-button title buttons";
+ grid-template-columns: 28px 1fr auto;
align-items: center;
line-height: 1;
width: var(--track-shell-width);
@@ -209,9 +205,15 @@
.fold-button {
grid-area: fold-button;
}
- .track-button {
- font-size: 20px;
+
+ .track-buttons {
+ grid-area: buttons;
+ display: flex;
+ height: 100%;
+ align-items: center;
+ font-size: 18px;
}
+
&:hover {
cursor: pointer;
.fold-button {
@@ -233,3 +235,27 @@
}
}
}
+
+.pf-panel-group {
+ .track-shell {
+ .track-menubar {
+ top: 40px;
+ }
+ }
+}
+
+// If the track is short, center the track titlebar vertically
+@container (height < 26px) {
+ .track {
+ .track-shell {
+ display: flex;
+ flex-direction: column;
+ align-items: stretch;
+ justify-content: center;
+
+ .track-menubar {
+ padding-block: 0px;
+ }
+ }
+ }
+}
diff --git a/ui/src/assets/viewer_page.scss b/ui/src/assets/viewer_page.scss
index 2ccc9eb..c090dc9 100644
--- a/ui/src/assets/viewer_page.scss
+++ b/ui/src/assets/viewer_page.scss
@@ -81,6 +81,9 @@
.notes-panel {
height: 20px;
+ .pf-toolbar {
+ font-size: 24px;
+ }
}
.time-selection-panel {
diff --git a/ui/src/assets/widgets/button.scss b/ui/src/assets/widgets/button.scss
index 1c7ef99..a5e8f9a 100644
--- a/ui/src/assets/widgets/button.scss
+++ b/ui/src/assets/widgets/button.scss
@@ -36,7 +36,8 @@
margin-left: 6px; // Make some room between the icon and label
}
- & > .material-icons {
+ & > .material-icons,
+ & > .material-icons-filled {
font-size: inherit;
line-height: inherit;
}
@@ -66,7 +67,7 @@
// Remove default background in minimal mode, showing only the text
&.pf-minimal {
background: $pf-minimal-background;
- color: $pf-minimal-foreground;
+ color: inherit;
&:hover {
background: $pf-minimal-background-hover;
diff --git a/ui/src/base/monitor.ts b/ui/src/base/monitor.ts
index d4e0f87..e26eb84 100644
--- a/ui/src/base/monitor.ts
+++ b/ui/src/base/monitor.ts
@@ -26,11 +26,24 @@
this.cached = reducers.map(() => undefined);
}
- ifStateChanged(callback: Callback): void {
- const state = this.reducers.map((f) => f());
- if (state.some((x, i) => x !== this.cached[i])) {
- callback();
+ /**
+ * Invokes all reducers and compares values against with the previous values.
+ *
+ * If any of the values have changed, |callback| is called (if present) and
+ * returns true, otherwise no callback is called and returns false.
+ *
+ * @param callback Optional callback to call when diffs are detected.
+ * @returns True if diffs were detected, false otherwise.
+ */
+ ifStateChanged(callback?: Callback): boolean {
+ const oldState = this.cached;
+ const newState = this.reducers.map((f) => f());
+ this.cached = newState;
+ if (newState.some((x, i) => x !== oldState[i])) {
+ callback?.();
+ return true;
}
- this.cached = state;
+
+ return false;
}
}
diff --git a/ui/src/common/actions.ts b/ui/src/common/actions.ts
index f99ae5c..4910cbd 100644
--- a/ui/src/common/actions.ts
+++ b/ui/src/common/actions.ts
@@ -54,7 +54,6 @@
NewEngineMode,
OmniboxMode,
OmniboxState,
- Pagination,
PendingDeeplinkState,
PivotTableResult,
ProfileType,
@@ -851,10 +850,6 @@
};
},
- updateLogsPagination(state: StateDraft, args: Pagination): void {
- state.logsPagination = args;
- },
-
startRecording(state: StateDraft, _: {}): void {
state.recordingInProgress = true;
state.lastRecordingError = undefined;
@@ -1202,31 +1197,6 @@
aggregations,
);
},
-
- setMinimumLogLevel(state: StateDraft, args: {minimumLevel: number}) {
- state.logFilteringCriteria.minimumLevel = args.minimumLevel;
- },
-
- addLogTag(state: StateDraft, args: {tag: string}) {
- if (!state.logFilteringCriteria.tags.includes(args.tag)) {
- state.logFilteringCriteria.tags.push(args.tag);
- }
- },
-
- removeLogTag(state: StateDraft, args: {tag: string}) {
- state.logFilteringCriteria.tags = state.logFilteringCriteria.tags.filter(
- (t) => t !== args.tag,
- );
- },
-
- updateLogFilterText(state: StateDraft, args: {textEntry: string}) {
- state.logFilteringCriteria.textEntry = args.textEntry;
- },
-
- toggleCollapseByTextEntry(state: StateDraft, _: {}) {
- state.logFilteringCriteria.hideNonMatching =
- !state.logFilteringCriteria.hideNonMatching;
- },
};
// When we are on the frontend side, we don't really want to execute the
diff --git a/ui/src/common/empty_state.ts b/ui/src/common/empty_state.ts
index 4d987d6..5bf1f5a 100644
--- a/ui/src/common/empty_state.ts
+++ b/ui/src/common/empty_state.ts
@@ -124,11 +124,6 @@
mode: 'SEARCH',
},
- logsPagination: {
- offset: 0,
- count: 0,
- },
-
status: {msg: '', timestamp: 0},
selection: {
kind: 'empty',
@@ -163,14 +158,6 @@
chromeCategories: undefined,
nonSerializableState: createEmptyNonSerializableState(),
- logFilteringCriteria: {
- // The first two log priorities are ignored.
- minimumLevel: 2,
- tags: [],
- textEntry: '',
- hideNonMatching: true,
- },
-
// Somewhere to store plugins' persistent state.
plugins: {},
};
diff --git a/ui/src/common/logs.ts b/ui/src/common/logs.ts
deleted file mode 100644
index d0366c0..0000000
--- a/ui/src/common/logs.ts
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright (C) 2019 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 {time} from '../base/time';
-
-export const LogExistsKey = 'log-exists';
-export const LogBoundsKey = 'log-bounds';
-export const LogEntriesKey = 'log-entries';
-
-export interface LogExists {
- exists: boolean;
-}
-
-export interface LogBounds {
- firstLogTs: time;
- lastLogTs: time;
- firstVisibleLogTs: time;
- lastVisibleLogTs: time;
- totalVisibleLogs: number;
-}
-
-export interface LogEntries {
- offset: number;
- timestamps: time[];
- priorities: number[];
- tags: string[];
- messages: string[];
- isHighlighted: boolean[];
- processName: string[];
-}
diff --git a/ui/src/common/plugins.ts b/ui/src/common/plugins.ts
index dfb93d7..ba60270 100644
--- a/ui/src/common/plugins.ts
+++ b/ui/src/common/plugins.ts
@@ -16,7 +16,7 @@
import {Disposable, Trash} from '../base/disposable';
import {Registry} from '../base/registry';
-import {time} from '../base/time';
+import {Span, duration, time} from '../base/time';
import {globals} from '../frontend/globals';
import {
Command,
@@ -25,7 +25,6 @@
MetricVisualisation,
Migrate,
Plugin,
- PluginClass,
PluginContext,
PluginContextTrace,
PluginDescriptor,
@@ -46,6 +45,7 @@
import {assertExists} from '../base/logging';
import {raf} from '../core/raf_scheduler';
import {defaultPlugins} from '../core/default_plugins';
+import {HighPrecisionTimeSpan} from './high_precision_time';
// Every plugin gets its own PluginContext. This is how we keep track
// what each plugin is doing and how we can blame issues on particular
@@ -311,6 +311,15 @@
panToTimestamp(ts: time): void {
globals.panToTimestamp(ts);
},
+
+ setViewportTime(start: time, end: time): void {
+ const interval = HighPrecisionTimeSpan.fromTime(start, end);
+ globals.timeline.updateVisibleTime(interval);
+ },
+
+ get viewport(): Span<time, duration> {
+ return globals.timeline.visibleTimeSpan;
+ },
};
dispose(): void {
@@ -321,6 +330,12 @@
mountStore<T>(migrate: Migrate<T>): Store<T> {
return globals.store.createSubStore(['plugins', this.pluginId], migrate);
}
+
+ readonly trace = {
+ get span(): Span<time, duration> {
+ return globals.stateTraceTimeTP();
+ },
+ };
}
function isPinned(trackId: string): boolean {
@@ -341,20 +356,13 @@
previousOnTraceLoadTimeMillis?: number;
}
-function isPluginClass(v: unknown): v is PluginClass {
- return typeof v === 'function' && !!v.prototype.onActivate;
-}
-
function makePlugin(info: PluginDescriptor): Plugin {
const {plugin} = info;
+ // Class refs are functions, concrete plugins are not
if (typeof plugin === 'function') {
- if (isPluginClass(plugin)) {
- const PluginClass = plugin;
- return new PluginClass();
- } else {
- return plugin();
- }
+ const PluginClass = plugin;
+ return new PluginClass();
} else {
return plugin;
}
@@ -433,7 +441,7 @@
const context = new PluginContextImpl(id);
- plugin.onActivate(context);
+ plugin.onActivate?.(context);
const pluginDetails: PluginDetails = {
plugin,
diff --git a/ui/src/common/state.ts b/ui/src/common/state.ts
index 396df65..3b27e16 100644
--- a/ui/src/common/state.ts
+++ b/ui/src/common/state.ts
@@ -149,7 +149,8 @@
// 50. Remove ftrace filter state.
// 51. Changed structure of FlamegraphState.expandedCallsiteByViewingOption.
// 52. Update track group state - don't make the summary track the first track.
-export const STATE_VERSION = 52;
+// 53. Remove android log state.
+export const STATE_VERSION = 53;
export const SCROLLING_TRACK_GROUP = 'ScrollingTracks';
@@ -450,13 +451,6 @@
pivotTable: PivotTableState;
}
-export interface LogFilteringCriteria {
- minimumLevel: number;
- tags: string[];
- textEntry: string;
- hideNonMatching: boolean;
-}
-
export interface PendingDeeplinkState {
ts?: string;
dur?: string;
@@ -505,7 +499,6 @@
status: Status;
selection: Selection;
currentFlamegraphState: FlamegraphState | null;
- logsPagination: Pagination;
traceConversionInProgress: boolean;
/**
@@ -556,9 +549,6 @@
// be serialized at the moment, such as ES6 Set and Map.
nonSerializableState: NonSerializableState;
- // Android logs filtering state.
- logFilteringCriteria: LogFilteringCriteria;
-
// Omnibox info.
omniboxState: OmniboxState;
diff --git a/ui/src/controller/logs_controller.ts b/ui/src/controller/logs_controller.ts
deleted file mode 100644
index 74077be..0000000
--- a/ui/src/controller/logs_controller.ts
+++ /dev/null
@@ -1,328 +0,0 @@
-// Copyright (C) 2019 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 {duration, Span, time, Time, TimeSpan} from '../base/time';
-import {
- LogBounds,
- LogBoundsKey,
- LogEntries,
- LogEntriesKey,
- LogExistsKey,
-} from '../common/logs';
-import {LogFilteringCriteria} from '../common/state';
-import {globals} from '../frontend/globals';
-import {publishTrackData} from '../frontend/publish';
-import {Engine} from '../trace_processor/engine';
-import {LONG, LONG_NULL, NUM, STR} from '../trace_processor/query_result';
-import {escapeGlob, escapeQuery} from '../trace_processor/query_utils';
-
-import {Controller} from './controller';
-
-async function updateLogBounds(
- engine: Engine,
- span: Span<time, duration>,
-): Promise<LogBounds> {
- const vizStartNs = span.start;
- const vizEndNs = span.end;
-
- const vizFilter = `ts between ${vizStartNs} and ${vizEndNs}`;
-
- const result = await engine.query(`select
- min(ts) as minTs,
- max(ts) as maxTs,
- min(case when ${vizFilter} then ts end) as minVizTs,
- max(case when ${vizFilter} then ts end) as maxVizTs,
- count(case when ${vizFilter} then ts end) as countTs
- from filtered_logs`);
-
- const data = result.firstRow({
- minTs: LONG_NULL,
- maxTs: LONG_NULL,
- minVizTs: LONG_NULL,
- maxVizTs: LONG_NULL,
- countTs: NUM,
- });
-
- const firstLogTs = Time.fromRaw(data.minTs ?? 0n);
- const lastLogTs = Time.fromRaw(data.maxTs ?? Time.MAX);
-
- const bounds: LogBounds = {
- firstLogTs,
- lastLogTs,
- firstVisibleLogTs: Time.fromRaw(data.minVizTs ?? firstLogTs),
- lastVisibleLogTs: Time.fromRaw(data.maxVizTs ?? lastLogTs),
- totalVisibleLogs: data.countTs,
- };
-
- return bounds;
-}
-
-async function updateLogEntries(
- engine: Engine,
- span: Span<time, duration>,
- pagination: Pagination,
-): Promise<LogEntries> {
- const vizStartNs = span.start;
- const vizEndNs = span.end;
- const vizSqlBounds = `ts >= ${vizStartNs} and ts <= ${vizEndNs}`;
-
- const rowsResult = await engine.query(`
- select
- ts,
- prio,
- ifnull(tag, '[NULL]') as tag,
- ifnull(msg, '[NULL]') as msg,
- is_msg_highlighted as isMsgHighlighted,
- is_process_highlighted as isProcessHighlighted,
- ifnull(process_name, '') as processName
- from filtered_logs
- where ${vizSqlBounds}
- order by ts
- limit ${pagination.start}, ${pagination.count}
- `);
-
- const timestamps: time[] = [];
- const priorities = [];
- const tags = [];
- const messages = [];
- const isHighlighted = [];
- const processName = [];
-
- const it = rowsResult.iter({
- ts: LONG,
- prio: NUM,
- tag: STR,
- msg: STR,
- isMsgHighlighted: NUM,
- isProcessHighlighted: NUM,
- processName: STR,
- });
- for (; it.valid(); it.next()) {
- timestamps.push(Time.fromRaw(it.ts));
- priorities.push(it.prio);
- tags.push(it.tag);
- messages.push(it.msg);
- isHighlighted.push(
- it.isMsgHighlighted === 1 || it.isProcessHighlighted === 1,
- );
- processName.push(it.processName);
- }
-
- return {
- offset: pagination.start,
- timestamps,
- priorities,
- tags,
- messages,
- isHighlighted,
- processName,
- };
-}
-
-class Pagination {
- private _offset: number;
- private _count: number;
-
- constructor(offset: number, count: number) {
- this._offset = offset;
- this._count = count;
- }
-
- get start() {
- return this._offset;
- }
-
- get count() {
- return this._count;
- }
-
- get end() {
- return this._offset + this._count;
- }
-
- contains(other: Pagination): boolean {
- return this.start <= other.start && other.end <= this.end;
- }
-
- grow(n: number): Pagination {
- const newStart = Math.max(0, this.start - n / 2);
- const newCount = this.count + n;
- return new Pagination(newStart, newCount);
- }
-}
-
-export interface LogsControllerArgs {
- engine: Engine;
-}
-
-/**
- * LogsController looks at three parts of the state:
- * 1. The visible trace window
- * 2. The requested offset and count the log lines to display
- * 3. The log filtering criteria.
- * And keeps two bits of published information up to date:
- * 1. The total number of log messages in visible range
- * 2. The logs lines that should be displayed
- * Based on the log filtering criteria, it also builds the filtered_logs view
- * and keeps it up to date.
- */
-export class LogsController extends Controller<'main'> {
- private engine: Engine;
- private span: Span<time, duration>;
- private pagination: Pagination;
- private hasLogs = false;
- private logFilteringCriteria?: LogFilteringCriteria;
- private requestingData = false;
- private queuedRunRequest = false;
-
- constructor(args: LogsControllerArgs) {
- super('main');
- this.engine = args.engine;
- this.span = new TimeSpan(Time.ZERO, Time.fromSeconds(10));
- this.pagination = new Pagination(0, 0);
- this.hasAnyLogs().then((exists) => {
- this.hasLogs = exists;
- publishTrackData({
- id: LogExistsKey,
- data: {
- exists,
- },
- });
- });
- }
-
- async hasAnyLogs() {
- const result = await this.engine.query(`
- select count(*) as cnt from android_logs
- `);
- return result.firstRow({cnt: NUM}).cnt > 0;
- }
-
- run() {
- if (!this.hasLogs) return;
- if (this.requestingData) {
- this.queuedRunRequest = true;
- return;
- }
- this.requestingData = true;
- this.updateLogTracks().finally(() => {
- this.requestingData = false;
- if (this.queuedRunRequest) {
- this.queuedRunRequest = false;
- this.run();
- }
- });
- }
-
- private async updateLogTracks() {
- const newSpan = globals.stateVisibleTime();
- const oldSpan = this.span;
-
- const pagination = globals.state.logsPagination;
- // This can occur when loading old traces.
- // TODO(hjd): Fix the problem of accessing state from a previous version of
- // the UI in a general way.
- if (pagination === undefined) {
- return;
- }
-
- const {offset, count} = pagination;
- const requestedPagination = new Pagination(offset, count);
- const oldPagination = this.pagination;
-
- const newFilteringCriteria =
- this.logFilteringCriteria !== globals.state.logFilteringCriteria;
- const needBoundsUpdate = !oldSpan.equals(newSpan) || newFilteringCriteria;
- const needEntriesUpdate =
- !oldPagination.contains(requestedPagination) || needBoundsUpdate;
-
- if (newFilteringCriteria) {
- this.logFilteringCriteria = globals.state.logFilteringCriteria;
- await this.engine.query('drop view if exists filtered_logs');
-
- const globMatch = LogsController.composeGlobMatch(
- this.logFilteringCriteria.hideNonMatching,
- this.logFilteringCriteria.textEntry,
- );
- let selectedRows = `select prio, ts, tag, msg,
- process.name as process_name, ${globMatch}
- from android_logs
- left join thread using(utid)
- left join process using(upid)
- where prio >= ${this.logFilteringCriteria.minimumLevel}`;
- if (this.logFilteringCriteria.tags.length) {
- selectedRows += ` and tag in (${LogsController.serializeTags(
- this.logFilteringCriteria.tags,
- )})`;
- }
-
- // We extract only the rows which will be visible.
- await this.engine.query(`create view filtered_logs as select *
- from (${selectedRows})
- where is_msg_chosen is 1 or is_process_chosen is 1`);
- }
-
- if (needBoundsUpdate) {
- this.span = newSpan;
- const logBounds = await updateLogBounds(this.engine, newSpan);
- publishTrackData({
- id: LogBoundsKey,
- data: logBounds,
- });
- }
-
- if (needEntriesUpdate) {
- this.pagination = requestedPagination.grow(100);
- const logEntries = await updateLogEntries(
- this.engine,
- newSpan,
- this.pagination,
- );
- publishTrackData({
- id: LogEntriesKey,
- data: logEntries,
- });
- }
- }
-
- private static serializeTags(tags: string[]) {
- return tags.map((tag) => escapeQuery(tag)).join();
- }
-
- private static composeGlobMatch(isCollaped: boolean, textEntry: string) {
- if (isCollaped) {
- // If the entries are collapsed, we won't highlight any lines.
- return `msg glob ${escapeGlob(textEntry)} as is_msg_chosen,
- (process.name is not null and process.name glob ${escapeGlob(
- textEntry,
- )}) as is_process_chosen,
- 0 as is_msg_highlighted,
- 0 as is_process_highlighted`;
- } else if (!textEntry) {
- // If there is no text entry, we will show all lines, but won't highlight.
- // any.
- return `1 as is_msg_chosen,
- 1 as is_process_chosen,
- 0 as is_msg_highlighted,
- 0 as is_process_highlighted`;
- } else {
- return `1 as is_msg_chosen,
- 1 as is_process_chosen,
- msg glob ${escapeGlob(textEntry)} as is_msg_highlighted,
- (process.name is not null and process.name glob ${escapeGlob(
- textEntry,
- )}) as is_process_highlighted`;
- }
- }
-}
diff --git a/ui/src/controller/trace_controller.ts b/ui/src/controller/trace_controller.ts
index de8fde3..5194215 100644
--- a/ui/src/controller/trace_controller.ts
+++ b/ui/src/controller/trace_controller.ts
@@ -82,7 +82,6 @@
FlowEventsControllerArgs,
} from './flow_events_controller';
import {LoadingManager} from './loading_manager';
-import {LogsController} from './logs_controller';
import {
PIVOT_TABLE_REDUX_FLAG,
PivotTableController,
@@ -343,13 +342,6 @@
);
childControllers.push(
- Child('logs', LogsController, {
- engine,
- app: globals,
- }),
- );
-
- childControllers.push(
Child('traceError', TraceErrorController, {engine}),
);
diff --git a/ui/src/controller/track_decider.ts b/ui/src/controller/track_decider.ts
index 3f942e9..d8f42fb 100644
--- a/ui/src/controller/track_decider.ts
+++ b/ui/src/controller/track_decider.ts
@@ -483,6 +483,7 @@
new RegExp('^Trace Triggers$'),
new RegExp('^Android App Startups$'),
new RegExp('^Device State.*$'),
+ new RegExp('^Android logs$'),
];
let groupUuid = undefined;
@@ -544,22 +545,6 @@
}
}
- async addLogsTrack(engine: EngineProxy): Promise<void> {
- const result = await engine.query(
- `select count(1) as cnt from android_logs`,
- );
- const count = result.firstRow({cnt: NUM}).cnt;
-
- if (count > 0) {
- this.tracksToAdd.push({
- uri: 'perfetto.AndroidLog',
- name: 'Android logs',
- trackSortKey: PrimaryTrackSortKey.ORDINARY_TRACK,
- trackGroup: SCROLLING_TRACK_GROUP,
- });
- }
- }
-
async addAnnotationTracks(engine: EngineProxy): Promise<void> {
const sliceResult = await engine.query(`
select id, name, upid, group_name
@@ -1652,7 +1637,6 @@
await this.addThreadCpuSampleTracks(
this.engine.getProxy('TrackDecider::addThreadCpuSampleTracks'),
);
- await this.addLogsTrack(this.engine.getProxy('TrackDecider::addLogsTrack'));
// TODO(hjd): Move into plugin API.
{
diff --git a/ui/src/frontend/base_counter_track.ts b/ui/src/frontend/base_counter_track.ts
index 98730e0..e87f38b 100644
--- a/ui/src/frontend/base_counter_track.ts
+++ b/ui/src/frontend/base_counter_track.ts
@@ -450,14 +450,14 @@
return m(
PopupMenu2,
{
- trigger: m(Button, {icon: 'show_chart', minimal: true}),
+ trigger: m(Button, {icon: 'show_chart', minimal: true, compact: true}),
},
this.getCounterContextMenuItems(),
);
}
getTrackShellButtons(): m.Children {
- return [this.getCounterContextMenu()];
+ return this.getCounterContextMenu();
}
async onCreate(): Promise<void> {
diff --git a/ui/src/frontend/close_track_button.ts b/ui/src/frontend/close_track_button.ts
index 0b3a46c..e7b667b 100644
--- a/ui/src/frontend/close_track_button.ts
+++ b/ui/src/frontend/close_track_button.ts
@@ -18,7 +18,7 @@
import {Actions} from '../common/actions';
import {globals} from './globals';
-import {TrackButton} from './track_panel';
+import {Button} from '../widgets/button';
export interface CloseTrackButtonAttrs {
trackKey: string;
@@ -28,13 +28,14 @@
implements m.ClassComponent<CloseTrackButtonAttrs>
{
view({attrs}: m.CVnode<CloseTrackButtonAttrs>) {
- return m(TrackButton, {
- action: () => {
+ return m(Button, {
+ onclick: () => {
globals.dispatch(Actions.removeTracks({trackKeys: [attrs.trackKey]}));
},
- i: Icons.Close,
- tooltip: 'Close',
- showButton: true,
+ icon: Icons.Close,
+ title: 'Close',
+ minimal: true,
+ compact: true,
});
}
}
diff --git a/ui/src/frontend/globals.ts b/ui/src/frontend/globals.ts
index 5cecd7e..8fc392d 100644
--- a/ui/src/frontend/globals.ts
+++ b/ui/src/frontend/globals.ts
@@ -673,6 +673,7 @@
set isInternalUser(value: boolean) {
localStorage.setItem('isInternalUser', value ? '1' : '0');
this._isInternalUser = value;
+ raf.scheduleFullRedraw();
}
get testing() {
diff --git a/ui/src/frontend/logs_filters.ts b/ui/src/frontend/logs_filters.ts
deleted file mode 100644
index 93239e7..0000000
--- a/ui/src/frontend/logs_filters.ts
+++ /dev/null
@@ -1,186 +0,0 @@
-// Copyright (C) 2022 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 m from 'mithril';
-
-import {Actions} from '../common/actions';
-import {Button} from '../widgets/button';
-import {Select} from '../widgets/select';
-import {TextInput} from '../widgets/text_input';
-
-import {globals} from './globals';
-
-export const LOG_PRIORITIES = [
- '-',
- '-',
- 'Verbose',
- 'Debug',
- 'Info',
- 'Warn',
- 'Error',
- 'Fatal',
-];
-const IGNORED_STATES = 2;
-
-interface LogPriorityWidgetAttrs {
- options: string[];
- selectedIndex: number;
- onSelect: (id: number) => void;
-}
-
-interface LogTagChipAttrs {
- name: string;
- removeTag: (name: string) => void;
-}
-
-interface LogTagsWidgetAttrs {
- tags: string[];
-}
-
-interface FilterByTextWidgetAttrs {
- hideNonMatching: boolean;
-}
-
-class LogPriorityWidget implements m.ClassComponent<LogPriorityWidgetAttrs> {
- view(vnode: m.Vnode<LogPriorityWidgetAttrs>) {
- const attrs = vnode.attrs;
- const optionComponents = [];
- for (let i = IGNORED_STATES; i < attrs.options.length; i++) {
- const selected = i === attrs.selectedIndex;
- optionComponents.push(
- m('option', {value: i, selected}, attrs.options[i]),
- );
- }
- return m(
- Select,
- {
- onchange: (e: Event) => {
- const selectionValue = (e.target as HTMLSelectElement).value;
- attrs.onSelect(Number(selectionValue));
- },
- },
- optionComponents,
- );
- }
-}
-
-class LogTagChip implements m.ClassComponent<LogTagChipAttrs> {
- view({attrs}: m.CVnode<LogTagChipAttrs>) {
- return m(Button, {
- label: attrs.name,
- rightIcon: 'close',
- onclick: () => attrs.removeTag(attrs.name),
- });
- }
-}
-
-class LogTagsWidget implements m.ClassComponent<LogTagsWidgetAttrs> {
- removeTag(tag: string) {
- globals.dispatch(Actions.removeLogTag({tag}));
- }
-
- view(vnode: m.Vnode<LogTagsWidgetAttrs>) {
- const tags = vnode.attrs.tags;
- return [
- tags.map((tag) =>
- m(LogTagChip, {
- name: tag,
- removeTag: this.removeTag.bind(this),
- }),
- ),
- m(TextInput, {
- placeholder: 'Filter by tag...',
- onkeydown: (e: KeyboardEvent) => {
- // This is to avoid zooming on 'w'(and other unexpected effects
- // of key presses in this input field).
- e.stopPropagation();
- const htmlElement = e.target as HTMLInputElement;
-
- // When the user clicks 'Backspace' we delete the previous tag.
- if (
- e.key === 'Backspace' &&
- tags.length > 0 &&
- htmlElement.value === ''
- ) {
- globals.dispatch(
- Actions.removeLogTag({tag: tags[tags.length - 1]}),
- );
- return;
- }
-
- if (e.key !== 'Enter') {
- return;
- }
- if (htmlElement.value === '') {
- return;
- }
- globals.dispatch(Actions.addLogTag({tag: htmlElement.value.trim()}));
- htmlElement.value = '';
- },
- }),
- ];
- }
-}
-
-class LogTextWidget implements m.ClassComponent {
- view() {
- return m(TextInput, {
- placeholder: 'Search logs...',
- onkeyup: (e: KeyboardEvent) => {
- // We want to use the value of the input field after it has been
- // updated with the latest key (onkeyup).
- const htmlElement = e.target as HTMLInputElement;
- globals.dispatch(
- Actions.updateLogFilterText({textEntry: htmlElement.value}),
- );
- },
- });
- }
-}
-
-class FilterByTextWidget implements m.ClassComponent<FilterByTextWidgetAttrs> {
- view({attrs}: m.Vnode<FilterByTextWidgetAttrs>) {
- const icon = attrs.hideNonMatching ? 'unfold_less' : 'unfold_more';
- const tooltip = attrs.hideNonMatching
- ? 'Expand all and view highlighted'
- : 'Collapse all';
- return m(Button, {
- icon,
- title: tooltip,
- disabled: globals.state.logFilteringCriteria.textEntry === '',
- minimal: true,
- onclick: () => globals.dispatch(Actions.toggleCollapseByTextEntry({})),
- });
- }
-}
-
-export class LogsFilters implements m.ClassComponent {
- view(_: m.CVnode<{}>) {
- return [
- m('.log-label', 'Log Level'),
- m(LogPriorityWidget, {
- options: LOG_PRIORITIES,
- selectedIndex: globals.state.logFilteringCriteria.minimumLevel,
- onSelect: (minimumLevel) => {
- globals.dispatch(Actions.setMinimumLogLevel({minimumLevel}));
- },
- }),
- m(LogTagsWidget, {tags: globals.state.logFilteringCriteria.tags}),
- m(LogTextWidget),
- m(FilterByTextWidget, {
- hideNonMatching: globals.state.logFilteringCriteria.hideNonMatching,
- }),
- ];
- }
-}
diff --git a/ui/src/frontend/logs_panel.ts b/ui/src/frontend/logs_panel.ts
deleted file mode 100644
index 18165a6..0000000
--- a/ui/src/frontend/logs_panel.ts
+++ /dev/null
@@ -1,197 +0,0 @@
-// Copyright (C) 2019 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 m from 'mithril';
-
-import {time, Time} from '../base/time';
-import {Actions} from '../common/actions';
-import {HighPrecisionTimeSpan} from '../common/high_precision_time';
-import {
- LogBounds,
- LogBoundsKey,
- LogEntries,
- LogEntriesKey,
-} from '../common/logs';
-import {raf} from '../core/raf_scheduler';
-import {DetailsShell} from '../widgets/details_shell';
-import {VirtualScrollContainer} from '../widgets/virtual_scroll_container';
-
-import {SELECTED_LOG_ROWS_COLOR} from './css_constants';
-import {globals} from './globals';
-import {LOG_PRIORITIES, LogsFilters} from './logs_filters';
-import {Timestamp} from './widgets/timestamp';
-
-const ROW_H = 20;
-
-export class LogPanel implements m.ClassComponent {
- private bounds?: LogBounds;
- private entries?: LogEntries;
-
- private visibleRowOffset = 0;
- private visibleRowCount = 0;
-
- recomputeVisibleRowsAndUpdate(scrollContainer: HTMLElement) {
- const prevOffset = this.visibleRowOffset;
- const prevCount = this.visibleRowCount;
- this.visibleRowOffset = Math.floor(scrollContainer.scrollTop / ROW_H);
- this.visibleRowCount = Math.ceil(scrollContainer.clientHeight / ROW_H);
-
- if (
- this.visibleRowOffset !== prevOffset ||
- this.visibleRowCount !== prevCount
- ) {
- globals.dispatch(
- Actions.updateLogsPagination({
- offset: this.visibleRowOffset,
- count: this.visibleRowCount,
- }),
- );
- }
- }
-
- oncreate(_: m.CVnodeDOM) {
- // TODO(stevegolton): Type assersions are a source of bugs.
- // Let's try to find another way of doing this.
- this.bounds = globals.trackDataStore.get(LogBoundsKey) as LogBounds;
- this.entries = globals.trackDataStore.get(LogEntriesKey) as LogEntries;
- }
-
- onbeforeupdate(_: m.CVnode) {
- // TODO(stevegolton): Type assersions are a source of bugs.
- // Let's try to find another way of doing this.
- this.bounds = globals.trackDataStore.get(LogBoundsKey) as LogBounds;
- this.entries = globals.trackDataStore.get(LogEntriesKey) as LogEntries;
- }
-
- onScroll = (scrollContainer: HTMLElement) => {
- this.recomputeVisibleRowsAndUpdate(scrollContainer);
- raf.scheduleFullRedraw();
- };
-
- onRowOver(ts: time) {
- globals.dispatch(Actions.setHoverCursorTimestamp({ts}));
- }
-
- onRowOut() {
- globals.dispatch(Actions.setHoverCursorTimestamp({ts: Time.INVALID}));
- }
-
- private totalRows(): {
- isStale: boolean;
- total: number;
- offset: number;
- count: number;
- } {
- if (!this.bounds) {
- return {isStale: false, total: 0, offset: 0, count: 0};
- }
- const {totalVisibleLogs, firstVisibleLogTs, lastVisibleLogTs} = this.bounds;
- const vis = globals.timeline.visibleWindowTime;
-
- const visibleLogSpan = new HighPrecisionTimeSpan(
- firstVisibleLogTs,
- lastVisibleLogTs,
- );
- const isStale = !vis.contains(visibleLogSpan);
- const offset = Math.min(this.visibleRowOffset, totalVisibleLogs);
- const visCount = Math.min(totalVisibleLogs - offset, this.visibleRowCount);
- return {isStale, total: totalVisibleLogs, count: visCount, offset};
- }
-
- view(_: m.CVnode<{}>) {
- const {isStale, total, offset, count} = this.totalRows();
-
- const hasProcessNames =
- this.entries &&
- this.entries.processName.filter((name) => name).length > 0;
-
- const rows: m.Children = [];
- rows.push(
- m(
- `.row`,
- m('.cell.row-header', 'Timestamp'),
- m('.cell.row-header', 'Level'),
- m('.cell.row-header', 'Tag'),
- hasProcessNames
- ? m('.cell.with-process.row-header', 'Process name')
- : undefined,
- hasProcessNames
- ? m('.cell.with-process.row-header', 'Message')
- : m('.cell.no-process.row-header', 'Message'),
- m('br'),
- ),
- );
- if (this.entries) {
- const offset = this.entries.offset;
- const timestamps = this.entries.timestamps;
- const priorities = this.entries.priorities;
- const tags = this.entries.tags;
- const messages = this.entries.messages;
- const processNames = this.entries.processName;
- for (let i = 0; i < this.entries.timestamps.length; i++) {
- const priorityLetter = LOG_PRIORITIES[priorities[i]][0];
- const ts = timestamps[i];
- const prioClass = priorityLetter || '';
- const style: {top: string; backgroundColor?: string} = {
- // 1.5 is for the width of the header
- top: `${(offset + i + 1.5) * ROW_H}px`,
- };
- if (this.entries.isHighlighted[i]) {
- style.backgroundColor = SELECTED_LOG_ROWS_COLOR;
- }
-
- rows.push(
- m(
- `.row.${prioClass}`,
- {
- class: isStale ? 'stale' : '',
- style,
- onmouseover: this.onRowOver.bind(this, ts),
- onmouseout: this.onRowOut.bind(this),
- },
- m('.cell', m(Timestamp, {ts})),
- m('.cell', priorityLetter || '?'),
- m('.cell', tags[i]),
- hasProcessNames
- ? m('.cell.with-process', processNames[i])
- : undefined,
- hasProcessNames
- ? m('.cell.with-process', messages[i])
- : m('.cell.no-process', messages[i]),
- m('br'),
- ),
- );
- }
- }
-
- // TODO(stevegolton): Add a 'loading' state to DetailsShell, which shows a
- // scrolling scrolly bar at the bottom of the banner & map isStale to it
- return m(
- DetailsShell,
- {
- title: 'Android Logs',
- description: `[${offset}, ${offset + count}] / ${total}`,
- buttons: m(LogsFilters),
- },
- m(
- VirtualScrollContainer,
- {onScroll: this.onScroll},
- m(
- '.log-panel',
- m('.rows', {style: {height: `${total * ROW_H}px`}}, rows),
- ),
- ),
- );
- }
-}
diff --git a/ui/src/frontend/notes_panel.ts b/ui/src/frontend/notes_panel.ts
index 69362e45..85cbe07 100644
--- a/ui/src/frontend/notes_panel.ts
+++ b/ui/src/frontend/notes_panel.ts
@@ -21,7 +21,7 @@
import {randomColor} from '../core/colorizer';
import {AreaNote, Note, getLegacySelection} from '../common/state';
import {raf} from '../core/raf_scheduler';
-import {Button} from '../widgets/button';
+import {Button, ButtonBar} from '../widgets/button';
import {BottomTab, NewBottomTabArgs} from './bottom_tab';
import {TRACK_SHELL_WIDTH} from './css_constants';
@@ -89,46 +89,39 @@
globals.dispatch(Actions.setHoveredNoteTimestamp({ts: Time.INVALID}));
},
},
- isTraceLoaded()
- ? [
- m(
- 'button',
- {
- onclick: (e: Event) => {
- e.preventDefault();
- if (allCollapsed) {
- globals.commandManager.runCommand(
- 'dev.perfetto.CoreCommands#ExpandAllGroups',
- );
- } else {
- globals.commandManager.runCommand(
- 'dev.perfetto.CoreCommands#CollapseAllGroups',
- );
- }
- },
- },
- m(
- 'i.material-icons',
- {title: allCollapsed ? 'Expand all' : 'Collapse all'},
- allCollapsed ? 'unfold_more' : 'unfold_less',
- ),
- ),
- m(
- 'button',
- {
- onclick: (e: Event) => {
- e.preventDefault();
- globals.dispatch(Actions.clearAllPinnedTracks({}));
- },
- },
- m(
- 'i.material-icons',
- {title: 'Clear all pinned tracks'},
- 'clear_all',
- ),
- ),
- ]
- : '',
+ isTraceLoaded() &&
+ m(
+ ButtonBar,
+ {className: 'pf-toolbar'},
+ m(Button, {
+ onclick: (e: Event) => {
+ e.preventDefault();
+ if (allCollapsed) {
+ globals.commandManager.runCommand(
+ 'dev.perfetto.CoreCommands#ExpandAllGroups',
+ );
+ } else {
+ globals.commandManager.runCommand(
+ 'dev.perfetto.CoreCommands#CollapseAllGroups',
+ );
+ }
+ },
+ title: allCollapsed ? 'Expand all' : 'Collapse all',
+ icon: allCollapsed ? 'unfold_more' : 'unfold_less',
+ minimal: true,
+ compact: true,
+ }),
+ m(Button, {
+ onclick: (e: Event) => {
+ e.preventDefault();
+ globals.dispatch(Actions.clearAllPinnedTracks({}));
+ },
+ title: 'Clear all pinned tracks',
+ icon: 'clear_all',
+ minimal: true,
+ compact: true,
+ }),
+ ),
);
}
diff --git a/ui/src/frontend/panel_container.ts b/ui/src/frontend/panel_container.ts
index 517ae4b..9214430 100644
--- a/ui/src/frontend/panel_container.ts
+++ b/ui/src/frontend/panel_container.ts
@@ -270,7 +270,7 @@
renderTree(node: PanelOrGroup, path: string): m.Vnode {
if (node.kind === 'group') {
return m(
- 'div',
+ 'div.pf-panel-group',
{key: path},
this.renderPanel(
node.header,
diff --git a/ui/src/frontend/publish.ts b/ui/src/frontend/publish.ts
index 46773b2..f8c36cb 100644
--- a/ui/src/frontend/publish.ts
+++ b/ui/src/frontend/publish.ts
@@ -16,12 +16,6 @@
import {Actions} from '../common/actions';
import {AggregateData} from '../common/aggregation_data';
import {ConversionJobStatusUpdate} from '../common/conversion_jobs';
-import {
- LogBoundsKey,
- LogEntriesKey,
- LogExists,
- LogExistsKey,
-} from '../common/logs';
import {MetricResult} from '../common/metric_data';
import {CurrentSearchResults, SearchSummary} from '../common/search_data';
import {raf} from '../core/raf_scheduler';
@@ -64,13 +58,7 @@
export function publishTrackData(args: {id: string; data: {}}) {
globals.setTrackData(args.id, args.data);
- if ([LogExistsKey, LogBoundsKey, LogEntriesKey].includes(args.id)) {
- const trackDataStore = globals.trackDataStore;
- const data = trackDataStore.get(LogExistsKey) as LogExists | undefined;
- if (data && data.exists) raf.scheduleFullRedraw();
- } else {
- raf.scheduleRedraw();
- }
+ raf.scheduleRedraw();
}
export function publishMetricResult(metricResult: MetricResult) {
diff --git a/ui/src/frontend/sidebar.ts b/ui/src/frontend/sidebar.ts
index 05ca28f..be1d20e 100644
--- a/ui/src/frontend/sidebar.ts
+++ b/ui/src/frontend/sidebar.ts
@@ -128,158 +128,160 @@
appendOpenedTraceTitle?: boolean;
}
-const SECTIONS: Section[] = [
- {
- title: 'Navigation',
- summary: 'Open or record a new trace',
- expanded: true,
- items: [
- {t: 'Open trace file', a: popupFileSelectionDialog, i: 'folder_open'},
- {
- t: 'Open with legacy UI',
- a: popupFileSelectionDialogOldUI,
- i: 'filter_none',
- },
- {t: 'Record new trace', a: navigateRecord, i: 'fiber_smart_record'},
- {
- t: 'Widgets',
- a: navigateWidgets,
- i: 'widgets',
- isVisible: () => WIDGETS_PAGE_IN_NAV_FLAG.get(),
- },
- {
- t: 'Plugins',
- a: navigatePlugins,
- i: 'extension',
- isVisible: () => PLUGINS_PAGE_IN_NAV_FLAG.get(),
- },
- ],
- },
+function getSections(): Section[] {
+ return [
+ {
+ title: 'Navigation',
+ summary: 'Open or record a new trace',
+ expanded: true,
+ items: [
+ {t: 'Open trace file', a: popupFileSelectionDialog, i: 'folder_open'},
+ {
+ t: 'Open with legacy UI',
+ a: popupFileSelectionDialogOldUI,
+ i: 'filter_none',
+ },
+ {t: 'Record new trace', a: navigateRecord, i: 'fiber_smart_record'},
+ {
+ t: 'Widgets',
+ a: navigateWidgets,
+ i: 'widgets',
+ isVisible: () => WIDGETS_PAGE_IN_NAV_FLAG.get(),
+ },
+ {
+ t: 'Plugins',
+ a: navigatePlugins,
+ i: 'extension',
+ isVisible: () => PLUGINS_PAGE_IN_NAV_FLAG.get(),
+ },
+ ],
+ },
- {
- title: 'Current Trace',
- summary: 'Actions on the current trace',
- expanded: true,
- hideIfNoTraceLoaded: true,
- appendOpenedTraceTitle: true,
- items: [
- {t: 'Show timeline', a: navigateViewer, i: 'line_style'},
- {
- t: 'Share',
- a: handleShareTrace,
- i: 'share',
- internalUserOnly: true,
- isPending: () =>
- globals.getConversionJobStatus('create_permalink') ===
- ConversionJobStatus.InProgress,
- },
- {
- t: 'Download',
- a: downloadTrace,
- i: 'file_download',
- checkDownloadDisabled: true,
- },
- {t: 'Query (SQL)', a: navigateQuery, i: 'database'},
- {
- t: 'Insights',
- a: navigateInsights,
- i: 'insights',
- isVisible: () => INSIGHTS_PAGE_IN_NAV_FLAG.get(),
- },
- {
- t: 'Viz',
- a: navigateViz,
- i: 'area_chart',
- isVisible: () => VIZ_PAGE_IN_NAV_FLAG.get(),
- },
- {t: 'Metrics', a: navigateMetrics, i: 'speed'},
- {t: 'Info and stats', a: navigateInfo, i: 'info'},
- ],
- },
+ {
+ title: 'Current Trace',
+ summary: 'Actions on the current trace',
+ expanded: true,
+ hideIfNoTraceLoaded: true,
+ appendOpenedTraceTitle: true,
+ items: [
+ {t: 'Show timeline', a: navigateViewer, i: 'line_style'},
+ {
+ t: 'Share',
+ a: handleShareTrace,
+ i: 'share',
+ internalUserOnly: true,
+ isPending: () =>
+ globals.getConversionJobStatus('create_permalink') ===
+ ConversionJobStatus.InProgress,
+ },
+ {
+ t: 'Download',
+ a: downloadTrace,
+ i: 'file_download',
+ checkDownloadDisabled: true,
+ },
+ {t: 'Query (SQL)', a: navigateQuery, i: 'database'},
+ {
+ t: 'Insights',
+ a: navigateInsights,
+ i: 'insights',
+ isVisible: () => INSIGHTS_PAGE_IN_NAV_FLAG.get(),
+ },
+ {
+ t: 'Viz',
+ a: navigateViz,
+ i: 'area_chart',
+ isVisible: () => VIZ_PAGE_IN_NAV_FLAG.get(),
+ },
+ {t: 'Metrics', a: navigateMetrics, i: 'speed'},
+ {t: 'Info and stats', a: navigateInfo, i: 'info'},
+ ],
+ },
- {
- title: 'Convert trace',
- summary: 'Convert to other formats',
- expanded: true,
- hideIfNoTraceLoaded: true,
- items: [
- {
- t: 'Switch to legacy UI',
- a: openCurrentTraceWithOldUI,
- i: 'filter_none',
- isPending: () =>
- globals.getConversionJobStatus('open_in_legacy') ===
- ConversionJobStatus.InProgress,
- },
- {
- t: 'Convert to .json',
- a: convertTraceToJson,
- i: 'file_download',
- isPending: () =>
- globals.getConversionJobStatus('convert_json') ===
- ConversionJobStatus.InProgress,
- checkDownloadDisabled: true,
- },
+ {
+ title: 'Convert trace',
+ summary: 'Convert to other formats',
+ expanded: true,
+ hideIfNoTraceLoaded: true,
+ items: [
+ {
+ t: 'Switch to legacy UI',
+ a: openCurrentTraceWithOldUI,
+ i: 'filter_none',
+ isPending: () =>
+ globals.getConversionJobStatus('open_in_legacy') ===
+ ConversionJobStatus.InProgress,
+ },
+ {
+ t: 'Convert to .json',
+ a: convertTraceToJson,
+ i: 'file_download',
+ isPending: () =>
+ globals.getConversionJobStatus('convert_json') ===
+ ConversionJobStatus.InProgress,
+ checkDownloadDisabled: true,
+ },
- {
- t: 'Convert to .systrace',
- a: convertTraceToSystrace,
- i: 'file_download',
- isVisible: () => globals.hasFtrace,
- isPending: () =>
- globals.getConversionJobStatus('convert_systrace') ===
- ConversionJobStatus.InProgress,
- checkDownloadDisabled: true,
- },
- ],
- },
+ {
+ t: 'Convert to .systrace',
+ a: convertTraceToSystrace,
+ i: 'file_download',
+ isVisible: () => globals.hasFtrace,
+ isPending: () =>
+ globals.getConversionJobStatus('convert_systrace') ===
+ ConversionJobStatus.InProgress,
+ checkDownloadDisabled: true,
+ },
+ ],
+ },
- {
- title: 'Example Traces',
- expanded: true,
- summary: 'Open an example trace',
- items: [
- {
- t: 'Open Android example',
- a: openTraceUrl(EXAMPLE_ANDROID_TRACE_URL),
- i: 'description',
- },
- {
- t: 'Open Chrome example',
- a: openTraceUrl(EXAMPLE_CHROME_TRACE_URL),
- i: 'description',
- },
- ],
- },
+ {
+ title: 'Example Traces',
+ expanded: true,
+ summary: 'Open an example trace',
+ items: [
+ {
+ t: 'Open Android example',
+ a: openTraceUrl(EXAMPLE_ANDROID_TRACE_URL),
+ i: 'description',
+ },
+ {
+ t: 'Open Chrome example',
+ a: openTraceUrl(EXAMPLE_CHROME_TRACE_URL),
+ i: 'description',
+ },
+ ],
+ },
- {
- title: 'Support',
- expanded: true,
- summary: 'Documentation & Bugs',
- items: [
- {t: 'Keyboard shortcuts', a: openHelp, i: 'help'},
- {t: 'Documentation', a: 'https://perfetto.dev/docs', i: 'find_in_page'},
- {t: 'Flags', a: navigateFlags, i: 'emoji_flags'},
- {
- t: 'Report a bug',
- a: () => window.open(getBugReportUrl()),
- i: 'bug_report',
- },
- {
- t: 'Record metatrace',
- a: recordMetatrace,
- i: 'fiber_smart_record',
- checkMetatracingDisabled: true,
- },
- {
- t: 'Finalise metatrace',
- a: finaliseMetatrace,
- i: 'file_download',
- checkMetatracingEnabled: true,
- },
- ],
- },
-];
+ {
+ title: 'Support',
+ expanded: true,
+ summary: 'Documentation & Bugs',
+ items: [
+ {t: 'Keyboard shortcuts', a: openHelp, i: 'help'},
+ {t: 'Documentation', a: 'https://perfetto.dev/docs', i: 'find_in_page'},
+ {t: 'Flags', a: navigateFlags, i: 'emoji_flags'},
+ {
+ t: 'Report a bug',
+ a: getBugReportUrl(),
+ i: 'bug_report',
+ },
+ {
+ t: 'Record metatrace',
+ a: recordMetatrace,
+ i: 'fiber_smart_record',
+ checkMetatracingDisabled: true,
+ },
+ {
+ t: 'Finalise metatrace',
+ a: finaliseMetatrace,
+ i: 'file_download',
+ checkMetatracingEnabled: true,
+ },
+ ],
+ },
+ ];
+}
function openHelp(e: Event) {
e.preventDefault();
@@ -812,7 +814,7 @@
view() {
if (globals.hideSidebar) return null;
const vdomSections = [];
- for (const section of SECTIONS) {
+ for (const section of getSections()) {
if (section.hideIfNoTraceLoaded && !isTraceLoaded()) continue;
const vdomItems = [];
for (const item of section.items) {
diff --git a/ui/src/frontend/simple_counter_track.ts b/ui/src/frontend/simple_counter_track.ts
index 78aa012..084c14f 100644
--- a/ui/src/frontend/simple_counter_track.ts
+++ b/ui/src/frontend/simple_counter_track.ts
@@ -52,7 +52,7 @@
}
getTrackShellButtons(): m.Children {
- return [this.getCounterContextMenu()];
+ return this.getCounterContextMenu();
}
getSqlSource(): string {
diff --git a/ui/src/frontend/track_group_panel.ts b/ui/src/frontend/track_group_panel.ts
index 0f0f401..1e35329 100644
--- a/ui/src/frontend/track_group_panel.ts
+++ b/ui/src/frontend/track_group_panel.ts
@@ -35,6 +35,7 @@
TrackContent,
} from './track_panel';
import {canvasClip} from '../common/canvas_utils';
+import {Button} from '../widgets/button';
interface Attrs {
trackGroupId: string;
@@ -133,24 +134,26 @@
m('h1.track-title', {title: name}, name, renderChips(tags)),
collapsed && child !== null ? m('h2.track-subtitle', child) : null,
),
- error && m(CrashButton, {error}),
- selection && selection.kind === 'AREA'
- ? m(
- 'i.material-icons.track-button',
- {
- onclick: (e: MouseEvent) => {
- globals.dispatch(
- Actions.toggleTrackSelection({
- id: trackGroupId,
- isTrackGroup: true,
- }),
- );
- e.stopPropagation();
- },
+ m(
+ '.track-buttons',
+ error && m(CrashButton, {error}),
+ selection &&
+ selection.kind === 'AREA' &&
+ m(Button, {
+ onclick: (e: MouseEvent) => {
+ globals.dispatch(
+ Actions.toggleTrackSelection({
+ id: trackGroupId,
+ isTrackGroup: true,
+ }),
+ );
+ e.stopPropagation();
},
- checkBox,
- )
- : '',
+ icon: checkBox,
+ minimal: true,
+ compact: true,
+ }),
+ ),
),
trackFSM
? m(
@@ -158,6 +161,7 @@
{
track: trackFSM.track,
hasError: Boolean(trackFSM.getError()),
+ height: this.attrs.trackFSM?.track.getHeight(),
},
!collapsed && child !== null ? m('span', child) : null,
)
diff --git a/ui/src/frontend/track_panel.ts b/ui/src/frontend/track_panel.ts
index 4240ef4..59c9857 100644
--- a/ui/src/frontend/track_panel.ts
+++ b/ui/src/frontend/track_panel.ts
@@ -32,12 +32,13 @@
import {verticalScrollToTrack} from './scroll_helper';
import {drawVerticalLineAtTime} from './vertical_line_helper';
import {classNames} from '../base/classnames';
-import {Button} from '../widgets/button';
+import {Button, ButtonBar} from '../widgets/button';
import {Popup} from '../widgets/popup';
import {canvasClip} from '../common/canvas_utils';
import {TimeScale} from './time_scale';
import {getLegacySelection} from '../common/state';
import {CloseTrackButton} from './close_track_button';
+import {exists} from '../base/utils';
function getTitleSize(title: string): string | undefined {
const length = title.length;
@@ -146,6 +147,7 @@
}
const currentSelection = getLegacySelection(globals.state);
+ const pinned = isPinned(attrs.trackKey);
return m(
`.track-shell[draggable=true]`,
@@ -162,51 +164,57 @@
ondrop: (e: DragEvent) => this.ondrop(e, attrs.trackKey),
},
m(
- 'h1',
- {
- title: attrs.title,
- style: {
- 'font-size': getTitleSize(attrs.title),
+ '.track-menubar',
+ m(
+ 'h1',
+ {
+ title: attrs.title,
+ style: {
+ 'font-size': getTitleSize(attrs.title),
+ },
},
- },
- attrs.title,
- renderChips(attrs.tags),
- ),
- m(
- '.track-buttons',
- attrs.buttons,
- m(TrackButton, {
- action: () => {
- globals.dispatch(
- Actions.toggleTrackPinned({trackKey: attrs.trackKey}),
- );
- },
- i: Icons.Pin,
- filledIcon: isPinned(attrs.trackKey),
- tooltip: isPinned(attrs.trackKey) ? 'Unpin' : 'Pin to top',
- showButton: isPinned(attrs.trackKey),
- fullHeight: true,
- }),
- currentSelection !== null && currentSelection.kind === 'AREA'
- ? m(TrackButton, {
- action: (e: MouseEvent) => {
- globals.dispatch(
- Actions.toggleTrackSelection({
- id: attrs.trackKey,
- isTrackGroup: false,
- }),
- );
- e.stopPropagation();
- },
- i: isSelected(attrs.trackKey)
- ? Icons.Checkbox
- : Icons.BlankCheckbox,
- tooltip: isSelected(attrs.trackKey)
- ? 'Remove track'
- : 'Add track to selection',
- showButton: true,
- })
- : '',
+ attrs.title,
+ renderChips(attrs.tags),
+ ),
+ m(
+ ButtonBar,
+ {className: 'track-buttons'},
+ attrs.buttons,
+ m(Button, {
+ className: classNames(!pinned && 'pf-visible-on-hover'),
+ onclick: () => {
+ globals.dispatch(
+ Actions.toggleTrackPinned({trackKey: attrs.trackKey}),
+ );
+ },
+ icon: Icons.Pin,
+ iconFilled: pinned,
+ title: pinned ? 'Unpin' : 'Pin to top',
+ minimal: true,
+ compact: true,
+ }),
+ currentSelection !== null && currentSelection.kind === 'AREA'
+ ? m(Button, {
+ onclick: (e: MouseEvent) => {
+ globals.dispatch(
+ Actions.toggleTrackSelection({
+ id: attrs.trackKey,
+ isTrackGroup: false,
+ }),
+ );
+ e.stopPropagation();
+ },
+ minimal: true,
+ compact: true,
+ icon: isSelected(attrs.trackKey)
+ ? Icons.Checkbox
+ : Icons.BlankCheckbox,
+ title: isSelected(attrs.trackKey)
+ ? 'Remove track'
+ : 'Add track to selection',
+ })
+ : '',
+ ),
),
);
}
@@ -264,6 +272,7 @@
export interface TrackContentAttrs {
track: Track;
hasError?: boolean;
+ height?: number;
}
export class TrackContent implements m.ClassComponent<TrackContentAttrs> {
private mouseDownX?: number;
@@ -275,6 +284,9 @@
return m(
'.track-content',
{
+ style: exists(attrs.height) && {
+ height: `${attrs.height}px`,
+ },
className: classNames(attrs.hasError && 'pf-track-content-error'),
onmousemove: (e: MouseEvent) => {
attrs.track.onMouseMove?.(currentTargetOffset(e));
@@ -372,6 +384,7 @@
m(TrackContent, {
track: attrs.track,
hasError: Boolean(attrs.error),
+ height: attrs.heightPx,
}),
],
);
@@ -395,34 +408,6 @@
}
}
-export interface TrackButtonAttrs {
- action: (e: MouseEvent) => void;
- i: string;
- tooltip: string;
- showButton: boolean;
- fullHeight?: boolean;
- filledIcon?: boolean;
-}
-export class TrackButton implements m.ClassComponent<TrackButtonAttrs> {
- view({attrs}: m.CVnode<TrackButtonAttrs>) {
- return m(
- 'i.track-button',
- {
- class: [
- attrs.showButton ? 'show' : '',
- attrs.fullHeight ? 'full-height' : '',
- attrs.filledIcon ? 'material-icons-filled' : 'material-icons',
- ]
- .filter(Boolean)
- .join(' '),
- onclick: attrs.action,
- title: attrs.tooltip,
- },
- attrs.i,
- );
- }
-}
-
interface TrackPanelAttrs {
trackKey: string;
title: string;
diff --git a/ui/src/plugins/dev.perfetto.AndroidBinderViz/index.ts b/ui/src/plugins/dev.perfetto.AndroidBinderViz/index.ts
index e7ddcb1..ffda5a3 100644
--- a/ui/src/plugins/dev.perfetto.AndroidBinderViz/index.ts
+++ b/ui/src/plugins/dev.perfetto.AndroidBinderViz/index.ts
@@ -12,12 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-import {
- MetricVisualisation,
- Plugin,
- PluginContext,
- PluginDescriptor,
-} from '../../public';
+import {MetricVisualisation, Plugin, PluginDescriptor} from '../../public';
const SPEC = `
{
@@ -37,10 +32,6 @@
`;
class AndroidBinderVizPlugin implements Plugin {
- onActivate(_: PluginContext): void {
- //
- }
-
metricVisualisations(): MetricVisualisation[] {
return [
{
diff --git a/ui/src/plugins/dev.perfetto.AndroidClientServer/index.ts b/ui/src/plugins/dev.perfetto.AndroidClientServer/index.ts
index 5ebbdcb..d60fdb7 100644
--- a/ui/src/plugins/dev.perfetto.AndroidClientServer/index.ts
+++ b/ui/src/plugins/dev.perfetto.AndroidClientServer/index.ts
@@ -16,7 +16,6 @@
NUM,
NUM_NULL,
Plugin,
- PluginContext,
PluginContextTrace,
PluginDescriptor,
STR,
@@ -24,8 +23,6 @@
import {addDebugSliceTrack} from '../../public';
class AndroidClientServer implements Plugin {
- onActivate(_: PluginContext): void {}
-
async onTraceLoad(ctx: PluginContextTrace): Promise<void> {
ctx.registerCommand({
id: 'dev.perfetto.AndroidClientServer#ThreadRuntimeIPC',
diff --git a/ui/src/plugins/dev.perfetto.AndroidCujs/index.ts b/ui/src/plugins/dev.perfetto.AndroidCujs/index.ts
index 0d60ccf..5fb1a1a 100644
--- a/ui/src/plugins/dev.perfetto.AndroidCujs/index.ts
+++ b/ui/src/plugins/dev.perfetto.AndroidCujs/index.ts
@@ -14,12 +14,7 @@
import {runQuery} from '../../common/queries';
import {addDebugSliceTrack} from '../../public';
-import {
- Plugin,
- PluginContext,
- PluginContextTrace,
- PluginDescriptor,
-} from '../../public';
+import {Plugin, PluginContextTrace, PluginDescriptor} from '../../public';
const JANK_CUJ_QUERY_PRECONDITIONS = `
SELECT RUN_METRIC('android/android_jank_cuj.sql');
@@ -131,8 +126,6 @@
const LATENCY_COLUMNS = ['name', 'dur_ms', 'ts', 'dur', 'track_id', 'slice_id'];
class AndroidCujs implements Plugin {
- onActivate(_ctx: PluginContext): void {}
-
async onTraceLoad(ctx: PluginContextTrace): Promise<void> {
ctx.registerCommand({
id: 'dev.perfetto.AndroidCujs#PinJankCUJs',
diff --git a/ui/src/plugins/dev.perfetto.AndroidLongBatteryTracing/index.ts b/ui/src/plugins/dev.perfetto.AndroidLongBatteryTracing/index.ts
index c022dba..414a662 100644
--- a/ui/src/plugins/dev.perfetto.AndroidLongBatteryTracing/index.ts
+++ b/ui/src/plugins/dev.perfetto.AndroidLongBatteryTracing/index.ts
@@ -12,12 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-import {
- Plugin,
- PluginContext,
- PluginContextTrace,
- PluginDescriptor,
-} from '../../public';
+import {Plugin, PluginContextTrace, PluginDescriptor} from '../../public';
import {EngineProxy} from '../../trace_processor/engine';
import {
SimpleSliceTrack,
@@ -1086,8 +1081,6 @@
`;
class AndroidLongBatteryTracing implements Plugin {
- onActivate(_: PluginContext): void {}
-
addSliceTrack(
ctx: PluginContextTrace,
name: string,
diff --git a/ui/src/plugins/dev.perfetto.AndroidNetwork/index.ts b/ui/src/plugins/dev.perfetto.AndroidNetwork/index.ts
index 419c356..0eb7e0f 100644
--- a/ui/src/plugins/dev.perfetto.AndroidNetwork/index.ts
+++ b/ui/src/plugins/dev.perfetto.AndroidNetwork/index.ts
@@ -12,18 +12,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-import {EngineProxy} from '../../trace_processor/engine';
-import {
- Plugin,
- PluginContext,
- PluginContextTrace,
- PluginDescriptor,
-} from '../../public';
+import {Plugin, PluginContextTrace, PluginDescriptor} from '../../public';
import {addDebugSliceTrack} from '../../public';
+import {EngineProxy} from '../../trace_processor/engine';
class AndroidNetwork implements Plugin {
- onActivate(_ctx: PluginContext): void {}
-
// Adds a debug track using the provided query and given columns. The columns
// must be start with ts, dur, and a name column. The name column and all
// following columns are shown as arguments in slice details.
diff --git a/ui/src/plugins/dev.perfetto.AndroidPerf/index.ts b/ui/src/plugins/dev.perfetto.AndroidPerf/index.ts
index a221db6..a53ff20 100644
--- a/ui/src/plugins/dev.perfetto.AndroidPerf/index.ts
+++ b/ui/src/plugins/dev.perfetto.AndroidPerf/index.ts
@@ -15,15 +15,12 @@
import {
addDebugSliceTrack,
Plugin,
- PluginContext,
PluginContextTrace,
PluginDescriptor,
} from '../../public';
import {EngineProxy} from '../../trace_processor/engine';
class AndroidPerf implements Plugin {
- onActivate(_ctx: PluginContext): void {}
-
async addAppProcessStartsDebugTrack(
engine: EngineProxy,
reason: string,
diff --git a/ui/src/plugins/dev.perfetto.AndroidPerfTraceCounters/index.ts b/ui/src/plugins/dev.perfetto.AndroidPerfTraceCounters/index.ts
index e7d6639..2ec9223 100644
--- a/ui/src/plugins/dev.perfetto.AndroidPerfTraceCounters/index.ts
+++ b/ui/src/plugins/dev.perfetto.AndroidPerfTraceCounters/index.ts
@@ -12,12 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-import {
- Plugin,
- PluginContext,
- PluginContextTrace,
- PluginDescriptor,
-} from '../../public';
+import {Plugin, PluginContextTrace, PluginDescriptor} from '../../public';
import {addDebugSliceTrack} from '../../public';
import {runQuery} from '../../common/queries';
@@ -31,8 +26,6 @@
`;
class AndroidPerfTraceCounters implements Plugin {
- onActivate(_: PluginContext): void {}
-
async onTraceLoad(ctx: PluginContextTrace): Promise<void> {
const resp = await runQuery(PERF_TRACE_COUNTERS_PRECONDITION, ctx.engine);
if (resp.totalRowCount === 0) return;
diff --git a/ui/src/plugins/dev.perfetto.AndroidStartup/index.ts b/ui/src/plugins/dev.perfetto.AndroidStartup/index.ts
index ebb10b8..4092621 100644
--- a/ui/src/plugins/dev.perfetto.AndroidStartup/index.ts
+++ b/ui/src/plugins/dev.perfetto.AndroidStartup/index.ts
@@ -12,21 +12,13 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-import {
- LONG,
- Plugin,
- PluginContext,
- PluginContextTrace,
- PluginDescriptor,
-} from '../../public';
+import {LONG, Plugin, PluginContextTrace, PluginDescriptor} from '../../public';
import {
SimpleSliceTrack,
SimpleSliceTrackConfig,
} from '../../frontend/simple_slice_track';
class AndroidStartup implements Plugin {
- onActivate(_ctx: PluginContext): void {}
-
async onTraceLoad(ctx: PluginContextTrace): Promise<void> {
const e = ctx.engine;
await e.query(`include perfetto module android.startup.startups;`);
diff --git a/ui/src/plugins/dev.perfetto.CoreCommands/index.ts b/ui/src/plugins/dev.perfetto.CoreCommands/index.ts
index 6e5d474..8dc6a6f 100644
--- a/ui/src/plugins/dev.perfetto.CoreCommands/index.ts
+++ b/ui/src/plugins/dev.perfetto.CoreCommands/index.ts
@@ -88,7 +88,7 @@
order by total_self_size desc
limit 100;`;
-const coreCommands: Plugin = {
+class CoreCommandsPlugin implements Plugin {
onActivate(ctx: PluginContext) {
ctx.registerCommand({
id: 'dev.perfetto.CoreCommands#ToggleLeftSidebar',
@@ -102,7 +102,7 @@
},
defaultHotkey: '!Mod+B',
});
- },
+ }
async onTraceLoad(ctx: PluginContextTrace): Promise<void> {
ctx.registerCommand({
@@ -249,8 +249,8 @@
ctx.tabs.showTab('current_selection');
},
});
- },
-};
+ }
+}
function promptForTimestamp(message: string): time | undefined {
const tsStr = window.prompt(message);
@@ -266,5 +266,5 @@
export const plugin: PluginDescriptor = {
pluginId: 'dev.perfetto.CoreCommands',
- plugin: coreCommands,
+ plugin: CoreCommandsPlugin,
};
diff --git a/ui/src/plugins/dev.perfetto.ExampleState/index.ts b/ui/src/plugins/dev.perfetto.ExampleState/index.ts
index 0f3c584..41e2562 100644
--- a/ui/src/plugins/dev.perfetto.ExampleState/index.ts
+++ b/ui/src/plugins/dev.perfetto.ExampleState/index.ts
@@ -15,7 +15,6 @@
import {
createStore,
Plugin,
- PluginContext,
PluginContextTrace,
PluginDescriptor,
Store,
@@ -43,10 +42,6 @@
}
}
- onActivate(_: PluginContext): void {
- //
- }
-
async onTraceLoad(ctx: PluginContextTrace): Promise<void> {
this.store = ctx.mountStore((init: unknown) => this.migrate(init));
diff --git a/ui/src/plugins/dev.perfetto.LargeScreensPerf/index.ts b/ui/src/plugins/dev.perfetto.LargeScreensPerf/index.ts
index 3ccc12c..9bd57d3 100644
--- a/ui/src/plugins/dev.perfetto.LargeScreensPerf/index.ts
+++ b/ui/src/plugins/dev.perfetto.LargeScreensPerf/index.ts
@@ -12,16 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-import {
- Plugin,
- PluginContext,
- PluginContextTrace,
- PluginDescriptor,
-} from '../../public';
+import {Plugin, PluginContextTrace, PluginDescriptor} from '../../public';
class LargeScreensPerf implements Plugin {
- onActivate(_ctx: PluginContext): void {}
-
async onTraceLoad(ctx: PluginContextTrace): Promise<void> {
ctx.registerCommand({
id: 'dev.perfetto.LargeScreensPerf#PinUnfoldLatencyTracks',
diff --git a/ui/src/plugins/org.kernel.LinuxKernelDevices/index.ts b/ui/src/plugins/org.kernel.LinuxKernelDevices/index.ts
index e9bf9b0..d7a37d8 100644
--- a/ui/src/plugins/org.kernel.LinuxKernelDevices/index.ts
+++ b/ui/src/plugins/org.kernel.LinuxKernelDevices/index.ts
@@ -15,7 +15,6 @@
import {
NUM,
Plugin,
- PluginContext,
PluginContextTrace,
PluginDescriptor,
STR_NULL,
@@ -26,8 +25,6 @@
// This plugin renders visualizations of runtime power state transitions for
// Linux kernel devices (devices managed by Linux drivers).
class LinuxKernelDevices implements Plugin {
- onActivate(_: PluginContext): void {}
-
async onTraceLoad(ctx: PluginContextTrace): Promise<void> {
const result = await ctx.engine.query(`
with
diff --git a/ui/src/public/index.ts b/ui/src/public/index.ts
index 97cee3c..e51d5d5 100644
--- a/ui/src/public/index.ts
+++ b/ui/src/public/index.ts
@@ -15,7 +15,7 @@
import m from 'mithril';
import {Hotkey} from '../base/hotkeys';
-import {duration, time} from '../base/time';
+import {Span, duration, time} from '../base/time';
import {Migrate, Store} from '../base/store';
import {ColorScheme} from '../core/colorizer';
import {LegacySelection} from '../common/state';
@@ -376,6 +376,12 @@
// Bring a timestamp into view.
panToTimestamp(ts: time): void;
+
+ // Move the viewport
+ setViewportTime(start: time, end: time): void;
+
+ // A span representing the current viewport location
+ readonly viewport: Span<time, duration>;
};
// Control over the bottom details pane.
@@ -421,11 +427,16 @@
// Create a store mounted over the top of this plugin's persistent state.
mountStore<T>(migrate: Migrate<T>): Store<T>;
+
+ trace: {
+ // A span representing the start and end time of the trace
+ readonly span: Span<time, duration>;
+ };
}
export interface Plugin {
// Lifecycle methods.
- onActivate(ctx: PluginContext): void;
+ onActivate?(ctx: PluginContext): void;
onTraceLoad?(ctx: PluginContextTrace): Promise<void>;
onTraceUnload?(ctx: PluginContextTrace): Promise<void>;
onDeactivate?(ctx: PluginContext): void;
@@ -504,9 +515,8 @@
[key: string]: string | number | boolean | undefined;
};
-// Plugins can be passed as class refs, factory functions, or concrete plugin
-// implementations.
-export type PluginFactory = PluginClass | Plugin | (() => Plugin);
+// Plugins can be class refs or concrete plugin implementations.
+export type PluginFactory = PluginClass | Plugin;
export interface PluginDescriptor {
// A unique string for your plugin. To ensure the name is unique you
diff --git a/ui/src/tracks/android_log/index.ts b/ui/src/tracks/android_log/index.ts
index b83202b..c35143e 100644
--- a/ui/src/tracks/android_log/index.ts
+++ b/ui/src/tracks/android_log/index.ts
@@ -14,159 +14,49 @@
import m from 'mithril';
-import {duration, Time, time} from '../../base/time';
-import {LIMIT, TrackData} from '../../common/track_data';
-import {TimelineFetcher} from '../../common/track_helper';
-import {checkerboardExcept} from '../../frontend/checkerboard';
-import {globals} from '../../frontend/globals';
-import {LogPanel} from '../../frontend/logs_panel';
-import {PanelSize} from '../../frontend/panel';
+import {LogFilteringCriteria, LogPanel} from './logs_panel';
import {
- EngineProxy,
Plugin,
- PluginContext,
PluginContextTrace,
PluginDescriptor,
- Track,
} from '../../public';
-import {LONG, NUM} from '../../trace_processor/query_result';
+import {NUM} from '../../trace_processor/query_result';
+import {AndroidLogTrack} from './logs_track';
export const ANDROID_LOGS_TRACK_KIND = 'AndroidLogTrack';
-export interface Data extends TrackData {
- // Total number of log events within [start, end], before any quantization.
- numEvents: number;
+const VERSION = 1;
- // Below: data quantized by resolution and aggregated by event priority.
- timestamps: BigInt64Array;
+const DEFAULT_STATE: AndroidLogPluginState = {
+ version: VERSION,
+ filter: {
+ // The first two log priorities are ignored.
+ minimumLevel: 2,
+ tags: [],
+ textEntry: '',
+ hideNonMatching: true,
+ },
+};
- // Each Uint8 value has the i-th bit is set if there is at least one log
- // event at the i-th priority level at the corresponding time in |timestamps|.
- priorities: Uint8Array;
-}
-
-export interface Config {}
-
-interface LevelCfg {
- color: string;
- prios: number[];
-}
-
-const LEVELS: LevelCfg[] = [
- {color: 'hsl(122, 39%, 49%)', prios: [0, 1, 2, 3]}, // Up to DEBUG: Green.
- {color: 'hsl(0, 0%, 70%)', prios: [4]}, // 4 (INFO) -> Gray.
- {color: 'hsl(45, 100%, 51%)', prios: [5]}, // 5 (WARN) -> Amber.
- {color: 'hsl(4, 90%, 58%)', prios: [6]}, // 6 (ERROR) -> Red.
- {color: 'hsl(291, 64%, 42%)', prios: [7]}, // 7 (FATAL) -> Purple
-];
-
-const MARGIN_TOP = 2;
-const RECT_HEIGHT = 35;
-const EVT_PX = 2; // Width of an event tick in pixels.
-
-class AndroidLogTrack implements Track {
- private fetcher = new TimelineFetcher<Data>(this.onBoundsChange.bind(this));
-
- constructor(private engine: EngineProxy) {}
-
- async onUpdate(): Promise<void> {
- await this.fetcher.requestDataForCurrentTime();
- }
-
- async onDestroy(): Promise<void> {
- this.fetcher.dispose();
- }
-
- getHeight(): number {
- return 40;
- }
-
- async onBoundsChange(
- start: time,
- end: time,
- resolution: duration,
- ): Promise<Data> {
- const queryRes = await this.engine.query(`
- select
- cast(ts / ${resolution} as integer) * ${resolution} as tsQuant,
- prio,
- count(prio) as numEvents
- from android_logs
- where ts >= ${start} and ts <= ${end}
- group by tsQuant, prio
- order by tsQuant, prio limit ${LIMIT};`);
-
- const rowCount = queryRes.numRows();
- const result = {
- start,
- end,
- resolution,
- length: rowCount,
- numEvents: 0,
- timestamps: new BigInt64Array(rowCount),
- priorities: new Uint8Array(rowCount),
- };
-
- const it = queryRes.iter({tsQuant: LONG, prio: NUM, numEvents: NUM});
- for (let row = 0; it.valid(); it.next(), row++) {
- result.timestamps[row] = it.tsQuant;
- const prio = Math.min(it.prio, 7);
- result.priorities[row] |= 1 << prio;
- result.numEvents += it.numEvents;
- }
- return result;
- }
-
- render(ctx: CanvasRenderingContext2D, size: PanelSize): void {
- const {visibleTimeScale} = globals.timeline;
-
- const data = this.fetcher.data;
-
- if (data === undefined) return; // Can't possibly draw anything.
-
- const dataStartPx = visibleTimeScale.timeToPx(data.start);
- const dataEndPx = visibleTimeScale.timeToPx(data.end);
-
- checkerboardExcept(
- ctx,
- this.getHeight(),
- 0,
- size.width,
- dataStartPx,
- dataEndPx,
- );
-
- const quantWidth = Math.max(
- EVT_PX,
- visibleTimeScale.durationToPx(data.resolution),
- );
- const blockH = RECT_HEIGHT / LEVELS.length;
- for (let i = 0; i < data.timestamps.length; i++) {
- for (let lev = 0; lev < LEVELS.length; lev++) {
- let hasEventsForCurColor = false;
- for (const prio of LEVELS[lev].prios) {
- if (data.priorities[i] & (1 << prio)) hasEventsForCurColor = true;
- }
- if (!hasEventsForCurColor) continue;
- ctx.fillStyle = LEVELS[lev].color;
- const timestamp = Time.fromRaw(data.timestamps[i]);
- const px = Math.floor(visibleTimeScale.timeToPx(timestamp));
- ctx.fillRect(px, MARGIN_TOP + blockH * lev, quantWidth, blockH);
- } // for(lev)
- } // for (timestamps)
- }
+interface AndroidLogPluginState {
+ version: number;
+ filter: LogFilteringCriteria;
}
class AndroidLog implements Plugin {
- onActivate(_ctx: PluginContext): void {}
-
async onTraceLoad(ctx: PluginContextTrace): Promise<void> {
+ const store = ctx.mountStore<AndroidLogPluginState>((init) => {
+ return init && (init as {version: unknown}).version === VERSION
+ ? (init as AndroidLogPluginState)
+ : DEFAULT_STATE;
+ });
+
const result = await ctx.engine.query(
`select count(1) as cnt from android_logs`,
);
const logCount = result.firstRow({cnt: NUM}).cnt;
if (logCount > 0) {
- ctx.registerTrack({
+ ctx.registerStaticTrack({
uri: 'perfetto.AndroidLog',
displayName: 'Android logs',
kind: ANDROID_LOGS_TRACK_KIND,
@@ -177,11 +67,17 @@
const androidLogsTabUri = 'perfetto.AndroidLog#tab';
// Eternal tabs should always be available even if there is nothing to show
+ const filterStore = store.createSubStore(
+ ['filter'],
+ (x) => x as LogFilteringCriteria,
+ );
+
ctx.registerTab({
isEphemeral: false,
uri: androidLogsTabUri,
content: {
- render: () => m(LogPanel),
+ render: () =>
+ m(LogPanel, {filterStore: filterStore, engine: ctx.engine}),
getTitle: () => 'Android Logs',
},
});
diff --git a/ui/src/tracks/android_log/logs_panel.ts b/ui/src/tracks/android_log/logs_panel.ts
new file mode 100644
index 0000000..1a8d233
--- /dev/null
+++ b/ui/src/tracks/android_log/logs_panel.ts
@@ -0,0 +1,548 @@
+// Copyright (C) 2019 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 m from 'mithril';
+
+import {duration, Span, time, Time, TimeSpan} from '../../base/time';
+import {Actions} from '../../common/actions';
+import {raf} from '../../core/raf_scheduler';
+import {DetailsShell} from '../../widgets/details_shell';
+import {VirtualScrollContainer} from '../../widgets/virtual_scroll_container';
+
+import {SELECTED_LOG_ROWS_COLOR} from '../../frontend/css_constants';
+import {globals} from '../../frontend/globals';
+import {Timestamp} from '../../frontend/widgets/timestamp';
+import {createStore, EngineProxy, LONG, NUM, Store, STR} from '../../public';
+import {Monitor} from '../../base/monitor';
+import {AsyncLimiter} from '../../base/async_limiter';
+import {escapeGlob, escapeQuery} from '../../trace_processor/query_utils';
+import {Select} from '../../widgets/select';
+import {Button} from '../../widgets/button';
+import {TextInput} from '../../widgets/text_input';
+
+const ROW_H = 20;
+
+export interface LogFilteringCriteria {
+ minimumLevel: number;
+ tags: string[];
+ textEntry: string;
+ hideNonMatching: boolean;
+}
+
+export interface LogPanelAttrs {
+ filterStore: Store<LogFilteringCriteria>;
+ engine: EngineProxy;
+}
+
+interface Pagination {
+ offset: number;
+ count: number;
+}
+
+interface LogEntries {
+ offset: number;
+ timestamps: time[];
+ priorities: number[];
+ tags: string[];
+ messages: string[];
+ isHighlighted: boolean[];
+ processName: string[];
+ totalEvents: number; // Count of the total number of events within this window
+}
+
+export class LogPanel implements m.ClassComponent<LogPanelAttrs> {
+ private readonly SKIRT_SIZE = 50;
+ private entries?: LogEntries;
+ private isStale = true;
+ private viewportBounds = {top: 0, bottom: 0};
+
+ private readonly paginationStore = createStore<Pagination>({
+ offset: 0,
+ count: 0,
+ });
+ private readonly rowsMonitor: Monitor;
+ private readonly filterMonitor: Monitor;
+ private readonly queryLimiter = new AsyncLimiter();
+
+ constructor({attrs}: m.CVnode<LogPanelAttrs>) {
+ this.rowsMonitor = new Monitor([
+ () => attrs.filterStore.state,
+ () => globals.state.frontendLocalState.visibleState.start,
+ () => globals.state.frontendLocalState.visibleState.end,
+ () => this.paginationStore.state,
+ ]);
+
+ this.filterMonitor = new Monitor([() => attrs.filterStore.state]);
+ }
+
+ view({attrs}: m.CVnode<LogPanelAttrs>) {
+ if (this.rowsMonitor.ifStateChanged()) {
+ this.queryLimiter.schedule(async () => {
+ this.isStale = true;
+ raf.scheduleFullRedraw();
+
+ const visibleState = globals.state.frontendLocalState.visibleState;
+ const visibleSpan = new TimeSpan(visibleState.start, visibleState.end);
+
+ if (this.filterMonitor.ifStateChanged()) {
+ await updateLogView(attrs.engine, attrs.filterStore.state);
+ }
+
+ this.entries = await updateLogEntries(
+ attrs.engine,
+ visibleSpan,
+ this.paginationStore.state,
+ );
+
+ raf.scheduleFullRedraw();
+ this.isStale = false;
+ });
+ }
+
+ const hasProcessNames =
+ this.entries &&
+ this.entries.processName.filter((name) => name).length > 0;
+
+ const rows: m.Children = [];
+ rows.push(
+ m(
+ `.row`,
+ m('.cell.row-header', 'Timestamp'),
+ m('.cell.row-header', 'Level'),
+ m('.cell.row-header', 'Tag'),
+ hasProcessNames
+ ? m('.cell.with-process.row-header', 'Process name')
+ : undefined,
+ hasProcessNames
+ ? m('.cell.with-process.row-header', 'Message')
+ : m('.cell.no-process.row-header', 'Message'),
+ m('br'),
+ ),
+ );
+ if (this.entries) {
+ const offset = this.entries.offset;
+ const timestamps = this.entries.timestamps;
+ const priorities = this.entries.priorities;
+ const tags = this.entries.tags;
+ const messages = this.entries.messages;
+ const processNames = this.entries.processName;
+ const totalEvents = this.entries.totalEvents;
+
+ for (let i = 0; i < this.entries.timestamps.length; i++) {
+ const priorityLetter = LOG_PRIORITIES[priorities[i]][0];
+ const ts = timestamps[i];
+ const prioClass = priorityLetter || '';
+ const style: {top: string; backgroundColor?: string} = {
+ // 1.5 is for the width of the header
+ top: `${(offset + i + 1.5) * ROW_H}px`,
+ };
+ if (this.entries.isHighlighted[i]) {
+ style.backgroundColor = SELECTED_LOG_ROWS_COLOR;
+ }
+
+ rows.push(
+ m(
+ `.row.${prioClass}`,
+ {
+ class: this.isStale ? 'stale' : '',
+ style,
+ onmouseover: () => {
+ globals.dispatch(Actions.setHoverCursorTimestamp({ts}));
+ },
+ onmouseout: () => {
+ globals.dispatch(
+ Actions.setHoverCursorTimestamp({ts: Time.INVALID}),
+ );
+ },
+ },
+ m('.cell', m(Timestamp, {ts})),
+ m('.cell', priorityLetter || '?'),
+ m('.cell', tags[i]),
+ hasProcessNames
+ ? m('.cell.with-process', processNames[i])
+ : undefined,
+ hasProcessNames
+ ? m('.cell.with-process', messages[i])
+ : m('.cell.no-process', messages[i]),
+ m('br'),
+ ),
+ );
+ }
+
+ return m(
+ DetailsShell,
+ {
+ title: 'Android Logs',
+ description: `[${this.viewportBounds.top}, ${this.viewportBounds.bottom}] / ${totalEvents}`,
+ buttons: m(LogsFilters, {store: attrs.filterStore}),
+ },
+ m(
+ VirtualScrollContainer,
+ {
+ onScroll: (scrollContainer: HTMLElement) => {
+ this.recomputeVisibleRowsAndUpdate(scrollContainer);
+ raf.scheduleFullRedraw();
+ },
+ },
+ m(
+ '.log-panel',
+ m('.rows', {style: {height: `${totalEvents * ROW_H}px`}}, rows),
+ ),
+ ),
+ );
+ }
+
+ return null;
+ }
+
+ recomputeVisibleRowsAndUpdate(scrollContainer: HTMLElement) {
+ const viewportTop = Math.floor(scrollContainer.scrollTop / ROW_H);
+ const viewportHeight = Math.ceil(scrollContainer.clientHeight / ROW_H);
+ const viewportBottom = viewportTop + viewportHeight;
+
+ this.viewportBounds = {
+ top: viewportTop,
+ bottom: viewportBottom,
+ };
+
+ const curPage = this.paginationStore.state;
+
+ if (
+ viewportTop < curPage.offset ||
+ viewportBottom >= curPage.offset + curPage.count
+ ) {
+ this.paginationStore.edit((draft) => {
+ const offset = Math.max(0, viewportTop - this.SKIRT_SIZE);
+ // Make it even so alternating coloured rows line up
+ const offsetEven = Math.floor(offset / 2) * 2;
+ draft.offset = offsetEven;
+ draft.count = viewportHeight + this.SKIRT_SIZE * 2;
+ });
+ }
+ }
+}
+
+export const LOG_PRIORITIES = [
+ '-',
+ '-',
+ 'Verbose',
+ 'Debug',
+ 'Info',
+ 'Warn',
+ 'Error',
+ 'Fatal',
+];
+const IGNORED_STATES = 2;
+
+interface LogPriorityWidgetAttrs {
+ options: string[];
+ selectedIndex: number;
+ onSelect: (id: number) => void;
+}
+
+class LogPriorityWidget implements m.ClassComponent<LogPriorityWidgetAttrs> {
+ view(vnode: m.Vnode<LogPriorityWidgetAttrs>) {
+ const attrs = vnode.attrs;
+ const optionComponents = [];
+ for (let i = IGNORED_STATES; i < attrs.options.length; i++) {
+ const selected = i === attrs.selectedIndex;
+ optionComponents.push(
+ m('option', {value: i, selected}, attrs.options[i]),
+ );
+ }
+ return m(
+ Select,
+ {
+ onchange: (e: Event) => {
+ const selectionValue = (e.target as HTMLSelectElement).value;
+ attrs.onSelect(Number(selectionValue));
+ },
+ },
+ optionComponents,
+ );
+ }
+}
+
+interface LogTagChipAttrs {
+ name: string;
+ removeTag: (name: string) => void;
+}
+
+class LogTagChip implements m.ClassComponent<LogTagChipAttrs> {
+ view({attrs}: m.CVnode<LogTagChipAttrs>) {
+ return m(Button, {
+ label: attrs.name,
+ rightIcon: 'close',
+ onclick: () => attrs.removeTag(attrs.name),
+ });
+ }
+}
+
+interface LogTagsWidgetAttrs {
+ tags: string[];
+ onRemoveTag: (tag: string) => void;
+ onAddTag: (tag: string) => void;
+}
+
+class LogTagsWidget implements m.ClassComponent<LogTagsWidgetAttrs> {
+ view(vnode: m.Vnode<LogTagsWidgetAttrs>) {
+ const tags = vnode.attrs.tags;
+ return [
+ tags.map((tag) =>
+ m(LogTagChip, {
+ name: tag,
+ removeTag: (tag) => vnode.attrs.onRemoveTag(tag),
+ }),
+ ),
+ m(TextInput, {
+ placeholder: 'Filter by tag...',
+ onkeydown: (e: KeyboardEvent) => {
+ // This is to avoid zooming on 'w'(and other unexpected effects
+ // of key presses in this input field).
+ e.stopPropagation();
+ const htmlElement = e.target as HTMLInputElement;
+
+ // When the user clicks 'Backspace' we delete the previous tag.
+ if (
+ e.key === 'Backspace' &&
+ tags.length > 0 &&
+ htmlElement.value === ''
+ ) {
+ vnode.attrs.onRemoveTag(tags[tags.length - 1]);
+ return;
+ }
+
+ if (e.key !== 'Enter') {
+ return;
+ }
+ if (htmlElement.value === '') {
+ return;
+ }
+ vnode.attrs.onAddTag(htmlElement.value.trim());
+ htmlElement.value = '';
+ },
+ }),
+ ];
+ }
+}
+
+interface LogTextWidgetAttrs {
+ onChange: (value: string) => void;
+}
+
+class LogTextWidget implements m.ClassComponent<LogTextWidgetAttrs> {
+ view({attrs}: m.CVnode<LogTextWidgetAttrs>) {
+ return m(TextInput, {
+ placeholder: 'Search logs...',
+ onkeyup: (e: KeyboardEvent) => {
+ // We want to use the value of the input field after it has been
+ // updated with the latest key (onkeyup).
+ const htmlElement = e.target as HTMLInputElement;
+ attrs.onChange(htmlElement.value);
+ },
+ });
+ }
+}
+
+interface FilterByTextWidgetAttrs {
+ hideNonMatching: boolean;
+ disabled: boolean;
+ onClick: () => void;
+}
+
+class FilterByTextWidget implements m.ClassComponent<FilterByTextWidgetAttrs> {
+ view({attrs}: m.Vnode<FilterByTextWidgetAttrs>) {
+ const icon = attrs.hideNonMatching ? 'unfold_less' : 'unfold_more';
+ const tooltip = attrs.hideNonMatching
+ ? 'Expand all and view highlighted'
+ : 'Collapse all';
+ return m(Button, {
+ icon,
+ title: tooltip,
+ disabled: attrs.disabled,
+ minimal: true,
+ onclick: attrs.onClick,
+ });
+ }
+}
+
+interface LogsFiltersAttrs {
+ store: Store<LogFilteringCriteria>;
+}
+
+export class LogsFilters implements m.ClassComponent<LogsFiltersAttrs> {
+ view({attrs}: m.CVnode<LogsFiltersAttrs>) {
+ return [
+ m('.log-label', 'Log Level'),
+ m(LogPriorityWidget, {
+ options: LOG_PRIORITIES,
+ selectedIndex: attrs.store.state.minimumLevel,
+ onSelect: (minimumLevel) => {
+ attrs.store.edit((draft) => {
+ draft.minimumLevel = minimumLevel;
+ });
+ },
+ }),
+ m(LogTagsWidget, {
+ tags: attrs.store.state.tags,
+ onAddTag: (tag) => {
+ attrs.store.edit((draft) => {
+ draft.tags.push(tag);
+ });
+ },
+ onRemoveTag: (tag) => {
+ attrs.store.edit((draft) => {
+ draft.tags = draft.tags.filter((t) => t !== tag);
+ });
+ },
+ }),
+ m(LogTextWidget, {
+ onChange: (text) => {
+ attrs.store.edit((draft) => {
+ draft.textEntry = text;
+ });
+ },
+ }),
+ m(FilterByTextWidget, {
+ hideNonMatching: attrs.store.state.hideNonMatching,
+ onClick: () => {
+ attrs.store.edit((draft) => {
+ draft.hideNonMatching = !draft.hideNonMatching;
+ });
+ },
+ disabled: attrs.store.state.textEntry === '',
+ }),
+ ];
+ }
+}
+
+async function updateLogEntries(
+ engine: EngineProxy,
+ span: Span<time, duration>,
+ pagination: Pagination,
+): Promise<LogEntries> {
+ const rowsResult = await engine.query(`
+ select
+ ts,
+ prio,
+ ifnull(tag, '[NULL]') as tag,
+ ifnull(msg, '[NULL]') as msg,
+ is_msg_highlighted as isMsgHighlighted,
+ is_process_highlighted as isProcessHighlighted,
+ ifnull(process_name, '') as processName
+ from filtered_logs
+ where ts >= ${span.start} and ts <= ${span.end}
+ order by ts
+ limit ${pagination.offset}, ${pagination.count}
+ `);
+
+ const timestamps: time[] = [];
+ const priorities = [];
+ const tags = [];
+ const messages = [];
+ const isHighlighted = [];
+ const processName = [];
+
+ const it = rowsResult.iter({
+ ts: LONG,
+ prio: NUM,
+ tag: STR,
+ msg: STR,
+ isMsgHighlighted: NUM,
+ isProcessHighlighted: NUM,
+ processName: STR,
+ });
+ for (; it.valid(); it.next()) {
+ timestamps.push(Time.fromRaw(it.ts));
+ priorities.push(it.prio);
+ tags.push(it.tag);
+ messages.push(it.msg);
+ isHighlighted.push(
+ it.isMsgHighlighted === 1 || it.isProcessHighlighted === 1,
+ );
+ processName.push(it.processName);
+ }
+
+ const queryRes = await engine.query(`
+ select
+ count(*) as totalEvents
+ from filtered_logs
+ where ts >= ${span.start} and ts <= ${span.end}
+ `);
+ const {totalEvents} = queryRes.firstRow({totalEvents: NUM});
+
+ return {
+ offset: pagination.offset,
+ timestamps,
+ priorities,
+ tags,
+ messages,
+ isHighlighted,
+ processName,
+ totalEvents,
+ };
+}
+
+async function updateLogView(
+ engine: EngineProxy,
+ filter: LogFilteringCriteria,
+) {
+ await engine.query('drop view if exists filtered_logs');
+
+ const globMatch = composeGlobMatch(filter.hideNonMatching, filter.textEntry);
+ let selectedRows = `select prio, ts, tag, msg,
+ process.name as process_name, ${globMatch}
+ from android_logs
+ left join thread using(utid)
+ left join process using(upid)
+ where prio >= ${filter.minimumLevel}`;
+ if (filter.tags.length) {
+ selectedRows += ` and tag in (${serializeTags(filter.tags)})`;
+ }
+
+ // We extract only the rows which will be visible.
+ await engine.query(`create view filtered_logs as select *
+ from (${selectedRows})
+ where is_msg_chosen is 1 or is_process_chosen is 1`);
+}
+
+function serializeTags(tags: string[]) {
+ return tags.map((tag) => escapeQuery(tag)).join();
+}
+
+function composeGlobMatch(isCollaped: boolean, textEntry: string) {
+ if (isCollaped) {
+ // If the entries are collapsed, we won't highlight any lines.
+ return `msg glob ${escapeGlob(textEntry)} as is_msg_chosen,
+ (process.name is not null and process.name glob ${escapeGlob(
+ textEntry,
+ )}) as is_process_chosen,
+ 0 as is_msg_highlighted,
+ 0 as is_process_highlighted`;
+ } else if (!textEntry) {
+ // If there is no text entry, we will show all lines, but won't highlight.
+ // any.
+ return `1 as is_msg_chosen,
+ 1 as is_process_chosen,
+ 0 as is_msg_highlighted,
+ 0 as is_process_highlighted`;
+ } else {
+ return `1 as is_msg_chosen,
+ 1 as is_process_chosen,
+ msg glob ${escapeGlob(textEntry)} as is_msg_highlighted,
+ (process.name is not null and process.name glob ${escapeGlob(
+ textEntry,
+ )}) as is_process_highlighted`;
+ }
+}
diff --git a/ui/src/tracks/android_log/logs_track.ts b/ui/src/tracks/android_log/logs_track.ts
new file mode 100644
index 0000000..1c5b3c6
--- /dev/null
+++ b/ui/src/tracks/android_log/logs_track.ts
@@ -0,0 +1,143 @@
+// Copyright (C) 2024 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 {Time, duration, time} from '../../base/time';
+import {LIMIT, TrackData} from '../../common/track_data';
+import {LONG, NUM, TimelineFetcher} from '../../common/track_helper';
+import {checkerboardExcept} from '../../frontend/checkerboard';
+import {globals} from '../../frontend/globals';
+import {PanelSize} from '../../frontend/panel';
+import {EngineProxy, Track} from '../../public';
+
+export interface Data extends TrackData {
+ // Total number of log events within [start, end], before any quantization.
+ numEvents: number;
+
+ // Below: data quantized by resolution and aggregated by event priority.
+ timestamps: BigInt64Array;
+
+ // Each Uint8 value has the i-th bit is set if there is at least one log
+ // event at the i-th priority level at the corresponding time in |timestamps|.
+ priorities: Uint8Array;
+}
+
+const LEVELS: LevelCfg[] = [
+ {color: 'hsl(122, 39%, 49%)', prios: [0, 1, 2, 3]}, // Up to DEBUG: Green.
+ {color: 'hsl(0, 0%, 70%)', prios: [4]}, // 4 (INFO) -> Gray.
+ {color: 'hsl(45, 100%, 51%)', prios: [5]}, // 5 (WARN) -> Amber.
+ {color: 'hsl(4, 90%, 58%)', prios: [6]}, // 6 (ERROR) -> Red.
+ {color: 'hsl(291, 64%, 42%)', prios: [7]}, // 7 (FATAL) -> Purple
+];
+
+const MARGIN_TOP = 2;
+const RECT_HEIGHT = 35;
+const EVT_PX = 2; // Width of an event tick in pixels.
+
+interface LevelCfg {
+ color: string;
+ prios: number[];
+}
+
+export class AndroidLogTrack implements Track {
+ private fetcher = new TimelineFetcher<Data>(this.onBoundsChange.bind(this));
+
+ constructor(private engine: EngineProxy) {}
+
+ async onUpdate(): Promise<void> {
+ await this.fetcher.requestDataForCurrentTime();
+ }
+
+ async onDestroy(): Promise<void> {
+ this.fetcher.dispose();
+ }
+
+ getHeight(): number {
+ return 40;
+ }
+
+ async onBoundsChange(
+ start: time,
+ end: time,
+ resolution: duration,
+ ): Promise<Data> {
+ const queryRes = await this.engine.query(`
+ select
+ cast(ts / ${resolution} as integer) * ${resolution} as tsQuant,
+ prio,
+ count(prio) as numEvents
+ from android_logs
+ where ts >= ${start} and ts <= ${end}
+ group by tsQuant, prio
+ order by tsQuant, prio limit ${LIMIT};`);
+
+ const rowCount = queryRes.numRows();
+ const result = {
+ start,
+ end,
+ resolution,
+ length: rowCount,
+ numEvents: 0,
+ timestamps: new BigInt64Array(rowCount),
+ priorities: new Uint8Array(rowCount),
+ };
+
+ const it = queryRes.iter({tsQuant: LONG, prio: NUM, numEvents: NUM});
+ for (let row = 0; it.valid(); it.next(), row++) {
+ result.timestamps[row] = it.tsQuant;
+ const prio = Math.min(it.prio, 7);
+ result.priorities[row] |= 1 << prio;
+ result.numEvents += it.numEvents;
+ }
+ return result;
+ }
+
+ render(ctx: CanvasRenderingContext2D, size: PanelSize): void {
+ const {visibleTimeScale} = globals.timeline;
+
+ const data = this.fetcher.data;
+
+ if (data === undefined) return; // Can't possibly draw anything.
+
+ const dataStartPx = visibleTimeScale.timeToPx(data.start);
+ const dataEndPx = visibleTimeScale.timeToPx(data.end);
+
+ checkerboardExcept(
+ ctx,
+ this.getHeight(),
+ 0,
+ size.width,
+ dataStartPx,
+ dataEndPx,
+ );
+
+ const quantWidth = Math.max(
+ EVT_PX,
+ visibleTimeScale.durationToPx(data.resolution),
+ );
+ const blockH = RECT_HEIGHT / LEVELS.length;
+ for (let i = 0; i < data.timestamps.length; i++) {
+ for (let lev = 0; lev < LEVELS.length; lev++) {
+ let hasEventsForCurColor = false;
+ for (const prio of LEVELS[lev].prios) {
+ if (data.priorities[i] & (1 << prio)) hasEventsForCurColor = true;
+ }
+ if (!hasEventsForCurColor) continue;
+ ctx.fillStyle = LEVELS[lev].color;
+ const timestamp = Time.fromRaw(data.timestamps[i]);
+ const px = Math.floor(visibleTimeScale.timeToPx(timestamp));
+ ctx.fillRect(px, MARGIN_TOP + blockH * lev, quantWidth, blockH);
+ } // for(lev)
+ } // for (timestamps)
+ }
+}
diff --git a/ui/src/tracks/annotation/index.ts b/ui/src/tracks/annotation/index.ts
index 6fc3973..d36e9a2 100644
--- a/ui/src/tracks/annotation/index.ts
+++ b/ui/src/tracks/annotation/index.ts
@@ -12,19 +12,12 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-import {
- Plugin,
- PluginContext,
- PluginContextTrace,
- PluginDescriptor,
-} from '../../public';
+import {Plugin, PluginContextTrace, PluginDescriptor} from '../../public';
import {NUM, NUM_NULL, STR} from '../../trace_processor/query_result';
import {ChromeSliceTrack, SLICE_TRACK_KIND} from '../chrome_slices/';
import {COUNTER_TRACK_KIND, TraceProcessorCounterTrack} from '../counter';
class AnnotationPlugin implements Plugin {
- onActivate(_ctx: PluginContext): void {}
-
async onTraceLoad(ctx: PluginContextTrace): Promise<void> {
await this.addAnnotationTracks(ctx);
await this.addAnnotationCounterTracks(ctx);
diff --git a/ui/src/tracks/async_slices/index.ts b/ui/src/tracks/async_slices/index.ts
index c4f55c9..2e8b3d5 100644
--- a/ui/src/tracks/async_slices/index.ts
+++ b/ui/src/tracks/async_slices/index.ts
@@ -12,12 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-import {
- Plugin,
- PluginContext,
- PluginContextTrace,
- PluginDescriptor,
-} from '../../public';
+import {Plugin, PluginContextTrace, PluginDescriptor} from '../../public';
import {getTrackName} from '../../public/utils';
import {NUM, NUM_NULL, STR, STR_NULL} from '../../trace_processor/query_result';
@@ -26,8 +21,6 @@
export const ASYNC_SLICE_TRACK_KIND = 'AsyncSliceTrack';
class AsyncSlicePlugin implements Plugin {
- onActivate(_ctx: PluginContext) {}
-
async onTraceLoad(ctx: PluginContextTrace): Promise<void> {
await this.addGlobalAsyncTracks(ctx);
await this.addProcessAsyncSliceTracks(ctx);
diff --git a/ui/src/tracks/chrome_scroll_jank/index.ts b/ui/src/tracks/chrome_scroll_jank/index.ts
index 41917bb..dc59118 100644
--- a/ui/src/tracks/chrome_scroll_jank/index.ts
+++ b/ui/src/tracks/chrome_scroll_jank/index.ts
@@ -23,7 +23,6 @@
BottomTabToSCSAdapter,
NUM,
Plugin,
- PluginContext,
PluginContextTrace,
PluginDescriptor,
} from '../../public';
@@ -148,8 +147,6 @@
}
class ChromeScrollJankPlugin implements Plugin {
- onActivate(_ctx: PluginContext): void {}
-
async onTraceLoad(ctx: PluginContextTrace): Promise<void> {
await this.addChromeScrollJankTrack(ctx);
await this.addTopLevelScrollTrack(ctx);
diff --git a/ui/src/tracks/chrome_slices/index.ts b/ui/src/tracks/chrome_slices/index.ts
index d7410b5..cae2557 100644
--- a/ui/src/tracks/chrome_slices/index.ts
+++ b/ui/src/tracks/chrome_slices/index.ts
@@ -29,7 +29,6 @@
BottomTabToSCSAdapter,
EngineProxy,
Plugin,
- PluginContext,
PluginContextTrace,
PluginDescriptor,
} from '../../public';
@@ -222,8 +221,6 @@
}
class ChromeSlicesPlugin implements Plugin {
- onActivate(_ctx: PluginContext): void {}
-
async onTraceLoad(ctx: PluginContextTrace): Promise<void> {
const {engine} = ctx;
const result = await engine.query(`
diff --git a/ui/src/tracks/counter/index.ts b/ui/src/tracks/counter/index.ts
index 56ed65a..2ac64d6 100644
--- a/ui/src/tracks/counter/index.ts
+++ b/ui/src/tracks/counter/index.ts
@@ -25,7 +25,6 @@
LONG_NULL,
NUM,
Plugin,
- PluginContext,
PluginContextTrace,
PluginDescriptor,
PrimaryTrackSortKey,
@@ -175,8 +174,6 @@
}
class CounterPlugin implements Plugin {
- onActivate(_ctx: PluginContext): void {}
-
async onTraceLoad(ctx: PluginContextTrace): Promise<void> {
await this.addCounterTracks(ctx);
await this.addGpuFrequencyTracks(ctx);
diff --git a/ui/src/tracks/cpu_freq/index.ts b/ui/src/tracks/cpu_freq/index.ts
index a2327fa..52708e9 100644
--- a/ui/src/tracks/cpu_freq/index.ts
+++ b/ui/src/tracks/cpu_freq/index.ts
@@ -29,7 +29,6 @@
import {
EngineProxy,
Plugin,
- PluginContext,
PluginContextTrace,
PluginDescriptor,
Track,
@@ -522,8 +521,6 @@
}
class CpuFreq implements Plugin {
- onActivate(_ctx: PluginContext): void {}
-
async onTraceLoad(ctx: PluginContextTrace): Promise<void> {
const {engine} = ctx;
diff --git a/ui/src/tracks/cpu_profile/index.ts b/ui/src/tracks/cpu_profile/index.ts
index 344f0e3..4d3e87f 100644
--- a/ui/src/tracks/cpu_profile/index.ts
+++ b/ui/src/tracks/cpu_profile/index.ts
@@ -26,7 +26,6 @@
import {
EngineProxy,
Plugin,
- PluginContext,
PluginContextTrace,
PluginDescriptor,
Track,
@@ -263,8 +262,6 @@
}
class CpuProfile implements Plugin {
- onActivate(_ctx: PluginContext): void {}
-
async onTraceLoad(ctx: PluginContextTrace): Promise<void> {
const result = await ctx.engine.query(`
with thread_cpu_sample as (
diff --git a/ui/src/tracks/cpu_slices/index.ts b/ui/src/tracks/cpu_slices/index.ts
index c561cbd..412ee6a 100644
--- a/ui/src/tracks/cpu_slices/index.ts
+++ b/ui/src/tracks/cpu_slices/index.ts
@@ -38,7 +38,6 @@
import {
EngineProxy,
Plugin,
- PluginContext,
PluginContextTrace,
PluginDescriptor,
Track,
@@ -543,10 +542,6 @@
}
class CpuSlices implements Plugin {
- onActivate(_ctx: PluginContext): void {
- // No-op
- }
-
async onTraceLoad(ctx: PluginContextTrace): Promise<void> {
const cpus = await ctx.engine.getCpus();
const cpuToSize = await this.guessCpuSizes(ctx.engine);
diff --git a/ui/src/tracks/custom_sql_table_slices/index.ts b/ui/src/tracks/custom_sql_table_slices/index.ts
index 2222f9b..72f2075 100644
--- a/ui/src/tracks/custom_sql_table_slices/index.ts
+++ b/ui/src/tracks/custom_sql_table_slices/index.ts
@@ -26,7 +26,7 @@
NamedSliceTrackTypes,
} from '../../frontend/named_slice_track';
import {NewTrackArgs} from '../../frontend/track';
-import {Plugin, PluginContext, PluginDescriptor} from '../../public';
+import {Plugin, PluginDescriptor} from '../../public';
export interface CustomSqlImportConfig {
modules: string[];
@@ -140,9 +140,7 @@
}
}
-class CustomSqlTrackPlugin implements Plugin {
- onActivate(_ctx: PluginContext): void {}
-}
+class CustomSqlTrackPlugin implements Plugin {}
export const plugin: PluginDescriptor = {
pluginId: 'perfetto.CustomSqlTrack',
diff --git a/ui/src/tracks/debug/index.ts b/ui/src/tracks/debug/index.ts
index 9ab23c0..fad9cae 100644
--- a/ui/src/tracks/debug/index.ts
+++ b/ui/src/tracks/debug/index.ts
@@ -20,7 +20,6 @@
import {
BottomTabToSCSAdapter,
Plugin,
- PluginContext,
PluginContextTrace,
PluginDescriptor,
} from '../../public';
@@ -31,8 +30,6 @@
import {GenericSliceDetailsTabConfig} from '../../frontend/generic_slice_details_tab';
class DebugTrackPlugin implements Plugin {
- onActivate(_ctx: PluginContext): void {}
-
async onTraceLoad(ctx: PluginContextTrace): Promise<void> {
ctx.registerTrack({
uri: DEBUG_SLICE_TRACK_URI,
diff --git a/ui/src/tracks/frames/index.ts b/ui/src/tracks/frames/index.ts
index ccf9ae6..47e88ff 100644
--- a/ui/src/tracks/frames/index.ts
+++ b/ui/src/tracks/frames/index.ts
@@ -12,12 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-import {
- Plugin,
- PluginContext,
- PluginContextTrace,
- PluginDescriptor,
-} from '../../public';
+import {Plugin, PluginContextTrace, PluginDescriptor} from '../../public';
import {getTrackName} from '../../public/utils';
import {NUM, NUM_NULL, STR, STR_NULL} from '../../trace_processor/query_result';
@@ -28,8 +23,6 @@
export const ACTUAL_FRAMES_SLICE_TRACK_KIND = 'ActualFramesSliceTrack';
class FramesPlugin implements Plugin {
- onActivate(_ctx: PluginContext): void {}
-
async onTraceLoad(ctx: PluginContextTrace): Promise<void> {
this.addExpectedFrames(ctx);
this.addActualFrames(ctx);
diff --git a/ui/src/tracks/ftrace/index.ts b/ui/src/tracks/ftrace/index.ts
index b3fd003..7542232 100644
--- a/ui/src/tracks/ftrace/index.ts
+++ b/ui/src/tracks/ftrace/index.ts
@@ -18,7 +18,6 @@
import {
EngineProxy,
Plugin,
- PluginContext,
PluginContextTrace,
PluginDescriptor,
} from '../../public';
@@ -39,8 +38,6 @@
class FtraceRawPlugin implements Plugin {
private trash = new Trash();
- onActivate(_: PluginContext) {}
-
async onTraceLoad(ctx: PluginContextTrace): Promise<void> {
const store = ctx.mountStore<FtracePluginState>((init: unknown) => {
if (
diff --git a/ui/src/tracks/heap_profile/index.ts b/ui/src/tracks/heap_profile/index.ts
index b905ef7..512af1a 100644
--- a/ui/src/tracks/heap_profile/index.ts
+++ b/ui/src/tracks/heap_profile/index.ts
@@ -27,7 +27,6 @@
import {NewTrackArgs} from '../../frontend/track';
import {
Plugin,
- PluginContext,
PluginContextTrace,
PluginDescriptor,
Slice,
@@ -115,7 +114,6 @@
}
class HeapProfilePlugin implements Plugin {
- onActivate(_ctx: PluginContext): void {}
async onTraceLoad(ctx: PluginContextTrace): Promise<void> {
const result = await ctx.engine.query(`
select distinct(upid) from heap_profile_allocation
diff --git a/ui/src/tracks/perf_samples_profile/index.ts b/ui/src/tracks/perf_samples_profile/index.ts
index 6720142..752684a 100644
--- a/ui/src/tracks/perf_samples_profile/index.ts
+++ b/ui/src/tracks/perf_samples_profile/index.ts
@@ -26,7 +26,6 @@
import {
EngineProxy,
Plugin,
- PluginContext,
PluginContextTrace,
PluginDescriptor,
Track,
@@ -245,8 +244,6 @@
}
class PerfSamplesProfilePlugin implements Plugin {
- onActivate(_ctx: PluginContext): void {}
-
async onTraceLoad(ctx: PluginContextTrace): Promise<void> {
const result = await ctx.engine.query(`
select distinct upid, pid
diff --git a/ui/src/tracks/process_summary/index.ts b/ui/src/tracks/process_summary/index.ts
index 70e22e6..47a93b0 100644
--- a/ui/src/tracks/process_summary/index.ts
+++ b/ui/src/tracks/process_summary/index.ts
@@ -14,12 +14,7 @@
import {v4 as uuidv4} from 'uuid';
-import {
- Plugin,
- PluginContext,
- PluginContextTrace,
- PluginDescriptor,
-} from '../../public';
+import {Plugin, PluginContextTrace, PluginDescriptor} from '../../public';
import {
LONG_NULL,
NUM,
@@ -45,8 +40,6 @@
private upidToUuid = new Map<number, string>();
private utidToUuid = new Map<number, string>();
- onActivate(_ctx: PluginContext): void {}
-
async onTraceLoad(ctx: PluginContextTrace): Promise<void> {
await this.addProcessTrackGroups(ctx);
await this.addKernelThreadSummary(ctx);
diff --git a/ui/src/tracks/sched/active_cpu_count.ts b/ui/src/tracks/sched/active_cpu_count.ts
index a5fd9d7..721a884 100644
--- a/ui/src/tracks/sched/active_cpu_count.ts
+++ b/ui/src/tracks/sched/active_cpu_count.ts
@@ -69,11 +69,9 @@
}
getTrackShellButtons(): m.Children {
- return [
- m(CloseTrackButton, {
- trackKey: this.trackKey,
- }),
- ];
+ return m(CloseTrackButton, {
+ trackKey: this.trackKey,
+ });
}
protected getDefaultCounterOptions(): CounterOptions {
diff --git a/ui/src/tracks/sched/runnable_thread_count.ts b/ui/src/tracks/sched/runnable_thread_count.ts
index 4522588..f5ab7ca 100644
--- a/ui/src/tracks/sched/runnable_thread_count.ts
+++ b/ui/src/tracks/sched/runnable_thread_count.ts
@@ -49,11 +49,9 @@
}
getTrackShellButtons(): m.Children {
- return [
- m(CloseTrackButton, {
- trackKey: this.trackKey,
- }),
- ];
+ return m(CloseTrackButton, {
+ trackKey: this.trackKey,
+ });
}
protected getDefaultCounterOptions(): CounterOptions {
diff --git a/ui/src/tracks/screenshots/index.ts b/ui/src/tracks/screenshots/index.ts
index aa55903..029f818 100644
--- a/ui/src/tracks/screenshots/index.ts
+++ b/ui/src/tracks/screenshots/index.ts
@@ -20,7 +20,6 @@
BottomTabToSCSAdapter,
NUM,
Plugin,
- PluginContext,
PluginContextTrace,
PluginDescriptor,
PrimaryTrackSortKey,
@@ -84,8 +83,6 @@
}
class ScreenshotsPlugin implements Plugin {
- onActivate(_ctx: PluginContext): void {}
-
async onTraceLoad(ctx: PluginContextTrace): Promise<void> {
await ctx.engine.query(`INCLUDE PERFETTO MODULE android.screenshots`);
diff --git a/ui/src/tracks/thread_state/index.ts b/ui/src/tracks/thread_state/index.ts
index cc8bcc2..b38eb1d 100644
--- a/ui/src/tracks/thread_state/index.ts
+++ b/ui/src/tracks/thread_state/index.ts
@@ -18,7 +18,6 @@
import {
BottomTabToSCSAdapter,
Plugin,
- PluginContext,
PluginContextTrace,
PluginDescriptor,
} from '../../public';
@@ -30,8 +29,6 @@
export const THREAD_STATE_TRACK_KIND = 'ThreadStateTrack';
class ThreadState implements Plugin {
- onActivate(_ctx: PluginContext): void {}
-
async onTraceLoad(ctx: PluginContextTrace): Promise<void> {
const {engine} = ctx;
const result = await engine.query(`
diff --git a/ui/src/tracks/visualised_args/index.ts b/ui/src/tracks/visualised_args/index.ts
index 434874f..d2ede0c 100644
--- a/ui/src/tracks/visualised_args/index.ts
+++ b/ui/src/tracks/visualised_args/index.ts
@@ -12,18 +12,14 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-// import {NewTrackArgs, Track} from '../../frontend/track';
-// import {TrackButton, TrackButtonAttrs} from '../../frontend/track_panel';
import m from 'mithril';
import {v4 as uuidv4} from 'uuid';
import {Actions} from '../../common/actions';
import {globals} from '../../frontend/globals';
-import {TrackButton} from '../../frontend/track_panel';
import {
EngineProxy,
Plugin,
- PluginContext,
PluginContextTrace,
PluginDescriptor,
TrackContext,
@@ -33,6 +29,8 @@
VISUALISED_ARGS_SLICE_TRACK_URI,
VisualisedArgsState,
} from '../../frontend/visualized_args_tracks';
+import {Button} from '../../widgets/button';
+import {Icons} from '../../base/semantic_icons';
export class VisualisedArgsTrack extends ChromeSliceTrack {
private helperViewName: string;
@@ -90,8 +88,8 @@
}
getTrackShellButtons(): m.Children {
- return m(TrackButton, {
- action: () => {
+ return m(Button, {
+ onclick: () => {
// This behavior differs to the original behavior a little.
// Originally, hitting the close button on a single track removed ALL
// tracks with this argName, whereas this one only closes the single
@@ -100,16 +98,15 @@
// tracks instead of this "initial state" approach to add these tracks.
globals.dispatch(Actions.removeTracks({trackKeys: [this.trackKey]}));
},
- i: 'close',
- tooltip: 'Close',
- showButton: true,
+ icon: Icons.Close,
+ title: 'Close',
+ minimal: true,
+ compact: true,
});
}
}
class VisualisedArgsPlugin implements Plugin {
- onActivate(_ctx: PluginContext): void {}
-
async onTraceLoad(ctx: PluginContextTrace): Promise<void> {
ctx.registerTrack({
uri: VISUALISED_ARGS_SLICE_TRACK_URI,
diff --git a/ui/src/widgets/button.ts b/ui/src/widgets/button.ts
index 619f23c..276b2f4 100644
--- a/ui/src/widgets/button.ts
+++ b/ui/src/widgets/button.ts
@@ -16,7 +16,7 @@
import {classNames} from '../base/classnames';
-import {HTMLButtonAttrs} from './common';
+import {HTMLAttrs, HTMLButtonAttrs} from './common';
import {Icon} from './icon';
import {Popup} from './popup';
import {Spinner} from './spinner';
@@ -44,6 +44,9 @@
// Show loading spinner instead of icon.
// Defaults to false.
loading?: boolean;
+ // Whether to use a filled icon
+ // Defaults to false;
+ iconFilled?: boolean;
}
interface IconButtonAttrs extends CommonAttrs {
@@ -70,6 +73,7 @@
rightIcon,
className,
dismissPopup,
+ iconFilled,
...htmlAttrs
} = attrs;
@@ -81,7 +85,6 @@
minimal && 'pf-minimal',
icon && !label && 'pf-icon-only',
dismissPopup && Popup.DISMISS_POPUP_GROUP_CLASS,
- // loading && 'pf-loading',
className,
);
@@ -92,17 +95,23 @@
className: classes,
},
this.renderIcon(attrs),
- rightIcon && m(Icon, {className: 'pf-right-icon', icon: rightIcon}),
+ rightIcon &&
+ m(Icon, {
+ className: 'pf-right-icon',
+ icon: rightIcon,
+ filled: iconFilled,
+ }),
label || '\u200B', // Zero width space keeps button in-flow
);
}
private renderIcon(attrs: ButtonAttrs): m.Children {
+ const {icon, iconFilled} = attrs;
const className = 'pf-left-icon';
if (attrs.loading) {
return m(Spinner, {className});
- } else if (attrs.icon) {
- return m(Icon, {className, icon: attrs.icon});
+ } else if (icon) {
+ return m(Icon, {className, icon, filled: iconFilled});
} else {
return undefined;
}
@@ -112,8 +121,8 @@
/**
* Space buttons out with a little gap between each one.
*/
-export class ButtonBar implements m.ClassComponent {
- view({children}: m.CVnode): m.Children {
- return m('.pf-button-bar', children);
+export class ButtonBar implements m.ClassComponent<HTMLAttrs> {
+ view({attrs, children}: m.CVnode<HTMLAttrs>): m.Children {
+ return m('.pf-button-bar', attrs, children);
}
}