Merge "Move ScopedReadMmap to ext/base" into main
diff --git a/Android.bp b/Android.bp
index dc3f8de..ece4ad0 100644
--- a/Android.bp
+++ b/Android.bp
@@ -494,6 +494,7 @@
":perfetto_include_perfetto_ext_base_base",
":perfetto_include_perfetto_ext_base_version",
":perfetto_include_perfetto_ext_ipc_ipc",
+ ":perfetto_include_perfetto_ext_protozero_protozero",
":perfetto_include_perfetto_ext_traced_sys_stats_counters",
":perfetto_include_perfetto_ext_traced_traced",
":perfetto_include_perfetto_ext_tracing_core_core",
@@ -1358,6 +1359,7 @@
":perfetto_include_perfetto_ext_base_base",
":perfetto_include_perfetto_ext_base_version",
":perfetto_include_perfetto_ext_ipc_ipc",
+ ":perfetto_include_perfetto_ext_protozero_protozero",
":perfetto_include_perfetto_ext_traced_sys_stats_counters",
":perfetto_include_perfetto_ext_traced_traced",
":perfetto_include_perfetto_ext_tracing_core_core",
@@ -1656,6 +1658,7 @@
":perfetto_include_perfetto_ext_base_base",
":perfetto_include_perfetto_ext_base_version",
":perfetto_include_perfetto_ext_ipc_ipc",
+ ":perfetto_include_perfetto_ext_protozero_protozero",
":perfetto_include_perfetto_ext_traced_sys_stats_counters",
":perfetto_include_perfetto_ext_traced_traced",
":perfetto_include_perfetto_ext_tracing_core_core",
@@ -2025,6 +2028,11 @@
name: "perfetto_include_perfetto_ext_ipc_ipc",
}
+// GN: //include/perfetto/ext/protozero:protozero
+filegroup {
+ name: "perfetto_include_perfetto_ext_protozero_protozero",
+}
+
// GN: //include/perfetto/ext/trace_processor:demangle
filegroup {
name: "perfetto_include_perfetto_ext_trace_processor_demangle",
@@ -2155,6 +2163,7 @@
":perfetto_include_perfetto_ext_base_base",
":perfetto_include_perfetto_ext_base_version",
":perfetto_include_perfetto_ext_ipc_ipc",
+ ":perfetto_include_perfetto_ext_protozero_protozero",
":perfetto_include_perfetto_ext_trace_processor_demangle",
":perfetto_include_perfetto_ext_trace_processor_export_json",
":perfetto_include_perfetto_ext_trace_processor_importers_memory_tracker_memory_tracker",
@@ -13661,6 +13670,7 @@
":perfetto_include_perfetto_ext_base_threading_threading",
":perfetto_include_perfetto_ext_base_version",
":perfetto_include_perfetto_ext_ipc_ipc",
+ ":perfetto_include_perfetto_ext_protozero_protozero",
":perfetto_include_perfetto_ext_trace_processor_demangle",
":perfetto_include_perfetto_ext_trace_processor_export_json",
":perfetto_include_perfetto_ext_trace_processor_importers_memory_tracker_memory_tracker",
@@ -14212,6 +14222,7 @@
":perfetto_include_perfetto_ext_base_base",
":perfetto_include_perfetto_ext_base_version",
":perfetto_include_perfetto_ext_ipc_ipc",
+ ":perfetto_include_perfetto_ext_protozero_protozero",
":perfetto_include_perfetto_ext_traced_sys_stats_counters",
":perfetto_include_perfetto_ext_traced_traced",
":perfetto_include_perfetto_ext_tracing_core_core",
@@ -14527,6 +14538,7 @@
":perfetto_include_perfetto_ext_base_base",
":perfetto_include_perfetto_ext_base_http_http",
":perfetto_include_perfetto_ext_base_version",
+ ":perfetto_include_perfetto_ext_protozero_protozero",
":perfetto_include_perfetto_ext_trace_processor_demangle",
":perfetto_include_perfetto_ext_trace_processor_export_json",
":perfetto_include_perfetto_ext_trace_processor_importers_memory_tracker_memory_tracker",
@@ -14765,6 +14777,7 @@
":perfetto_include_perfetto_base_base",
":perfetto_include_perfetto_ext_base_base",
":perfetto_include_perfetto_ext_base_version",
+ ":perfetto_include_perfetto_ext_protozero_protozero",
":perfetto_include_perfetto_ext_trace_processor_demangle",
":perfetto_include_perfetto_ext_trace_processor_export_json",
":perfetto_include_perfetto_ext_trace_processor_importers_memory_tracker_memory_tracker",
diff --git a/BUILD b/BUILD
index 8e771b0..367a2fe 100644
--- a/BUILD
+++ b/BUILD
@@ -287,6 +287,7 @@
hdrs = [
":include_perfetto_base_base",
":include_perfetto_ext_base_base",
+ ":include_perfetto_ext_protozero_protozero",
":include_perfetto_ext_trace_processor_demangle",
":include_perfetto_ext_trace_processor_export_json",
":include_perfetto_ext_trace_processor_importers_memory_tracker_memory_tracker",
@@ -474,6 +475,7 @@
":include_perfetto_base_base",
":include_perfetto_ext_base_base",
":include_perfetto_ext_ipc_ipc",
+ ":include_perfetto_ext_protozero_protozero",
":include_perfetto_ext_traced_sys_stats_counters",
":include_perfetto_ext_traced_traced",
":include_perfetto_ext_tracing_core_core",
@@ -651,6 +653,14 @@
],
)
+# GN target: //include/perfetto/ext/protozero:protozero
+perfetto_filegroup(
+ name = "include_perfetto_ext_protozero_protozero",
+ srcs = [
+ "include/perfetto/ext/protozero/proto_ring_buffer.h",
+ ],
+)
+
# GN target: //include/perfetto/ext/trace_processor/importers/memory_tracker:memory_tracker
perfetto_filegroup(
name = "include_perfetto_ext_trace_processor_importers_memory_tracker_memory_tracker",
@@ -1310,7 +1320,6 @@
name = "src_protozero_proto_ring_buffer",
srcs = [
"src/protozero/proto_ring_buffer.cc",
- "src/protozero/proto_ring_buffer.h",
],
)
@@ -5717,6 +5726,7 @@
srcs = [
":include_perfetto_base_base",
":include_perfetto_ext_base_base",
+ ":include_perfetto_ext_protozero_protozero",
":include_perfetto_ext_trace_processor_demangle",
":include_perfetto_ext_trace_processor_export_json",
":include_perfetto_ext_trace_processor_importers_memory_tracker_memory_tracker",
@@ -5942,6 +5952,7 @@
srcs = [
":include_perfetto_base_base",
":include_perfetto_ext_base_base",
+ ":include_perfetto_ext_protozero_protozero",
":include_perfetto_ext_trace_processor_demangle",
":include_perfetto_ext_trace_processor_export_json",
":include_perfetto_ext_trace_processor_importers_memory_tracker_memory_tracker",
diff --git a/include/perfetto/ext/base/version.h b/include/perfetto/ext/base/version.h
index 212424a..ad78372 100644
--- a/include/perfetto/ext/base/version.h
+++ b/include/perfetto/ext/base/version.h
@@ -20,9 +20,27 @@
namespace perfetto {
namespace base {
-// The returned pointer is a static string is safe to pass around.
+// The returned pointer is a static string and safe to pass around.
+// Returns a human readable string currently of the approximate form:
+// Perfetto v42.1-deadbeef0 (deadbeef03c641e4b4ea9cf38e9b5696670175a9)
+// However you should not depend on the format of this string.
+// It maybe not be possible to determine the version. In which case the
+// string will be of the approximate form:
+// Perfetto v0.0 (unknown)
const char* GetVersionString();
+// The returned pointer is a static string and safe to pass around.
+// Returns the short code used to identity the version:
+// v42.1-deadbeef0
+// It maybe not be possible to determine the version. In which case
+// this returns nullptr.
+// This can be compared with equality to other
+// version codes to detect matched builds (for example to see if
+// trace_processor_shell and the UI were built at the same revision)
+// but you should not attempt to parse it as the format may change
+// without warning.
+const char* GetVersionCode();
+
} // namespace base
} // namespace perfetto
diff --git a/include/perfetto/ext/protozero/BUILD.gn b/include/perfetto/ext/protozero/BUILD.gn
new file mode 100644
index 0000000..5354e2c
--- /dev/null
+++ b/include/perfetto/ext/protozero/BUILD.gn
@@ -0,0 +1,21 @@
+# Copyright (C) 2024 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import("../../../../gn/perfetto.gni")
+
+source_set("protozero") {
+ public_deps = [ "../base" ]
+ deps = [ "../../../../gn:default_deps" ]
+ sources = [ "proto_ring_buffer.h" ]
+}
diff --git a/src/protozero/proto_ring_buffer.h b/include/perfetto/ext/protozero/proto_ring_buffer.h
similarity index 96%
rename from src/protozero/proto_ring_buffer.h
rename to include/perfetto/ext/protozero/proto_ring_buffer.h
index 6459426..8db542c 100644
--- a/src/protozero/proto_ring_buffer.h
+++ b/include/perfetto/ext/protozero/proto_ring_buffer.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef SRC_PROTOZERO_PROTO_RING_BUFFER_H_
-#define SRC_PROTOZERO_PROTO_RING_BUFFER_H_
+#ifndef INCLUDE_PERFETTO_EXT_PROTOZERO_PROTO_RING_BUFFER_H_
+#define INCLUDE_PERFETTO_EXT_PROTOZERO_PROTO_RING_BUFFER_H_
#include <stdint.h>
@@ -150,4 +150,4 @@
} // namespace protozero
-#endif // SRC_PROTOZERO_PROTO_RING_BUFFER_H_
+#endif // INCLUDE_PERFETTO_EXT_PROTOZERO_PROTO_RING_BUFFER_H_
diff --git a/protos/perfetto/trace_processor/trace_processor.proto b/protos/perfetto/trace_processor/trace_processor.proto
index c96caa0..1e579ca 100644
--- a/protos/perfetto/trace_processor/trace_processor.proto
+++ b/protos/perfetto/trace_processor/trace_processor.proto
@@ -38,9 +38,18 @@
enum TraceProcessorApiVersion {
// This variable has been introduced in v15 and is used to deal with API
- // mismatches between UI and trace_processor_shell --httpd. Increment this
- // every time a new feature that the UI depends on is being introduced (e.g.
- // new tables, new SQL operators, metrics that are required by the UI).
+ // mismatches between UI and trace_processor_shell --httpd.
+ //
+ // Prior to API version 11 this was incremented every time a new
+ // feature that the UI depended on was introduced (e.g. new tables,
+ // new SQL operators, metrics that are required by the UI, etc).
+ // This:
+ // a. Tended to be forgotten
+ // b. Still led to issues when the TP dropped *backwards*
+ // compatibility of a feature (since we checked TP >= UI
+ // TRACE_PROCESSOR_CURRENT_API_VERSION).
+ // Now the UI attempts to redirect the user to the matched version
+ // of the UI if one exists.
// See also StatusResult.api_version (below).
// Changes:
// 7. Introduce GUESS_CPU_SIZE
@@ -48,10 +57,12 @@
// 9. Add get_thread_state_summary_for_interval.
// 10. Add 'slice_is_ancestor' to stdlib.
// 11. Removal of experimental module from stdlib.
- TRACE_PROCESSOR_CURRENT_API_VERSION = 11;
+ // 12. Changed UI to be more aggresive about version matching.
+ // Added version_code.
+ TRACE_PROCESSOR_CURRENT_API_VERSION = 12;
}
-// At lowest level, the wire-format of the RPC procol is a linear sequence of
+// At lowest level, the wire-format of the RPC protocol is a linear sequence of
// TraceProcessorRpc messages on each side of the byte pipe
// Each message is prefixed by a tag (field = 1, type = length delimited) and a
// varint encoding its size (this is so the whole stream can also be read /
@@ -236,6 +247,15 @@
// The API version is incremented every time a change that the UI depends
// on is introduced (e.g. adding a new table that the UI queries).
optional int32 api_version = 3;
+
+ // Typically something like "v42.1-deadbeef0", but could be just
+ // "v42", "v0.0", or unset for binaries built from Bazel or other
+ // build configurations. This can be compared with equality to other
+ // version codes to detect matched builds (for example to see if
+ // trace_processor_shell and the UI were built at the same revision)
+ // but you should not attempt to parse it as the format may change
+ // without warning.
+ optional string version_code = 4;
}
// Input for the /compute_metric endpoint.
diff --git a/python/perfetto/trace_processor/trace_processor.descriptor b/python/perfetto/trace_processor/trace_processor.descriptor
index 261ab0b..ce0bc66 100644
--- a/python/perfetto/trace_processor/trace_processor.descriptor
+++ b/python/perfetto/trace_processor/trace_processor.descriptor
Binary files differ
diff --git a/src/base/version.cc b/src/base/version.cc
index 18569d3..e989534 100644
--- a/src/base/version.cc
+++ b/src/base/version.cc
@@ -23,18 +23,26 @@
#if PERFETTO_BUILDFLAG(PERFETTO_VERSION_GEN)
#include "perfetto_version.gen.h"
#else
-#define PERFETTO_VERSION_STRING() "v0.0"
+#define PERFETTO_VERSION_STRING() nullptr
#define PERFETTO_VERSION_SCM_REVISION() "unknown"
#endif
namespace perfetto {
namespace base {
+const char* GetVersionCode() {
+ return PERFETTO_VERSION_STRING();
+}
+
const char* GetVersionString() {
static const char* version_str = [] {
static constexpr size_t kMaxLen = 256;
+ const char* version_code = PERFETTO_VERSION_STRING();
+ if (version_code == nullptr) {
+ version_code = "v0.0";
+ }
char* version = new char[kMaxLen + 1];
- snprintf(version, kMaxLen, "Perfetto %s (%s)", PERFETTO_VERSION_STRING(),
+ snprintf(version, kMaxLen, "Perfetto %s (%s)", version_code,
PERFETTO_VERSION_SCM_REVISION());
return version;
}();
diff --git a/src/protozero/BUILD.gn b/src/protozero/BUILD.gn
index 0082a8c..4d940bc 100644
--- a/src/protozero/BUILD.gn
+++ b/src/protozero/BUILD.gn
@@ -45,15 +45,13 @@
}
source_set("proto_ring_buffer") {
+ public_deps = [ "../../include/perfetto/ext/protozero" ]
deps = [
":protozero",
"../../gn:default_deps",
"../base",
]
- sources = [
- "proto_ring_buffer.cc",
- "proto_ring_buffer.h",
- ]
+ sources = [ "proto_ring_buffer.cc" ]
}
perfetto_unittest_source_set("unittests") {
diff --git a/src/protozero/proto_ring_buffer.cc b/src/protozero/proto_ring_buffer.cc
index 6f82a42..7b12a1b 100644
--- a/src/protozero/proto_ring_buffer.cc
+++ b/src/protozero/proto_ring_buffer.cc
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "src/protozero/proto_ring_buffer.h"
+#include "perfetto/ext/protozero/proto_ring_buffer.h"
#include "perfetto/base/logging.h"
#include "perfetto/ext/base/paged_memory.h"
diff --git a/src/protozero/proto_ring_buffer_unittest.cc b/src/protozero/proto_ring_buffer_unittest.cc
index 30cc3f1..5766d0a 100644
--- a/src/protozero/proto_ring_buffer_unittest.cc
+++ b/src/protozero/proto_ring_buffer_unittest.cc
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "src/protozero/proto_ring_buffer.h"
+#include "perfetto/ext/protozero/proto_ring_buffer.h"
#include <stdint.h>
#include <sys/types.h>
diff --git a/src/protozero/test/proto_ring_buffer_benchmark.cc b/src/protozero/test/proto_ring_buffer_benchmark.cc
index b65da3b..0c0f7f9 100644
--- a/src/protozero/test/proto_ring_buffer_benchmark.cc
+++ b/src/protozero/test/proto_ring_buffer_benchmark.cc
@@ -18,8 +18,8 @@
#include <string>
#include "perfetto/ext/base/file_utils.h"
+#include "perfetto/ext/protozero/proto_ring_buffer.h"
#include "src/base/test/utils.h"
-#include "src/protozero/proto_ring_buffer.h"
static void BM_ProtoRingBufferReadLargeChunks(benchmark::State& state) {
std::string trace_data;
diff --git a/src/trace_processor/rpc/rpc.cc b/src/trace_processor/rpc/rpc.cc
index 68e0732..58fb245 100644
--- a/src/trace_processor/rpc/rpc.cc
+++ b/src/trace_processor/rpc/rpc.cc
@@ -24,11 +24,11 @@
#include "perfetto/base/time.h"
#include "perfetto/ext/base/utils.h"
#include "perfetto/ext/base/version.h"
+#include "perfetto/ext/protozero/proto_ring_buffer.h"
#include "perfetto/ext/trace_processor/rpc/query_result_serializer.h"
#include "perfetto/protozero/scattered_heap_buffer.h"
#include "perfetto/protozero/scattered_stream_writer.h"
#include "perfetto/trace_processor/trace_processor.h"
-#include "src/protozero/proto_ring_buffer.h"
#include "src/trace_processor/tp_metatrace.h"
#include "protos/perfetto/trace_processor/trace_processor.pbzero.h"
@@ -491,6 +491,10 @@
protozero::HeapBuffered<protos::pbzero::StatusResult> status;
status->set_loaded_trace_name(trace_processor_->GetCurrentTraceName());
status->set_human_readable_version(base::GetVersionString());
+ const char* version_code = base::GetVersionCode();
+ if (version_code) {
+ status->set_version_code(version_code);
+ }
status->set_api_version(protos::pbzero::TRACE_PROCESSOR_CURRENT_API_VERSION);
return status.SerializeAsArray();
}
diff --git a/src/trace_processor/rpc/rpc.h b/src/trace_processor/rpc/rpc.h
index c2ef645..c10d4bf 100644
--- a/src/trace_processor/rpc/rpc.h
+++ b/src/trace_processor/rpc/rpc.h
@@ -24,9 +24,9 @@
#include <stddef.h>
#include <stdint.h>
+#include "perfetto/ext/protozero/proto_ring_buffer.h"
#include "perfetto/trace_processor/basic_types.h"
#include "perfetto/trace_processor/status.h"
-#include "src/protozero/proto_ring_buffer.h"
namespace perfetto {
diff --git a/src/trace_processor/sqlite/db_sqlite_table.cc b/src/trace_processor/sqlite/db_sqlite_table.cc
index 4d38bd6..51e95d6 100644
--- a/src/trace_processor/sqlite/db_sqlite_table.cc
+++ b/src/trace_processor/sqlite/db_sqlite_table.cc
@@ -434,7 +434,19 @@
DbSqliteTable::Cursor::Cursor(DbSqliteTable* sqlite_table, QueryCache* cache)
: SqliteTable::BaseCursor(sqlite_table),
db_sqlite_table_(sqlite_table),
- cache_(cache) {}
+ cache_(cache) {
+ switch (db_sqlite_table_->context_->computation) {
+ case TableComputation::kStatic:
+ upstream_table_ = db_sqlite_table_->context_->static_table;
+ break;
+ case TableComputation::kRuntime:
+ upstream_table_ = db_sqlite_table_->runtime_table_;
+ break;
+ case TableComputation::kTableFunction: {
+ break;
+ }
+ }
+}
DbSqliteTable::Cursor::~Cursor() = default;
void DbSqliteTable::Cursor::TryCacheCreateSortedTable(
@@ -535,17 +547,7 @@
// Setup the upstream table based on the computation state.
switch (db_sqlite_table_->context_->computation) {
case TableComputation::kStatic:
- // If we have a static table, just set the upstream table to be the static
- // table.
- upstream_table_ = db_sqlite_table_->context_->static_table;
-
- // Tries to create a sorted cached table which can be used to speed up
- // filters below.
- TryCacheCreateSortedTable(qc, history);
- break;
case TableComputation::kRuntime:
- upstream_table_ = db_sqlite_table_->runtime_table_;
-
// Tries to create a sorted cached table which can be used to speed up
// filters below.
TryCacheCreateSortedTable(qc, history);
diff --git a/src/traceconv/trace_to_text.cc b/src/traceconv/trace_to_text.cc
index 1deac65..ef7e03a 100644
--- a/src/traceconv/trace_to_text.cc
+++ b/src/traceconv/trace_to_text.cc
@@ -19,7 +19,7 @@
#include "perfetto/base/logging.h"
#include "perfetto/ext/base/file_utils.h"
#include "perfetto/ext/base/scoped_file.h"
-#include "src/protozero/proto_ring_buffer.h"
+#include "perfetto/ext/protozero/proto_ring_buffer.h"
#include "src/traceconv/trace.descriptor.h"
#include "src/traceconv/utils.h"
diff --git a/src/traced/probes/statsd_client/statsd_binder_data_source.h b/src/traced/probes/statsd_client/statsd_binder_data_source.h
index 6268eb7..19aa5f5 100644
--- a/src/traced/probes/statsd_client/statsd_binder_data_source.h
+++ b/src/traced/probes/statsd_client/statsd_binder_data_source.h
@@ -22,10 +22,10 @@
#include "perfetto/base/task_runner.h"
#include "perfetto/ext/base/utils.h"
#include "perfetto/ext/base/weak_ptr.h"
+#include "perfetto/ext/protozero/proto_ring_buffer.h"
#include "perfetto/ext/tracing/core/basic_types.h"
#include "perfetto/ext/tracing/core/trace_writer.h"
#include "perfetto/tracing/core/forward_decls.h"
-#include "src/protozero/proto_ring_buffer.h"
#include "src/traced/probes/probes_data_source.h"
namespace perfetto {
diff --git a/ui/src/assets/modal.scss b/ui/src/assets/modal.scss
index f7ed990..25e7706 100644
--- a/ui/src/assets/modal.scss
+++ b/ui/src/assets/modal.scss
@@ -127,7 +127,7 @@
background-color: #e6e6e6;
color: rgba(0, 0, 0, 0.8);
border: 2px solid transparent;
- border-radius: 4px;
+ border-radius: $pf-border-radius;
cursor: pointer;
text-transform: none;
overflow: visible;
diff --git a/ui/src/frontend/aggregation_tab.ts b/ui/src/frontend/aggregation_tab.ts
index 44166f0..30dd743 100644
--- a/ui/src/frontend/aggregation_tab.ts
+++ b/ui/src/frontend/aggregation_tab.ts
@@ -21,14 +21,21 @@
import {Button, ButtonBar} from '../widgets/button';
import {raf} from '../core/raf_scheduler';
import {EmptyState} from '../widgets/empty_state';
+import {FlowEventsAreaSelectedPanel} from './flow_events_panel';
+import {PivotTable} from './pivot_table';
+
+interface View {
+ key: string;
+ name: string;
+ content: m.Children;
+};
class AreaDetailsPanel implements m.ClassComponent {
private currentTab: string|undefined = undefined;
- private getCurrentAggType(): string|undefined {
- const types = Array.from(globals.aggregateDataStore.entries())
- .filter(([_, value]) => !isEmptyData(value))
- .map(([type, _]) => type);
+ private getCurrentView(): string|undefined {
+ const types = this.getViews()
+ .map(({key}) => key);
if (types.length === 0) {
return undefined;
@@ -45,47 +52,80 @@
return this.currentTab;
}
- view(_: m.Vnode): m.Children {
- const aggregationButtons = Array.from(globals.aggregateDataStore.entries())
- .filter(([_, value]) => !isEmptyData(value))
- .map(([type, value]) => {
- return m(Button,
- {
- onclick: () => {
- this.currentTab = type;
- raf.scheduleFullRedraw();
- },
- key: type,
- label: value.tabName,
- active: this.getCurrentAggType() === type,
- minimal: true,
- },
- );
+ private getViews(): View[] {
+ const views = [];
+
+ for (const [key, value] of globals.aggregateDataStore.entries()) {
+ if (!isEmptyData(value)) {
+ views.push({
+ key: value.tabName,
+ name: value.tabName,
+ content: m(AggregationPanel, {kind: key, key, data: value}),
+ });
+ }
+ }
+
+ // Add this after all aggregation panels, to make it appear after 'Slices'
+ if (globals.selectedFlows.length > 0) {
+ views.push({
+ key: 'selected_flows',
+ name: 'Flow Events',
+ content: m(FlowEventsAreaSelectedPanel),
});
+ }
- const content = this.renderAggregationContent();
+ const pivotTableState = globals.state.nonSerializableState.pivotTable;
+ if (pivotTableState.selectionArea !== undefined) {
+ views.push({
+ key: 'pivot_table',
+ name: 'Pivot Table',
+ content: m(PivotTable, {
+ selectionArea:
+ pivotTableState.selectionArea,
+ }),
+ });
+ }
+ return views;
+ }
+
+ view(_: m.Vnode): m.Children {
+ const views = this.getViews();
+ const currentViewKey = this.getCurrentView();
+
+ const aggregationButtons = views.map(({key, name}) => {
+ return m(Button,
+ {
+ onclick: () => {
+ this.currentTab = key;
+ raf.scheduleFullRedraw();
+ },
+ key,
+ label: name,
+ active: currentViewKey === key,
+ minimal: true,
+ },
+ );
+ });
+
+ if (currentViewKey === undefined) {
+ return this.renderEmptyState();
+ }
+
+ const content = views.find(({key}) => key === currentViewKey)?.content;
if (content === undefined) {
return this.renderEmptyState();
}
return m(DetailsShell,
{
- title: 'Aggregate',
+ title: 'Area Selection',
description: m(ButtonBar, aggregationButtons),
},
content,
);
}
- private renderAggregationContent(): m.Children {
- const currentTab = this.getCurrentAggType();
- if (currentTab === undefined) return undefined;
-
- const data = globals.aggregateDataStore.get(currentTab);
- return m(AggregationPanel, {kind: currentTab, data});
- }
-
private renderEmptyState(): m.Children {
return m(EmptyState, {
className: 'pf-noselection',
diff --git a/ui/src/frontend/router.ts b/ui/src/frontend/router.ts
index 29028b0..c6c316b 100644
--- a/ui/src/frontend/router.ts
+++ b/ui/src/frontend/router.ts
@@ -308,4 +308,40 @@
throw new Error('History rewriting livelock');
}
}
+
+ static getUrlForVersion(versionCode: string): string {
+ const url = `${window.location.origin}/${versionCode}/`;
+ return url;
+ }
+
+ static async isVersionAvailable(versionCode: string):
+ Promise<string|undefined> {
+ if (versionCode === '') {
+ return undefined;
+ }
+ const controller = new AbortController();
+ const timeoutId = setTimeout(() => controller.abort(), 1000);
+ const url = Router.getUrlForVersion(versionCode);
+ let r;
+ try {
+ r = await fetch(url, {signal: controller.signal});
+ } catch (e) {
+ console.error(`No UI version for ${versionCode} at ${url}. This is an error if ${versionCode} is a released Perfetto version`);
+ return undefined;
+ } finally {
+ clearTimeout(timeoutId);
+ }
+ if (!r.ok) {
+ return undefined;
+ }
+ return url;
+ }
+
+ static navigateToVersion(versionCode: string): void {
+ const url = Router.getUrlForVersion(versionCode);
+ if (url === undefined) {
+ throw new Error(`No URL known for UI version ${versionCode}.`);
+ }
+ window.location.replace(url);
+ }
}
diff --git a/ui/src/frontend/rpc_http_dialog.ts b/ui/src/frontend/rpc_http_dialog.ts
index f29c846..97c186e 100644
--- a/ui/src/frontend/rpc_http_dialog.ts
+++ b/ui/src/frontend/rpc_http_dialog.ts
@@ -20,6 +20,7 @@
import {StatusResult, TraceProcessorApiVersion} from '../protos';
import {HttpRpcEngine} from '../trace_processor/http_rpc_engine';
import {showModal} from '../widgets/modal';
+import {Router} from './router';
import {globals} from './globals';
import {publishHttpRpcState} from './publish';
@@ -27,9 +28,9 @@
const CURRENT_API_VERSION =
TraceProcessorApiVersion.TRACE_PROCESSOR_CURRENT_API_VERSION;
-const PROMPT = () => `Trace Processor Native Accelerator detected on ` +
-`${HttpRpcEngine.hostAndPort} with:
-$loadedTraceName
+function getPromptMessage(tpStatus: StatusResult): string {
+ return `Trace Processor Native Accelerator detected on ${HttpRpcEngine.hostAndPort} with:
+${tpStatus.loadedTraceName}
YES, use loaded trace:
Will load from the current state of Trace Processor. If you did run
@@ -46,13 +47,11 @@
Using the native accelerator has some minor caveats:
- Only one tab can be using the accelerator.
- Sharing, downloading and conversion-to-legacy aren't supported.
-- You may encounter UI errors if the Trace Processor version you are using is
-too old. Get the latest version from get.perfetto.dev/trace_processor.
`;
+}
-
-const MSG_TOO_OLD = () => `The Trace Processor instance on ` +
-`${HttpRpcEngine.hostAndPort} is too old.
+function getIncompatibleRpcMessage(tpStatus: StatusResult): string {
+ return `The Trace Processor instance on ${HttpRpcEngine.hostAndPort} is too old.
This UI requires TraceProcessor features that are not present in the
Trace Processor native accelerator you are currently running.
@@ -64,14 +63,88 @@
chmod +x ./trace_processor
./trace_processor --httpd
-UI version: ${VERSION}
-TraceProcessor RPC API required: ${CURRENT_API_VERSION} or higher
+UI version code: ${VERSION}
+UI RPC API: ${CURRENT_API_VERSION}
-TraceProcessor version: $tpVersion
-RPC API: $tpApi
+Trace processor version: ${tpStatus.humanReadableVersion}
+Trace processor version code: ${tpStatus.versionCode}
+Trace processor RPC API: ${tpStatus.apiVersion}
`;
+}
-let forceUseOldVersion = false;
+function getVersionMismatchMessage(tpStatus: StatusResult): string {
+ return `The trace processor instance on ${HttpRpcEngine.hostAndPort} is a different build from the UI.
+
+This may cause problems. Where possible it is better to use the matched version of the UI.
+You can do this by clicking the button below.
+
+UI version code: ${VERSION}
+UI RPC API: ${CURRENT_API_VERSION}
+
+Trace processor version: ${tpStatus.humanReadableVersion}
+Trace processor version code: ${tpStatus.versionCode}
+Trace processor RPC API: ${tpStatus.apiVersion}
+`;
+}
+
+// The flow is fairly complicated:
+// +-----------------------------------+
+// | User loads the UI |
+// +-----------------+-----------------+
+// |
+// +-----------------+-----------------+
+// | Is trace_processor present at |
+// | HttpRpcEngine.hostAndPort? |
+// +--------------------------+--------+
+// |No |Yes
+// | +--------------+-------------------------------+
+// | | Does version code of UI and TP match? |
+// | +--------------+----------------------------+--+
+// | |No |Yes
+// | | |
+// | | |
+// | +-------------+-------------+ |
+// | |Is a build of the UI at the| |
+// | |TP version code existant | |
+// | |and reachable? | |
+// | +---+----------------+------+ |
+// | | No | Yes |
+// | | | |
+// | | +--------+-------+ |
+// | | |Dialog: Mismatch| |
+// | | |Load matched UI +-------------------------------+
+// | | |Continue +-+ | |
+// | | +----------------+ | | |
+// | | | | |
+// | +------+--------------------------+----+ | |
+// | |TP RPC version >= UI RPC version | | |
+// | +----+-------------------+-------------+ | |
+// | | No |Yes | |
+// | +----+--------------+ | | |
+// | |Dialog: Bad RPC | | | |
+// | +---+Use built-in WASM | | | |
+// | | |Continue anyway +----| | |
+// | | +-------------------+ | +-----------+-----------+ |
+// | | +--------+TP has preloaded trace?| |
+// | | +-+---------------+-----+ |
+// | | |No |Yes |
+// | | | +---------------------+ |
+// | | | | Dialog: Preloaded? | |
+// | | +--+ YES, use loaded trace |
+// | | +--------| YES, but reset state| |
+// | | +---------------------------------------| NO, Use builtin Wasm| |
+// | | | | | +---------------------+ |
+// | | | | | |
+// | | | Reset TP | |
+// | | | | | |
+// | | | | | |
+// Show the UI Show the UI Link to
+// (WASM mode) (RPC mode) matched UI
+
+// There are three options in the end:
+// - Show the UI (WASM mode)
+// - Show the UI (RPC mode)
+// - Redirect to a matched version of the UI
// Try to connect to the external Trace Processor HTTP RPC accelerator (if
// available, often it isn't). If connected it will populate the
@@ -83,73 +156,184 @@
export async function CheckHttpRpcConnection(): Promise<void> {
const state = await HttpRpcEngine.checkConnection();
publishHttpRpcState(state);
- if (!state.connected) return;
+ if (!state.connected) {
+ // No RPC = exit immediately to the WASM UI.
+ return;
+ }
const tpStatus = assertExists(state.status);
- if (tpStatus.apiVersion < CURRENT_API_VERSION) {
- await showDialogTraceProcessorTooOld(tpStatus);
- if (!forceUseOldVersion) return;
+ function forceWasm() {
+ globals.dispatch(Actions.setNewEngineMode({mode: 'FORCE_BUILTIN_WASM'}));
}
+ // Check short version:
+ if (tpStatus.versionCode !== '' && tpStatus.versionCode !== VERSION) {
+ const url = await Router.isVersionAvailable(tpStatus.versionCode);
+ if (url !== undefined) {
+ // If matched UI available show a dialog asking the user to
+ // switch.
+ const result = await showDialogVersionMismatch(tpStatus, url);
+ switch (result) {
+ case MismatchedVersionDialog.Dismissed:
+ case MismatchedVersionDialog.UseMatchingUi:
+ Router.navigateToVersion(tpStatus.versionCode);
+ return;
+ case MismatchedVersionDialog.UseMismatchedRpc:
+ break;
+ case MismatchedVersionDialog.UseWasm:
+ forceWasm();
+ return;
+ default:
+ const x: never = result;
+ throw new Error(`Unsupported result ${x}`);
+ }
+ }
+ }
+
+ // Check the RPC version:
+ if (tpStatus.apiVersion < CURRENT_API_VERSION) {
+ const result = await showDialogIncompatibleRPC(tpStatus);
+ switch (result) {
+ case IncompatibleRpcDialogResult.Dismissed:
+ case IncompatibleRpcDialogResult.UseWasm:
+ forceWasm();
+ return;
+ case IncompatibleRpcDialogResult.UseIncompatibleRpc:
+ break;
+ default:
+ const x: never = result;
+ throw new Error(`Unsupported result ${x}`);
+ }
+ }
+
+ // Check if pre-loaded:
if (tpStatus.loadedTraceName) {
// If a trace is already loaded in the trace processor (e.g., the user
// launched trace_processor_shell -D trace_file.pftrace), prompt the user to
// initialize the UI with the already-loaded trace.
- return showDialogToUsePreloadedTrace(tpStatus);
+ const result = await showDialogToUsePreloadedTrace(tpStatus);
+ switch (result) {
+ case PreloadedDialogResult.Dismissed:
+ case PreloadedDialogResult.UseRpcWithPreloadedTrace:
+ globals.dispatch(Actions.openTraceFromHttpRpc({}));
+ return;
+ case PreloadedDialogResult.UseRpc:
+ // Resetting state is the default.
+ return;
+ case PreloadedDialogResult.UseWasm:
+ forceWasm();
+ return;
+ default:
+ const x: never = result;
+ throw new Error(`Unsupported result ${x}`);
+ }
}
}
-async function showDialogTraceProcessorTooOld(tpStatus: StatusResult) {
- return showModal({
- title: 'Your Trace Processor binary is outdated',
- content:
- m('.modal-pre',
- MSG_TOO_OLD().replace('$tpVersion', tpStatus.humanReadableVersion)
- .replace('$tpApi', `${tpStatus.apiVersion}`)),
+enum MismatchedVersionDialog {
+ UseMatchingUi = 'useMatchingUi',
+ UseWasm = 'useWasm',
+ UseMismatchedRpc = 'useMismatchedRpc',
+ Dismissed = 'dismissed',
+}
+
+async function showDialogVersionMismatch(tpStatus: StatusResult,
+ url: string):
+ Promise<MismatchedVersionDialog> {
+ let result = MismatchedVersionDialog.Dismissed;
+ await showModal({
+ title: 'Version mismatch',
+ content: m('.modal-pre', getVersionMismatchMessage(tpStatus)),
+ buttons: [
+ {
+ primary: true,
+ text: `Open ${url}`,
+ action: () => {
+ result = MismatchedVersionDialog.UseMatchingUi;
+ },
+ },
+ {
+ text: 'Use builtin Wasm',
+ action: () => {
+ result = MismatchedVersionDialog.UseWasm;
+ },
+ },
+ {
+ text: 'Use mismatched version regardless (might crash)',
+ action: () => {
+ result = MismatchedVersionDialog.UseMismatchedRpc;
+ },
+ },
+ ],
+ });
+ return result;
+}
+
+enum IncompatibleRpcDialogResult {
+ UseWasm = 'useWasm',
+ UseIncompatibleRpc = 'useIncompatibleRpc',
+ Dismissed = 'dismissed',
+}
+
+async function showDialogIncompatibleRPC(tpStatus: StatusResult):
+ Promise<IncompatibleRpcDialogResult> {
+ let result = IncompatibleRpcDialogResult.Dismissed;
+ await showModal({
+ title: 'Incompatible RPC version',
+ content: m('.modal-pre', getIncompatibleRpcMessage(tpStatus)),
buttons: [
{
text: 'Use builtin Wasm',
primary: true,
action: () => {
- globals.dispatch(
- Actions.setNewEngineMode({mode: 'FORCE_BUILTIN_WASM'}));
+ result = IncompatibleRpcDialogResult.UseWasm;
},
},
{
- text: 'Use old version regardless (might crash)',
- primary: false,
+ text: 'Use old version regardless (will crash)',
action: () => {
- forceUseOldVersion = true;
+ result = IncompatibleRpcDialogResult.UseIncompatibleRpc;
},
},
],
});
+ return result;
}
-async function showDialogToUsePreloadedTrace(tpStatus: StatusResult) {
- return showModal({
- title: 'Use Trace Processor Native Acceleration?',
- content:
- m('.modal-pre',
- PROMPT().replace('$loadedTraceName', tpStatus.loadedTraceName)),
+enum PreloadedDialogResult {
+ UseRpcWithPreloadedTrace = 'useRpcWithPreloadedTrace',
+ UseRpc = 'useRpc',
+ UseWasm = 'useWasm',
+ Dismissed = 'dismissed',
+}
+
+async function showDialogToUsePreloadedTrace(tpStatus: StatusResult):
+ Promise<PreloadedDialogResult> {
+ let result = PreloadedDialogResult.Dismissed;
+ await showModal({
+ title: 'Use trace processor native acceleration?',
+ content: m('.modal-pre', getPromptMessage(tpStatus)),
buttons: [
{
text: 'YES, use loaded trace',
primary: true,
action: () => {
- globals.dispatch(Actions.openTraceFromHttpRpc({}));
+ result = PreloadedDialogResult.UseRpcWithPreloadedTrace;
},
},
{
text: 'YES, but reset state',
+ action: () => {
+ result = PreloadedDialogResult.UseRpc;
+ },
},
{
- text: 'NO, Use builtin Wasm',
+ text: 'NO, Use builtin WASM',
action: () => {
- globals.dispatch(
- Actions.setNewEngineMode({mode: 'FORCE_BUILTIN_WASM'}));
+ result = PreloadedDialogResult.UseWasm;
},
},
],
});
+ return result;
}
diff --git a/ui/src/plugins/dev.perfetto.AndroidPerfTraceCounters/index.ts b/ui/src/plugins/dev.perfetto.AndroidPerfTraceCounters/index.ts
index cbd5c9d..eb596c2 100644
--- a/ui/src/plugins/dev.perfetto.AndroidPerfTraceCounters/index.ts
+++ b/ui/src/plugins/dev.perfetto.AndroidPerfTraceCounters/index.ts
@@ -110,7 +110,7 @@
sum(stall_backend_mem) as total_stall_backend_mem,
sum(l3_cache_miss) as total_l3_cache_miss
FROM target_thread_ipc_slice WHERE ts IS NOT NULL`,
- 'target thread ipc statistic'
+ 'target thread ipc statistic',
);
},
});
diff --git a/ui/src/tracks/flows/index.ts b/ui/src/tracks/flows/index.ts
deleted file mode 100644
index 626c671..0000000
--- a/ui/src/tracks/flows/index.ts
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright (C) 2024 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-import {
- FlowEventsAreaSelectedPanel,
- FlowEventsPanel,
-} from '../../frontend/flow_events_panel';
-import {globals} from '../../frontend/globals';
-import {
- Plugin,
- PluginContext,
- PluginContextTrace,
- PluginDescriptor,
-} from '../../public';
-
-class FlowsPlugin implements Plugin {
- onActivate(_ctx: PluginContext): void {}
-
- async onTraceLoad(ctx: PluginContextTrace): Promise<void> {
- const tabUri = 'perfetto.Flows#FlowEvents';
- ctx.registerTab({
- isEphemeral: false,
- uri: tabUri,
- content: {
- render: () => {
- const selection = globals.state.currentSelection;
- if (selection?.kind === 'AREA') {
- return m(FlowEventsAreaSelectedPanel);
- } else {
- return m(FlowEventsPanel);
- }
- },
- getTitle: () => 'Flow Events',
- },
- });
-
- ctx.registerCommand({
- id: 'perfetto.Flows#ShowFlowsTab',
- name: `Show Flows Tab`,
- callback: () => {
- ctx.tabs.showTab(tabUri);
- },
- });
- }
-}
-
-export const plugin: PluginDescriptor = {
- pluginId: 'perfetto.Flows',
- plugin: FlowsPlugin,
-};
diff --git a/ui/src/tracks/pivot_table/index.ts b/ui/src/tracks/pivot_table/index.ts
deleted file mode 100644
index e9d14cd..0000000
--- a/ui/src/tracks/pivot_table/index.ts
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright (C) 2024 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-import {PIVOT_TABLE_REDUX_FLAG} from '../../controller/pivot_table_controller';
-import {globals} from '../../frontend/globals';
-import {PivotTable} from '../../frontend/pivot_table';
-import {
- Plugin,
- PluginContext,
- PluginContextTrace,
- PluginDescriptor,
-} from '../../public';
-
-class PivotTablePlugin implements Plugin {
- onActivate(_ctx: PluginContext): void {}
-
- async onTraceLoad(ctx: PluginContextTrace): Promise<void> {
- if (PIVOT_TABLE_REDUX_FLAG.get()) {
- ctx.registerTab({
- isEphemeral: false,
- uri: 'perfetto.PivotTable#PivotTable',
- content: {
- render: () => m(PivotTable, {
- selectionArea:
- globals.state.nonSerializableState.pivotTable.selectionArea,
- }),
- getTitle: () => 'Pivot Table',
- },
- });
- }
- }
-}
-
-export const plugin: PluginDescriptor = {
- pluginId: 'perfetto.PivotTable',
- plugin: PivotTablePlugin,
-};