Merge "Add a new "restricted" metric name to reduce noise."
diff --git a/Android.bp b/Android.bp
index 290dfd8..1fad0af 100644
--- a/Android.bp
+++ b/Android.bp
@@ -3692,6 +3692,7 @@
"protos/perfetto/metrics/android/powrails_metric.proto",
"protos/perfetto/metrics/android/process_metadata.proto",
"protos/perfetto/metrics/android/profiler_smaps.proto",
+ "protos/perfetto/metrics/android/rt_runtime_metric.proto",
"protos/perfetto/metrics/android/simpleperf.proto",
"protos/perfetto/metrics/android/startup_metric.proto",
"protos/perfetto/metrics/android/surfaceflinger.proto",
@@ -3751,6 +3752,7 @@
"protos/perfetto/metrics/android/powrails_metric.proto",
"protos/perfetto/metrics/android/process_metadata.proto",
"protos/perfetto/metrics/android/profiler_smaps.proto",
+ "protos/perfetto/metrics/android/rt_runtime_metric.proto",
"protos/perfetto/metrics/android/simpleperf.proto",
"protos/perfetto/metrics/android/startup_metric.proto",
"protos/perfetto/metrics/android/surfaceflinger.proto",
@@ -8094,6 +8096,7 @@
"src/trace_processor/metrics/sql/android/android_package_list.sql",
"src/trace_processor/metrics/sql/android/android_powrails.sql",
"src/trace_processor/metrics/sql/android/android_proxy_power.sql",
+ "src/trace_processor/metrics/sql/android/android_rt_runtime.sql",
"src/trace_processor/metrics/sql/android/android_simpleperf.sql",
"src/trace_processor/metrics/sql/android/android_startup.sql",
"src/trace_processor/metrics/sql/android/android_surfaceflinger.sql",
@@ -10419,14 +10422,14 @@
filegroup {
name: "perfetto-trace-processor-python-srcs",
- srcs: ["src/trace_processor/python/perfetto/**/*.py"],
- path: "src/trace_processor/python",
+ srcs: ["python/perfetto/trace_processor/*.py"],
+ path: "python",
}
filegroup {
name: "perfetto-trace-processor-python-data",
- srcs: ["src/trace_processor/python/perfetto/**/*.descriptor*"],
- path: "src/trace_processor/python",
+ srcs: ["python/perfetto/trace_processor/*.descriptor*"],
+ path: "python",
}
// Added automatically by a large-scale-change that took the approach of
diff --git a/Android.bp.extras b/Android.bp.extras
index c447a86..d6deb97 100644
--- a/Android.bp.extras
+++ b/Android.bp.extras
@@ -112,14 +112,14 @@
filegroup {
name: "perfetto-trace-processor-python-srcs",
- srcs: ["src/trace_processor/python/perfetto/**/*.py"],
- path: "src/trace_processor/python",
+ srcs: ["python/perfetto/trace_processor/*.py"],
+ path: "python",
}
filegroup {
name: "perfetto-trace-processor-python-data",
- srcs: ["src/trace_processor/python/perfetto/**/*.descriptor*"],
- path: "src/trace_processor/python",
+ srcs: ["python/perfetto/trace_processor/*.descriptor*"],
+ path: "python",
}
// Added automatically by a large-scale-change that took the approach of
diff --git a/BUILD b/BUILD
index 3e7abd7..723d6a4 100644
--- a/BUILD
+++ b/BUILD
@@ -1059,6 +1059,7 @@
"src/trace_processor/metrics/sql/android/android_package_list.sql",
"src/trace_processor/metrics/sql/android/android_powrails.sql",
"src/trace_processor/metrics/sql/android/android_proxy_power.sql",
+ "src/trace_processor/metrics/sql/android/android_rt_runtime.sql",
"src/trace_processor/metrics/sql/android/android_simpleperf.sql",
"src/trace_processor/metrics/sql/android/android_startup.sql",
"src/trace_processor/metrics/sql/android/android_surfaceflinger.sql",
@@ -2627,6 +2628,7 @@
"protos/perfetto/metrics/android/powrails_metric.proto",
"protos/perfetto/metrics/android/process_metadata.proto",
"protos/perfetto/metrics/android/profiler_smaps.proto",
+ "protos/perfetto/metrics/android/rt_runtime_metric.proto",
"protos/perfetto/metrics/android/simpleperf.proto",
"protos/perfetto/metrics/android/startup_metric.proto",
"protos/perfetto/metrics/android/surfaceflinger.proto",
@@ -4185,77 +4187,3 @@
main = "tools/write_version_header.py",
python_version = "PY3",
)
-
-perfetto_py_binary(
- name = "trace_processor_py_example",
- srcs = ["src/trace_processor/python/example.py"],
- deps = [":trace_processor_py"] + PERFETTO_CONFIG.deps.pandas_py,
- main = "src/trace_processor/python/example.py",
- python_version = "PY3",
-)
-
-perfetto_py_library(
- name = "trace_processor_py",
- srcs = glob(["src/trace_processor/python/perfetto/trace_processor/*.py"]),
- data = [
- "src/trace_processor/python/perfetto/trace_processor/trace_processor.descriptor",
- "src/trace_processor/python/perfetto/trace_processor/metrics.descriptor",
- ":trace_processor_shell",
- ] + PERFETTO_CONFIG.deps.tp_init_py,
- deps = PERFETTO_CONFIG.deps.gfile_py +
- PERFETTO_CONFIG.deps.protobuf_py +
- PERFETTO_CONFIG.deps.protobuf_descriptor_pb2_py +
- PERFETTO_CONFIG.deps.pyglib_py,
- imports = [
- "src/trace_processor/python",
- ],
- visibility = PERFETTO_CONFIG.public_visibility,
-)
-
-perfetto_py_library(
- name = "experimental_slice_breakdown_lib",
- srcs = glob(["tools/slice_breakdown/perfetto/slice_breakdown/*.py"]),
- deps = [
- ":trace_processor_py",
- ],
- imports = [
- "tools/slice_breakdown",
- ],
-)
-
-perfetto_py_binary(
- name = "experimental_slice_breakdown_bin",
- srcs = ["tools/slice_breakdown/main.py"],
- main = "tools/slice_breakdown/main.py",
- deps = [
- ":experimental_slice_breakdown_lib",
- ":trace_processor_py",
- ] + PERFETTO_CONFIG.deps.pandas_py,
- python_version = "PY3",
- legacy_create_init = 0,
-)
-
-perfetto_py_library(
- name = "batch_trace_processor",
- srcs = glob([
- "tools/batch_trace_processor/perfetto/batch_trace_processor/*.py"
- ]),
- deps = [
- ":trace_processor_py",
- ] + PERFETTO_CONFIG.deps.pandas_py,
- imports = [
- "tools/batch_trace_processor",
- ],
-)
-
-perfetto_py_binary(
- name = "batch_trace_processor_shell",
- srcs = ["tools/batch_trace_processor/main.py"],
- main = "tools/batch_trace_processor/main.py",
- deps = [
- ":trace_processor_py",
- ":batch_trace_processor",
- ] + PERFETTO_CONFIG.deps.pandas_py,
- python_version = "PY3",
- legacy_create_init = 0,
-)
diff --git a/BUILD.extras b/BUILD.extras
index 8c39316..f91b2f4 100644
--- a/BUILD.extras
+++ b/BUILD.extras
@@ -92,77 +92,3 @@
main = "tools/write_version_header.py",
python_version = "PY3",
)
-
-perfetto_py_binary(
- name = "trace_processor_py_example",
- srcs = ["src/trace_processor/python/example.py"],
- deps = [":trace_processor_py"] + PERFETTO_CONFIG.deps.pandas_py,
- main = "src/trace_processor/python/example.py",
- python_version = "PY3",
-)
-
-perfetto_py_library(
- name = "trace_processor_py",
- srcs = glob(["src/trace_processor/python/perfetto/trace_processor/*.py"]),
- data = [
- "src/trace_processor/python/perfetto/trace_processor/trace_processor.descriptor",
- "src/trace_processor/python/perfetto/trace_processor/metrics.descriptor",
- ":trace_processor_shell",
- ] + PERFETTO_CONFIG.deps.tp_init_py,
- deps = PERFETTO_CONFIG.deps.gfile_py +
- PERFETTO_CONFIG.deps.protobuf_py +
- PERFETTO_CONFIG.deps.protobuf_descriptor_pb2_py +
- PERFETTO_CONFIG.deps.pyglib_py,
- imports = [
- "src/trace_processor/python",
- ],
- visibility = PERFETTO_CONFIG.public_visibility,
-)
-
-perfetto_py_library(
- name = "experimental_slice_breakdown_lib",
- srcs = glob(["tools/slice_breakdown/perfetto/slice_breakdown/*.py"]),
- deps = [
- ":trace_processor_py",
- ],
- imports = [
- "tools/slice_breakdown",
- ],
-)
-
-perfetto_py_binary(
- name = "experimental_slice_breakdown_bin",
- srcs = ["tools/slice_breakdown/main.py"],
- main = "tools/slice_breakdown/main.py",
- deps = [
- ":experimental_slice_breakdown_lib",
- ":trace_processor_py",
- ] + PERFETTO_CONFIG.deps.pandas_py,
- python_version = "PY3",
- legacy_create_init = 0,
-)
-
-perfetto_py_library(
- name = "batch_trace_processor",
- srcs = glob([
- "tools/batch_trace_processor/perfetto/batch_trace_processor/*.py"
- ]),
- deps = [
- ":trace_processor_py",
- ] + PERFETTO_CONFIG.deps.pandas_py,
- imports = [
- "tools/batch_trace_processor",
- ],
-)
-
-perfetto_py_binary(
- name = "batch_trace_processor_shell",
- srcs = ["tools/batch_trace_processor/main.py"],
- main = "tools/batch_trace_processor/main.py",
- deps = [
- ":trace_processor_py",
- ":batch_trace_processor",
- ] + PERFETTO_CONFIG.deps.pandas_py,
- python_version = "PY3",
- legacy_create_init = 0,
-)
diff --git a/BUILD.gn b/BUILD.gn
index b36d588..2e07e14 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -89,6 +89,7 @@
}
all_targets += [
":perfetto_integrationtests",
+ "examples/sdk:sdk_example",
"test:client_api_example",
"test/stress_test",
]
diff --git a/CHANGELOG b/CHANGELOG
index 19f75ba..8dbe728 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -9,6 +9,35 @@
*
+v23.0 - 2022-01-11:
+ Tracing service and probes:
+ * Added workaround for a kernel ftrace bug causing some "comm" fields to be
+ not null-terminated. https://github.com/torvalds/linux/commit/f0a5157803 .
+ * Added ability to talk to the newer AIDL-based health hal in traced_probes.
+ It still falls back on the older HIDL interface for older devices.
+ Trace Processor:
+ * Changed the argument for the trace path in constructor of TraceProcessor
+ in the Python API from |file_path| to |trace|.
+ |file_path| is deprecated and may be removed in the future.
+ * Changed the Python API constructor. Now it takes a TraceProcessorConfig
+ instead of passing parameters directly. This may break existing code
+ but migration should be trivial (all current options are still
+ supported).
+ * Fixed a HTTP keepalive bug in trace_processor --httpd. The bug, introduced
+ in v22.0, caused each RPC request to close the connection, effectively
+ defeating the 'Connection: Keep-Alive', after each query made by the UI.
+ * Added parsing of netif_receive_skb events from proto traces.
+ * Added android_netperf metric based on netif events.
+ * Fixed a bug that would cause fetch errors when loading traces > 32 MB when
+ using trace_processor --httpd.
+ * Added a workaround to tokenize properly /proc/pid/cmdline for chrome
+ processes on Linux/CrOS. Chrome rewrites its cmdline replacing \0 -> ' '.
+ UI:
+ *
+ SDK:
+ *
+
+
v22.1 - 2021-12-07:
Tracing service and probes:
* Added workaround for a Linux kernel bug causing some ftrace strings to
diff --git a/docs/analysis/trace-processor.md b/docs/analysis/trace-processor.md
index 3606c00..2385175 100644
--- a/docs/analysis/trace-processor.md
+++ b/docs/analysis/trace-processor.md
@@ -583,17 +583,17 @@
```python
from perfetto.trace_processor import TraceProcessor
# Initialise TraceProcessor with a trace file
-tp = TraceProcessor(file_path='trace.perfetto-trace')
+tp = TraceProcessor(trace='trace.perfetto-trace')
```
NOTE: The TraceProcessor can be initialized in a combination of ways including:
<br> - An address at which there exists a running instance of `trace_processor` with a
- loaded trace (e.g. `TraceProcessor(addr='localhost:9001')`)
+ loaded trace (e.g.`TraceProcessor(addr='localhost:9001')`)
<br> - An address at which there exists a running instance of `trace_processor` and
needs a trace to be loaded in
- (e.g. `TraceProcessor(addr='localhost:9001', file_path='trace.perfetto-trace')`)
+ (e.g. `TraceProcessor(trace='trace.perfetto-trace', addr='localhost:9001')`)
<br> - A path to a `trace_processor` binary and the trace to be loaded in
- (e.g. `TraceProcessor(bin_path='./trace_processor', file_path='trace.perfetto-trace')`)
+ (e.g. `TraceProcessor(trace='trace.perfetto-trace', config=TraceProcessorConfig(bin_path='./trace_processor'))`)
### API
@@ -608,7 +608,7 @@
```python
from perfetto.trace_processor import TraceProcessor
-tp = TraceProcessor(file_path='trace.perfetto-trace')
+tp = TraceProcessor(trace='trace.perfetto-trace')
qr_it = tp.query('SELECT ts, dur, name FROM slice')
for row in qr_it:
@@ -627,7 +627,7 @@
requires you to have both the `NumPy` and `Pandas` modules installed.
```python
from perfetto.trace_processor import TraceProcessor
-tp = TraceProcessor(file_path='trace.perfetto-trace')
+tp = TraceProcessor(trace='trace.perfetto-trace')
qr_it = tp.query('SELECT ts, dur, name FROM slice')
qr_df = qr_it.as_pandas_dataframe()
@@ -648,7 +648,7 @@
make visualisations from the trace data.
```python
from perfetto.trace_processor import TraceProcessor
-tp = TraceProcessor(file_path='trace.perfetto-trace')
+tp = TraceProcessor(trace='trace.perfetto-trace')
qr_it = tp.query('SELECT ts, value FROM counter WHERE track_id=50')
qr_df = qr_it.as_pandas_dataframe()
@@ -665,7 +665,7 @@
```python
from perfetto.trace_processor import TraceProcessor
-tp = TraceProcessor(file_path='trace.perfetto-trace')
+tp = TraceProcessor(trace='trace.perfetto-trace')
ad_cpu_metrics = tp.metric(['android_cpu'])
print(ad_cpu_metrics)
diff --git a/docs/instrumentation/tracing-sdk.md b/docs/instrumentation/tracing-sdk.md
index 252e637..0af249c 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 v22.1
+git clone https://android.googlesource.com/platform/external/perfetto -b v23.0
```
The SDK consists of two files, `sdk/perfetto.h` and `sdk/perfetto.cc`. These are
diff --git a/docs/quickstart/trace-analysis.md b/docs/quickstart/trace-analysis.md
index 7141394..62269dc 100644
--- a/docs/quickstart/trace-analysis.md
+++ b/docs/quickstart/trace-analysis.md
@@ -334,7 +334,7 @@
#### Query
```python
from perfetto.trace_processor import TraceProcessor
-tp = TraceProcessor(file_path='trace.perfetto-trace')
+tp = TraceProcessor(trace='trace.perfetto-trace')
qr_it = tp.query('SELECT name FROM slice')
for row in qr_it:
@@ -352,7 +352,7 @@
#### Query as Pandas DataFrame
```python
from perfetto.trace_processor import TraceProcessor
-tp = TraceProcessor(file_path='trace.perfetto-trace')
+tp = TraceProcessor(trace='trace.perfetto-trace')
qr_it = tp.query('SELECT ts, name FROM slice')
qr_df = qr_it.as_pandas_dataframe()
@@ -372,7 +372,7 @@
#### Metric
```python
from perfetto.trace_processor import TraceProcessor
-tp = TraceProcessor(file_path='trace.perfetto-trace')
+tp = TraceProcessor(trace='trace.perfetto-trace')
cpu_metrics = tp.metric(['android_cpu'])
print(cpu_metrics)
diff --git a/docs/visualization/perfetto-ui-release-process.md b/docs/visualization/perfetto-ui-release-process.md
index 8f12b1a..ed0af8d 100644
--- a/docs/visualization/perfetto-ui-release-process.md
+++ b/docs/visualization/perfetto-ui-release-process.md
@@ -103,3 +103,6 @@
[go/perfetto-ui-autopush](http://go/perfetto-ui-autopush) and
[go/perfetto-ui-channels](http://go/perfetto-ui-channels) for the design docs of
the serving infrastructure.
+
+## Publishing the Perfetto Chrome extension
+Googlers: see go/perfetto-release-chrome-extension
diff --git a/examples/sdk/BUILD.gn b/examples/sdk/BUILD.gn
new file mode 100644
index 0000000..8da2991
--- /dev/null
+++ b/examples/sdk/BUILD.gn
@@ -0,0 +1,30 @@
+# 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("../../gn/perfetto.gni")
+
+executable("sdk_example") {
+ sources = [
+ "example.cc",
+ "trace_categories.cc",
+ "trace_categories.h",
+ ]
+ configs -= [ "//gn/standalone:extra_warnings" ]
+ cflags = [ "-DPERFETTO_SDK_EXAMPLE_USE_INTERNAL_HEADERS" ]
+ testonly = true
+ deps = [
+ "../..:libperfetto_client_experimental",
+ "../../gn:default_deps",
+ ]
+}
diff --git a/examples/sdk/README.md b/examples/sdk/README.md
index 8c56873..aa88171 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 v22.1
+git clone https://android.googlesource.com/platform/external/perfetto -b v23.0
```
Then, build using CMake:
diff --git a/examples/sdk/example.cc b/examples/sdk/example.cc
index b282617..8ac92ab 100644
--- a/examples/sdk/example.cc
+++ b/examples/sdk/example.cc
@@ -15,6 +15,14 @@
*/
// This example demonstrates in-process tracing with Perfetto.
+// This program adds trace in a few example functions like DrawPlayer DrawGame
+// etc. and collect the trace in file `example.pftrace`.
+// This output file is not readable directly. It can be read after converting
+// it to text, by running the command:
+// `./tools/traceconv text example.pftrace`
+// or it can be opened in UI : https://ui.perfetto.dev
+//
+// To compile this file, run: `./tools/ninja -C out/default sdk_example`.
#include "trace_categories.h"
@@ -22,6 +30,8 @@
#include <fstream>
#include <thread>
+namespace {
+
void InitializePerfetto() {
perfetto::TracingInitArgs args;
// The backends determine where trace events are recorded. For this example we
@@ -61,8 +71,11 @@
// directly into a file by passing a file descriptor into Setup() above.
std::ofstream output;
output.open("example.pftrace", std::ios::out | std::ios::binary);
- output.write(&trace_data[0], trace_data.size());
+ output.write(&trace_data[0], std::streamsize(trace_data.size()));
output.close();
+ PERFETTO_LOG(
+ "Trace written in example.pftrace file. To read this trace in "
+ "text form, run `./tools/traceconv text example.pftrace`");
}
void DrawPlayer(int player_number) {
@@ -83,6 +96,8 @@
TRACE_COUNTER("rendering", "Framerate", 120);
}
+} // namespace
+
int main(int, const char**) {
InitializePerfetto();
auto tracing_session = StartTracing();
diff --git a/examples/sdk/trace_categories.cc b/examples/sdk/trace_categories.cc
index cce90f8..646af7a 100644
--- a/examples/sdk/trace_categories.cc
+++ b/examples/sdk/trace_categories.cc
@@ -17,4 +17,4 @@
#include "trace_categories.h"
// Reserves internal static storage for our tracing categories.
-PERFETTO_TRACK_EVENT_STATIC_STORAGE();
\ No newline at end of file
+PERFETTO_TRACK_EVENT_STATIC_STORAGE();
diff --git a/examples/sdk/trace_categories.h b/examples/sdk/trace_categories.h
index c2dd852..2fbfe12 100644
--- a/examples/sdk/trace_categories.h
+++ b/examples/sdk/trace_categories.h
@@ -17,7 +17,17 @@
#ifndef TRACE_CATEGORIES_H
#define TRACE_CATEGORIES_H
+// This source file can be built in two ways:
+// 1. As part of the regular GN build, against standard includes.
+// 2. To test that the amalgmated SDK works, against the perfetto.h source.
+#ifdef PERFETTO_SDK_EXAMPLE_USE_INTERNAL_HEADERS
+#include "perfetto/tracing/core/trace_config.h"
+#include "perfetto/tracing/tracing.h"
+#include "perfetto/tracing/track_event.h"
+#include "protos/perfetto/trace/track_event/process_descriptor.gen.h"
+#else
#include <perfetto.h>
+#endif
// The set of track event categories that the example is using.
PERFETTO_DEFINE_CATEGORIES(
diff --git a/include/perfetto/base/logging.h b/include/perfetto/base/logging.h
index eaa5710..3599dda 100644
--- a/include/perfetto/base/logging.h
+++ b/include/perfetto/base/logging.h
@@ -147,7 +147,8 @@
__LINE__, ##__VA_ARGS__); \
} while (0)
#elif defined(PERFETTO_DISABLE_LOG)
-#define PERFETTO_XLOG(...) ::perfetto::base::ignore_result(__VA_ARGS__)
+#define PERFETTO_XLOG(level, fmt, ...) ::perfetto::base::ignore_result(level, \
+ fmt, ##__VA_ARGS__)
#else
#define PERFETTO_XLOG(level, fmt, ...) \
::perfetto::base::LogMessage(level, ::perfetto::base::Basename(__FILE__), \
diff --git a/protos/perfetto/metrics/android/BUILD.gn b/protos/perfetto/metrics/android/BUILD.gn
index f09aa37..3e0b2e7 100644
--- a/protos/perfetto/metrics/android/BUILD.gn
+++ b/protos/perfetto/metrics/android/BUILD.gn
@@ -46,6 +46,7 @@
"powrails_metric.proto",
"process_metadata.proto",
"profiler_smaps.proto",
+ "rt_runtime_metric.proto",
"simpleperf.proto",
"startup_metric.proto",
"surfaceflinger.proto",
diff --git a/protos/perfetto/metrics/android/rt_runtime_metric.proto b/protos/perfetto/metrics/android/rt_runtime_metric.proto
new file mode 100644
index 0000000..edb66c5
--- /dev/null
+++ b/protos/perfetto/metrics/android/rt_runtime_metric.proto
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+syntax = "proto2";
+
+package perfetto.protos;
+
+// measure max RT runtime and RT tasks running over 5ms.
+message AndroidRtRuntimeMetric {
+ message RtSlice {
+ // thread name
+ optional string tname = 1;
+ // timestamp
+ optional int64 ts = 2;
+ // runtime of RT task
+ optional int64 dur = 3;
+ }
+
+ // max runtime of RT tasks
+ optional int64 max_runtime = 1;
+ // how many RT tasks are over 5ms.
+ optional int64 over_5ms_count = 2;
+ // information for top 10 RT tasks
+ repeated RtSlice longest_rt_slices = 3;
+}
+
diff --git a/protos/perfetto/metrics/metrics.proto b/protos/perfetto/metrics/metrics.proto
index d8a29a1..8b1a173 100644
--- a/protos/perfetto/metrics/metrics.proto
+++ b/protos/perfetto/metrics/metrics.proto
@@ -43,6 +43,7 @@
import "protos/perfetto/metrics/android/package_list.proto";
import "protos/perfetto/metrics/android/powrails_metric.proto";
import "protos/perfetto/metrics/android/profiler_smaps.proto";
+import "protos/perfetto/metrics/android/rt_runtime_metric.proto";
import "protos/perfetto/metrics/android/simpleperf.proto";
import "protos/perfetto/metrics/android/startup_metric.proto";
import "protos/perfetto/metrics/android/surfaceflinger.proto";
@@ -96,7 +97,7 @@
// Root message for all Perfetto-based metrics.
//
-// Next id: 42
+// Next id: 43
message TraceMetrics {
reserved 4, 10, 13, 14, 16, 19;
@@ -206,6 +207,8 @@
// is clear that this data is necessary.
optional AndroidCameraUnaggregatedMetric android_camera_unagg = 41;
+ optional AndroidRtRuntimeMetric android_rt_runtime = 42;
+
// Demo extensions.
extensions 450 to 499;
diff --git a/protos/perfetto/metrics/perfetto_merged_metrics.proto b/protos/perfetto/metrics/perfetto_merged_metrics.proto
index 100c76c..7472ce3 100644
--- a/protos/perfetto/metrics/perfetto_merged_metrics.proto
+++ b/protos/perfetto/metrics/perfetto_merged_metrics.proto
@@ -980,6 +980,30 @@
// End of protos/perfetto/metrics/android/profiler_smaps.proto
+// Begin of protos/perfetto/metrics/android/rt_runtime_metric.proto
+
+// measure max RT runtime and RT tasks running over 5ms.
+message AndroidRtRuntimeMetric {
+ message RtSlice {
+ // thread name
+ optional string tname = 1;
+ // timestamp
+ optional int64 ts = 2;
+ // runtime of RT task
+ optional int64 dur = 3;
+ }
+
+ // max runtime of RT tasks
+ optional int64 max_runtime = 1;
+ // how many RT tasks are over 5ms.
+ optional int64 over_5ms_count = 2;
+ // information for top 10 RT tasks
+ repeated RtSlice longest_rt_slices = 3;
+}
+
+
+// End of protos/perfetto/metrics/android/rt_runtime_metric.proto
+
// Begin of protos/perfetto/metrics/android/simpleperf.proto
// Metric that stores information related to atrace events generated by
@@ -1396,7 +1420,7 @@
// Root message for all Perfetto-based metrics.
//
-// Next id: 42
+// Next id: 43
message TraceMetrics {
reserved 4, 10, 13, 14, 16, 19;
@@ -1506,6 +1530,8 @@
// is clear that this data is necessary.
optional AndroidCameraUnaggregatedMetric android_camera_unagg = 41;
+ optional AndroidRtRuntimeMetric android_rt_runtime = 42;
+
// Demo extensions.
extensions 450 to 499;
diff --git a/python/BUILD b/python/BUILD
new file mode 100644
index 0000000..f330ba8
--- /dev/null
+++ b/python/BUILD
@@ -0,0 +1,98 @@
+# 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.
+
+load("@perfetto_cfg//:perfetto_cfg.bzl", "PERFETTO_CONFIG")
+load(
+ "@perfetto//bazel:rules.bzl",
+ "perfetto_py_binary",
+ "perfetto_py_library",
+)
+
+licenses(["notice"])
+
+package(default_visibility = ["//visibility:private"])
+
+perfetto_py_binary(
+ name = "trace_processor_py_example",
+ srcs = ["example.py"],
+ deps = [":trace_processor_py"] + PERFETTO_CONFIG.deps.pandas_py,
+ main = "example.py",
+ python_version = "PY3",
+)
+
+perfetto_py_library(
+ name = "trace_processor_py",
+ srcs = glob(["perfetto/trace_processor/*.py"]),
+ data = [
+ "perfetto/trace_processor/trace_processor.descriptor",
+ "perfetto/trace_processor/metrics.descriptor",
+ PERFETTO_CONFIG.root + ":trace_processor_shell",
+ ] + PERFETTO_CONFIG.deps.tp_init_py,
+ deps = PERFETTO_CONFIG.deps.gfile_py +
+ PERFETTO_CONFIG.deps.protobuf_py +
+ PERFETTO_CONFIG.deps.protobuf_descriptor_pb2_py +
+ PERFETTO_CONFIG.deps.pyglib_py,
+ imports = [
+ ".",
+ ],
+ visibility = PERFETTO_CONFIG.public_visibility,
+)
+
+perfetto_py_library(
+ name = "experimental_slice_breakdown_lib",
+ srcs = glob(["perfetto/experimental/slice_breakdown/*.py"]),
+ deps = [
+ ":trace_processor_py",
+ ],
+ imports = [
+ "tools/slice_breakdown",
+ ],
+)
+
+perfetto_py_binary(
+ name = "experimental_slice_breakdown_bin",
+ srcs = ["tools/slice_breakdown.py"],
+ main = "tools/slice_breakdown.py",
+ deps = [
+ ":experimental_slice_breakdown_lib",
+ ":trace_processor_py",
+ ] + PERFETTO_CONFIG.deps.pandas_py,
+ python_version = "PY3",
+ legacy_create_init = 0,
+)
+
+perfetto_py_library(
+ name = "batch_trace_processor",
+ srcs = glob([
+ "perfetto/batch_trace_processor/*.py"
+ ]),
+ deps = [
+ ":trace_processor_py",
+ ] + PERFETTO_CONFIG.deps.pandas_py,
+ imports = [
+ ".",
+ ],
+)
+
+perfetto_py_binary(
+ name = "batch_trace_processor_shell",
+ srcs = ["tools/batch_trace_processor_shell.py"],
+ main = "tools/batch_trace_processor_shell.py",
+ deps = [
+ ":trace_processor_py",
+ ":batch_trace_processor",
+ ] + PERFETTO_CONFIG.deps.pandas_py,
+ python_version = "PY3",
+ legacy_create_init = 0,
+)
diff --git a/src/trace_processor/python/LICENSE b/python/LICENSE
similarity index 100%
rename from src/trace_processor/python/LICENSE
rename to python/LICENSE
diff --git a/src/trace_processor/python/README.md b/python/README.md
similarity index 100%
rename from src/trace_processor/python/README.md
rename to python/README.md
diff --git a/src/trace_processor/python/example.py b/python/example.py
similarity index 85%
rename from src/trace_processor/python/example.py
rename to python/example.py
index b3925a4..ffdd9ac 100644
--- a/src/trace_processor/python/example.py
+++ b/python/example.py
@@ -15,7 +15,7 @@
import argparse
-from perfetto.trace_processor import TraceProcessor
+from perfetto.trace_processor import TraceProcessor, TraceProcessorConfig
def main():
@@ -34,16 +34,17 @@
parser.add_argument("-f", "--file", help="Absolute path to trace", type=str)
args = parser.parse_args()
+ config = TraceProcessorConfig(bin_path=args.binary)
+
# Pass arguments into api to construct the trace processor and load the trace
if args.address is None and args.file is None:
raise Exception("You must specify an address or a file path to trace")
elif args.address is None:
- tp = TraceProcessor(file_path=args.file, bin_path=args.binary)
+ tp = TraceProcessor(trace=args.file, config=config)
elif args.file is None:
- tp = TraceProcessor(addr=args.address)
+ tp = TraceProcessor(addr=args.address, config=config)
else:
- tp = TraceProcessor(
- addr=args.address, file_path=args.file, bin_path=args.binary)
+ tp = TraceProcessor(trace=args.file, addr=args.address, config=config)
# Iterate through QueryResultIterator
res_it = tp.query('select * from slice limit 10')
diff --git a/src/trace_processor/python/perfetto/__init__.py b/python/perfetto/__init__.py
similarity index 100%
rename from src/trace_processor/python/perfetto/__init__.py
rename to python/perfetto/__init__.py
diff --git a/src/trace_processor/python/perfetto/trace_processor/__init__.py b/python/perfetto/batch_trace_processor/__init__.py
similarity index 67%
rename from src/trace_processor/python/perfetto/trace_processor/__init__.py
rename to python/perfetto/batch_trace_processor/__init__.py
index 7106a6c..9d9f785 100644
--- a/src/trace_processor/python/perfetto/trace_processor/__init__.py
+++ b/python/perfetto/batch_trace_processor/__init__.py
@@ -1,5 +1,4 @@
-#!/usr/bin/env python3
-# Copyright (C) 2020 The Android Open Source Project
+# 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.
@@ -13,5 +12,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-from .api import TraceProcessor, TraceProcessorException
-from .http import TraceProcessorHttp
+from perfetto.batch_trace_processor.api import BatchLoadableTrace
+from perfetto.batch_trace_processor.api import BatchTraceProcessorConfig
+from perfetto.batch_trace_processor.api import BatchTraceProcessor
diff --git a/python/perfetto/batch_trace_processor/api.py b/python/perfetto/batch_trace_processor/api.py
new file mode 100644
index 0000000..caf9f74
--- /dev/null
+++ b/python/perfetto/batch_trace_processor/api.py
@@ -0,0 +1,307 @@
+#!/usr/bin/env python3
+# Copyright (C) 2021 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Contains classes for BatchTraceProcessor API."""
+
+from concurrent.futures.thread import ThreadPoolExecutor
+import dataclasses as dc
+import multiprocessing
+from typing import Any, Callable, Dict, Optional, Tuple, Union, List
+from numpy.lib.npyio import load
+
+import pandas as pd
+
+from perfetto.trace_processor import LoadableTrace
+from perfetto.trace_processor import TraceProcessor
+from perfetto.trace_processor import TraceProcessorException
+from perfetto.trace_processor import TraceProcessorConfig
+
+
+@dc.dataclass
+class BatchLoadableTrace:
+ trace: LoadableTrace
+ args: Dict[str, str]
+
+
+@dc.dataclass
+class BatchTraceProcessorConfig:
+ TraceProvider = Callable[[str], List[
+ Union[LoadableTrace, BatchLoadableTrace]]]
+
+ tp_config: TraceProcessorConfig
+
+ query_executor: Optional[ThreadPoolExecutor]
+ load_executor: Optional[ThreadPoolExecutor]
+
+ trace_provider: TraceProvider
+
+ def __default_trace_provider(custom_string: str):
+ del custom_string
+ raise TraceProcessorException(
+ 'Passed a string to batch trace processor constructor without '
+ 'a trace provider being registered.')
+
+ def __init__(self,
+ tp_config: TraceProcessorConfig = TraceProcessorConfig(),
+ query_executor: Optional[ThreadPoolExecutor] = None,
+ load_executor: Optional[ThreadPoolExecutor] = None,
+ trace_provider: TraceProvider = __default_trace_provider):
+ self.tp_config = tp_config
+
+ self.query_executor = query_executor
+ self.load_executor = load_executor
+
+ self.trace_provider = trace_provider
+
+ try:
+ # This is the only place in batch trace processor which should import
+ # from a "vendor" namespace - the purpose of this code is to allow
+ # for users to set their own "default" config for batch trace processor
+ # without needing to specify the config in every place when batch
+ # trace processor is used.
+ from .vendor import override_batch_tp_config
+ override_batch_tp_config(self)
+ except ModuleNotFoundError:
+ pass
+
+
+class BatchTraceProcessor:
+ """Run ad-hoc SQL queries across many Perfetto traces.
+
+ Usage:
+ with BatchTraceProcessor(traces) as btp:
+ dfs = btp.query('select * from slice')
+ for df in dfs:
+ print(df)
+ """
+
+ def __init__(
+ self,
+ traces: Union[str, List[Union[LoadableTrace, BatchLoadableTrace]]],
+ config: BatchTraceProcessorConfig = BatchTraceProcessorConfig()):
+ """Creates a batch trace processor instance.
+
+ BatchTraceProcessor is the blessed way of running ad-hoc queries in
+ Python across many traces.
+
+ Args:
+ traces: Either a list of traces or a custom string which will be
+ converted to a list of traces.
+
+ If a list, each item can be one of the following types:
+ 1) path to a trace file to open and read
+ 2) a file like object (file, io.BytesIO or similar) to read
+ 3) a generator yielding bytes
+ 4) a BatchLoadableTrace object; this is basically a wrapper around
+ one of the above types plus an args field; see |query_and_flatten|
+ for the motivation for the args field.
+
+ If a string, it is passed to BatchTraceProcessorConfig.trace_provider to
+ convert to a list of traces; the default implementation of this
+ function just throws an exception so an implementation must be provided
+ if strings will be passed.
+ config: configuration options which customize functionality of batch
+ trace processor and underlying trace processors.
+ """
+
+ def _create_batch_trace(x: Union[LoadableTrace, BatchLoadableTrace]
+ ) -> BatchLoadableTrace:
+ if isinstance(x, BatchLoadableTrace):
+ return x
+ return BatchLoadableTrace(trace=x, args={})
+
+ def create_tp(trace: BatchLoadableTrace) -> TraceProcessor:
+ return TraceProcessor(trace=trace.trace, config=config.tp_config)
+
+ if isinstance(traces, str):
+ trace_list = config.trace_provider(traces)
+ else:
+ trace_list = traces
+
+ batch_traces = [_create_batch_trace(t) for t in trace_list]
+
+ # As trace processor is completely CPU bound, it makes sense to just
+ # max out the CPUs available.
+ query_executor = config.query_executor or ThreadPoolExecutor(
+ max_workers=multiprocessing.cpu_count())
+ load_exectuor = config.load_executor or query_executor
+
+ self.tps = None
+ self.closed = False
+ self.query_executor = query_executor
+ self.args = [t.args for t in batch_traces]
+ self.tps = list(load_exectuor.map(create_tp, batch_traces))
+
+ def metric(self, metrics: List[str]):
+ """Computes the provided metrics.
+
+ The computation happens in parallel across all the traces.
+
+ Args:
+ metrics: A list of valid metrics as defined in TraceMetrics
+
+ Returns:
+ A list of TraceMetric protos (one for each trace).
+ """
+ return self.execute(lambda tp: tp.metric(metrics))
+
+ def query(self, sql: str):
+ """Executes the provided SQL statement (returning a single row).
+
+ The execution happens in parallel across all the traces.
+
+ Args:
+ sql: The SQL statement to execute.
+
+ Returns:
+ A list of Pandas dataframes with the result of executing the query (one
+ per trace).
+
+ Raises:
+ TraceProcessorException: An error occurred running the query.
+ """
+ return self.execute(lambda tp: tp.query(sql).as_pandas_dataframe())
+
+ def query_and_flatten(self, sql: str):
+ """Executes the provided SQL statement and flattens the result.
+
+ The execution happens in parallel across all the traces and the
+ resulting Pandas dataframes are flattened into a single dataframe.
+
+ Args:
+ sql: The SQL statement to execute.
+
+ Returns:
+ A concatenated Pandas dataframe containing the result of executing the
+ query across all the traces.
+
+ If |BatchLoadableTrace| objects were passed to the constructor, the
+ contents of the |args| dictionary will also be emitted as extra columns
+ (key being column name, value being the value in the dataframe).
+
+ For example:
+ traces = [BatchLoadableTrace(trace='/tmp/path', args={"foo": "bar"})]
+ with BatchTraceProcessor(traces) as btp:
+ df = btp.query_and_flatten('select count(1) as cnt from slice')
+
+ Then df will look like this:
+ cnt foo
+ 100 bar
+
+ Raises:
+ TraceProcessorException: An error occurred running the query.
+ """
+ return self.execute_and_flatten(lambda tp: tp.query(sql).
+ as_pandas_dataframe())
+
+ def query_single_result(self, sql: str):
+ """Executes the provided SQL statement (returning a single row).
+
+ The execution happens in parallel across all the traces.
+
+ Args:
+ sql: The SQL statement to execute. This statement should return exactly
+ one row on any trace.
+
+ Returns:
+ A list of values with the result of executing the query (one per trace).
+
+ Raises:
+ TraceProcessorException: An error occurred running the query or more than
+ one result was returned.
+ """
+
+ def query_single_result_inner(tp):
+ df = tp.query(sql).as_pandas_dataframe()
+ if len(df.index) != 1:
+ raise TraceProcessorException("Query should only return a single row")
+
+ if len(df.columns) != 1:
+ raise TraceProcessorException(
+ "Query should only return a single column")
+
+ return df.iloc[0, 0]
+
+ return self.execute(query_single_result_inner)
+
+ def execute(self, fn: Callable[[TraceProcessor], Any]) -> List[Any]:
+ """Executes the provided function.
+
+ The execution happens in parallel across all the trace processor instances
+ owned by this object.
+
+ Args:
+ fn: The function to execute.
+
+ Returns:
+ A list of values with the result of executing the fucntion (one per
+ trace).
+ """
+ return list(self.query_executor.map(fn, self.tps))
+
+ def execute_and_flatten(self, fn: Callable[[TraceProcessor], pd.DataFrame]
+ ) -> pd.DataFrame:
+ """Executes the provided function and flattens the result.
+
+ The execution happens in parallel across all the trace processor
+ instances owned by this object and the returned Pandas dataframes are
+ flattened into a single dataframe.
+
+ Args:
+ fn: The function to execute which returns a Pandas dataframe.
+
+ Returns:
+ A Pandas dataframe containing the result of executing the query across all
+ the traces. Extra columns containing the file path and args will
+ be added to the dataframe (see |query_and_flatten| for details).
+ """
+
+ def wrapped(pair: Tuple[TraceProcessor, BatchLoadableTrace]):
+ (tp, args) = pair
+ df = fn(tp)
+ for key, value in args.items():
+ df[key] = value
+ return df
+
+ df = pd.concat(
+ list(self.query_executor.map(wrapped, zip(self.tps, self.args))))
+ return df.reset_index(drop=True)
+
+ def close(self):
+ """Closes this batch trace processor instance.
+
+ This closes all spawned trace processor instances, releasing all the memory
+ and resources those instances take.
+
+ No further calls to other methods in this class should be made after
+ calling this method.
+ """
+ if self.closed:
+ return
+ self.closed = True
+
+ if self.tps:
+ for tp in self.tps:
+ tp.close()
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, a, b, c):
+ del a, b, c # Unused.
+ self.close()
+ return False
+
+ def __del__(self):
+ self.close()
diff --git a/tools/slice_breakdown/perfetto/slice_breakdown/__init__.py b/python/perfetto/experimental/slice_breakdown/__init__.py
similarity index 78%
rename from tools/slice_breakdown/perfetto/slice_breakdown/__init__.py
rename to python/perfetto/experimental/slice_breakdown/__init__.py
index 6e6169f..53d1e85 100644
--- a/tools/slice_breakdown/perfetto/slice_breakdown/__init__.py
+++ b/python/perfetto/experimental/slice_breakdown/__init__.py
@@ -12,4 +12,5 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-from .breakdown import compute_breakdown, compute_breakdown_for_startup
\ No newline at end of file
+from perfetto.experimental.slice_breakdown.breakdown import compute_breakdown
+from perfetto.experimental.slice_breakdown.breakdown import compute_breakdown_for_startup
\ No newline at end of file
diff --git a/tools/slice_breakdown/perfetto/slice_breakdown/breakdown.py b/python/perfetto/experimental/slice_breakdown/breakdown.py
similarity index 100%
rename from tools/slice_breakdown/perfetto/slice_breakdown/breakdown.py
rename to python/perfetto/experimental/slice_breakdown/breakdown.py
diff --git a/src/trace_processor/python/perfetto/trace_processor/__init__.py b/python/perfetto/trace_processor/__init__.py
similarity index 67%
copy from src/trace_processor/python/perfetto/trace_processor/__init__.py
copy to python/perfetto/trace_processor/__init__.py
index 7106a6c..e151656 100644
--- a/src/trace_processor/python/perfetto/trace_processor/__init__.py
+++ b/python/perfetto/trace_processor/__init__.py
@@ -13,5 +13,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-from .api import TraceProcessor, TraceProcessorException
-from .http import TraceProcessorHttp
+from perfetto.trace_processor.api import LoadableTrace
+from perfetto.trace_processor.api import TraceProcessor
+from perfetto.trace_processor.api import TraceProcessorConfig
+from perfetto.trace_processor.api import TraceProcessorException
+from perfetto.trace_processor.http import TraceProcessorHttp
diff --git a/src/trace_processor/python/perfetto/trace_processor/api.py b/python/perfetto/trace_processor/api.py
similarity index 64%
rename from src/trace_processor/python/perfetto/trace_processor/api.py
rename to python/perfetto/trace_processor/api.py
index ce06edf..3f24a13 100644
--- a/src/trace_processor/python/perfetto/trace_processor/api.py
+++ b/python/perfetto/trace_processor/api.py
@@ -12,12 +12,18 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+import dataclasses as dc
+from enum import unique
from urllib.parse import urlparse
+from typing import BinaryIO, Callable, Generator, List, Optional, Tuple, Union
-from .http import TraceProcessorHttp
-from .loader import get_loader
-from .protos import ProtoFactory
-from .shell import load_shell
+from perfetto.trace_processor.http import TraceProcessorHttp
+from perfetto.trace_processor.loader import get_loader
+from perfetto.trace_processor.protos import ProtoFactory
+from perfetto.trace_processor.shell import load_shell
+
+# Union of types supported for a trace which can be loaded by shell.
+LoadableTrace = Union[None, str, BinaryIO, Generator[bytes, None, None]]
# Custom exception raised if any trace_processor functions return a
@@ -28,6 +34,53 @@
super().__init__(message)
+@dc.dataclass
+class TraceProcessorConfig:
+ bin_path: Optional[str]
+ unique_port: bool
+ verbose: bool
+
+ read_tp_descriptor: Callable[[], bytes]
+ read_metrics_descriptor: Callable[[], bytes]
+ parse_file: Callable[[TraceProcessorHttp, str], TraceProcessorHttp]
+ get_shell_path: Callable[[str], None]
+ get_free_port: Callable[[bool], Tuple[str, str]]
+
+ def __init__(
+ self,
+ bin_path: Optional[str] = None,
+ unique_port: bool = True,
+ verbose: bool = False,
+ read_tp_descriptor: Callable[[], bytes] = get_loader().read_tp_descriptor,
+ read_metrics_descriptor: Callable[[], bytes] = get_loader(
+ ).read_metrics_descriptor,
+ parse_file: Callable[[TraceProcessorHttp, str],
+ TraceProcessorHttp] = get_loader().parse_file,
+ get_shell_path: Callable[[str], None] = get_loader().get_shell_path,
+ get_free_port: Callable[[bool], Tuple[str, str]] = get_loader(
+ ).get_free_port):
+ self.bin_path = bin_path
+ self.unique_port = unique_port
+ self.verbose = verbose
+
+ self.read_tp_descriptor = read_tp_descriptor
+ self.read_metrics_descriptor = read_metrics_descriptor
+ self.parse_file = parse_file
+ self.get_shell_path = get_shell_path
+ self.get_free_port = get_free_port
+
+ try:
+ # This is the only place in trace processor which should import
+ # from a "vendor" namespace - the purpose of this code is to allow
+ # for users to set their own "default" config for trace processor
+ # without needing to specify the config in every place when trace
+ # processor is used.
+ from .vendor import override_default_tp_config
+ return override_default_tp_config(self)
+ except ModuleNotFoundError:
+ pass
+
+
class TraceProcessor:
# Values of these constants correspond to the QueryResponse message at
@@ -122,7 +175,6 @@
# TraceProcesor.
def as_pandas_dataframe(self):
try:
- import numpy as np
import pandas as pd
# Populate the dataframe with the query results
@@ -144,7 +196,8 @@
rows.append(row)
df = pd.DataFrame(rows, columns=self.__column_names)
- return df.where(df.notnull(), None).reset_index(drop=True)
+ return df.astype(object).where(df.notnull(),
+ None).reset_index(drop=True)
except ModuleNotFoundError:
raise TraceProcessorException(
@@ -176,27 +229,69 @@
return result
def __init__(self,
- addr=None,
- file_path=None,
- bin_path=None,
- unique_port=True,
- verbose=False):
- # Load trace_processor_shell or access via given address
- if addr:
- p = urlparse(addr)
- tp = TraceProcessorHttp(p.netloc if p.netloc else p.path)
- else:
+ trace: LoadableTrace = None,
+ addr: Optional[str] = None,
+ config: TraceProcessorConfig = TraceProcessorConfig(),
+ file_path: Optional[str] = None):
+ """Create a trace processor instance.
+
+ Args:
+ trace: trace to be loaded into the trace processor instance. One of
+ three types of argument is supported:
+ 1) path to a trace file to open and read
+ 2) a file like object (file, io.BytesIO or similar) to read
+ 3) a generator yielding bytes
+ 4) a custom string format which can be understood by
+ TraceProcessorConfig.parse_file function. The default
+ implementation of this function only supports file paths (i.e. option
+ 1) but callers can choose to change the implementation to parse
+ a custom string format and use that to retrieve a race.
+ addr: address of a running trace processor instance. Useful to query an
+ already loaded trace.
+ config: configuration options which customize functionality of trace
+ processor and the Python binding.
+ file_path (deprecated): path to a trace file to load. Use
+ |trace| instead of this field: specifying both will cause
+ an exception to be thrown.
+ """
+
+ def create_tp_http(protos: ProtoFactory) -> TraceProcessorHttp:
+ if addr:
+ p = urlparse(addr)
+ return TraceProcessorHttp(
+ p.netloc if p.netloc else p.path, protos=protos)
+
url, self.subprocess = load_shell(
- bin_path=bin_path, unique_port=unique_port, verbose=verbose)
- tp = TraceProcessorHttp(url)
- self.http = tp
- self.protos = ProtoFactory()
+ bin_path=config.bin_path,
+ unique_port=config.unique_port,
+ verbose=config.verbose)
+ return TraceProcessorHttp(url, protos=protos)
- # Parse trace by its file_path into the loaded instance of trace_processor
+ if trace and file_path:
+ raise TraceProcessorException(
+ "trace and file_path cannot both be specified.")
+
+ self.protos = ProtoFactory(config.read_tp_descriptor(),
+ config.read_metrics_descriptor())
+ self.http = create_tp_http(self.protos)
+
if file_path:
- get_loader().parse_file(self.http, file_path)
+ config.parse_file(self.http, file_path)
+ elif isinstance(trace, str):
+ config.parse_file(self.http, trace)
+ elif hasattr(trace, 'read'):
+ while True:
+ chunk = trace.read(32 * 1024 * 1024)
+ if not chunk:
+ break
+ self.http.parse(chunk)
+ self.http.notify_eof()
+ elif trace:
+ for chunk in trace:
+ self.http.parse(chunk)
+ self.http.notify_eof()
- def query(self, sql):
+ def query(self, sql: str):
"""Executes passed in SQL query using class defined HTTP API, and returns
the response as a QueryResultIterator. Raises TraceProcessorException if
the response returns with an error.
@@ -216,7 +311,7 @@
return TraceProcessor.QueryResultIterator(response.column_names,
response.batch)
- def metric(self, metrics):
+ def metric(self, metrics: List[str]):
"""Returns the metrics data corresponding to the passed in trace metric.
Raises TraceProcessorException if the response returns with an error.
@@ -254,7 +349,8 @@
def __enter__(self):
return self
- def __exit__(self, _, __, ___):
+ def __exit__(self, a, b, c):
+ del a, b, c # Unused.
self.close()
return False
diff --git a/src/trace_processor/python/perfetto/trace_processor/http.py b/python/perfetto/trace_processor/http.py
similarity index 88%
rename from src/trace_processor/python/perfetto/trace_processor/http.py
rename to python/perfetto/trace_processor/http.py
index bf751f9..71db4ab 100644
--- a/src/trace_processor/python/perfetto/trace_processor/http.py
+++ b/python/perfetto/trace_processor/http.py
@@ -14,17 +14,18 @@
# limitations under the License.
import http.client
+from typing import List
-from .protos import ProtoFactory
+from perfetto.trace_processor.protos import ProtoFactory
class TraceProcessorHttp:
- def __init__(self, url):
- self.protos = ProtoFactory()
+ def __init__(self, url: str, protos: ProtoFactory):
+ self.protos = protos
self.conn = http.client.HTTPConnection(url)
- def execute_query(self, query):
+ def execute_query(self, query: str):
args = self.protos.RawQueryArgs()
args.sql_query = query
byte_data = args.SerializeToString()
@@ -34,7 +35,7 @@
result.ParseFromString(f.read())
return result
- def compute_metric(self, metrics):
+ def compute_metric(self, metrics: List[str]):
args = self.protos.ComputeMetricArgs()
args.metric_names.extend(metrics)
byte_data = args.SerializeToString()
@@ -44,7 +45,7 @@
result.ParseFromString(f.read())
return result
- def parse(self, chunk):
+ def parse(self, chunk: bytes):
self.conn.request('POST', '/parse', body=chunk)
with self.conn.getresponse() as f:
return f.read()
diff --git a/src/trace_processor/python/perfetto/trace_processor/loader.py b/python/perfetto/trace_processor/loader.py
similarity index 94%
rename from src/trace_processor/python/perfetto/trace_processor/loader.py
rename to python/perfetto/trace_processor/loader.py
index e57145f..0a1b16b 100644
--- a/src/trace_processor/python/perfetto/trace_processor/loader.py
+++ b/python/perfetto/trace_processor/loader.py
@@ -53,7 +53,7 @@
tp_http.notify_eof()
return tp_http
- def get_shell_path(bin_path=None):
+ def get_shell_path(bin_path):
# Try to use preexisting binary before attempting to download
# trace_processor
if bin_path is None:
@@ -68,7 +68,7 @@
raise Exception('Path to binary is not valid')
return bin_path
- def get_free_port(unique_port=False):
+ def get_free_port(unique_port):
if not unique_port:
return LoaderStandalone.TP_PORT, f'localhost:{LoaderStandalone.TP_PORT}'
free_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
@@ -80,6 +80,8 @@
# Return vendor class if it exists before falling back on LoaderStandalone
+# TODO(lalitm): remove this after migrating all consumers to
+# TraceProcessorConfig.
def get_loader():
try:
from .loader_vendor import LoaderVendor
diff --git a/src/trace_processor/python/perfetto/trace_processor/metrics.descriptor b/python/perfetto/trace_processor/metrics.descriptor
similarity index 96%
rename from src/trace_processor/python/perfetto/trace_processor/metrics.descriptor
rename to python/perfetto/trace_processor/metrics.descriptor
index e3a3ea8..053e838 100644
--- a/src/trace_processor/python/perfetto/trace_processor/metrics.descriptor
+++ b/python/perfetto/trace_processor/metrics.descriptor
Binary files differ
diff --git a/python/perfetto/trace_processor/metrics.descriptor.sha1 b/python/perfetto/trace_processor/metrics.descriptor.sha1
new file mode 100644
index 0000000..17f0868
--- /dev/null
+++ b/python/perfetto/trace_processor/metrics.descriptor.sha1
@@ -0,0 +1,6 @@
+
+// SHA1(tools/gen_binary_descriptors)
+// c4a38769074f8a8c2ffbf514b267919b5f2d47df
+// SHA1(protos/perfetto/metrics/metrics.proto)
+// 22722c7fde543d5abd1299f48edd49c69c5f5c3e
+
\ No newline at end of file
diff --git a/src/trace_processor/python/perfetto/trace_processor/protos.py b/python/perfetto/trace_processor/protos.py
similarity index 90%
rename from src/trace_processor/python/perfetto/trace_processor/protos.py
rename to python/perfetto/trace_processor/protos.py
index b5e3700..0053fdb 100644
--- a/src/trace_processor/python/perfetto/trace_processor/protos.py
+++ b/python/perfetto/trace_processor/protos.py
@@ -16,27 +16,23 @@
from google.protobuf import message_factory
from google.protobuf.descriptor_pool import DescriptorPool
-from .loader import get_loader
-
class ProtoFactory:
- def __init__(self):
+ def __init__(self, tp_descriptor: bytes, metrics_descriptor: bytes):
# Declare descriptor pool
self.descriptor_pool = DescriptorPool()
# Load trace processor descriptor and add to descriptor pool
- tp_descriptor_bytes = get_loader().read_tp_descriptor()
tp_file_desc_set_pb2 = descriptor_pb2.FileDescriptorSet()
- tp_file_desc_set_pb2.MergeFromString(tp_descriptor_bytes)
+ tp_file_desc_set_pb2.MergeFromString(tp_descriptor)
for f_desc_pb2 in tp_file_desc_set_pb2.file:
self.descriptor_pool.Add(f_desc_pb2)
# Load metrics descriptor and add to descriptor pool
- metrics_descriptor_bytes = get_loader().read_metrics_descriptor()
metrics_file_desc_set_pb2 = descriptor_pb2.FileDescriptorSet()
- metrics_file_desc_set_pb2.MergeFromString(metrics_descriptor_bytes)
+ metrics_file_desc_set_pb2.MergeFromString(metrics_descriptor)
for f_desc_pb2 in metrics_file_desc_set_pb2.file:
self.descriptor_pool.Add(f_desc_pb2)
diff --git a/src/trace_processor/python/perfetto/trace_processor/shell.py b/python/perfetto/trace_processor/shell.py
similarity index 96%
rename from src/trace_processor/python/perfetto/trace_processor/shell.py
rename to python/perfetto/trace_processor/shell.py
index 00749d1..8daa956 100644
--- a/src/trace_processor/python/perfetto/trace_processor/shell.py
+++ b/python/perfetto/trace_processor/shell.py
@@ -18,7 +18,7 @@
import time
from urllib import request, error
-from .loader import get_loader
+from perfetto.trace_processor.loader import get_loader
def load_shell(bin_path, unique_port, verbose):
diff --git a/src/trace_processor/python/perfetto/trace_processor/trace_processor.descriptor b/python/perfetto/trace_processor/trace_processor.descriptor
similarity index 100%
rename from src/trace_processor/python/perfetto/trace_processor/trace_processor.descriptor
rename to python/perfetto/trace_processor/trace_processor.descriptor
Binary files differ
diff --git a/src/trace_processor/python/perfetto/trace_processor/trace_processor.descriptor.sha1 b/python/perfetto/trace_processor/trace_processor.descriptor.sha1
similarity index 76%
rename from src/trace_processor/python/perfetto/trace_processor/trace_processor.descriptor.sha1
rename to python/perfetto/trace_processor/trace_processor.descriptor.sha1
index 23712a1..92ce69e 100644
--- a/src/trace_processor/python/perfetto/trace_processor/trace_processor.descriptor.sha1
+++ b/python/perfetto/trace_processor/trace_processor.descriptor.sha1
@@ -1,6 +1,6 @@
// SHA1(tools/gen_binary_descriptors)
-// 9fc6d77de57ec76a80b76aa282f4c7cf5ce55eec
+// c4a38769074f8a8c2ffbf514b267919b5f2d47df
// SHA1(protos/perfetto/trace_processor/trace_processor.proto)
// e303e1fc877a9fe4f8dd8413c03266ee68dfd3aa
\ No newline at end of file
diff --git a/tools/run_python_api_tests.py b/python/run_tests.py
similarity index 82%
rename from tools/run_python_api_tests.py
rename to python/run_tests.py
index 78a78a1..6ac0977 100755
--- a/tools/run_python_api_tests.py
+++ b/python/run_tests.py
@@ -18,6 +18,9 @@
import sys
import unittest
+from test import api_unittest
+from test import api_integrationtest
+
ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
@@ -29,13 +32,6 @@
print('Cannot proceed. Please `pip3 install pandas numpy`', file=sys.stderr)
return 1
- # Append test and src paths so that all imports are loaded in correctly
- sys.path.append(os.path.join(ROOT_DIR, 'test', 'trace_processor', 'python'))
- sys.path.append(
- os.path.join(ROOT_DIR, 'src', 'trace_processor', 'python', 'perfetto'))
- import api_unittest
- import api_integrationtest
-
# Set paths to trace_processor_shell and root directory as environment
# variables
parser = argparse.ArgumentParser()
@@ -43,7 +39,6 @@
os.environ["SHELL_PATH"] = parser.parse_args().shell
os.environ["ROOT_DIR"] = ROOT_DIR
- # Initialise test suite
loader = unittest.TestLoader()
suite = unittest.TestSuite()
diff --git a/src/trace_processor/python/setup.py b/python/setup.py
similarity index 100%
rename from src/trace_processor/python/setup.py
rename to python/setup.py
diff --git a/tools/batch_trace_processor/perfetto/batch_trace_processor/__init__.py b/python/test/__init__.py
similarity index 100%
rename from tools/batch_trace_processor/perfetto/batch_trace_processor/__init__.py
rename to python/test/__init__.py
diff --git a/python/test/api_integrationtest.py b/python/test/api_integrationtest.py
new file mode 100644
index 0000000..8d83eaf
--- /dev/null
+++ b/python/test/api_integrationtest.py
@@ -0,0 +1,105 @@
+#!/usr/bin/env python3
+# Copyright (C) 2020 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 io
+import os
+from typing import Optional
+import unittest
+
+from perfetto.trace_processor.api import TraceProcessor
+from perfetto.trace_processor.api import TraceProcessorConfig
+from perfetto.trace_processor.api import LoadableTrace
+
+
+def create_tp(trace: LoadableTrace):
+ return TraceProcessor(
+ trace=trace,
+ config=TraceProcessorConfig(bin_path=os.environ["SHELL_PATH"]))
+
+
+def example_android_trace_path():
+ return os.path.join(os.environ["ROOT_DIR"], 'test', 'data',
+ 'example_android_trace_30s.pb')
+
+
+class TestApi(unittest.TestCase):
+
+ def test_trace_path(self):
+ # Get path to trace_processor_shell and construct TraceProcessor
+ tp = create_tp(trace=example_android_trace_path())
+ qr_iterator = tp.query('select * from slice limit 10')
+ dur_result = [
+ 178646, 119740, 58073, 155000, 173177, 20209377, 3589167, 90104, 275312,
+ 65313
+ ]
+
+ for num, row in enumerate(qr_iterator):
+ self.assertEqual(row.type, 'internal_slice')
+ self.assertEqual(row.dur, dur_result[num])
+
+ # Test the batching logic by issuing a large query and ensuring we receive
+ # all rows, not just a truncated subset.
+ qr_iterator = tp.query('select count(*) as cnt from slice')
+ expected_count = next(qr_iterator).cnt
+ self.assertGreater(expected_count, 0)
+
+ qr_iterator = tp.query('select * from slice')
+ count = sum(1 for _ in qr_iterator)
+ self.assertEqual(count, expected_count)
+
+ tp.close()
+
+ def test_trace_byteio(self):
+ f = io.BytesIO(
+ b'\n(\n&\x08\x00\x12\x12\x08\x01\x10\xc8\x01\x1a\x0b\x12\t'
+ b'B|200|foo\x12\x0e\x08\x02\x10\xc8\x01\x1a\x07\x12\x05E|200')
+ with create_tp(trace=f) as tp:
+ qr_iterator = tp.query('select * from slice limit 10')
+ res = list(qr_iterator)
+
+ self.assertEqual(len(res), 1)
+
+ row = res[0]
+ self.assertEqual(row.ts, 1)
+ self.assertEqual(row.dur, 1)
+ self.assertEqual(row.name, 'foo')
+
+ def test_trace_file(self):
+ with open(example_android_trace_path(), 'rb') as file:
+ with create_tp(trace=file) as tp:
+ qr_iterator = tp.query('select * from slice limit 10')
+ dur_result = [
+ 178646, 119740, 58073, 155000, 173177, 20209377, 3589167, 90104,
+ 275312, 65313
+ ]
+
+ for num, row in enumerate(qr_iterator):
+ self.assertEqual(row.dur, dur_result[num])
+
+ def test_trace_generator(self):
+
+ def reader_generator():
+ with open(example_android_trace_path(), 'rb') as file:
+ yield file.read(1024)
+
+ with create_tp(trace=reader_generator()) as tp:
+ qr_iterator = tp.query('select * from slice limit 10')
+ dur_result = [
+ 178646, 119740, 58073, 155000, 173177, 20209377, 3589167, 90104,
+ 275312, 65313
+ ]
+
+ for num, row in enumerate(qr_iterator):
+ self.assertEqual(row.dur, dur_result[num])
diff --git a/test/trace_processor/python/api_unittest.py b/python/test/api_unittest.py
similarity index 90%
rename from test/trace_processor/python/api_unittest.py
rename to python/test/api_unittest.py
index 29abd5f..732438a 100755
--- a/test/trace_processor/python/api_unittest.py
+++ b/python/test/api_unittest.py
@@ -15,23 +15,30 @@
import unittest
-from trace_processor.api import TraceProcessor, TraceProcessorException
-from trace_processor.protos import ProtoFactory
+from perfetto.trace_processor.api import TraceProcessor
+from perfetto.trace_processor.api import TraceProcessorException
+from perfetto.trace_processor.api import TraceProcessorConfig
+from perfetto.trace_processor.protos import ProtoFactory
+
+TP_CONFIG = TraceProcessorConfig()
+PROTO_FACTORY = ProtoFactory(
+ tp_descriptor=TP_CONFIG.read_tp_descriptor(),
+ metrics_descriptor=TP_CONFIG.read_metrics_descriptor())
class TestQueryResultIterator(unittest.TestCase):
# The numbers input into cells correspond the CellType enum values
# defined under trace_processor.proto
- CELL_VARINT = ProtoFactory().CellsBatch().CELL_VARINT
- CELL_STRING = ProtoFactory().CellsBatch().CELL_STRING
- CELL_INVALID = ProtoFactory().CellsBatch().CELL_INVALID
- CELL_NULL = ProtoFactory().CellsBatch().CELL_NULL
+ CELL_VARINT = PROTO_FACTORY.CellsBatch().CELL_VARINT
+ CELL_STRING = PROTO_FACTORY.CellsBatch().CELL_STRING
+ CELL_INVALID = PROTO_FACTORY.CellsBatch().CELL_INVALID
+ CELL_NULL = PROTO_FACTORY.CellsBatch().CELL_NULL
def test_one_batch(self):
int_values = [100, 200]
str_values = ['bar1', 'bar2']
- batch = ProtoFactory().CellsBatch()
+ batch = PROTO_FACTORY.CellsBatch()
batch.cells.extend([
TestQueryResultIterator.CELL_STRING,
TestQueryResultIterator.CELL_VARINT,
@@ -56,7 +63,7 @@
int_values = [100, 200, 300, 400]
str_values = ['bar1', 'bar2', 'bar3', 'bar4']
- batch_1 = ProtoFactory().CellsBatch()
+ batch_1 = PROTO_FACTORY.CellsBatch()
batch_1.cells.extend([
TestQueryResultIterator.CELL_STRING,
TestQueryResultIterator.CELL_VARINT,
@@ -69,7 +76,7 @@
batch_1.string_cells = "\0".join(str_values[:2]) + "\0"
batch_1.is_last_batch = False
- batch_2 = ProtoFactory().CellsBatch()
+ batch_2 = PROTO_FACTORY.CellsBatch()
batch_2.cells.extend([
TestQueryResultIterator.CELL_STRING,
TestQueryResultIterator.CELL_VARINT,
@@ -91,7 +98,7 @@
self.assertEqual(row.foo_null, None)
def test_empty_batch(self):
- batch = ProtoFactory().CellsBatch()
+ batch = PROTO_FACTORY.CellsBatch()
batch.is_last_batch = True
qr_iterator = TraceProcessor.QueryResultIterator([], [batch])
@@ -101,7 +108,7 @@
self.assertIsNone(row.foo_num)
def test_invalid_batch(self):
- batch = ProtoFactory().CellsBatch()
+ batch = PROTO_FACTORY.CellsBatch()
# Since the batch isn't defined as the last batch, the QueryResultsIterator
# expects another batch and thus raises IndexError as no next batch exists.
@@ -112,7 +119,7 @@
int_values = [100, 200, 300, 500, 600]
str_values = ['bar1', 'bar2', 'bar3']
- batch = ProtoFactory().CellsBatch()
+ batch = PROTO_FACTORY.CellsBatch()
batch.cells.extend([
TestQueryResultIterator.CELL_STRING,
TestQueryResultIterator.CELL_VARINT,
@@ -143,7 +150,7 @@
def test_incorrect_cells_batch(self):
str_values = ['bar1', 'bar2']
- batch = ProtoFactory().CellsBatch()
+ batch = PROTO_FACTORY.CellsBatch()
batch.cells.extend([
TestQueryResultIterator.CELL_STRING,
TestQueryResultIterator.CELL_VARINT,
@@ -163,7 +170,7 @@
pass
def test_incorrect_columns_batch(self):
- batch = ProtoFactory().CellsBatch()
+ batch = PROTO_FACTORY.CellsBatch()
batch.cells.extend([
TestQueryResultIterator.CELL_VARINT, TestQueryResultIterator.CELL_VARINT
])
@@ -178,7 +185,7 @@
['foo_id', 'foo_num', 'foo_dur', 'foo_ms'], [batch])
def test_invalid_cell_type(self):
- batch = ProtoFactory().CellsBatch()
+ batch = PROTO_FACTORY.CellsBatch()
batch.cells.extend([
TestQueryResultIterator.CELL_INVALID,
TestQueryResultIterator.CELL_VARINT
@@ -200,7 +207,7 @@
int_values = [100, 200]
str_values = ['bar1', 'bar2']
- batch = ProtoFactory().CellsBatch()
+ batch = PROTO_FACTORY.CellsBatch()
batch.cells.extend([
TestQueryResultIterator.CELL_STRING,
TestQueryResultIterator.CELL_VARINT,
@@ -226,7 +233,7 @@
int_values = [100, 200, 300, 400]
str_values = ['bar1', 'bar2', 'bar3', 'bar4']
- batch_1 = ProtoFactory().CellsBatch()
+ batch_1 = PROTO_FACTORY.CellsBatch()
batch_1.cells.extend([
TestQueryResultIterator.CELL_STRING,
TestQueryResultIterator.CELL_VARINT,
@@ -239,7 +246,7 @@
batch_1.string_cells = "\0".join(str_values[:2]) + "\0"
batch_1.is_last_batch = False
- batch_2 = ProtoFactory().CellsBatch()
+ batch_2 = PROTO_FACTORY.CellsBatch()
batch_2.cells.extend([
TestQueryResultIterator.CELL_STRING,
TestQueryResultIterator.CELL_VARINT,
@@ -262,7 +269,7 @@
self.assertEqual(row['foo_null'], None)
def test_empty_batch_as_pandas(self):
- batch = ProtoFactory().CellsBatch()
+ batch = PROTO_FACTORY.CellsBatch()
batch.is_last_batch = True
qr_iterator = TraceProcessor.QueryResultIterator([], [batch])
@@ -276,7 +283,7 @@
int_values = [100, 200, 300, 500, 600]
str_values = ['bar1', 'bar2', 'bar3']
- batch = ProtoFactory().CellsBatch()
+ batch = PROTO_FACTORY.CellsBatch()
batch.cells.extend([
TestQueryResultIterator.CELL_STRING,
TestQueryResultIterator.CELL_VARINT,
@@ -308,7 +315,7 @@
def test_incorrect_cells_batch_as_pandas(self):
str_values = ['bar1', 'bar2']
- batch = ProtoFactory().CellsBatch()
+ batch = PROTO_FACTORY.CellsBatch()
batch.cells.extend([
TestQueryResultIterator.CELL_STRING,
TestQueryResultIterator.CELL_VARINT,
@@ -327,7 +334,7 @@
qr_df = qr_iterator.as_pandas_dataframe()
def test_invalid_cell_type_as_pandas(self):
- batch = ProtoFactory().CellsBatch()
+ batch = PROTO_FACTORY.CellsBatch()
batch.cells.extend([
TestQueryResultIterator.CELL_INVALID,
TestQueryResultIterator.CELL_VARINT
diff --git a/tools/batch_trace_processor/main.py b/python/tools/batch_trace_processor_shell.py
similarity index 91%
rename from tools/batch_trace_processor/main.py
rename to python/tools/batch_trace_processor_shell.py
index b73f7d9..651247d 100644
--- a/tools/batch_trace_processor/main.py
+++ b/python/tools/batch_trace_processor_shell.py
@@ -23,8 +23,8 @@
import pandas as pd
import plotille
-from perfetto.batch_trace_processor.api import BatchTraceProcessor
-from perfetto.trace_processor import TraceProcessorException
+from perfetto.batch_trace_processor.api import BatchTraceProcessor, BatchTraceProcessorConfig
+from perfetto.trace_processor import TraceProcessorException, TraceProcessorConfig
from typing import List
@@ -107,8 +107,13 @@
logging.info("At least one file must be specified in files or file list")
logging.info('Loading traces...')
- with BatchTraceProcessor(
- files, bin_path=args.shell_path, verbose=args.verbose) as batch_tp:
+ config = BatchTraceProcessorConfig(
+ tp_config=TraceProcessorConfig(
+ bin_path=args.shell_path,
+ verbose=args.verbose,
+ ))
+
+ with BatchTraceProcessor(files, config) as batch_tp:
if args.query_file:
logging.info('Running query file...')
diff --git a/tools/slice_breakdown/main.py b/python/tools/slice_breakdown.py
similarity index 75%
rename from tools/slice_breakdown/main.py
rename to python/tools/slice_breakdown.py
index 960e44b..9c481ba 100644
--- a/tools/slice_breakdown/main.py
+++ b/python/tools/slice_breakdown.py
@@ -19,21 +19,21 @@
import argparse
import sys
-from perfetto.slice_breakdown import compute_breakdown, compute_breakdown_for_startup
+from perfetto.experimental.slice_breakdown import compute_breakdown
+from perfetto.experimental.slice_breakdown import compute_breakdown_for_startup
from perfetto.trace_processor import TraceProcessor
+from perfetto.trace_processor import TraceProcessorConfig
def compute_breakdown_wrapper(args):
- tp = TraceProcessor(
- file_path=args.file, bin_path=args.shell_path, verbose=args.verbose)
- if args.startup_bounds:
- breakdown = compute_breakdown_for_startup(tp, args.startup_package,
- args.process_name)
- else:
- breakdown = compute_breakdown(tp, args.start_ts, args.end_ts,
- args.process_name)
- tp.close()
-
+ config = TraceProcessorConfig(bin_path=args.shell_path, verbose=args.verbose)
+ with TraceProcessor(trace=args.file, config=config) as tp:
+ if args.startup_bounds:
+ breakdown = compute_breakdown_for_startup(tp, args.startup_package,
+ args.process_name)
+ else:
+ breakdown = compute_breakdown(tp, args.start_ts, args.end_ts,
+ args.process_name)
return breakdown
diff --git a/src/base/file_utils.cc b/src/base/file_utils.cc
index 91a5fc4..e3139bf 100644
--- a/src/base/file_utils.cc
+++ b/src/base/file_utils.cc
@@ -44,6 +44,14 @@
namespace base {
namespace {
constexpr size_t kBufSize = 2048;
+
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+// Wrap FindClose to: (1) make the return unix-style; (2) deal with stdcall.
+int CloseFindHandle(HANDLE h) {
+ return FindClose(h) ? 0 : -1;
+};
+#endif
+
} // namespace
ssize_t Read(int fd, void* dst, size_t dst_size) {
@@ -238,9 +246,7 @@
return base::ErrStatus("Directory path %s is too long", dir_path.c_str());
WIN32_FIND_DATAA ffd;
- // Wrap FindClose to: (1) make the return unix-style; (2) deal w/ stdcall.
- static auto find_close = [](HANDLE h) { return FindClose(h) ? 0 : -1; };
- base::ScopedResource<HANDLE, find_close, nullptr, false,
+ base::ScopedResource<HANDLE, CloseFindHandle, nullptr, false,
base::PlatformHandleChecker>
hFind(FindFirstFileA(glob_path.c_str(), &ffd));
if (!hFind) {
diff --git a/src/trace_processor/metrics/sql/BUILD.gn b/src/trace_processor/metrics/sql/BUILD.gn
index 9432bf5..6d9f8f3 100644
--- a/src/trace_processor/metrics/sql/BUILD.gn
+++ b/src/trace_processor/metrics/sql/BUILD.gn
@@ -62,6 +62,7 @@
"android/process_metadata.sql",
"android/process_oom_score.sql",
"android/profiler_smaps.sql",
+ "android/android_rt_runtime.sql",
"android/mem_stats_priority_breakdown.sql",
"android/android_multiuser.sql",
"android/android_multiuser_populator.sql",
diff --git a/src/trace_processor/metrics/sql/android/android_rt_runtime.sql b/src/trace_processor/metrics/sql/android/android_rt_runtime.sql
new file mode 100644
index 0000000..01d8a64
--- /dev/null
+++ b/src/trace_processor/metrics/sql/android/android_rt_runtime.sql
@@ -0,0 +1,46 @@
+--
+-- Copyright 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
+--
+-- https://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.
+
+DROP VIEW IF EXISTS rt_runtime_all;
+
+CREATE VIEW rt_runtime_all
+AS
+SELECT ts, dur, thread.name AS tname
+FROM sched_slice
+LEFT JOIN thread
+ USING (utid)
+LEFT JOIN process
+ USING (upid)
+WHERE priority < 100
+ORDER BY dur DESC;
+
+DROP VIEW IF EXISTS android_rt_runtime_output;
+
+CREATE VIEW android_rt_runtime_output
+AS
+SELECT
+ AndroidRtRuntimeMetric(
+ 'max_runtime',
+ (SELECT dur FROM rt_runtime_all LIMIT 1),
+ 'over_5ms_count',
+ (SELECT COUNT(*) FROM rt_runtime_all WHERE dur > 5e6),
+ 'longest_rt_slices',
+ (
+ SELECT
+ RepeatedField(
+ AndroidRtRuntimeMetric_RtSlice(
+ 'tname', tname, 'ts', ts, 'dur', dur))
+ FROM (SELECT ts, dur, tname FROM rt_runtime_all LIMIT 10)
+ ));
diff --git a/src/trace_processor/python/perfetto/trace_processor/metrics.descriptor.sha1 b/src/trace_processor/python/perfetto/trace_processor/metrics.descriptor.sha1
deleted file mode 100644
index 9658367..0000000
--- a/src/trace_processor/python/perfetto/trace_processor/metrics.descriptor.sha1
+++ /dev/null
@@ -1,6 +0,0 @@
-
-// SHA1(tools/gen_binary_descriptors)
-// 9fc6d77de57ec76a80b76aa282f4c7cf5ce55eec
-// SHA1(protos/perfetto/metrics/metrics.proto)
-// 3d9357a253dc649bdd67069d156fc6217f2e6a39
-
\ No newline at end of file
diff --git a/src/trace_processor/rpc/httpd.cc b/src/trace_processor/rpc/httpd.cc
index 72c0f12..7b467a6 100644
--- a/src/trace_processor/rpc/httpd.cc
+++ b/src/trace_processor/rpc/httpd.cc
@@ -169,7 +169,6 @@
// Terminate chunked stream.
conn.SendResponseBody("0\r\n\r\n", 5);
- conn.Close();
return;
}
diff --git a/src/trace_processor/trace_processor_shell.cc b/src/trace_processor/trace_processor_shell.cc
index 1eede6f..f601930 100644
--- a/src/trace_processor/trace_processor_shell.cc
+++ b/src/trace_processor/trace_processor_shell.cc
@@ -35,6 +35,7 @@
#include "perfetto/base/time.h"
#include "perfetto/ext/base/file_utils.h"
#include "perfetto/ext/base/getopt.h"
+#include "perfetto/ext/base/optional.h"
#include "perfetto/ext/base/scoped_file.h"
#include "perfetto/ext/base/string_splitter.h"
#include "perfetto/ext/base/string_utils.h"
@@ -1254,7 +1255,9 @@
".load-metrics-sql Reloads SQL from extension and custom metric paths\n"
" specified in command line args.\n"
".run-metrics Runs metrics specified in command line args\n"
- " and prints the result.\n");
+ " and prints the result.\n"
+ ".width WIDTH Changes the column width of interactive query\n"
+ " output.");
}
struct InteractiveOptions {
@@ -1268,6 +1271,7 @@
util::Status StartInteractiveShell(const InteractiveOptions& options) {
SetupLineEditor();
+ uint32_t column_width = options.column_width;
for (;;) {
ScopedLine line = GetLine("> ");
if (!line)
@@ -1294,6 +1298,13 @@
if (!status.ok()) {
PERFETTO_ELOG("%s", status.c_message());
}
+ } else if (strcmp(command, "width") == 0 && strlen(arg)) {
+ base::Optional<uint32_t> width = base::CStringToUInt32(arg);
+ if (!width) {
+ PERFETTO_ELOG("Invalid column width specified");
+ continue;
+ }
+ column_width = *width;
} else if (strcmp(command, "load-metrics-sql") == 0) {
base::Status status =
LoadMetricsAndExtensionsSql(options.metrics, options.extensions);
@@ -1319,7 +1330,7 @@
base::TimeNanos t_start = base::GetWallTimeNs();
auto it = g_tp->ExecuteQuery(line.get());
- PrintQueryResultInteractively(&it, t_start, options.column_width);
+ PrintQueryResultInteractively(&it, t_start, column_width);
}
return util::OkStatus();
}
diff --git a/test/ci/linux_tests.sh b/test/ci/linux_tests.sh
index fd165f2..1a68291 100755
--- a/test/ci/linux_tests.sh
+++ b/test/ci/linux_tests.sh
@@ -41,7 +41,7 @@
--perf-file=/ci/artifacts/perf/tp-perf-all.json \
${TP_SHELL}
-tools/run_python_api_tests.py ${TP_SHELL}
+python/run_tests.py ${TP_SHELL}
# Don't run benchmarks under x86 (running out of address space because of 4GB)
# limit or debug (too slow and pointless).
diff --git a/test/trace_processor/python/api_integrationtest.py b/test/trace_processor/python/api_integrationtest.py
deleted file mode 100644
index 392e28e..0000000
--- a/test/trace_processor/python/api_integrationtest.py
+++ /dev/null
@@ -1,50 +0,0 @@
-#!/usr/bin/env python3
-# Copyright (C) 2020 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 os
-import unittest
-
-from trace_processor.api import TraceProcessor
-
-
-class TestApi(unittest.TestCase):
-
- def test_trace_file(self):
- # Get path to trace_processor_shell and construct TraceProcessor
- tp = TraceProcessor(
- file_path=os.path.join(os.environ["ROOT_DIR"], 'test', 'data',
- 'example_android_trace_30s.pb'),
- bin_path=os.environ["SHELL_PATH"])
- qr_iterator = tp.query('select * from slice limit 10')
- dur_result = [
- 178646, 119740, 58073, 155000, 173177, 20209377, 3589167, 90104, 275312,
- 65313
- ]
-
- for num, row in enumerate(qr_iterator):
- self.assertEqual(row.type, 'internal_slice')
- self.assertEqual(row.dur, dur_result[num])
-
- # Test the batching logic by issuing a large query and ensuring we receive
- # all rows, not just a truncated subset.
- qr_iterator = tp.query('select count(*) as cnt from slice')
- expected_count = next(qr_iterator).cnt
- self.assertGreater(expected_count, 0)
-
- qr_iterator = tp.query('select * from slice')
- count = sum(1 for _ in qr_iterator)
- self.assertEqual(count, expected_count)
-
- tp.close()
diff --git a/tools/batch_trace_processor/perfetto/batch_trace_processor/api.py b/tools/batch_trace_processor/perfetto/batch_trace_processor/api.py
deleted file mode 100644
index fad76d8..0000000
--- a/tools/batch_trace_processor/perfetto/batch_trace_processor/api.py
+++ /dev/null
@@ -1,252 +0,0 @@
-#!/usr/bin/env python3
-# Copyright (C) 2021 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-
-"""Contains classes for BatchTraceProcessor API."""
-
-import concurrent.futures as cf
-import dataclasses as dc
-from typing import Any, Callable, Dict, Tuple, Union, List
-
-import pandas as pd
-
-from perfetto.trace_processor import TraceProcessor
-from perfetto.trace_processor import TraceProcessorException
-
-
-@dc.dataclass
-class _TpArg:
- bin_path: str
- verbose: bool
- file: str
-
-
-@dc.dataclass
-class TraceFile:
- trace_path: str
- args: Dict[str, str]
-
-
-def _create_trace_file(path_or_trace_file: Union[str, TraceFile]) -> TraceFile:
- if isinstance(path_or_trace_file, str):
- return TraceFile(trace_path=path_or_trace_file, args={})
- return path_or_trace_file
-
-
-class BatchTraceProcessor:
- """Run ad-hoc SQL queries across many Perfetto traces.
-
- Usage:
- with BatchTraceProcessor(files=files) as btp:
- dfs = btp.query('select * from slice')
- for df in dfs:
- print(df)
- """
-
- def __init__(self,
- files: Union[List[TraceFile], List[str]],
- bin_path: str = None,
- verbose: bool = False):
- """Creates a batch trace processor instance.
-
- BatchTraceProcessor is the blessed way of running ad-hoc queries in
- Python across many traces.
-
- Args:
- files: Either a list of trace file paths or a list of TraceFile objects
- indicating the traces to load into this batch trace processor instance.
- bin_path: Optional path to a trace processor shell binary to use to
- load the traces.
- verbose: Optional flag indiciating whether verbose trace processor
- output should be printed to stderr.
- """
- self.tps = None
- self.closed = False
- self.executor = cf.ThreadPoolExecutor()
-
- self.files = [_create_trace_file(file) for file in files]
-
- def create_tp(arg: _TpArg) -> TraceProcessor:
- return TraceProcessor(
- file_path=arg.file, bin_path=arg.bin_path, verbose=arg.verbose)
-
- tp_args = [
- _TpArg(bin_path, verbose, file.trace_path) for file in self.files
- ]
- self.tps = list(self.executor.map(create_tp, tp_args))
-
- def metric(self, metrics: List[str]):
- """Computes the provided metrics.
-
- The computation happens in parallel across all the traces.
-
- Args:
- metrics: A list of valid metrics as defined in TraceMetrics
-
- Returns:
- A list of TraceMetric protos (one for each trace).
- """
- return self.execute(lambda tp: tp.metric(metrics))
-
- def query(self, sql: str):
- """Executes the provided SQL statement (returning a single row).
-
- The execution happens in parallel across all the traces.
-
- Args:
- sql: The SQL statement to execute.
-
- Returns:
- A list of Pandas dataframes with the result of executing the query (one
- per trace).
-
- Raises:
- TraceProcessorException: An error occurred running the query.
- """
- return self.execute(lambda tp: tp.query(sql).as_pandas_dataframe())
-
- def query_and_flatten(self, sql: str):
- """Executes the provided SQL statement and flattens the result.
-
- The execution happens in parallel across all the traces and the
- resulting Pandas dataframes are flattened into a single dataframe.
-
- Args:
- sql: The SQL statement to execute.
-
- Returns:
- A Pandas dataframe containing the result of executing the query across all
- the traces. The dataframe will have an additional column 'trace_path'
- indicating the trace file associated with that row. Also, if |TraceFile|
- objects were passed to the constructor, the contents of the |args|
- dictionary will also be emitted as other columns (key being column name,
- value being the value in the dataframe).
-
- For example:
- files = [TraceFile(trace_path='/tmp/path', args={"foo": "bar"})]
- with BatchTraceProcessor(files=files) as btp:
- df = btp.query_and_flatten('select count(1) as cnt from slice')
-
- Then df will look like this:
- cnt trace_path foo
- 100 /tmp/path bar
-
- Raises:
- TraceProcessorException: An error occurred running the query.
- """
- return self.execute_and_flatten(lambda tp: tp.query(sql).
- as_pandas_dataframe())
-
- def query_single_result(self, sql: str):
- """Executes the provided SQL statement (returning a single row).
-
- The execution happens in parallel across all the traces.
-
- Args:
- sql: The SQL statement to execute. This statement should return exactly
- one row on any trace.
-
- Returns:
- A list of values with the result of executing the query (one per trace).
-
- Raises:
- TraceProcessorException: An error occurred running the query or more than
- one result was returned.
- """
-
- def query_single_result_inner(tp):
- df = tp.query(sql).as_pandas_dataframe()
- if len(df.index) != 1:
- raise TraceProcessorException("Query should only return a single row")
-
- if len(df.columns) != 1:
- raise TraceProcessorException(
- "Query should only return a single column")
-
- return df.iloc[0, 0]
-
- return self.execute(query_single_result_inner)
-
- def execute(self, fn: Callable[[TraceProcessor], Any]) -> List[Any]:
- """Executes the provided function.
-
- The execution happens in parallel across all the trace processor instances
- owned by this object.
-
- Args:
- fn: The function to execute.
-
- Returns:
- A list of values with the result of executing the fucntion (one per
- trace).
- """
- return list(self.executor.map(fn, self.tps))
-
- def execute_and_flatten(self, fn: Callable[[TraceProcessor], pd.DataFrame]
- ) -> pd.DataFrame:
- """Executes the provided function and flattens the result.
-
- The execution happens in parallel across all the trace processor
- instances owned by this object and the returned Pandas dataframes are
- flattened into a single dataframe.
-
- Args:
- fn: The function to execute which returns a Pandas dataframe.
-
- Returns:
- A Pandas dataframe containing the result of executing the query across all
- the traces. Extra columns containing the file path and args will
- be added to the dataframe (see |query_and_flatten| for details).
- """
-
- def wrapped(pair: Tuple[TraceProcessor, TraceFile]):
- (tp, file) = pair
- df = fn(tp)
- df["trace_path"] = file.trace_path
- for key, value in file.args.items():
- df[key] = value
- return df
-
- df = pd.concat(list(self.executor.map(wrapped, zip(self.tps, self.files))))
- return df.reset_index(drop=True)
-
- def close(self):
- """Closes this batch trace processor instance.
-
- This closes all spawned trace processor instances, releasing all the memory
- and resources those instances take.
-
- No further calls to other methods in this class should be made after
- calling this method.
- """
- if self.closed:
- return
- self.closed = True
- self.executor.shutdown()
-
- if self.tps:
- for tp in self.tps:
- tp.close()
-
- def __enter__(self):
- return self
-
- def __exit__(self, a, b, c):
- del a, b, c # Unused.
- self.close()
- return False
-
- def __del__(self):
- self.close()
diff --git a/tools/gen_binary_descriptors b/tools/gen_binary_descriptors
index 5388c48..dbbf8c7 100755
--- a/tools/gen_binary_descriptors
+++ b/tools/gen_binary_descriptors
@@ -26,10 +26,10 @@
SOURCE_TARGET = [
('protos/perfetto/trace_processor/trace_processor.proto',
- 'src/trace_processor/python/perfetto/trace_processor/trace_processor.descriptor'
+ 'python/perfetto/trace_processor/trace_processor.descriptor'
),
('protos/perfetto/metrics/metrics.proto',
- 'src/trace_processor/python/perfetto/trace_processor/metrics.descriptor'),
+ 'python/perfetto/trace_processor/metrics.descriptor'),
]
ROOT_DIR = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
diff --git a/tools/heap_profile b/tools/heap_profile
index a327133..6eaaa47 100755
--- a/tools/heap_profile
+++ b/tools/heap_profile
@@ -576,7 +576,7 @@
# BEGIN_SECTION_GENERATED_BY(roll-prebuilts)
-# Revision: v22.1
+# Revision: v23.0
PERFETTO_PREBUILT_MANIFEST = [{
'tool':
'trace_to_text',
@@ -585,11 +585,11 @@
'file_name':
'trace_to_text',
'file_size':
- 6956224,
+ 6939864,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v22.1/mac-amd64/trace_to_text',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v23.0/mac-amd64/trace_to_text',
'sha256':
- 'b40ec5ef358e35ecebacd490dba8320aa3a0bf223da4219f2eba1d3ee7ef3a48',
+ '1626880d1fbec8efc9702583b6c22d617079a08226df414d65888a6b3c7572c8',
'platform':
'darwin',
'machine': ['x86_64']
@@ -601,11 +601,11 @@
'file_name':
'trace_to_text.exe',
'file_size':
- 6663680,
+ 6658560,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v22.1/windows-amd64/trace_to_text.exe',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v23.0/windows-amd64/trace_to_text.exe',
'sha256':
- '603eb120cbb5db41cf258aa742902ea73ee700d8e6d61900f64fa996d3e1714b',
+ '14334fc93ecb0498201bf2ad72ebe69938c43cb6641cf94cfd7ad646603039ed',
'platform':
'win32',
'machine': ['amd64']
@@ -617,11 +617,11 @@
'file_name':
'trace_to_text',
'file_size':
- 7518480,
+ 7513024,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v22.1/linux-amd64/trace_to_text',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v23.0/linux-amd64/trace_to_text',
'sha256':
- '480e851deb76413f3f7ab113f230bcac19ca4bdd9f5c275f7a4d3cc9318c2db6',
+ 'e19163f152717d9922e1926489b64c50b30ea772ebb0f21f6abb6e8cd25615b3',
'platform':
'linux',
'machine': ['x86_64']
diff --git a/tools/open_trace_in_ui b/tools/open_trace_in_ui
index c2360bb..0ec63b4 100755
--- a/tools/open_trace_in_ui
+++ b/tools/open_trace_in_ui
@@ -50,32 +50,41 @@
print(colors + msg + ANSI.END)
-def open_trace_in_browser(path):
+def open_trace(path, open_browser):
# We reuse the HTTP+RPC port because it's the only one allowed by the CSP.
PORT = 9001
os.chdir(os.path.dirname(path))
fname = os.path.basename(path)
socketserver.TCPServer.allow_reuse_address = True
with socketserver.TCPServer(('127.0.0.1', PORT), HttpHandler) as httpd:
- webbrowser.open_new_tab(
- 'https://ui.perfetto.dev/#!/?url=http://127.0.0.1:%d/%s' %
- (PORT, fname))
+ if open_browser:
+ webbrowser.open_new_tab(
+ 'https://ui.perfetto.dev/#!/?url=http://127.0.0.1:%d/%s' %
+ (PORT, fname))
+ else:
+ print('Open URL in browser: '
+ 'https://ui.perfetto.dev/#!/?url=http://127.0.0.1:%d/%s' %
+ (PORT, fname))
+
while httpd.__dict__.get('last_request') != '/' + fname:
httpd.handle_request()
def main():
examples = '\n'.join([
- ANSI.BOLD + 'Usage:' + ANSI.END, ' -i path/trace_file_name'
+ ANSI.BOLD + 'Usage:' + ANSI.END, ' -i path/trace_file_name [-n]'
])
parser = argparse.ArgumentParser(
epilog=examples, formatter_class=argparse.RawTextHelpFormatter)
help = 'Input trace filename'
parser.add_argument('-i', '--trace', help=help)
+ parser.add_argument('-n', '--no-open-browser', action='store_true',
+ default=False)
args = parser.parse_args()
trace_file = args.trace
+ open_browser = not args.no_open_browser
if trace_file is None:
prt('Please specify trace file name with -i/--trace argument', ANSI.RED)
@@ -85,7 +94,7 @@
sys.exit(1)
prt('Opening the trace (%s) in the browser' % trace_file)
- open_trace_in_browser(trace_file)
+ open_trace(trace_file, open_browser)
if __name__ == '__main__':
diff --git a/tools/record_android_trace b/tools/record_android_trace
index bc3f826..ccd8473 100755
--- a/tools/record_android_trace
+++ b/tools/record_android_trace
@@ -380,7 +380,7 @@
# BEGIN_SECTION_GENERATED_BY(roll-prebuilts)
-# Revision: v22.1
+# Revision: v23.0
PERFETTO_PREBUILT_MANIFEST = [{
'tool':
'tracebox',
@@ -389,11 +389,11 @@
'file_name':
'tracebox',
'file_size':
- 1034636,
+ 1038732,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v22.1/android-arm/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v23.0/android-arm/tracebox',
'sha256':
- 'f97875395431b87a38830f73f22b45fedbf5bbcefcdd9f61ab87bcd64b0594e4'
+ 'b37507c28e8eade93fa9f0da86d6b9779f69aadea9d7e33cd3b85866c7b755fc'
}, {
'tool':
'tracebox',
@@ -402,11 +402,11 @@
'file_name':
'tracebox',
'file_size':
- 1563840,
+ 1572032,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v22.1/android-arm64/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v23.0/android-arm64/tracebox',
'sha256':
- '45cca4277d83b30d33ff5e2bf99120844498d5512bd15c40301157921b3482aa'
+ '83306c567da4f1b3eb910a0407abf88fcc099d22a191ceb096837381b2ebff79'
}, {
'tool':
'tracebox',
@@ -415,11 +415,11 @@
'file_name':
'tracebox',
'file_size':
- 1591652,
+ 1595748,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v22.1/android-x86/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v23.0/android-x86/tracebox',
'sha256':
- 'fc4f86b92837d3efee4df202da092cd5a945613078b4fe4b8829de0794bf5cdb'
+ '527c2ff54350fe73197b5164e6f7ed21f3d10c38a667e57781222d679dca4707'
}, {
'tool':
'tracebox',
@@ -428,11 +428,11 @@
'file_name':
'tracebox',
'file_size':
- 1809600,
+ 1821888,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v22.1/android-x64/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v23.0/android-x64/tracebox',
'sha256':
- '4610eff243aec24dc0d948503464e466d73045d0383bc625ee820cfd43d3f9a5'
+ '99cfbb37e7c3ae4ea70fc51811601c409fcd81589d4311a4b805a67f4760203b'
}]
diff --git a/tools/trace_processor b/tools/trace_processor
index e532901..69e8a91 100755
--- a/tools/trace_processor
+++ b/tools/trace_processor
@@ -27,7 +27,7 @@
TOOL_NAME = 'trace_processor_shell'
# BEGIN_SECTION_GENERATED_BY(roll-prebuilts)
-# Revision: v22.1
+# Revision: v23.0
PERFETTO_PREBUILT_MANIFEST = [{
'tool':
'trace_processor_shell',
@@ -36,11 +36,11 @@
'file_name':
'trace_processor_shell',
'file_size':
- 6924200,
+ 6924224,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v22.1/mac-amd64/trace_processor_shell',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v23.0/mac-amd64/trace_processor_shell',
'sha256':
- '428fc3b61b507053c72c4c65876c18a80c1dae013e5d9c8c4bbe10d08c3dddaf',
+ '08bde02f5920fa1af8dc64b857db9c000ac6940f2bb49030742d62adf04e3ff3',
'platform':
'darwin',
'machine': ['x86_64']
@@ -52,11 +52,11 @@
'file_name':
'trace_processor_shell.exe',
'file_size':
- 6655488,
+ 6656512,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v22.1/windows-amd64/trace_processor_shell.exe',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v23.0/windows-amd64/trace_processor_shell.exe',
'sha256':
- 'e8bd04f3de59a483036f58b86b47d79a9c2bb00f9b1c9590ed1a36250b4f91a0',
+ '8151996f74ad7b3e6fb8c04c5acd351a74fe24e939902cc74380e9789c203309',
'platform':
'win32',
'machine': ['amd64']
@@ -68,11 +68,11 @@
'file_name':
'trace_processor_shell',
'file_size':
- 7495384,
+ 7495496,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v22.1/linux-amd64/trace_processor_shell',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v23.0/linux-amd64/trace_processor_shell',
'sha256':
- '6a7d27e91ab233e82786d1652739dc84e9d86dde5782ec69392f2b5977142596',
+ 'e71bf3c16224a8ecbfb2485864dd3762f642fb052acf560d0631ef6c18a740fd',
'platform':
'linux',
'machine': ['x86_64']
@@ -84,11 +84,11 @@
'file_name':
'trace_processor_shell',
'file_size':
- 4870060,
+ 4867252,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v22.1/linux-arm/trace_processor_shell',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v23.0/linux-arm/trace_processor_shell',
'sha256':
- '3e260ece4b254886b8cf7db0abf05257e747ae69d8d8ea252edb9b518f7cf34a',
+ 'e909add14c46bcc5a2ed1736169886696867cebc17c5218cb9c143caced886f5',
'platform':
'linux',
'machine': ['armv6l', 'armv7l', 'armv8l']
@@ -100,11 +100,11 @@
'file_name':
'trace_processor_shell',
'file_size':
- 6742552,
+ 6742056,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v22.1/linux-arm64/trace_processor_shell',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v23.0/linux-arm64/trace_processor_shell',
'sha256':
- 'aa4834949fe4b81d7289b9b15e57c4a5437773b356dced7b55afe46655f696c2',
+ 'b2cad70adbb139a8878d69999e0dfad40ca24e94f001b7bd67dcbbedcdb6c6dc',
'platform':
'linux',
'machine': ['aarch64']
diff --git a/tools/tracebox b/tools/tracebox
index 069053e..ece2014 100755
--- a/tools/tracebox
+++ b/tools/tracebox
@@ -27,7 +27,7 @@
TOOL_NAME = 'tracebox'
# BEGIN_SECTION_GENERATED_BY(roll-prebuilts)
-# Revision: v22.1
+# Revision: v23.0
PERFETTO_PREBUILT_MANIFEST = [{
'tool':
'tracebox',
@@ -36,11 +36,11 @@
'file_name':
'tracebox',
'file_size':
- 1316160,
+ 1316192,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v22.1/mac-amd64/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v23.0/mac-amd64/tracebox',
'sha256':
- '48539da3f73f04fe1c22dcd0aeb8cbed45405df3f4dfb3f2ff4077d6d023463e',
+ '54101d81876ceed8c2d24701835fd11cd0edc4d43af655ed0420013809138951',
'platform':
'darwin',
'machine': ['x86_64']
@@ -52,11 +52,11 @@
'file_name':
'tracebox',
'file_size':
- 1733320,
+ 1739352,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v22.1/linux-amd64/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v23.0/linux-amd64/tracebox',
'sha256':
- 'b9ab0a535a7e042675f690b0543e158cad01fb8b3e56dc3b7748f44b821ff6d5',
+ 'b42cfaadf4dd35c5c540775a0d909dcbfa5338d1c022767db3a4b1324c19e58b',
'platform':
'linux',
'machine': ['x86_64']
@@ -68,11 +68,11 @@
'file_name':
'tracebox',
'file_size':
- 1733320,
+ 1739352,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v22.1/linux-amd64/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v23.0/linux-amd64/tracebox',
'sha256':
- 'b9ab0a535a7e042675f690b0543e158cad01fb8b3e56dc3b7748f44b821ff6d5',
+ 'b42cfaadf4dd35c5c540775a0d909dcbfa5338d1c022767db3a4b1324c19e58b',
'platform':
'linux',
'machine': ['x86_64']
@@ -84,11 +84,11 @@
'file_name':
'tracebox',
'file_size':
- 998700,
+ 1002132,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v22.1/linux-arm/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v23.0/linux-arm/tracebox',
'sha256':
- '825a1705f426f333c21679e38676c6118442b7b48379a0e2c2b87f052b3e2f8d',
+ '65351d250c3c52f8a69afa78069d9a87931c45cf3bf415c207e93de6eb75dbbe',
'platform':
'linux',
'machine': ['armv6l', 'armv7l', 'armv8l']
@@ -100,11 +100,11 @@
'file_name':
'tracebox',
'file_size':
- 1613536,
+ 1619248,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v22.1/linux-arm64/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v23.0/linux-arm64/tracebox',
'sha256':
- 'e664b2374a6842141b0f8c68838a37d0d387bae576b934db3168b4ae4999f182',
+ '2cb0be71da6b46167a8dd4a9d8af5229dba89b8e508554c16cde20b81f175d3d',
'platform':
'linux',
'machine': ['aarch64']
diff --git a/tools/traceconv b/tools/traceconv
index 406bd4d..4754a87 100755
--- a/tools/traceconv
+++ b/tools/traceconv
@@ -27,7 +27,7 @@
TOOL_NAME = 'trace_to_text'
# BEGIN_SECTION_GENERATED_BY(roll-prebuilts)
-# Revision: v22.1
+# Revision: v23.0
PERFETTO_PREBUILT_MANIFEST = [{
'tool':
'trace_to_text',
@@ -36,11 +36,11 @@
'file_name':
'trace_to_text',
'file_size':
- 6956224,
+ 6939864,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v22.1/mac-amd64/trace_to_text',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v23.0/mac-amd64/trace_to_text',
'sha256':
- 'b40ec5ef358e35ecebacd490dba8320aa3a0bf223da4219f2eba1d3ee7ef3a48',
+ '1626880d1fbec8efc9702583b6c22d617079a08226df414d65888a6b3c7572c8',
'platform':
'darwin',
'machine': ['x86_64']
@@ -52,11 +52,11 @@
'file_name':
'trace_to_text',
'file_size':
- 7518480,
+ 7513024,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v22.1/linux-amd64/trace_to_text',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v23.0/linux-amd64/trace_to_text',
'sha256':
- '480e851deb76413f3f7ab113f230bcac19ca4bdd9f5c275f7a4d3cc9318c2db6',
+ 'e19163f152717d9922e1926489b64c50b30ea772ebb0f21f6abb6e8cd25615b3',
'platform':
'linux',
'machine': ['x86_64']
@@ -68,11 +68,11 @@
'file_name':
'trace_to_text.exe',
'file_size':
- 6663680,
+ 6658560,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v22.1/windows-amd64/trace_to_text.exe',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v23.0/windows-amd64/trace_to_text.exe',
'sha256':
- '603eb120cbb5db41cf258aa742902ea73ee700d8e6d61900f64fa996d3e1714b',
+ '14334fc93ecb0498201bf2ad72ebe69938c43cb6641cf94cfd7ad646603039ed',
'platform':
'win32',
'machine': ['amd64']