Merge "Correct test folder typo" into main
diff --git a/Android.bp b/Android.bp
index 3b4f823..328fc3d 100644
--- a/Android.bp
+++ b/Android.bp
@@ -2293,7 +2293,6 @@
":perfetto_src_shared_lib_test_utils",
":perfetto_src_trace_processor_containers_containers",
":perfetto_src_trace_processor_db_db",
- ":perfetto_src_trace_processor_db_overlays_overlays",
":perfetto_src_trace_processor_db_storage_storage",
":perfetto_src_trace_processor_export_json",
":perfetto_src_trace_processor_importers_android_bugreport_android_bugreport",
@@ -5945,6 +5944,7 @@
"protos/perfetto/trace/ftrace/net.proto",
"protos/perfetto/trace/ftrace/oom.proto",
"protos/perfetto/trace/ftrace/panel.proto",
+ "protos/perfetto/trace/ftrace/perf_trace_counters.proto",
"protos/perfetto/trace/ftrace/power.proto",
"protos/perfetto/trace/ftrace/printk.proto",
"protos/perfetto/trace/ftrace/raw_syscalls.proto",
@@ -6363,6 +6363,7 @@
"protos/perfetto/trace/ftrace/net.proto",
"protos/perfetto/trace/ftrace/oom.proto",
"protos/perfetto/trace/ftrace/panel.proto",
+ "protos/perfetto/trace/ftrace/perf_trace_counters.proto",
"protos/perfetto/trace/ftrace/power.proto",
"protos/perfetto/trace/ftrace/printk.proto",
"protos/perfetto/trace/ftrace/raw_syscalls.proto",
@@ -6444,6 +6445,7 @@
"external/perfetto/protos/perfetto/trace/ftrace/net.gen.cc",
"external/perfetto/protos/perfetto/trace/ftrace/oom.gen.cc",
"external/perfetto/protos/perfetto/trace/ftrace/panel.gen.cc",
+ "external/perfetto/protos/perfetto/trace/ftrace/perf_trace_counters.gen.cc",
"external/perfetto/protos/perfetto/trace/ftrace/power.gen.cc",
"external/perfetto/protos/perfetto/trace/ftrace/printk.gen.cc",
"external/perfetto/protos/perfetto/trace/ftrace/raw_syscalls.gen.cc",
@@ -6525,6 +6527,7 @@
"external/perfetto/protos/perfetto/trace/ftrace/net.gen.h",
"external/perfetto/protos/perfetto/trace/ftrace/oom.gen.h",
"external/perfetto/protos/perfetto/trace/ftrace/panel.gen.h",
+ "external/perfetto/protos/perfetto/trace/ftrace/perf_trace_counters.gen.h",
"external/perfetto/protos/perfetto/trace/ftrace/power.gen.h",
"external/perfetto/protos/perfetto/trace/ftrace/printk.gen.h",
"external/perfetto/protos/perfetto/trace/ftrace/raw_syscalls.gen.h",
@@ -6602,6 +6605,7 @@
"protos/perfetto/trace/ftrace/net.proto",
"protos/perfetto/trace/ftrace/oom.proto",
"protos/perfetto/trace/ftrace/panel.proto",
+ "protos/perfetto/trace/ftrace/perf_trace_counters.proto",
"protos/perfetto/trace/ftrace/power.proto",
"protos/perfetto/trace/ftrace/printk.proto",
"protos/perfetto/trace/ftrace/raw_syscalls.proto",
@@ -6682,6 +6686,7 @@
"external/perfetto/protos/perfetto/trace/ftrace/net.pb.cc",
"external/perfetto/protos/perfetto/trace/ftrace/oom.pb.cc",
"external/perfetto/protos/perfetto/trace/ftrace/panel.pb.cc",
+ "external/perfetto/protos/perfetto/trace/ftrace/perf_trace_counters.pb.cc",
"external/perfetto/protos/perfetto/trace/ftrace/power.pb.cc",
"external/perfetto/protos/perfetto/trace/ftrace/printk.pb.cc",
"external/perfetto/protos/perfetto/trace/ftrace/raw_syscalls.pb.cc",
@@ -6762,6 +6767,7 @@
"external/perfetto/protos/perfetto/trace/ftrace/net.pb.h",
"external/perfetto/protos/perfetto/trace/ftrace/oom.pb.h",
"external/perfetto/protos/perfetto/trace/ftrace/panel.pb.h",
+ "external/perfetto/protos/perfetto/trace/ftrace/perf_trace_counters.pb.h",
"external/perfetto/protos/perfetto/trace/ftrace/power.pb.h",
"external/perfetto/protos/perfetto/trace/ftrace/printk.pb.h",
"external/perfetto/protos/perfetto/trace/ftrace/raw_syscalls.pb.h",
@@ -6839,6 +6845,7 @@
"protos/perfetto/trace/ftrace/net.proto",
"protos/perfetto/trace/ftrace/oom.proto",
"protos/perfetto/trace/ftrace/panel.proto",
+ "protos/perfetto/trace/ftrace/perf_trace_counters.proto",
"protos/perfetto/trace/ftrace/power.proto",
"protos/perfetto/trace/ftrace/printk.proto",
"protos/perfetto/trace/ftrace/raw_syscalls.proto",
@@ -6920,6 +6927,7 @@
"external/perfetto/protos/perfetto/trace/ftrace/net.pbzero.cc",
"external/perfetto/protos/perfetto/trace/ftrace/oom.pbzero.cc",
"external/perfetto/protos/perfetto/trace/ftrace/panel.pbzero.cc",
+ "external/perfetto/protos/perfetto/trace/ftrace/perf_trace_counters.pbzero.cc",
"external/perfetto/protos/perfetto/trace/ftrace/power.pbzero.cc",
"external/perfetto/protos/perfetto/trace/ftrace/printk.pbzero.cc",
"external/perfetto/protos/perfetto/trace/ftrace/raw_syscalls.pbzero.cc",
@@ -7001,6 +7009,7 @@
"external/perfetto/protos/perfetto/trace/ftrace/net.pbzero.h",
"external/perfetto/protos/perfetto/trace/ftrace/oom.pbzero.h",
"external/perfetto/protos/perfetto/trace/ftrace/panel.pbzero.h",
+ "external/perfetto/protos/perfetto/trace/ftrace/perf_trace_counters.pbzero.h",
"external/perfetto/protos/perfetto/trace/ftrace/power.pbzero.h",
"external/perfetto/protos/perfetto/trace/ftrace/printk.pbzero.h",
"external/perfetto/protos/perfetto/trace/ftrace/raw_syscalls.pbzero.h",
@@ -10952,24 +10961,11 @@
],
}
-// GN: //src/trace_processor/db/overlays:overlays
+// GN: //src/trace_processor/db/storage:fake_storage
filegroup {
- name: "perfetto_src_trace_processor_db_overlays_overlays",
+ name: "perfetto_src_trace_processor_db_storage_fake_storage",
srcs: [
- "src/trace_processor/db/overlays/arrangement_overlay.cc",
- "src/trace_processor/db/overlays/null_overlay.cc",
- "src/trace_processor/db/overlays/selector_overlay.cc",
- "src/trace_processor/db/overlays/storage_overlay.cc",
- ],
-}
-
-// GN: //src/trace_processor/db/overlays:unittests
-filegroup {
- name: "perfetto_src_trace_processor_db_overlays_unittests",
- srcs: [
- "src/trace_processor/db/overlays/arrangement_overlay_unittest.cc",
- "src/trace_processor/db/overlays/null_overlay_unittest.cc",
- "src/trace_processor/db/overlays/selector_overlay_unittest.cc",
+ "src/trace_processor/db/storage/fake_storage.cc",
],
}
@@ -10977,9 +10973,12 @@
filegroup {
name: "perfetto_src_trace_processor_db_storage_storage",
srcs: [
+ "src/trace_processor/db/storage/arrangement_storage.cc",
"src/trace_processor/db/storage/dummy_storage.cc",
"src/trace_processor/db/storage/id_storage.cc",
+ "src/trace_processor/db/storage/null_storage.cc",
"src/trace_processor/db/storage/numeric_storage.cc",
+ "src/trace_processor/db/storage/selector_storage.cc",
"src/trace_processor/db/storage/set_id_storage.cc",
"src/trace_processor/db/storage/storage.cc",
"src/trace_processor/db/storage/string_storage.cc",
@@ -10990,8 +10989,11 @@
filegroup {
name: "perfetto_src_trace_processor_db_storage_unittests",
srcs: [
+ "src/trace_processor/db/storage/arrangement_storage_unittest.cc",
"src/trace_processor/db/storage/id_storage_unittest.cc",
+ "src/trace_processor/db/storage/null_storage_unittest.cc",
"src/trace_processor/db/storage/numeric_storage_unittest.cc",
+ "src/trace_processor/db/storage/selector_storage_unittest.cc",
"src/trace_processor/db/storage/set_id_storage_unittest.cc",
"src/trace_processor/db/storage/string_storage_unittest.cc",
],
@@ -13375,6 +13377,7 @@
"protos/perfetto/trace/ftrace/net.proto",
"protos/perfetto/trace/ftrace/oom.proto",
"protos/perfetto/trace/ftrace/panel.proto",
+ "protos/perfetto/trace/ftrace/perf_trace_counters.proto",
"protos/perfetto/trace/ftrace/power.proto",
"protos/perfetto/trace/ftrace/printk.proto",
"protos/perfetto/trace/ftrace/raw_syscalls.proto",
@@ -13808,8 +13811,7 @@
":perfetto_src_trace_processor_containers_containers",
":perfetto_src_trace_processor_containers_unittests",
":perfetto_src_trace_processor_db_db",
- ":perfetto_src_trace_processor_db_overlays_overlays",
- ":perfetto_src_trace_processor_db_overlays_unittests",
+ ":perfetto_src_trace_processor_db_storage_fake_storage",
":perfetto_src_trace_processor_db_storage_storage",
":perfetto_src_trace_processor_db_storage_unittests",
":perfetto_src_trace_processor_db_unittests",
@@ -14539,7 +14541,6 @@
":perfetto_src_protozero_protozero",
":perfetto_src_trace_processor_containers_containers",
":perfetto_src_trace_processor_db_db",
- ":perfetto_src_trace_processor_db_overlays_overlays",
":perfetto_src_trace_processor_db_storage_storage",
":perfetto_src_trace_processor_export_json",
":perfetto_src_trace_processor_importers_android_bugreport_android_bugreport",
@@ -14775,7 +14776,6 @@
":perfetto_src_protozero_protozero",
":perfetto_src_trace_processor_containers_containers",
":perfetto_src_trace_processor_db_db",
- ":perfetto_src_trace_processor_db_overlays_overlays",
":perfetto_src_trace_processor_db_storage_storage",
":perfetto_src_trace_processor_export_json",
":perfetto_src_trace_processor_importers_android_bugreport_android_bugreport",
diff --git a/BUILD b/BUILD
index 2d28e55..cddab6b 100644
--- a/BUILD
+++ b/BUILD
@@ -218,7 +218,6 @@
":src_kernel_utils_syscall_table",
":src_protozero_proto_ring_buffer",
":src_trace_processor_db_db",
- ":src_trace_processor_db_overlays_overlays",
":src_trace_processor_db_storage_storage",
":src_trace_processor_export_json",
":src_trace_processor_importers_android_bugreport_android_bugreport",
@@ -1297,32 +1296,22 @@
linkstatic = True,
)
-# GN target: //src/trace_processor/db/overlays:overlays
-perfetto_filegroup(
- name = "src_trace_processor_db_overlays_overlays",
- srcs = [
- "src/trace_processor/db/overlays/arrangement_overlay.cc",
- "src/trace_processor/db/overlays/arrangement_overlay.h",
- "src/trace_processor/db/overlays/null_overlay.cc",
- "src/trace_processor/db/overlays/null_overlay.h",
- "src/trace_processor/db/overlays/selector_overlay.cc",
- "src/trace_processor/db/overlays/selector_overlay.h",
- "src/trace_processor/db/overlays/storage_overlay.cc",
- "src/trace_processor/db/overlays/storage_overlay.h",
- "src/trace_processor/db/overlays/types.h",
- ],
-)
-
# GN target: //src/trace_processor/db/storage:storage
perfetto_filegroup(
name = "src_trace_processor_db_storage_storage",
srcs = [
+ "src/trace_processor/db/storage/arrangement_storage.cc",
+ "src/trace_processor/db/storage/arrangement_storage.h",
"src/trace_processor/db/storage/dummy_storage.cc",
"src/trace_processor/db/storage/dummy_storage.h",
"src/trace_processor/db/storage/id_storage.cc",
"src/trace_processor/db/storage/id_storage.h",
+ "src/trace_processor/db/storage/null_storage.cc",
+ "src/trace_processor/db/storage/null_storage.h",
"src/trace_processor/db/storage/numeric_storage.cc",
"src/trace_processor/db/storage/numeric_storage.h",
+ "src/trace_processor/db/storage/selector_storage.cc",
+ "src/trace_processor/db/storage/selector_storage.h",
"src/trace_processor/db/storage/set_id_storage.cc",
"src/trace_processor/db/storage/set_id_storage.h",
"src/trace_processor/db/storage/storage.cc",
@@ -4471,6 +4460,7 @@
"protos/perfetto/trace/ftrace/net.proto",
"protos/perfetto/trace/ftrace/oom.proto",
"protos/perfetto/trace/ftrace/panel.proto",
+ "protos/perfetto/trace/ftrace/perf_trace_counters.proto",
"protos/perfetto/trace/ftrace/power.proto",
"protos/perfetto/trace/ftrace/printk.proto",
"protos/perfetto/trace/ftrace/raw_syscalls.proto",
@@ -5304,7 +5294,6 @@
srcs = [
":src_kernel_utils_syscall_table",
":src_trace_processor_db_db",
- ":src_trace_processor_db_overlays_overlays",
":src_trace_processor_db_storage_storage",
":src_trace_processor_export_json",
":src_trace_processor_importers_android_bugreport_android_bugreport",
@@ -5471,7 +5460,6 @@
":src_profiling_symbolizer_symbolizer",
":src_protozero_proto_ring_buffer",
":src_trace_processor_db_db",
- ":src_trace_processor_db_overlays_overlays",
":src_trace_processor_db_storage_storage",
":src_trace_processor_export_json",
":src_trace_processor_importers_android_bugreport_android_bugreport",
@@ -5696,7 +5684,6 @@
":src_profiling_symbolizer_symbolizer",
":src_protozero_proto_ring_buffer",
":src_trace_processor_db_db",
- ":src_trace_processor_db_overlays_overlays",
":src_trace_processor_db_storage_storage",
":src_trace_processor_export_json",
":src_trace_processor_importers_android_bugreport_android_bugreport",
diff --git a/CHANGELOG b/CHANGELOG
index 1c5e81b..35291b7 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -9,6 +9,17 @@
*
+v40.0 - 2023-12-04:
+ Tracing service and probes:
+ * Added support for collecting battery voltage from the Android Power HAL.
+ * Added support for emitting machine id from producers on remote hosts.
+ Trace Processor:
+ * Added of flow id from trace as a column in the flow table.
+ * Fixed computation of trace_bounds table when using UI native acceleration.
+ UI:
+ * Switched to use "v2" querying and rendering system for tracks by default.
+
+
v39.0 - 2023-11-15:
Tracing service and probes:
* Added reporting of TZ offset under system_info.timezone_off_mins .
@@ -18,12 +29,12 @@
* Added support for running on Linux & Android systems configured with 16K
pagetables.
Trace Processor:
- * New android_boot metric.
+ * Added android_boot metric.
* Added new PerfettoSQL syntax (CREATE PERFETTO VIEW) for adding schemas to views.
- * Support perf.data import format.
- * Add dvfs and cpu_idle to stdlib.
+ * Added support for the perf.data import format.
+ * Added dvfs and cpu_idle to stdlib.
UI:
- * Add a new type of debug tracks: counter.
+ * Added a new type of debug tracks: counter.
* Improved visualization of timestamps for durations.
diff --git a/docs/analysis/common-queries.md b/docs/analysis/common-queries.md
index adae686..6675bc0 100644
--- a/docs/analysis/common-queries.md
+++ b/docs/analysis/common-queries.md
@@ -52,8 +52,8 @@
SELECT
slice_id,
slice_name,
- SUM(CASE state = 'R' THEN dur ELSE 0 END) AS runnable_time,
- SUM(CASE state = 'D' THEN dur ELSE 0 END) AS uninterruptible_time
+ SUM(IIF(state = 'R', dur, 0)) AS runnable_time,
+ SUM(IIF(state = 'D', dur, 0)) AS uninterruptible_time
FROM slice_thread_state_breakdown
GROUP BY slice_id;
```
diff --git a/docs/data-sources/cpu-scheduling.md b/docs/data-sources/cpu-scheduling.md
index b8447ff..6023136 100644
--- a/docs/data-sources/cpu-scheduling.md
+++ b/docs/data-sources/cpu-scheduling.md
@@ -126,10 +126,11 @@
NOTE: `sched_waking` and `sched_wakeup` provide nearly the same information. The
difference lies in wakeup events across CPUs, which involve
- inter-processor interrupts. The former is emitted on the source (wakee)
- CPU, the latter on the destination (waked) CPU. `sched_waking` is usually
- sufficient for latency analysis, unless you are looking into breaking down
- latency due to inter-processor signaling.
+ inter-processor interrupts. The former is always emitted on the source (wakee)
+ CPU, the latter may be executed on either the source or the destination (waked) CPU
+ depending on several factors. `sched_waking` is usually sufficient for latency
+ analysis, unless you are looking into breaking down latency due to
+ the scheduler's wake up path, such as inter-processor signaling.
When enabling `sched_waking` events, the following will appear in the UI when
selecting a CPU slice:
diff --git a/include/perfetto/ext/base/sys_types.h b/include/perfetto/ext/base/sys_types.h
index 999a152..49eeb11 100644
--- a/include/perfetto/ext/base/sys_types.h
+++ b/include/perfetto/ext/base/sys_types.h
@@ -21,6 +21,7 @@
// missing on Windows.
#include <sys/types.h>
+#include <cstdint>
#include "perfetto/base/build_config.h"
@@ -43,6 +44,11 @@
namespace perfetto {
namespace base {
+// The machine ID used in the tracing core.
+using MachineID = uint32_t;
+// The default value reserved for the host trace.
+constexpr MachineID kDefaultMachineID = 0;
+
constexpr uid_t kInvalidUid = static_cast<uid_t>(-1);
constexpr pid_t kInvalidPid = static_cast<pid_t>(-1);
diff --git a/include/perfetto/ext/base/thread_annotations.h b/include/perfetto/ext/base/thread_annotations.h
index beb8c45..6aee16a 100644
--- a/include/perfetto/ext/base/thread_annotations.h
+++ b/include/perfetto/ext/base/thread_annotations.h
@@ -24,15 +24,13 @@
extern "C" {
void AnnotateBenignRaceSized(const char* file,
int line,
- unsigned long address,
- unsigned long size,
+ const volatile void* address,
+ size_t size,
const char* description);
}
-#define PERFETTO_ANNOTATE_BENIGN_RACE_SIZED(pointer, size, description) \
- AnnotateBenignRaceSized(__FILE__, __LINE__, \
- reinterpret_cast<unsigned long>(pointer), size, \
- description);
+#define PERFETTO_ANNOTATE_BENIGN_RACE_SIZED(pointer, size, description) \
+ AnnotateBenignRaceSized(__FILE__, __LINE__, pointer, size, description);
#else // defined(ADDRESS_SANITIZER)
#define PERFETTO_ANNOTATE_BENIGN_RACE_SIZED(pointer, size, description)
#endif // defined(ADDRESS_SANITIZER)
diff --git a/include/perfetto/ext/ipc/client_info.h b/include/perfetto/ext/ipc/client_info.h
index b7c997d..132ab69 100644
--- a/include/perfetto/ext/ipc/client_info.h
+++ b/include/perfetto/ext/ipc/client_info.h
@@ -18,6 +18,7 @@
#define INCLUDE_PERFETTO_EXT_IPC_CLIENT_INFO_H_
#include "perfetto/base/logging.h"
+#include "perfetto/ext/base/sys_types.h"
#include "perfetto/ext/base/utils.h"
#include "perfetto/ext/ipc/basic_types.h"
@@ -28,12 +29,16 @@
class ClientInfo {
public:
ClientInfo() = default;
- ClientInfo(ClientID client_id, uid_t uid, pid_t pid)
- : client_id_(client_id), uid_(uid), pid_(pid) {}
+ ClientInfo(ClientID client_id,
+ uid_t uid,
+ pid_t pid,
+ base::MachineID machine_id)
+ : client_id_(client_id), uid_(uid), pid_(pid), machine_id_(machine_id) {}
bool operator==(const ClientInfo& other) const {
- return std::tie(client_id_, uid_, pid_) ==
- std::tie(other.client_id_, other.uid_, other.pid_);
+ return std::tie(client_id_, uid_, pid_, machine_id_) ==
+ std::tie(other.client_id_, other.uid_, other.pid_,
+ other.machine_id_);
}
bool operator!=(const ClientInfo& other) const { return !(*this == other); }
@@ -54,12 +59,16 @@
// Posix process ID. Comes from the kernel and can be trusted.
int32_t pid() const { return pid_; }
+ // An integral ID that identifies the machine the client is on.
+ base::MachineID machine_id() const { return machine_id_; }
+
private:
ClientID client_id_ = 0;
// The following fields are emitted to trace packets and should be kept in
// sync with perfetto::ClientIdentity.
uid_t uid_ = kInvalidUid;
pid_t pid_ = base::kInvalidPid;
+ base::MachineID machine_id_ = base::kDefaultMachineID;
};
} // namespace ipc
diff --git a/include/perfetto/ext/tracing/core/basic_types.h b/include/perfetto/ext/tracing/core/basic_types.h
index b0090e9..c3484ac 100644
--- a/include/perfetto/ext/tracing/core/basic_types.h
+++ b/include/perfetto/ext/tracing/core/basic_types.h
@@ -98,6 +98,10 @@
constexpr TracingSessionID kBugreportSessionId =
static_cast<TracingSessionID>(-1);
+// The ID of a machine in a multi-machine tracing session.
+using MachineID = base::MachineID;
+constexpr MachineID kDefaultMachineID = base::kDefaultMachineID;
+
} // namespace perfetto
#endif // INCLUDE_PERFETTO_EXT_TRACING_CORE_BASIC_TYPES_H_
diff --git a/include/perfetto/ext/tracing/core/client_identity.h b/include/perfetto/ext/tracing/core/client_identity.h
index 1ab009a..3a18846 100644
--- a/include/perfetto/ext/tracing/core/client_identity.h
+++ b/include/perfetto/ext/tracing/core/client_identity.h
@@ -18,6 +18,7 @@
#define INCLUDE_PERFETTO_EXT_TRACING_CORE_CLIENT_IDENTITY_H_
#include "perfetto/ext/base/sys_types.h"
+#include "perfetto/ext/tracing/core/basic_types.h"
namespace perfetto {
@@ -26,7 +27,8 @@
class ClientIdentity {
public:
ClientIdentity() = default;
- ClientIdentity(uid_t uid, pid_t pid) : uid_(uid), pid_(pid) {}
+ ClientIdentity(uid_t uid, pid_t pid, MachineID machine_id = kDefaultMachineID)
+ : uid_(uid), pid_(pid), machine_id_(machine_id) {}
bool has_uid() const { return uid_ != base::kInvalidUid; }
uid_t uid() const { return uid_; }
@@ -34,9 +36,15 @@
bool has_pid() const { return pid_ != base::kInvalidPid; }
pid_t pid() const { return pid_; }
+ bool has_non_default_machine_id() const {
+ return machine_id_ != kDefaultMachineID;
+ }
+ base::MachineID machine_id() const { return machine_id_; }
+
private:
uid_t uid_ = base::kInvalidUid;
pid_t pid_ = base::kInvalidPid;
+ MachineID machine_id_ = kDefaultMachineID;
};
} // namespace perfetto
diff --git a/protos/perfetto/config/perfetto_config.proto b/protos/perfetto/config/perfetto_config.proto
index a4cab08..96aa5c8 100644
--- a/protos/perfetto/config/perfetto_config.proto
+++ b/protos/perfetto/config/perfetto_config.proto
@@ -1970,7 +1970,6 @@
ATOM_PERFETTO_TRIGGER = 329;
ATOM_TRANSCODING_DATA = 330;
ATOM_IMS_SERVICE_ENTITLEMENT_UPDATED = 331;
- ATOM_ART_DATUM_REPORTED = 332;
ATOM_DEVICE_ROTATED = 333;
ATOM_SIM_SPECIFIC_SETTINGS_RESTORED = 334;
ATOM_TEXT_CLASSIFIER_DOWNLOAD_REPORTED = 335;
@@ -2000,7 +1999,6 @@
ATOM_LOCATION_TIME_ZONE_PROVIDER_STATE_CHANGED = 359;
ATOM_FDTRACK_EVENT_OCCURRED = 364;
ATOM_TIMEOUT_AUTO_EXTENDED_REPORTED = 365;
- ATOM_ODREFRESH_REPORTED = 366;
ATOM_ALARM_BATCH_DELIVERED = 367;
ATOM_ALARM_SCHEDULED = 368;
ATOM_CAR_WATCHDOG_IO_OVERUSE_STATS_REPORTED = 369;
@@ -2068,6 +2066,8 @@
ATOM_HOTWORD_DETECTION_SERVICE_RESTARTED = 432;
ATOM_HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED = 433;
ATOM_HOTWORD_DETECTOR_EVENTS = 434;
+ ATOM_AD_SERVICES_API_CALLED = 435;
+ ATOM_AD_SERVICES_MESUREMENT_REPORTS_UPLOADED = 436;
ATOM_BOOT_COMPLETED_BROADCAST_COMPLETION_LATENCY_REPORTED = 437;
ATOM_CONTACTS_INDEXER_UPDATE_STATS_REPORTED = 440;
ATOM_APP_BACKGROUND_RESTRICTIONS_INFO = 441;
@@ -2089,24 +2089,47 @@
ATOM_ISOLATED_COMPILATION_SCHEDULED = 457;
ATOM_ISOLATED_COMPILATION_ENDED = 458;
ATOM_ONS_OPPORTUNISTIC_ESIM_PROVISIONING_COMPLETE = 459;
+ ATOM_SYSTEM_SERVER_PRE_WATCHDOG_OCCURRED = 460;
ATOM_TELEPHONY_ANOMALY_DETECTED = 461;
ATOM_LETTERBOX_POSITION_CHANGED = 462;
ATOM_REMOTE_KEY_PROVISIONING_ATTEMPT = 463;
ATOM_REMOTE_KEY_PROVISIONING_NETWORK_INFO = 464;
ATOM_REMOTE_KEY_PROVISIONING_TIMING = 465;
ATOM_MEDIAOUTPUT_OP_INTERACTION_REPORT = 466;
- ATOM_BACKGROUND_DEXOPT_JOB_ENDED = 467;
ATOM_SYNC_EXEMPTION_OCCURRED = 468;
ATOM_AUTOFILL_PRESENTATION_EVENT_REPORTED = 469;
ATOM_DOCK_STATE_CHANGED = 470;
+ ATOM_SAFETY_SOURCE_STATE_COLLECTED = 471;
+ ATOM_SAFETY_CENTER_SYSTEM_EVENT_REPORTED = 472;
+ ATOM_SAFETY_CENTER_INTERACTION_REPORTED = 473;
+ ATOM_SETTINGS_PROVIDER_SETTING_CHANGED = 474;
ATOM_BROADCAST_DELIVERY_EVENT_REPORTED = 475;
ATOM_SERVICE_REQUEST_EVENT_REPORTED = 476;
ATOM_PROVIDER_ACQUISITION_EVENT_REPORTED = 477;
ATOM_BLUETOOTH_DEVICE_NAME_REPORTED = 478;
+ ATOM_CB_CONFIG_UPDATED = 479;
+ ATOM_CB_MODULE_ERROR_REPORTED = 480;
+ ATOM_CB_SERVICE_FEATURE_CHANGED = 481;
+ ATOM_CB_RECEIVER_FEATURE_CHANGED = 482;
+ ATOM_JSSCRIPTENGINE_LATENCY_REPORTED = 483;
+ ATOM_PRIVACY_SIGNAL_NOTIFICATION_INTERACTION = 484;
+ ATOM_PRIVACY_SIGNAL_ISSUE_CARD_INTERACTION = 485;
+ ATOM_PRIVACY_SIGNALS_JOB_FAILURE = 486;
ATOM_VIBRATION_REPORTED = 487;
ATOM_UWB_RANGING_START = 489;
+ ATOM_MOBILE_DATA_DOWNLOAD_FILE_GROUP_STATUS_REPORTED = 490;
+ ATOM_APP_COMPACTED_V2 = 491;
+ ATOM_AD_SERVICES_SETTINGS_USAGE_REPORTED = 493;
ATOM_DISPLAY_BRIGHTNESS_CHANGED = 494;
ATOM_ACTIVITY_ACTION_BLOCKED = 495;
+ ATOM_BACKGROUND_FETCH_PROCESS_REPORTED = 496;
+ ATOM_UPDATE_CUSTOM_AUDIENCE_PROCESS_REPORTED = 497;
+ ATOM_RUN_AD_BIDDING_PROCESS_REPORTED = 498;
+ ATOM_RUN_AD_SCORING_PROCESS_REPORTED = 499;
+ ATOM_RUN_AD_SELECTION_PROCESS_REPORTED = 500;
+ ATOM_RUN_AD_BIDDING_PER_CA_PROCESS_REPORTED = 501;
+ ATOM_MOBILE_DATA_DOWNLOAD_DOWNLOAD_RESULT_REPORTED = 502;
+ ATOM_MOBILE_DATA_DOWNLOAD_FILE_GROUP_STORAGE_STATS_REPORTED = 503;
ATOM_NETWORK_DNS_SERVER_SUPPORT_REPORTED = 504;
ATOM_VM_BOOTED = 505;
ATOM_VM_EXITED = 506;
@@ -2115,13 +2138,19 @@
ATOM_MEDIAMETRICS_SPATIALIZERDEVICEENABLED_REPORTED = 509;
ATOM_MEDIAMETRICS_HEADTRACKERDEVICEENABLED_REPORTED = 510;
ATOM_MEDIAMETRICS_HEADTRACKERDEVICESUPPORTED_REPORTED = 511;
+ ATOM_AD_SERVICES_MEASUREMENT_REGISTRATIONS = 512;
ATOM_HEARING_AID_INFO_REPORTED = 513;
ATOM_DEVICE_WIDE_JOB_CONSTRAINT_CHANGED = 514;
+ ATOM_AMBIENT_MODE_CHANGED = 515;
+ ATOM_ANR_LATENCY_REPORTED = 516;
+ ATOM_RESOURCE_API_INFO = 517;
+ ATOM_SYSTEM_DEFAULT_NETWORK_CHANGED = 518;
ATOM_IWLAN_SETUP_DATA_CALL_RESULT_REPORTED = 519;
ATOM_IWLAN_PDN_DISCONNECTED_REASON_REPORTED = 520;
ATOM_AIRPLANE_MODE_SESSION_REPORTED = 521;
ATOM_VM_CPU_STATUS_REPORTED = 522;
ATOM_VM_MEM_STATUS_REPORTED = 523;
+ ATOM_PACKAGE_INSTALLATION_SESSION_REPORTED = 524;
ATOM_DEFAULT_NETWORK_REMATCH_INFO = 525;
ATOM_NETWORK_SELECTION_PERFORMANCE = 526;
ATOM_NETWORK_NSD_REPORTED = 527;
@@ -2131,22 +2160,65 @@
ATOM_BLUETOOTH_LOCAL_SUPPORTED_FEATURES_REPORTED = 532;
ATOM_BLUETOOTH_GATT_APP_INFO = 533;
ATOM_BRIGHTNESS_CONFIGURATION_UPDATED = 534;
+ ATOM_AD_SERVICES_GET_TOPICS_REPORTED = 535;
+ ATOM_AD_SERVICES_EPOCH_COMPUTATION_GET_TOP_TOPICS_REPORTED = 536;
+ ATOM_AD_SERVICES_EPOCH_COMPUTATION_CLASSIFIER_REPORTED = 537;
+ ATOM_WEAR_MEDIA_OUTPUT_SWITCHER_LAUNCHED = 538;
+ ATOM_WEAR_MEDIA_OUTPUT_SWITCHER_FINISHED = 539;
+ ATOM_WEAR_MEDIA_OUTPUT_SWITCHER_CONNECTION_REPORTED = 540;
+ ATOM_WEAR_MEDIA_OUTPUT_SWITCHER_DEVICE_SCAN_TRIGGERED = 541;
+ ATOM_WEAR_MEDIA_OUTPUT_SWITCHER_FIRST_DEVICE_SCAN_LATENCY = 542;
+ ATOM_WEAR_MEDIA_OUTPUT_SWITCHER_CONNECT_DEVICE_LATENCY = 543;
+ ATOM_PACKAGE_MANAGER_SNAPSHOT_REPORTED = 544;
+ ATOM_PACKAGE_MANAGER_APPS_FILTER_CACHE_BUILD_REPORTED = 545;
+ ATOM_PACKAGE_MANAGER_APPS_FILTER_CACHE_UPDATE_REPORTED = 546;
ATOM_LAUNCHER_IMPRESSION_EVENT = 547;
- ATOM_ODSIGN_REPORTED = 548;
- ATOM_ART_DEVICE_DATUM_REPORTED = 550;
+ ATOM_WEAR_MEDIA_OUTPUT_SWITCHER_ALL_DEVICES_SCAN_LATENCY = 549;
+ ATOM_WS_WATCH_FACE_EDITED = 551;
+ ATOM_WS_WATCH_FACE_FAVORITE_ACTION_REPORTED = 552;
+ ATOM_WS_WATCH_FACE_SET_ACTION_REPORTED = 553;
+ ATOM_PACKAGE_UNINSTALLATION_REPORTED = 554;
+ ATOM_GAME_MODE_CHANGED = 555;
+ ATOM_GAME_MODE_CONFIGURATION_CHANGED = 556;
+ ATOM_BEDTIME_MODE_STATE_CHANGED = 557;
ATOM_NETWORK_SLICE_SESSION_ENDED = 558;
ATOM_NETWORK_SLICE_DAILY_DATA_USAGE_REPORTED = 559;
ATOM_NFC_TAG_TYPE_OCCURRED = 560;
ATOM_NFC_AID_CONFLICT_OCCURRED = 561;
ATOM_NFC_READER_CONFLICT_OCCURRED = 562;
- ATOM_ART_DATUM_DELTA_REPORTED = 565;
+ ATOM_WS_TILE_LIST_CHANGED = 563;
+ ATOM_GET_TYPE_ACCESSED_WITHOUT_PERMISSION = 564;
+ ATOM_MOBILE_BUNDLED_APP_INFO_GATHERED = 566;
+ ATOM_WS_WATCH_FACE_COMPLICATION_SET_CHANGED = 567;
ATOM_MEDIA_DRM_CREATED = 568;
ATOM_MEDIA_DRM_ERRORED = 569;
ATOM_MEDIA_DRM_SESSION_OPENED = 570;
ATOM_MEDIA_DRM_SESSION_CLOSED = 571;
+ ATOM_USER_SELECTED_RESOLUTION = 572;
+ ATOM_UNSAFE_INTENT_EVENT_REPORTED = 573;
ATOM_PERFORMANCE_HINT_SESSION_REPORTED = 574;
+ ATOM_MEDIAMETRICS_MIDI_DEVICE_CLOSE_REPORTED = 576;
+ ATOM_BIOMETRIC_TOUCH_REPORTED = 577;
ATOM_HOTWORD_AUDIO_EGRESS_EVENT_REPORTED = 578;
+ ATOM_APP_SEARCH_SCHEMA_MIGRATION_STATS_REPORTED = 579;
+ ATOM_LOCATION_ENABLED_STATE_CHANGED = 580;
+ ATOM_IME_REQUEST_FINISHED = 581;
+ ATOM_USB_COMPLIANCE_WARNINGS_REPORTED = 582;
+ ATOM_APP_SUPPORTED_LOCALES_CHANGED = 583;
+ ATOM_GRAMMATICAL_INFLECTION_CHANGED = 584;
+ ATOM_MEDIA_PROVIDER_VOLUME_RECOVERY_REPORTED = 586;
+ ATOM_BIOMETRIC_PROPERTIES_COLLECTED = 587;
+ ATOM_KERNEL_WAKEUP_ATTRIBUTED = 588;
+ ATOM_SCREEN_STATE_CHANGED_V2 = 589;
+ ATOM_WS_BACKUP_ACTION_REPORTED = 590;
+ ATOM_WS_RESTORE_ACTION_REPORTED = 591;
+ ATOM_DEVICE_LOG_ACCESS_EVENT_REPORTED = 592;
+ ATOM_MEDIA_SESSION_UPDATED = 594;
+ ATOM_WEAR_OOBE_STATE_CHANGED = 595;
+ ATOM_WS_NOTIFICATION_UPDATED = 596;
ATOM_NETWORK_VALIDATION_FAILURE_STATS_DAILY_REPORTED = 601;
+ ATOM_WS_COMPLICATION_TAPPED = 602;
+ ATOM_WS_WEAR_TIME_SESSION = 610;
ATOM_WIFI_BYTES_TRANSFER = 10000;
ATOM_WIFI_BYTES_TRANSFER_BY_FG_BG = 10001;
ATOM_MOBILE_BYTES_TRANSFER = 10002;
@@ -2299,15 +2371,160 @@
ATOM_TELEPHONY_NETWORK_REQUESTS_V2 = 10153;
ATOM_DEVICE_TELEPHONY_PROPERTIES = 10154;
ATOM_REMOTE_KEY_PROVISIONING_ERROR_COUNTS = 10155;
+ ATOM_SAFETY_STATE = 10156;
ATOM_INCOMING_MMS = 10157;
ATOM_OUTGOING_MMS = 10158;
ATOM_MULTI_USER_INFO = 10160;
ATOM_NETWORK_BPF_MAP_INFO = 10161;
+ ATOM_OUTGOING_SHORT_CODE_SMS = 10162;
ATOM_CONNECTIVITY_STATE_SAMPLE = 10163;
ATOM_NETWORK_SELECTION_REMATCH_REASONS_INFO = 10164;
+ ATOM_GAME_MODE_INFO = 10165;
+ ATOM_GAME_MODE_CONFIGURATION = 10166;
+ ATOM_GAME_MODE_LISTENER = 10167;
ATOM_NETWORK_SLICE_REQUEST_COUNT = 10168;
+ ATOM_WS_TILE_SNAPSHOT = 10169;
+ ATOM_WS_ACTIVE_WATCH_FACE_COMPLICATION_SET_SNAPSHOT = 10170;
+ ATOM_PROCESS_STATE = 10171;
+ ATOM_PROCESS_ASSOCIATION = 10172;
ATOM_ADPF_SYSTEM_COMPONENT_INFO = 10173;
ATOM_NOTIFICATION_MEMORY_USE = 10174;
+ ATOM_HDR_CAPABILITIES = 10175;
+ ATOM_WS_FAVOURITE_WATCH_FACE_LIST_SNAPSHOT = 10176;
+ ATOM_WIFI_AWARE_NDP_REPORTED = 638;
+ ATOM_WIFI_AWARE_ATTACH_REPORTED = 639;
+ ATOM_WIFI_SELF_RECOVERY_TRIGGERED = 661;
+ ATOM_SOFT_AP_STARTED = 680;
+ ATOM_SOFT_AP_STOPPED = 681;
+ ATOM_WIFI_LOCK_RELEASED = 687;
+ ATOM_WIFI_LOCK_DEACTIVATED = 688;
+ ATOM_WIFI_CONFIG_SAVED = 689;
+ ATOM_WIFI_AWARE_RESOURCE_USING_CHANGED = 690;
+ ATOM_WIFI_AWARE_HAL_API_CALLED = 691;
+ ATOM_WIFI_LOCAL_ONLY_REQUEST_RECEIVED = 692;
+ ATOM_WIFI_LOCAL_ONLY_REQUEST_SCAN_TRIGGERED = 693;
+ ATOM_WIFI_THREAD_TASK_EXECUTED = 694;
+ ATOM_WIFI_STATE_CHANGED = 700;
+ ATOM_WIFI_AWARE_CAPABILITIES = 10190;
+ ATOM_WIFI_MODULE_INFO = 10193;
+ ATOM_SETTINGS_SPA_REPORTED = 622;
+ ATOM_EXPRESS_EVENT_REPORTED = 528;
+ ATOM_EXPRESS_HISTOGRAM_SAMPLE_REPORTED = 593;
+ ATOM_EXPRESS_UID_EVENT_REPORTED = 644;
+ ATOM_EXPRESS_UID_HISTOGRAM_SAMPLE_REPORTED = 658;
+ ATOM_PERMISSION_RATIONALE_DIALOG_VIEWED = 645;
+ ATOM_PERMISSION_RATIONALE_DIALOG_ACTION_REPORTED = 646;
+ ATOM_APP_DATA_SHARING_UPDATES_NOTIFICATION_INTERACTION = 647;
+ ATOM_APP_DATA_SHARING_UPDATES_FRAGMENT_VIEWED = 648;
+ ATOM_APP_DATA_SHARING_UPDATES_FRAGMENT_ACTION_REPORTED = 649;
+ ATOM_WS_INCOMING_CALL_ACTION_REPORTED = 626;
+ ATOM_WS_CALL_DISCONNECTION_REPORTED = 627;
+ ATOM_WS_CALL_DURATION_REPORTED = 628;
+ ATOM_WS_CALL_USER_EXPERIENCE_LATENCY_REPORTED = 629;
+ ATOM_WS_CALL_INTERACTION_REPORTED = 630;
+ ATOM_FULL_SCREEN_INTENT_LAUNCHED = 631;
+ ATOM_BAL_ALLOWED = 632;
+ ATOM_IN_TASK_ACTIVITY_STARTED = 685;
+ ATOM_CACHED_APPS_HIGH_WATERMARK = 10189;
+ ATOM_ODREFRESH_REPORTED = 366;
+ ATOM_ODSIGN_REPORTED = 548;
+ ATOM_ART_DATUM_REPORTED = 332;
+ ATOM_ART_DEVICE_DATUM_REPORTED = 550;
+ ATOM_ART_DATUM_DELTA_REPORTED = 565;
+ ATOM_BACKGROUND_DEXOPT_JOB_ENDED = 467;
+ ATOM_WEAR_ADAPTIVE_SUSPEND_STATS_REPORTED = 619;
+ ATOM_WEAR_POWER_ANOMALY_SERVICE_OPERATIONAL_STATS_REPORTED = 620;
+ ATOM_WEAR_POWER_ANOMALY_SERVICE_EVENT_STATS_REPORTED = 621;
+ ATOM_EMERGENCY_STATE_CHANGED = 633;
+ ATOM_DND_STATE_CHANGED = 657;
+ ATOM_MTE_STATE = 10181;
+ ATOM_AD_SERVICES_BACK_COMPAT_GET_TOPICS_REPORTED = 598;
+ ATOM_AD_SERVICES_BACK_COMPAT_EPOCH_COMPUTATION_CLASSIFIER_REPORTED = 599;
+ ATOM_AD_SERVICES_MEASUREMENT_DEBUG_KEYS = 640;
+ ATOM_AD_SERVICES_ERROR_REPORTED = 662;
+ ATOM_AD_SERVICES_BACKGROUND_JOBS_EXECUTION_REPORTED = 663;
+ ATOM_AD_SERVICES_MEASUREMENT_DELAYED_SOURCE_REGISTRATION = 673;
+ ATOM_AD_SERVICES_MEASUREMENT_ATTRIBUTION = 674;
+ ATOM_AD_SERVICES_MEASUREMENT_JOBS = 675;
+ ATOM_AD_SERVICES_MEASUREMENT_WIPEOUT = 676;
+ ATOM_AD_SERVICES_CONSENT_MIGRATED = 702;
+ ATOM_RKPD_POOL_STATS = 664;
+ ATOM_RKPD_CLIENT_OPERATION = 665;
+ ATOM_AUTOFILL_UI_EVENT_REPORTED = 603;
+ ATOM_AUTOFILL_FILL_REQUEST_REPORTED = 604;
+ ATOM_AUTOFILL_FILL_RESPONSE_REPORTED = 605;
+ ATOM_AUTOFILL_SAVE_EVENT_REPORTED = 606;
+ ATOM_AUTOFILL_SESSION_COMMITTED = 607;
+ ATOM_AUTOFILL_FIELD_CLASSIFICATION_EVENT_REPORTED = 659;
+ ATOM_TEST_EXTENSION_ATOM_REPORTED = 660;
+ ATOM_TEST_RESTRICTED_ATOM_REPORTED = 672;
+ ATOM_STATS_SOCKET_LOSS_REPORTED = 752;
+ ATOM_PLUGIN_INITIALIZED = 655;
+ ATOM_TV_LOW_POWER_STANDBY_POLICY = 679;
+ ATOM_LOCKSCREEN_SHORTCUT_SELECTED = 611;
+ ATOM_LOCKSCREEN_SHORTCUT_TRIGGERED = 612;
+ ATOM_EMERGENCY_NUMBERS_INFO = 10180;
+ ATOM_QUALIFIED_RAT_LIST_CHANGED = 634;
+ ATOM_QNS_IMS_CALL_DROP_STATS = 635;
+ ATOM_QNS_FALLBACK_RESTRICTION_CHANGED = 636;
+ ATOM_QNS_RAT_PREFERENCE_MISMATCH_INFO = 10177;
+ ATOM_QNS_HANDOVER_TIME_MILLIS = 10178;
+ ATOM_QNS_HANDOVER_PINGPONG = 10179;
+ ATOM_SATELLITE_CONTROLLER = 10182;
+ ATOM_SATELLITE_SESSION = 10183;
+ ATOM_SATELLITE_INCOMING_DATAGRAM = 10184;
+ ATOM_SATELLITE_OUTGOING_DATAGRAM = 10185;
+ ATOM_SATELLITE_PROVISION = 10186;
+ ATOM_SATELLITE_SOS_MESSAGE_RECOMMENDER = 10187;
+ ATOM_IKE_SESSION_TERMINATED = 678;
+ ATOM_IKE_LIVENESS_CHECK_SESSION_VALIDATED = 760;
+ ATOM_BLUETOOTH_HASHED_DEVICE_NAME_REPORTED = 613;
+ ATOM_BLUETOOTH_L2CAP_COC_CLIENT_CONNECTION = 614;
+ ATOM_BLUETOOTH_L2CAP_COC_SERVER_CONNECTION = 615;
+ ATOM_BLUETOOTH_LE_SESSION_CONNECTED = 656;
+ ATOM_RESTRICTED_BLUETOOTH_DEVICE_NAME_REPORTED = 666;
+ ATOM_BLUETOOTH_PROFILE_CONNECTION_ATTEMPTED = 696;
+ ATOM_HEALTH_CONNECT_UI_IMPRESSION = 623;
+ ATOM_HEALTH_CONNECT_UI_INTERACTION = 624;
+ ATOM_HEALTH_CONNECT_APP_OPENED_REPORTED = 625;
+ ATOM_HEALTH_CONNECT_API_CALLED = 616;
+ ATOM_HEALTH_CONNECT_USAGE_STATS = 617;
+ ATOM_HEALTH_CONNECT_STORAGE_STATS = 618;
+ ATOM_HEALTH_CONNECT_API_INVOKED = 643;
+ ATOM_EXERCISE_ROUTE_API_CALLED = 654;
+ ATOM_ATOM_9999 = 9999;
+ ATOM_ATOM_99999 = 99999;
+ ATOM_THREADNETWORK_TELEMETRY_DATA_REPORTED = 738;
+ ATOM_THREADNETWORK_TOPO_ENTRY_REPEATED = 739;
+ ATOM_THREADNETWORK_DEVICE_INFO_REPORTED = 740;
+ ATOM_EMERGENCY_NUMBER_DIALED = 637;
+ ATOM_SANDBOX_API_CALLED = 488;
+ ATOM_SANDBOX_ACTIVITY_EVENT_OCCURRED = 735;
+ ATOM_SANDBOX_SDK_STORAGE = 10159;
+ ATOM_CRONET_ENGINE_CREATED = 703;
+ ATOM_CRONET_TRAFFIC_REPORTED = 704;
+ ATOM_CRONET_ENGINE_BUILDER_INITIALIZED = 762;
+ ATOM_CRONET_HTTP_FLAGS_INITIALIZED = 763;
+ ATOM_CRONET_INITIALIZED = 764;
+ ATOM_DAILY_KEEPALIVE_INFO_REPORTED = 650;
+ ATOM_IP_CLIENT_RA_INFO_REPORTED = 778;
+ ATOM_APF_SESSION_INFO_REPORTED = 777;
+ ATOM_CREDENTIAL_MANAGER_API_CALLED = 585;
+ ATOM_CREDENTIAL_MANAGER_INIT_PHASE_REPORTED = 651;
+ ATOM_CREDENTIAL_MANAGER_CANDIDATE_PHASE_REPORTED = 652;
+ ATOM_CREDENTIAL_MANAGER_FINAL_PHASE_REPORTED = 653;
+ ATOM_CREDENTIAL_MANAGER_TOTAL_REPORTED = 667;
+ ATOM_CREDENTIAL_MANAGER_FINALNOUID_REPORTED = 668;
+ ATOM_CREDENTIAL_MANAGER_GET_REPORTED = 669;
+ ATOM_CREDENTIAL_MANAGER_AUTH_CLICK_REPORTED = 670;
+ ATOM_CREDENTIAL_MANAGER_APIV2_CALLED = 671;
+ ATOM_UWB_ACTIVITY_INFO = 10188;
+ ATOM_MEDIA_ACTION_REPORTED = 608;
+ ATOM_MEDIA_CONTROLS_LAUNCHED = 609;
+ ATOM_MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED = 600;
+ ATOM_MEDIA_CODEC_STARTED = 641;
+ ATOM_MEDIA_CODEC_STOPPED = 642;
+ ATOM_MEDIA_CODEC_RENDERED = 684;
}
// End of protos/perfetto/config/statsd/atom_ids.proto
diff --git a/protos/perfetto/config/statsd/atom_ids.proto b/protos/perfetto/config/statsd/atom_ids.proto
index fbdd194..c436571 100644
--- a/protos/perfetto/config/statsd/atom_ids.proto
+++ b/protos/perfetto/config/statsd/atom_ids.proto
@@ -349,7 +349,6 @@
ATOM_PERFETTO_TRIGGER = 329;
ATOM_TRANSCODING_DATA = 330;
ATOM_IMS_SERVICE_ENTITLEMENT_UPDATED = 331;
- ATOM_ART_DATUM_REPORTED = 332;
ATOM_DEVICE_ROTATED = 333;
ATOM_SIM_SPECIFIC_SETTINGS_RESTORED = 334;
ATOM_TEXT_CLASSIFIER_DOWNLOAD_REPORTED = 335;
@@ -379,7 +378,6 @@
ATOM_LOCATION_TIME_ZONE_PROVIDER_STATE_CHANGED = 359;
ATOM_FDTRACK_EVENT_OCCURRED = 364;
ATOM_TIMEOUT_AUTO_EXTENDED_REPORTED = 365;
- ATOM_ODREFRESH_REPORTED = 366;
ATOM_ALARM_BATCH_DELIVERED = 367;
ATOM_ALARM_SCHEDULED = 368;
ATOM_CAR_WATCHDOG_IO_OVERUSE_STATS_REPORTED = 369;
@@ -447,6 +445,8 @@
ATOM_HOTWORD_DETECTION_SERVICE_RESTARTED = 432;
ATOM_HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED = 433;
ATOM_HOTWORD_DETECTOR_EVENTS = 434;
+ ATOM_AD_SERVICES_API_CALLED = 435;
+ ATOM_AD_SERVICES_MESUREMENT_REPORTS_UPLOADED = 436;
ATOM_BOOT_COMPLETED_BROADCAST_COMPLETION_LATENCY_REPORTED = 437;
ATOM_CONTACTS_INDEXER_UPDATE_STATS_REPORTED = 440;
ATOM_APP_BACKGROUND_RESTRICTIONS_INFO = 441;
@@ -468,24 +468,47 @@
ATOM_ISOLATED_COMPILATION_SCHEDULED = 457;
ATOM_ISOLATED_COMPILATION_ENDED = 458;
ATOM_ONS_OPPORTUNISTIC_ESIM_PROVISIONING_COMPLETE = 459;
+ ATOM_SYSTEM_SERVER_PRE_WATCHDOG_OCCURRED = 460;
ATOM_TELEPHONY_ANOMALY_DETECTED = 461;
ATOM_LETTERBOX_POSITION_CHANGED = 462;
ATOM_REMOTE_KEY_PROVISIONING_ATTEMPT = 463;
ATOM_REMOTE_KEY_PROVISIONING_NETWORK_INFO = 464;
ATOM_REMOTE_KEY_PROVISIONING_TIMING = 465;
ATOM_MEDIAOUTPUT_OP_INTERACTION_REPORT = 466;
- ATOM_BACKGROUND_DEXOPT_JOB_ENDED = 467;
ATOM_SYNC_EXEMPTION_OCCURRED = 468;
ATOM_AUTOFILL_PRESENTATION_EVENT_REPORTED = 469;
ATOM_DOCK_STATE_CHANGED = 470;
+ ATOM_SAFETY_SOURCE_STATE_COLLECTED = 471;
+ ATOM_SAFETY_CENTER_SYSTEM_EVENT_REPORTED = 472;
+ ATOM_SAFETY_CENTER_INTERACTION_REPORTED = 473;
+ ATOM_SETTINGS_PROVIDER_SETTING_CHANGED = 474;
ATOM_BROADCAST_DELIVERY_EVENT_REPORTED = 475;
ATOM_SERVICE_REQUEST_EVENT_REPORTED = 476;
ATOM_PROVIDER_ACQUISITION_EVENT_REPORTED = 477;
ATOM_BLUETOOTH_DEVICE_NAME_REPORTED = 478;
+ ATOM_CB_CONFIG_UPDATED = 479;
+ ATOM_CB_MODULE_ERROR_REPORTED = 480;
+ ATOM_CB_SERVICE_FEATURE_CHANGED = 481;
+ ATOM_CB_RECEIVER_FEATURE_CHANGED = 482;
+ ATOM_JSSCRIPTENGINE_LATENCY_REPORTED = 483;
+ ATOM_PRIVACY_SIGNAL_NOTIFICATION_INTERACTION = 484;
+ ATOM_PRIVACY_SIGNAL_ISSUE_CARD_INTERACTION = 485;
+ ATOM_PRIVACY_SIGNALS_JOB_FAILURE = 486;
ATOM_VIBRATION_REPORTED = 487;
ATOM_UWB_RANGING_START = 489;
+ ATOM_MOBILE_DATA_DOWNLOAD_FILE_GROUP_STATUS_REPORTED = 490;
+ ATOM_APP_COMPACTED_V2 = 491;
+ ATOM_AD_SERVICES_SETTINGS_USAGE_REPORTED = 493;
ATOM_DISPLAY_BRIGHTNESS_CHANGED = 494;
ATOM_ACTIVITY_ACTION_BLOCKED = 495;
+ ATOM_BACKGROUND_FETCH_PROCESS_REPORTED = 496;
+ ATOM_UPDATE_CUSTOM_AUDIENCE_PROCESS_REPORTED = 497;
+ ATOM_RUN_AD_BIDDING_PROCESS_REPORTED = 498;
+ ATOM_RUN_AD_SCORING_PROCESS_REPORTED = 499;
+ ATOM_RUN_AD_SELECTION_PROCESS_REPORTED = 500;
+ ATOM_RUN_AD_BIDDING_PER_CA_PROCESS_REPORTED = 501;
+ ATOM_MOBILE_DATA_DOWNLOAD_DOWNLOAD_RESULT_REPORTED = 502;
+ ATOM_MOBILE_DATA_DOWNLOAD_FILE_GROUP_STORAGE_STATS_REPORTED = 503;
ATOM_NETWORK_DNS_SERVER_SUPPORT_REPORTED = 504;
ATOM_VM_BOOTED = 505;
ATOM_VM_EXITED = 506;
@@ -494,13 +517,19 @@
ATOM_MEDIAMETRICS_SPATIALIZERDEVICEENABLED_REPORTED = 509;
ATOM_MEDIAMETRICS_HEADTRACKERDEVICEENABLED_REPORTED = 510;
ATOM_MEDIAMETRICS_HEADTRACKERDEVICESUPPORTED_REPORTED = 511;
+ ATOM_AD_SERVICES_MEASUREMENT_REGISTRATIONS = 512;
ATOM_HEARING_AID_INFO_REPORTED = 513;
ATOM_DEVICE_WIDE_JOB_CONSTRAINT_CHANGED = 514;
+ ATOM_AMBIENT_MODE_CHANGED = 515;
+ ATOM_ANR_LATENCY_REPORTED = 516;
+ ATOM_RESOURCE_API_INFO = 517;
+ ATOM_SYSTEM_DEFAULT_NETWORK_CHANGED = 518;
ATOM_IWLAN_SETUP_DATA_CALL_RESULT_REPORTED = 519;
ATOM_IWLAN_PDN_DISCONNECTED_REASON_REPORTED = 520;
ATOM_AIRPLANE_MODE_SESSION_REPORTED = 521;
ATOM_VM_CPU_STATUS_REPORTED = 522;
ATOM_VM_MEM_STATUS_REPORTED = 523;
+ ATOM_PACKAGE_INSTALLATION_SESSION_REPORTED = 524;
ATOM_DEFAULT_NETWORK_REMATCH_INFO = 525;
ATOM_NETWORK_SELECTION_PERFORMANCE = 526;
ATOM_NETWORK_NSD_REPORTED = 527;
@@ -510,22 +539,65 @@
ATOM_BLUETOOTH_LOCAL_SUPPORTED_FEATURES_REPORTED = 532;
ATOM_BLUETOOTH_GATT_APP_INFO = 533;
ATOM_BRIGHTNESS_CONFIGURATION_UPDATED = 534;
+ ATOM_AD_SERVICES_GET_TOPICS_REPORTED = 535;
+ ATOM_AD_SERVICES_EPOCH_COMPUTATION_GET_TOP_TOPICS_REPORTED = 536;
+ ATOM_AD_SERVICES_EPOCH_COMPUTATION_CLASSIFIER_REPORTED = 537;
+ ATOM_WEAR_MEDIA_OUTPUT_SWITCHER_LAUNCHED = 538;
+ ATOM_WEAR_MEDIA_OUTPUT_SWITCHER_FINISHED = 539;
+ ATOM_WEAR_MEDIA_OUTPUT_SWITCHER_CONNECTION_REPORTED = 540;
+ ATOM_WEAR_MEDIA_OUTPUT_SWITCHER_DEVICE_SCAN_TRIGGERED = 541;
+ ATOM_WEAR_MEDIA_OUTPUT_SWITCHER_FIRST_DEVICE_SCAN_LATENCY = 542;
+ ATOM_WEAR_MEDIA_OUTPUT_SWITCHER_CONNECT_DEVICE_LATENCY = 543;
+ ATOM_PACKAGE_MANAGER_SNAPSHOT_REPORTED = 544;
+ ATOM_PACKAGE_MANAGER_APPS_FILTER_CACHE_BUILD_REPORTED = 545;
+ ATOM_PACKAGE_MANAGER_APPS_FILTER_CACHE_UPDATE_REPORTED = 546;
ATOM_LAUNCHER_IMPRESSION_EVENT = 547;
- ATOM_ODSIGN_REPORTED = 548;
- ATOM_ART_DEVICE_DATUM_REPORTED = 550;
+ ATOM_WEAR_MEDIA_OUTPUT_SWITCHER_ALL_DEVICES_SCAN_LATENCY = 549;
+ ATOM_WS_WATCH_FACE_EDITED = 551;
+ ATOM_WS_WATCH_FACE_FAVORITE_ACTION_REPORTED = 552;
+ ATOM_WS_WATCH_FACE_SET_ACTION_REPORTED = 553;
+ ATOM_PACKAGE_UNINSTALLATION_REPORTED = 554;
+ ATOM_GAME_MODE_CHANGED = 555;
+ ATOM_GAME_MODE_CONFIGURATION_CHANGED = 556;
+ ATOM_BEDTIME_MODE_STATE_CHANGED = 557;
ATOM_NETWORK_SLICE_SESSION_ENDED = 558;
ATOM_NETWORK_SLICE_DAILY_DATA_USAGE_REPORTED = 559;
ATOM_NFC_TAG_TYPE_OCCURRED = 560;
ATOM_NFC_AID_CONFLICT_OCCURRED = 561;
ATOM_NFC_READER_CONFLICT_OCCURRED = 562;
- ATOM_ART_DATUM_DELTA_REPORTED = 565;
+ ATOM_WS_TILE_LIST_CHANGED = 563;
+ ATOM_GET_TYPE_ACCESSED_WITHOUT_PERMISSION = 564;
+ ATOM_MOBILE_BUNDLED_APP_INFO_GATHERED = 566;
+ ATOM_WS_WATCH_FACE_COMPLICATION_SET_CHANGED = 567;
ATOM_MEDIA_DRM_CREATED = 568;
ATOM_MEDIA_DRM_ERRORED = 569;
ATOM_MEDIA_DRM_SESSION_OPENED = 570;
ATOM_MEDIA_DRM_SESSION_CLOSED = 571;
+ ATOM_USER_SELECTED_RESOLUTION = 572;
+ ATOM_UNSAFE_INTENT_EVENT_REPORTED = 573;
ATOM_PERFORMANCE_HINT_SESSION_REPORTED = 574;
+ ATOM_MEDIAMETRICS_MIDI_DEVICE_CLOSE_REPORTED = 576;
+ ATOM_BIOMETRIC_TOUCH_REPORTED = 577;
ATOM_HOTWORD_AUDIO_EGRESS_EVENT_REPORTED = 578;
+ ATOM_APP_SEARCH_SCHEMA_MIGRATION_STATS_REPORTED = 579;
+ ATOM_LOCATION_ENABLED_STATE_CHANGED = 580;
+ ATOM_IME_REQUEST_FINISHED = 581;
+ ATOM_USB_COMPLIANCE_WARNINGS_REPORTED = 582;
+ ATOM_APP_SUPPORTED_LOCALES_CHANGED = 583;
+ ATOM_GRAMMATICAL_INFLECTION_CHANGED = 584;
+ ATOM_MEDIA_PROVIDER_VOLUME_RECOVERY_REPORTED = 586;
+ ATOM_BIOMETRIC_PROPERTIES_COLLECTED = 587;
+ ATOM_KERNEL_WAKEUP_ATTRIBUTED = 588;
+ ATOM_SCREEN_STATE_CHANGED_V2 = 589;
+ ATOM_WS_BACKUP_ACTION_REPORTED = 590;
+ ATOM_WS_RESTORE_ACTION_REPORTED = 591;
+ ATOM_DEVICE_LOG_ACCESS_EVENT_REPORTED = 592;
+ ATOM_MEDIA_SESSION_UPDATED = 594;
+ ATOM_WEAR_OOBE_STATE_CHANGED = 595;
+ ATOM_WS_NOTIFICATION_UPDATED = 596;
ATOM_NETWORK_VALIDATION_FAILURE_STATS_DAILY_REPORTED = 601;
+ ATOM_WS_COMPLICATION_TAPPED = 602;
+ ATOM_WS_WEAR_TIME_SESSION = 610;
ATOM_WIFI_BYTES_TRANSFER = 10000;
ATOM_WIFI_BYTES_TRANSFER_BY_FG_BG = 10001;
ATOM_MOBILE_BYTES_TRANSFER = 10002;
@@ -678,13 +750,158 @@
ATOM_TELEPHONY_NETWORK_REQUESTS_V2 = 10153;
ATOM_DEVICE_TELEPHONY_PROPERTIES = 10154;
ATOM_REMOTE_KEY_PROVISIONING_ERROR_COUNTS = 10155;
+ ATOM_SAFETY_STATE = 10156;
ATOM_INCOMING_MMS = 10157;
ATOM_OUTGOING_MMS = 10158;
ATOM_MULTI_USER_INFO = 10160;
ATOM_NETWORK_BPF_MAP_INFO = 10161;
+ ATOM_OUTGOING_SHORT_CODE_SMS = 10162;
ATOM_CONNECTIVITY_STATE_SAMPLE = 10163;
ATOM_NETWORK_SELECTION_REMATCH_REASONS_INFO = 10164;
+ ATOM_GAME_MODE_INFO = 10165;
+ ATOM_GAME_MODE_CONFIGURATION = 10166;
+ ATOM_GAME_MODE_LISTENER = 10167;
ATOM_NETWORK_SLICE_REQUEST_COUNT = 10168;
+ ATOM_WS_TILE_SNAPSHOT = 10169;
+ ATOM_WS_ACTIVE_WATCH_FACE_COMPLICATION_SET_SNAPSHOT = 10170;
+ ATOM_PROCESS_STATE = 10171;
+ ATOM_PROCESS_ASSOCIATION = 10172;
ATOM_ADPF_SYSTEM_COMPONENT_INFO = 10173;
ATOM_NOTIFICATION_MEMORY_USE = 10174;
+ ATOM_HDR_CAPABILITIES = 10175;
+ ATOM_WS_FAVOURITE_WATCH_FACE_LIST_SNAPSHOT = 10176;
+ ATOM_WIFI_AWARE_NDP_REPORTED = 638;
+ ATOM_WIFI_AWARE_ATTACH_REPORTED = 639;
+ ATOM_WIFI_SELF_RECOVERY_TRIGGERED = 661;
+ ATOM_SOFT_AP_STARTED = 680;
+ ATOM_SOFT_AP_STOPPED = 681;
+ ATOM_WIFI_LOCK_RELEASED = 687;
+ ATOM_WIFI_LOCK_DEACTIVATED = 688;
+ ATOM_WIFI_CONFIG_SAVED = 689;
+ ATOM_WIFI_AWARE_RESOURCE_USING_CHANGED = 690;
+ ATOM_WIFI_AWARE_HAL_API_CALLED = 691;
+ ATOM_WIFI_LOCAL_ONLY_REQUEST_RECEIVED = 692;
+ ATOM_WIFI_LOCAL_ONLY_REQUEST_SCAN_TRIGGERED = 693;
+ ATOM_WIFI_THREAD_TASK_EXECUTED = 694;
+ ATOM_WIFI_STATE_CHANGED = 700;
+ ATOM_WIFI_AWARE_CAPABILITIES = 10190;
+ ATOM_WIFI_MODULE_INFO = 10193;
+ ATOM_SETTINGS_SPA_REPORTED = 622;
+ ATOM_EXPRESS_EVENT_REPORTED = 528;
+ ATOM_EXPRESS_HISTOGRAM_SAMPLE_REPORTED = 593;
+ ATOM_EXPRESS_UID_EVENT_REPORTED = 644;
+ ATOM_EXPRESS_UID_HISTOGRAM_SAMPLE_REPORTED = 658;
+ ATOM_PERMISSION_RATIONALE_DIALOG_VIEWED = 645;
+ ATOM_PERMISSION_RATIONALE_DIALOG_ACTION_REPORTED = 646;
+ ATOM_APP_DATA_SHARING_UPDATES_NOTIFICATION_INTERACTION = 647;
+ ATOM_APP_DATA_SHARING_UPDATES_FRAGMENT_VIEWED = 648;
+ ATOM_APP_DATA_SHARING_UPDATES_FRAGMENT_ACTION_REPORTED = 649;
+ ATOM_WS_INCOMING_CALL_ACTION_REPORTED = 626;
+ ATOM_WS_CALL_DISCONNECTION_REPORTED = 627;
+ ATOM_WS_CALL_DURATION_REPORTED = 628;
+ ATOM_WS_CALL_USER_EXPERIENCE_LATENCY_REPORTED = 629;
+ ATOM_WS_CALL_INTERACTION_REPORTED = 630;
+ ATOM_FULL_SCREEN_INTENT_LAUNCHED = 631;
+ ATOM_BAL_ALLOWED = 632;
+ ATOM_IN_TASK_ACTIVITY_STARTED = 685;
+ ATOM_CACHED_APPS_HIGH_WATERMARK = 10189;
+ ATOM_ODREFRESH_REPORTED = 366;
+ ATOM_ODSIGN_REPORTED = 548;
+ ATOM_ART_DATUM_REPORTED = 332;
+ ATOM_ART_DEVICE_DATUM_REPORTED = 550;
+ ATOM_ART_DATUM_DELTA_REPORTED = 565;
+ ATOM_BACKGROUND_DEXOPT_JOB_ENDED = 467;
+ ATOM_WEAR_ADAPTIVE_SUSPEND_STATS_REPORTED = 619;
+ ATOM_WEAR_POWER_ANOMALY_SERVICE_OPERATIONAL_STATS_REPORTED = 620;
+ ATOM_WEAR_POWER_ANOMALY_SERVICE_EVENT_STATS_REPORTED = 621;
+ ATOM_EMERGENCY_STATE_CHANGED = 633;
+ ATOM_DND_STATE_CHANGED = 657;
+ ATOM_MTE_STATE = 10181;
+ ATOM_AD_SERVICES_BACK_COMPAT_GET_TOPICS_REPORTED = 598;
+ ATOM_AD_SERVICES_BACK_COMPAT_EPOCH_COMPUTATION_CLASSIFIER_REPORTED = 599;
+ ATOM_AD_SERVICES_MEASUREMENT_DEBUG_KEYS = 640;
+ ATOM_AD_SERVICES_ERROR_REPORTED = 662;
+ ATOM_AD_SERVICES_BACKGROUND_JOBS_EXECUTION_REPORTED = 663;
+ ATOM_AD_SERVICES_MEASUREMENT_DELAYED_SOURCE_REGISTRATION = 673;
+ ATOM_AD_SERVICES_MEASUREMENT_ATTRIBUTION = 674;
+ ATOM_AD_SERVICES_MEASUREMENT_JOBS = 675;
+ ATOM_AD_SERVICES_MEASUREMENT_WIPEOUT = 676;
+ ATOM_AD_SERVICES_CONSENT_MIGRATED = 702;
+ ATOM_RKPD_POOL_STATS = 664;
+ ATOM_RKPD_CLIENT_OPERATION = 665;
+ ATOM_AUTOFILL_UI_EVENT_REPORTED = 603;
+ ATOM_AUTOFILL_FILL_REQUEST_REPORTED = 604;
+ ATOM_AUTOFILL_FILL_RESPONSE_REPORTED = 605;
+ ATOM_AUTOFILL_SAVE_EVENT_REPORTED = 606;
+ ATOM_AUTOFILL_SESSION_COMMITTED = 607;
+ ATOM_AUTOFILL_FIELD_CLASSIFICATION_EVENT_REPORTED = 659;
+ ATOM_TEST_EXTENSION_ATOM_REPORTED = 660;
+ ATOM_TEST_RESTRICTED_ATOM_REPORTED = 672;
+ ATOM_STATS_SOCKET_LOSS_REPORTED = 752;
+ ATOM_PLUGIN_INITIALIZED = 655;
+ ATOM_TV_LOW_POWER_STANDBY_POLICY = 679;
+ ATOM_LOCKSCREEN_SHORTCUT_SELECTED = 611;
+ ATOM_LOCKSCREEN_SHORTCUT_TRIGGERED = 612;
+ ATOM_EMERGENCY_NUMBERS_INFO = 10180;
+ ATOM_QUALIFIED_RAT_LIST_CHANGED = 634;
+ ATOM_QNS_IMS_CALL_DROP_STATS = 635;
+ ATOM_QNS_FALLBACK_RESTRICTION_CHANGED = 636;
+ ATOM_QNS_RAT_PREFERENCE_MISMATCH_INFO = 10177;
+ ATOM_QNS_HANDOVER_TIME_MILLIS = 10178;
+ ATOM_QNS_HANDOVER_PINGPONG = 10179;
+ ATOM_SATELLITE_CONTROLLER = 10182;
+ ATOM_SATELLITE_SESSION = 10183;
+ ATOM_SATELLITE_INCOMING_DATAGRAM = 10184;
+ ATOM_SATELLITE_OUTGOING_DATAGRAM = 10185;
+ ATOM_SATELLITE_PROVISION = 10186;
+ ATOM_SATELLITE_SOS_MESSAGE_RECOMMENDER = 10187;
+ ATOM_IKE_SESSION_TERMINATED = 678;
+ ATOM_IKE_LIVENESS_CHECK_SESSION_VALIDATED = 760;
+ ATOM_BLUETOOTH_HASHED_DEVICE_NAME_REPORTED = 613;
+ ATOM_BLUETOOTH_L2CAP_COC_CLIENT_CONNECTION = 614;
+ ATOM_BLUETOOTH_L2CAP_COC_SERVER_CONNECTION = 615;
+ ATOM_BLUETOOTH_LE_SESSION_CONNECTED = 656;
+ ATOM_RESTRICTED_BLUETOOTH_DEVICE_NAME_REPORTED = 666;
+ ATOM_BLUETOOTH_PROFILE_CONNECTION_ATTEMPTED = 696;
+ ATOM_HEALTH_CONNECT_UI_IMPRESSION = 623;
+ ATOM_HEALTH_CONNECT_UI_INTERACTION = 624;
+ ATOM_HEALTH_CONNECT_APP_OPENED_REPORTED = 625;
+ ATOM_HEALTH_CONNECT_API_CALLED = 616;
+ ATOM_HEALTH_CONNECT_USAGE_STATS = 617;
+ ATOM_HEALTH_CONNECT_STORAGE_STATS = 618;
+ ATOM_HEALTH_CONNECT_API_INVOKED = 643;
+ ATOM_EXERCISE_ROUTE_API_CALLED = 654;
+ ATOM_ATOM_9999 = 9999;
+ ATOM_ATOM_99999 = 99999;
+ ATOM_THREADNETWORK_TELEMETRY_DATA_REPORTED = 738;
+ ATOM_THREADNETWORK_TOPO_ENTRY_REPEATED = 739;
+ ATOM_THREADNETWORK_DEVICE_INFO_REPORTED = 740;
+ ATOM_EMERGENCY_NUMBER_DIALED = 637;
+ ATOM_SANDBOX_API_CALLED = 488;
+ ATOM_SANDBOX_ACTIVITY_EVENT_OCCURRED = 735;
+ ATOM_SANDBOX_SDK_STORAGE = 10159;
+ ATOM_CRONET_ENGINE_CREATED = 703;
+ ATOM_CRONET_TRAFFIC_REPORTED = 704;
+ ATOM_CRONET_ENGINE_BUILDER_INITIALIZED = 762;
+ ATOM_CRONET_HTTP_FLAGS_INITIALIZED = 763;
+ ATOM_CRONET_INITIALIZED = 764;
+ ATOM_DAILY_KEEPALIVE_INFO_REPORTED = 650;
+ ATOM_IP_CLIENT_RA_INFO_REPORTED = 778;
+ ATOM_APF_SESSION_INFO_REPORTED = 777;
+ ATOM_CREDENTIAL_MANAGER_API_CALLED = 585;
+ ATOM_CREDENTIAL_MANAGER_INIT_PHASE_REPORTED = 651;
+ ATOM_CREDENTIAL_MANAGER_CANDIDATE_PHASE_REPORTED = 652;
+ ATOM_CREDENTIAL_MANAGER_FINAL_PHASE_REPORTED = 653;
+ ATOM_CREDENTIAL_MANAGER_TOTAL_REPORTED = 667;
+ ATOM_CREDENTIAL_MANAGER_FINALNOUID_REPORTED = 668;
+ ATOM_CREDENTIAL_MANAGER_GET_REPORTED = 669;
+ ATOM_CREDENTIAL_MANAGER_AUTH_CLICK_REPORTED = 670;
+ ATOM_CREDENTIAL_MANAGER_APIV2_CALLED = 671;
+ ATOM_UWB_ACTIVITY_INFO = 10188;
+ ATOM_MEDIA_ACTION_REPORTED = 608;
+ ATOM_MEDIA_CONTROLS_LAUNCHED = 609;
+ ATOM_MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED = 600;
+ ATOM_MEDIA_CODEC_STARTED = 641;
+ ATOM_MEDIA_CODEC_STOPPED = 642;
+ ATOM_MEDIA_CODEC_RENDERED = 684;
}
\ No newline at end of file
diff --git a/protos/perfetto/ipc/wire_protocol.proto b/protos/perfetto/ipc/wire_protocol.proto
index 8117316..e01a798 100644
--- a/protos/perfetto/ipc/wire_protocol.proto
+++ b/protos/perfetto/ipc/wire_protocol.proto
@@ -72,8 +72,16 @@
// endpoont of the connection. for AF_UNIX sockets, this is ignored and traced
// uses instead the SO_PEERCRED.
message SetPeerIdentity {
+ // The UID and PID of the producer process.
optional int32 pid = 1;
optional int32 uid = 2;
+
+ // The hint for the tracing service to infer the machine ID. This field
+ // should satisfy the requriement that different machines should have
+ // different values. In practice, this filed contains the Linux kernel
+ // boot_id, or a hash of kernel bootup timestamp and uname(2) if boot_id
+ // isn't available.
+ optional string machine_id_hint = 3;
}
// The client is expected to send requests with monotonically increasing
diff --git a/protos/perfetto/trace/android/frame_timeline_event.proto b/protos/perfetto/trace/android/frame_timeline_event.proto
index f1f0df8..db6ed90 100644
--- a/protos/perfetto/trace/android/frame_timeline_event.proto
+++ b/protos/perfetto/trace/android/frame_timeline_event.proto
@@ -45,6 +45,14 @@
JANK_DROPPED = 1024;
};
+ // Specifies the severity of a jank.
+ enum JankSeverityType {
+ SEVERITY_UNKNOWN = 0;
+ SEVERITY_NONE = 1;
+ SEVERITY_PARTIAL = 2;
+ SEVERITY_FULL = 3;
+ }
+
// Specifies how a frame was presented on screen w.r.t. timing.
// Can be different for SurfaceFrame and DisplayFrame.
enum PresentType {
@@ -121,6 +129,7 @@
optional int32 jank_type = 9;
optional PredictionType prediction_type = 10;
optional bool is_buffer = 11;
+ optional JankSeverityType jank_severity_type = 12;
};
// Indicates the start of expected timeline slice for DisplayFrames.
@@ -166,6 +175,7 @@
// frame.
optional int32 jank_type = 7;
optional PredictionType prediction_type = 8;
+ optional JankSeverityType jank_severity_type = 9;
};
// FrameEnd just sends the cookie to indicate that the corresponding
diff --git a/protos/perfetto/trace/etw/etw_event.proto b/protos/perfetto/trace/etw/etw_event.proto
index 9ef1b4e..c52ad6c 100644
--- a/protos/perfetto/trace/etw/etw_event.proto
+++ b/protos/perfetto/trace/etw/etw_event.proto
@@ -21,6 +21,7 @@
message EtwTraceEvent {
optional uint64 timestamp = 1;
+ optional uint32 cpu = 4;
oneof event {
CSwitchEtwEvent c_switch = 2;
diff --git a/protos/perfetto/trace/ftrace/all_protos.gni b/protos/perfetto/trace/ftrace/all_protos.gni
index bd055ab..2237aef 100644
--- a/protos/perfetto/trace/ftrace/all_protos.gni
+++ b/protos/perfetto/trace/ftrace/all_protos.gni
@@ -57,6 +57,7 @@
"net.proto",
"oom.proto",
"panel.proto",
+ "perf_trace_counters.proto",
"power.proto",
"printk.proto",
"raw_syscalls.proto",
diff --git a/protos/perfetto/trace/ftrace/ftrace_event.proto b/protos/perfetto/trace/ftrace/ftrace_event.proto
index a068c9d..f7e314b 100644
--- a/protos/perfetto/trace/ftrace/ftrace_event.proto
+++ b/protos/perfetto/trace/ftrace/ftrace_event.proto
@@ -57,6 +57,7 @@
import "protos/perfetto/trace/ftrace/net.proto";
import "protos/perfetto/trace/ftrace/oom.proto";
import "protos/perfetto/trace/ftrace/panel.proto";
+import "protos/perfetto/trace/ftrace/perf_trace_counters.proto";
import "protos/perfetto/trace/ftrace/power.proto";
import "protos/perfetto/trace/ftrace/printk.proto";
import "protos/perfetto/trace/ftrace/raw_syscalls.proto";
@@ -601,5 +602,6 @@
SamsungTracingMarkWriteFtraceEvent samsung_tracing_mark_write = 484;
BinderCommandFtraceEvent binder_command = 485;
BinderReturnFtraceEvent binder_return = 486;
+ SchedSwitchWithCtrsFtraceEvent sched_switch_with_ctrs = 487;
}
}
diff --git a/protos/perfetto/trace/ftrace/perf_trace_counters.proto b/protos/perfetto/trace/ftrace/perf_trace_counters.proto
new file mode 100644
index 0000000..0e3531c
--- /dev/null
+++ b/protos/perfetto/trace/ftrace/perf_trace_counters.proto
@@ -0,0 +1,26 @@
+// Autogenerated by:
+// ../../src/tools/ftrace_proto_gen/ftrace_proto_gen.cc
+// Do not edit.
+
+syntax = "proto2";
+package perfetto.protos;
+
+message SchedSwitchWithCtrsFtraceEvent {
+ optional int32 old_pid = 1;
+ optional int32 new_pid = 2;
+ optional uint32 cctr = 3;
+ optional uint32 ctr0 = 4;
+ optional uint32 ctr1 = 5;
+ optional uint32 ctr2 = 6;
+ optional uint32 ctr3 = 7;
+ optional uint32 lctr0 = 8;
+ optional uint32 lctr1 = 9;
+ optional uint32 ctr4 = 10;
+ optional uint32 ctr5 = 11;
+ optional string prev_comm = 12;
+ optional int32 prev_pid = 13;
+ optional uint32 cyc = 14;
+ optional uint32 inst = 15;
+ optional uint32 stallbm = 16;
+ optional uint32 l3dm = 17;
+}
diff --git a/protos/perfetto/trace/perfetto_trace.proto b/protos/perfetto/trace/perfetto_trace.proto
index 232ccd5..8cfa67e 100644
--- a/protos/perfetto/trace/perfetto_trace.proto
+++ b/protos/perfetto/trace/perfetto_trace.proto
@@ -1970,7 +1970,6 @@
ATOM_PERFETTO_TRIGGER = 329;
ATOM_TRANSCODING_DATA = 330;
ATOM_IMS_SERVICE_ENTITLEMENT_UPDATED = 331;
- ATOM_ART_DATUM_REPORTED = 332;
ATOM_DEVICE_ROTATED = 333;
ATOM_SIM_SPECIFIC_SETTINGS_RESTORED = 334;
ATOM_TEXT_CLASSIFIER_DOWNLOAD_REPORTED = 335;
@@ -2000,7 +1999,6 @@
ATOM_LOCATION_TIME_ZONE_PROVIDER_STATE_CHANGED = 359;
ATOM_FDTRACK_EVENT_OCCURRED = 364;
ATOM_TIMEOUT_AUTO_EXTENDED_REPORTED = 365;
- ATOM_ODREFRESH_REPORTED = 366;
ATOM_ALARM_BATCH_DELIVERED = 367;
ATOM_ALARM_SCHEDULED = 368;
ATOM_CAR_WATCHDOG_IO_OVERUSE_STATS_REPORTED = 369;
@@ -2068,6 +2066,8 @@
ATOM_HOTWORD_DETECTION_SERVICE_RESTARTED = 432;
ATOM_HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED = 433;
ATOM_HOTWORD_DETECTOR_EVENTS = 434;
+ ATOM_AD_SERVICES_API_CALLED = 435;
+ ATOM_AD_SERVICES_MESUREMENT_REPORTS_UPLOADED = 436;
ATOM_BOOT_COMPLETED_BROADCAST_COMPLETION_LATENCY_REPORTED = 437;
ATOM_CONTACTS_INDEXER_UPDATE_STATS_REPORTED = 440;
ATOM_APP_BACKGROUND_RESTRICTIONS_INFO = 441;
@@ -2089,24 +2089,47 @@
ATOM_ISOLATED_COMPILATION_SCHEDULED = 457;
ATOM_ISOLATED_COMPILATION_ENDED = 458;
ATOM_ONS_OPPORTUNISTIC_ESIM_PROVISIONING_COMPLETE = 459;
+ ATOM_SYSTEM_SERVER_PRE_WATCHDOG_OCCURRED = 460;
ATOM_TELEPHONY_ANOMALY_DETECTED = 461;
ATOM_LETTERBOX_POSITION_CHANGED = 462;
ATOM_REMOTE_KEY_PROVISIONING_ATTEMPT = 463;
ATOM_REMOTE_KEY_PROVISIONING_NETWORK_INFO = 464;
ATOM_REMOTE_KEY_PROVISIONING_TIMING = 465;
ATOM_MEDIAOUTPUT_OP_INTERACTION_REPORT = 466;
- ATOM_BACKGROUND_DEXOPT_JOB_ENDED = 467;
ATOM_SYNC_EXEMPTION_OCCURRED = 468;
ATOM_AUTOFILL_PRESENTATION_EVENT_REPORTED = 469;
ATOM_DOCK_STATE_CHANGED = 470;
+ ATOM_SAFETY_SOURCE_STATE_COLLECTED = 471;
+ ATOM_SAFETY_CENTER_SYSTEM_EVENT_REPORTED = 472;
+ ATOM_SAFETY_CENTER_INTERACTION_REPORTED = 473;
+ ATOM_SETTINGS_PROVIDER_SETTING_CHANGED = 474;
ATOM_BROADCAST_DELIVERY_EVENT_REPORTED = 475;
ATOM_SERVICE_REQUEST_EVENT_REPORTED = 476;
ATOM_PROVIDER_ACQUISITION_EVENT_REPORTED = 477;
ATOM_BLUETOOTH_DEVICE_NAME_REPORTED = 478;
+ ATOM_CB_CONFIG_UPDATED = 479;
+ ATOM_CB_MODULE_ERROR_REPORTED = 480;
+ ATOM_CB_SERVICE_FEATURE_CHANGED = 481;
+ ATOM_CB_RECEIVER_FEATURE_CHANGED = 482;
+ ATOM_JSSCRIPTENGINE_LATENCY_REPORTED = 483;
+ ATOM_PRIVACY_SIGNAL_NOTIFICATION_INTERACTION = 484;
+ ATOM_PRIVACY_SIGNAL_ISSUE_CARD_INTERACTION = 485;
+ ATOM_PRIVACY_SIGNALS_JOB_FAILURE = 486;
ATOM_VIBRATION_REPORTED = 487;
ATOM_UWB_RANGING_START = 489;
+ ATOM_MOBILE_DATA_DOWNLOAD_FILE_GROUP_STATUS_REPORTED = 490;
+ ATOM_APP_COMPACTED_V2 = 491;
+ ATOM_AD_SERVICES_SETTINGS_USAGE_REPORTED = 493;
ATOM_DISPLAY_BRIGHTNESS_CHANGED = 494;
ATOM_ACTIVITY_ACTION_BLOCKED = 495;
+ ATOM_BACKGROUND_FETCH_PROCESS_REPORTED = 496;
+ ATOM_UPDATE_CUSTOM_AUDIENCE_PROCESS_REPORTED = 497;
+ ATOM_RUN_AD_BIDDING_PROCESS_REPORTED = 498;
+ ATOM_RUN_AD_SCORING_PROCESS_REPORTED = 499;
+ ATOM_RUN_AD_SELECTION_PROCESS_REPORTED = 500;
+ ATOM_RUN_AD_BIDDING_PER_CA_PROCESS_REPORTED = 501;
+ ATOM_MOBILE_DATA_DOWNLOAD_DOWNLOAD_RESULT_REPORTED = 502;
+ ATOM_MOBILE_DATA_DOWNLOAD_FILE_GROUP_STORAGE_STATS_REPORTED = 503;
ATOM_NETWORK_DNS_SERVER_SUPPORT_REPORTED = 504;
ATOM_VM_BOOTED = 505;
ATOM_VM_EXITED = 506;
@@ -2115,13 +2138,19 @@
ATOM_MEDIAMETRICS_SPATIALIZERDEVICEENABLED_REPORTED = 509;
ATOM_MEDIAMETRICS_HEADTRACKERDEVICEENABLED_REPORTED = 510;
ATOM_MEDIAMETRICS_HEADTRACKERDEVICESUPPORTED_REPORTED = 511;
+ ATOM_AD_SERVICES_MEASUREMENT_REGISTRATIONS = 512;
ATOM_HEARING_AID_INFO_REPORTED = 513;
ATOM_DEVICE_WIDE_JOB_CONSTRAINT_CHANGED = 514;
+ ATOM_AMBIENT_MODE_CHANGED = 515;
+ ATOM_ANR_LATENCY_REPORTED = 516;
+ ATOM_RESOURCE_API_INFO = 517;
+ ATOM_SYSTEM_DEFAULT_NETWORK_CHANGED = 518;
ATOM_IWLAN_SETUP_DATA_CALL_RESULT_REPORTED = 519;
ATOM_IWLAN_PDN_DISCONNECTED_REASON_REPORTED = 520;
ATOM_AIRPLANE_MODE_SESSION_REPORTED = 521;
ATOM_VM_CPU_STATUS_REPORTED = 522;
ATOM_VM_MEM_STATUS_REPORTED = 523;
+ ATOM_PACKAGE_INSTALLATION_SESSION_REPORTED = 524;
ATOM_DEFAULT_NETWORK_REMATCH_INFO = 525;
ATOM_NETWORK_SELECTION_PERFORMANCE = 526;
ATOM_NETWORK_NSD_REPORTED = 527;
@@ -2131,22 +2160,65 @@
ATOM_BLUETOOTH_LOCAL_SUPPORTED_FEATURES_REPORTED = 532;
ATOM_BLUETOOTH_GATT_APP_INFO = 533;
ATOM_BRIGHTNESS_CONFIGURATION_UPDATED = 534;
+ ATOM_AD_SERVICES_GET_TOPICS_REPORTED = 535;
+ ATOM_AD_SERVICES_EPOCH_COMPUTATION_GET_TOP_TOPICS_REPORTED = 536;
+ ATOM_AD_SERVICES_EPOCH_COMPUTATION_CLASSIFIER_REPORTED = 537;
+ ATOM_WEAR_MEDIA_OUTPUT_SWITCHER_LAUNCHED = 538;
+ ATOM_WEAR_MEDIA_OUTPUT_SWITCHER_FINISHED = 539;
+ ATOM_WEAR_MEDIA_OUTPUT_SWITCHER_CONNECTION_REPORTED = 540;
+ ATOM_WEAR_MEDIA_OUTPUT_SWITCHER_DEVICE_SCAN_TRIGGERED = 541;
+ ATOM_WEAR_MEDIA_OUTPUT_SWITCHER_FIRST_DEVICE_SCAN_LATENCY = 542;
+ ATOM_WEAR_MEDIA_OUTPUT_SWITCHER_CONNECT_DEVICE_LATENCY = 543;
+ ATOM_PACKAGE_MANAGER_SNAPSHOT_REPORTED = 544;
+ ATOM_PACKAGE_MANAGER_APPS_FILTER_CACHE_BUILD_REPORTED = 545;
+ ATOM_PACKAGE_MANAGER_APPS_FILTER_CACHE_UPDATE_REPORTED = 546;
ATOM_LAUNCHER_IMPRESSION_EVENT = 547;
- ATOM_ODSIGN_REPORTED = 548;
- ATOM_ART_DEVICE_DATUM_REPORTED = 550;
+ ATOM_WEAR_MEDIA_OUTPUT_SWITCHER_ALL_DEVICES_SCAN_LATENCY = 549;
+ ATOM_WS_WATCH_FACE_EDITED = 551;
+ ATOM_WS_WATCH_FACE_FAVORITE_ACTION_REPORTED = 552;
+ ATOM_WS_WATCH_FACE_SET_ACTION_REPORTED = 553;
+ ATOM_PACKAGE_UNINSTALLATION_REPORTED = 554;
+ ATOM_GAME_MODE_CHANGED = 555;
+ ATOM_GAME_MODE_CONFIGURATION_CHANGED = 556;
+ ATOM_BEDTIME_MODE_STATE_CHANGED = 557;
ATOM_NETWORK_SLICE_SESSION_ENDED = 558;
ATOM_NETWORK_SLICE_DAILY_DATA_USAGE_REPORTED = 559;
ATOM_NFC_TAG_TYPE_OCCURRED = 560;
ATOM_NFC_AID_CONFLICT_OCCURRED = 561;
ATOM_NFC_READER_CONFLICT_OCCURRED = 562;
- ATOM_ART_DATUM_DELTA_REPORTED = 565;
+ ATOM_WS_TILE_LIST_CHANGED = 563;
+ ATOM_GET_TYPE_ACCESSED_WITHOUT_PERMISSION = 564;
+ ATOM_MOBILE_BUNDLED_APP_INFO_GATHERED = 566;
+ ATOM_WS_WATCH_FACE_COMPLICATION_SET_CHANGED = 567;
ATOM_MEDIA_DRM_CREATED = 568;
ATOM_MEDIA_DRM_ERRORED = 569;
ATOM_MEDIA_DRM_SESSION_OPENED = 570;
ATOM_MEDIA_DRM_SESSION_CLOSED = 571;
+ ATOM_USER_SELECTED_RESOLUTION = 572;
+ ATOM_UNSAFE_INTENT_EVENT_REPORTED = 573;
ATOM_PERFORMANCE_HINT_SESSION_REPORTED = 574;
+ ATOM_MEDIAMETRICS_MIDI_DEVICE_CLOSE_REPORTED = 576;
+ ATOM_BIOMETRIC_TOUCH_REPORTED = 577;
ATOM_HOTWORD_AUDIO_EGRESS_EVENT_REPORTED = 578;
+ ATOM_APP_SEARCH_SCHEMA_MIGRATION_STATS_REPORTED = 579;
+ ATOM_LOCATION_ENABLED_STATE_CHANGED = 580;
+ ATOM_IME_REQUEST_FINISHED = 581;
+ ATOM_USB_COMPLIANCE_WARNINGS_REPORTED = 582;
+ ATOM_APP_SUPPORTED_LOCALES_CHANGED = 583;
+ ATOM_GRAMMATICAL_INFLECTION_CHANGED = 584;
+ ATOM_MEDIA_PROVIDER_VOLUME_RECOVERY_REPORTED = 586;
+ ATOM_BIOMETRIC_PROPERTIES_COLLECTED = 587;
+ ATOM_KERNEL_WAKEUP_ATTRIBUTED = 588;
+ ATOM_SCREEN_STATE_CHANGED_V2 = 589;
+ ATOM_WS_BACKUP_ACTION_REPORTED = 590;
+ ATOM_WS_RESTORE_ACTION_REPORTED = 591;
+ ATOM_DEVICE_LOG_ACCESS_EVENT_REPORTED = 592;
+ ATOM_MEDIA_SESSION_UPDATED = 594;
+ ATOM_WEAR_OOBE_STATE_CHANGED = 595;
+ ATOM_WS_NOTIFICATION_UPDATED = 596;
ATOM_NETWORK_VALIDATION_FAILURE_STATS_DAILY_REPORTED = 601;
+ ATOM_WS_COMPLICATION_TAPPED = 602;
+ ATOM_WS_WEAR_TIME_SESSION = 610;
ATOM_WIFI_BYTES_TRANSFER = 10000;
ATOM_WIFI_BYTES_TRANSFER_BY_FG_BG = 10001;
ATOM_MOBILE_BYTES_TRANSFER = 10002;
@@ -2299,15 +2371,160 @@
ATOM_TELEPHONY_NETWORK_REQUESTS_V2 = 10153;
ATOM_DEVICE_TELEPHONY_PROPERTIES = 10154;
ATOM_REMOTE_KEY_PROVISIONING_ERROR_COUNTS = 10155;
+ ATOM_SAFETY_STATE = 10156;
ATOM_INCOMING_MMS = 10157;
ATOM_OUTGOING_MMS = 10158;
ATOM_MULTI_USER_INFO = 10160;
ATOM_NETWORK_BPF_MAP_INFO = 10161;
+ ATOM_OUTGOING_SHORT_CODE_SMS = 10162;
ATOM_CONNECTIVITY_STATE_SAMPLE = 10163;
ATOM_NETWORK_SELECTION_REMATCH_REASONS_INFO = 10164;
+ ATOM_GAME_MODE_INFO = 10165;
+ ATOM_GAME_MODE_CONFIGURATION = 10166;
+ ATOM_GAME_MODE_LISTENER = 10167;
ATOM_NETWORK_SLICE_REQUEST_COUNT = 10168;
+ ATOM_WS_TILE_SNAPSHOT = 10169;
+ ATOM_WS_ACTIVE_WATCH_FACE_COMPLICATION_SET_SNAPSHOT = 10170;
+ ATOM_PROCESS_STATE = 10171;
+ ATOM_PROCESS_ASSOCIATION = 10172;
ATOM_ADPF_SYSTEM_COMPONENT_INFO = 10173;
ATOM_NOTIFICATION_MEMORY_USE = 10174;
+ ATOM_HDR_CAPABILITIES = 10175;
+ ATOM_WS_FAVOURITE_WATCH_FACE_LIST_SNAPSHOT = 10176;
+ ATOM_WIFI_AWARE_NDP_REPORTED = 638;
+ ATOM_WIFI_AWARE_ATTACH_REPORTED = 639;
+ ATOM_WIFI_SELF_RECOVERY_TRIGGERED = 661;
+ ATOM_SOFT_AP_STARTED = 680;
+ ATOM_SOFT_AP_STOPPED = 681;
+ ATOM_WIFI_LOCK_RELEASED = 687;
+ ATOM_WIFI_LOCK_DEACTIVATED = 688;
+ ATOM_WIFI_CONFIG_SAVED = 689;
+ ATOM_WIFI_AWARE_RESOURCE_USING_CHANGED = 690;
+ ATOM_WIFI_AWARE_HAL_API_CALLED = 691;
+ ATOM_WIFI_LOCAL_ONLY_REQUEST_RECEIVED = 692;
+ ATOM_WIFI_LOCAL_ONLY_REQUEST_SCAN_TRIGGERED = 693;
+ ATOM_WIFI_THREAD_TASK_EXECUTED = 694;
+ ATOM_WIFI_STATE_CHANGED = 700;
+ ATOM_WIFI_AWARE_CAPABILITIES = 10190;
+ ATOM_WIFI_MODULE_INFO = 10193;
+ ATOM_SETTINGS_SPA_REPORTED = 622;
+ ATOM_EXPRESS_EVENT_REPORTED = 528;
+ ATOM_EXPRESS_HISTOGRAM_SAMPLE_REPORTED = 593;
+ ATOM_EXPRESS_UID_EVENT_REPORTED = 644;
+ ATOM_EXPRESS_UID_HISTOGRAM_SAMPLE_REPORTED = 658;
+ ATOM_PERMISSION_RATIONALE_DIALOG_VIEWED = 645;
+ ATOM_PERMISSION_RATIONALE_DIALOG_ACTION_REPORTED = 646;
+ ATOM_APP_DATA_SHARING_UPDATES_NOTIFICATION_INTERACTION = 647;
+ ATOM_APP_DATA_SHARING_UPDATES_FRAGMENT_VIEWED = 648;
+ ATOM_APP_DATA_SHARING_UPDATES_FRAGMENT_ACTION_REPORTED = 649;
+ ATOM_WS_INCOMING_CALL_ACTION_REPORTED = 626;
+ ATOM_WS_CALL_DISCONNECTION_REPORTED = 627;
+ ATOM_WS_CALL_DURATION_REPORTED = 628;
+ ATOM_WS_CALL_USER_EXPERIENCE_LATENCY_REPORTED = 629;
+ ATOM_WS_CALL_INTERACTION_REPORTED = 630;
+ ATOM_FULL_SCREEN_INTENT_LAUNCHED = 631;
+ ATOM_BAL_ALLOWED = 632;
+ ATOM_IN_TASK_ACTIVITY_STARTED = 685;
+ ATOM_CACHED_APPS_HIGH_WATERMARK = 10189;
+ ATOM_ODREFRESH_REPORTED = 366;
+ ATOM_ODSIGN_REPORTED = 548;
+ ATOM_ART_DATUM_REPORTED = 332;
+ ATOM_ART_DEVICE_DATUM_REPORTED = 550;
+ ATOM_ART_DATUM_DELTA_REPORTED = 565;
+ ATOM_BACKGROUND_DEXOPT_JOB_ENDED = 467;
+ ATOM_WEAR_ADAPTIVE_SUSPEND_STATS_REPORTED = 619;
+ ATOM_WEAR_POWER_ANOMALY_SERVICE_OPERATIONAL_STATS_REPORTED = 620;
+ ATOM_WEAR_POWER_ANOMALY_SERVICE_EVENT_STATS_REPORTED = 621;
+ ATOM_EMERGENCY_STATE_CHANGED = 633;
+ ATOM_DND_STATE_CHANGED = 657;
+ ATOM_MTE_STATE = 10181;
+ ATOM_AD_SERVICES_BACK_COMPAT_GET_TOPICS_REPORTED = 598;
+ ATOM_AD_SERVICES_BACK_COMPAT_EPOCH_COMPUTATION_CLASSIFIER_REPORTED = 599;
+ ATOM_AD_SERVICES_MEASUREMENT_DEBUG_KEYS = 640;
+ ATOM_AD_SERVICES_ERROR_REPORTED = 662;
+ ATOM_AD_SERVICES_BACKGROUND_JOBS_EXECUTION_REPORTED = 663;
+ ATOM_AD_SERVICES_MEASUREMENT_DELAYED_SOURCE_REGISTRATION = 673;
+ ATOM_AD_SERVICES_MEASUREMENT_ATTRIBUTION = 674;
+ ATOM_AD_SERVICES_MEASUREMENT_JOBS = 675;
+ ATOM_AD_SERVICES_MEASUREMENT_WIPEOUT = 676;
+ ATOM_AD_SERVICES_CONSENT_MIGRATED = 702;
+ ATOM_RKPD_POOL_STATS = 664;
+ ATOM_RKPD_CLIENT_OPERATION = 665;
+ ATOM_AUTOFILL_UI_EVENT_REPORTED = 603;
+ ATOM_AUTOFILL_FILL_REQUEST_REPORTED = 604;
+ ATOM_AUTOFILL_FILL_RESPONSE_REPORTED = 605;
+ ATOM_AUTOFILL_SAVE_EVENT_REPORTED = 606;
+ ATOM_AUTOFILL_SESSION_COMMITTED = 607;
+ ATOM_AUTOFILL_FIELD_CLASSIFICATION_EVENT_REPORTED = 659;
+ ATOM_TEST_EXTENSION_ATOM_REPORTED = 660;
+ ATOM_TEST_RESTRICTED_ATOM_REPORTED = 672;
+ ATOM_STATS_SOCKET_LOSS_REPORTED = 752;
+ ATOM_PLUGIN_INITIALIZED = 655;
+ ATOM_TV_LOW_POWER_STANDBY_POLICY = 679;
+ ATOM_LOCKSCREEN_SHORTCUT_SELECTED = 611;
+ ATOM_LOCKSCREEN_SHORTCUT_TRIGGERED = 612;
+ ATOM_EMERGENCY_NUMBERS_INFO = 10180;
+ ATOM_QUALIFIED_RAT_LIST_CHANGED = 634;
+ ATOM_QNS_IMS_CALL_DROP_STATS = 635;
+ ATOM_QNS_FALLBACK_RESTRICTION_CHANGED = 636;
+ ATOM_QNS_RAT_PREFERENCE_MISMATCH_INFO = 10177;
+ ATOM_QNS_HANDOVER_TIME_MILLIS = 10178;
+ ATOM_QNS_HANDOVER_PINGPONG = 10179;
+ ATOM_SATELLITE_CONTROLLER = 10182;
+ ATOM_SATELLITE_SESSION = 10183;
+ ATOM_SATELLITE_INCOMING_DATAGRAM = 10184;
+ ATOM_SATELLITE_OUTGOING_DATAGRAM = 10185;
+ ATOM_SATELLITE_PROVISION = 10186;
+ ATOM_SATELLITE_SOS_MESSAGE_RECOMMENDER = 10187;
+ ATOM_IKE_SESSION_TERMINATED = 678;
+ ATOM_IKE_LIVENESS_CHECK_SESSION_VALIDATED = 760;
+ ATOM_BLUETOOTH_HASHED_DEVICE_NAME_REPORTED = 613;
+ ATOM_BLUETOOTH_L2CAP_COC_CLIENT_CONNECTION = 614;
+ ATOM_BLUETOOTH_L2CAP_COC_SERVER_CONNECTION = 615;
+ ATOM_BLUETOOTH_LE_SESSION_CONNECTED = 656;
+ ATOM_RESTRICTED_BLUETOOTH_DEVICE_NAME_REPORTED = 666;
+ ATOM_BLUETOOTH_PROFILE_CONNECTION_ATTEMPTED = 696;
+ ATOM_HEALTH_CONNECT_UI_IMPRESSION = 623;
+ ATOM_HEALTH_CONNECT_UI_INTERACTION = 624;
+ ATOM_HEALTH_CONNECT_APP_OPENED_REPORTED = 625;
+ ATOM_HEALTH_CONNECT_API_CALLED = 616;
+ ATOM_HEALTH_CONNECT_USAGE_STATS = 617;
+ ATOM_HEALTH_CONNECT_STORAGE_STATS = 618;
+ ATOM_HEALTH_CONNECT_API_INVOKED = 643;
+ ATOM_EXERCISE_ROUTE_API_CALLED = 654;
+ ATOM_ATOM_9999 = 9999;
+ ATOM_ATOM_99999 = 99999;
+ ATOM_THREADNETWORK_TELEMETRY_DATA_REPORTED = 738;
+ ATOM_THREADNETWORK_TOPO_ENTRY_REPEATED = 739;
+ ATOM_THREADNETWORK_DEVICE_INFO_REPORTED = 740;
+ ATOM_EMERGENCY_NUMBER_DIALED = 637;
+ ATOM_SANDBOX_API_CALLED = 488;
+ ATOM_SANDBOX_ACTIVITY_EVENT_OCCURRED = 735;
+ ATOM_SANDBOX_SDK_STORAGE = 10159;
+ ATOM_CRONET_ENGINE_CREATED = 703;
+ ATOM_CRONET_TRAFFIC_REPORTED = 704;
+ ATOM_CRONET_ENGINE_BUILDER_INITIALIZED = 762;
+ ATOM_CRONET_HTTP_FLAGS_INITIALIZED = 763;
+ ATOM_CRONET_INITIALIZED = 764;
+ ATOM_DAILY_KEEPALIVE_INFO_REPORTED = 650;
+ ATOM_IP_CLIENT_RA_INFO_REPORTED = 778;
+ ATOM_APF_SESSION_INFO_REPORTED = 777;
+ ATOM_CREDENTIAL_MANAGER_API_CALLED = 585;
+ ATOM_CREDENTIAL_MANAGER_INIT_PHASE_REPORTED = 651;
+ ATOM_CREDENTIAL_MANAGER_CANDIDATE_PHASE_REPORTED = 652;
+ ATOM_CREDENTIAL_MANAGER_FINAL_PHASE_REPORTED = 653;
+ ATOM_CREDENTIAL_MANAGER_TOTAL_REPORTED = 667;
+ ATOM_CREDENTIAL_MANAGER_FINALNOUID_REPORTED = 668;
+ ATOM_CREDENTIAL_MANAGER_GET_REPORTED = 669;
+ ATOM_CREDENTIAL_MANAGER_AUTH_CLICK_REPORTED = 670;
+ ATOM_CREDENTIAL_MANAGER_APIV2_CALLED = 671;
+ ATOM_UWB_ACTIVITY_INFO = 10188;
+ ATOM_MEDIA_ACTION_REPORTED = 608;
+ ATOM_MEDIA_CONTROLS_LAUNCHED = 609;
+ ATOM_MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED = 600;
+ ATOM_MEDIA_CODEC_STARTED = 641;
+ ATOM_MEDIA_CODEC_STOPPED = 642;
+ ATOM_MEDIA_CODEC_RENDERED = 684;
}
// End of protos/perfetto/config/statsd/atom_ids.proto
@@ -4004,6 +4221,14 @@
JANK_DROPPED = 1024;
};
+ // Specifies the severity of a jank.
+ enum JankSeverityType {
+ SEVERITY_UNKNOWN = 0;
+ SEVERITY_NONE = 1;
+ SEVERITY_PARTIAL = 2;
+ SEVERITY_FULL = 3;
+ }
+
// Specifies how a frame was presented on screen w.r.t. timing.
// Can be different for SurfaceFrame and DisplayFrame.
enum PresentType {
@@ -4080,6 +4305,7 @@
optional int32 jank_type = 9;
optional PredictionType prediction_type = 10;
optional bool is_buffer = 11;
+ optional JankSeverityType jank_severity_type = 12;
};
// Indicates the start of expected timeline slice for DisplayFrames.
@@ -4125,6 +4351,7 @@
// frame.
optional int32 jank_type = 7;
optional PredictionType prediction_type = 8;
+ optional JankSeverityType jank_severity_type = 9;
};
// FrameEnd just sends the cookie to indicate that the corresponding
@@ -5441,6 +5668,7 @@
message EtwTraceEvent {
optional uint64 timestamp = 1;
+ optional uint32 cpu = 4;
oneof event {
CSwitchEtwEvent c_switch = 2;
@@ -8258,6 +8486,30 @@
// End of protos/perfetto/trace/ftrace/panel.proto
+// Begin of protos/perfetto/trace/ftrace/perf_trace_counters.proto
+
+message SchedSwitchWithCtrsFtraceEvent {
+ optional int32 old_pid = 1;
+ optional int32 new_pid = 2;
+ optional uint32 cctr = 3;
+ optional uint32 ctr0 = 4;
+ optional uint32 ctr1 = 5;
+ optional uint32 ctr2 = 6;
+ optional uint32 ctr3 = 7;
+ optional uint32 lctr0 = 8;
+ optional uint32 lctr1 = 9;
+ optional uint32 ctr4 = 10;
+ optional uint32 ctr5 = 11;
+ optional string prev_comm = 12;
+ optional int32 prev_pid = 13;
+ optional uint32 cyc = 14;
+ optional uint32 inst = 15;
+ optional uint32 stallbm = 16;
+ optional uint32 l3dm = 17;
+}
+
+// End of protos/perfetto/trace/ftrace/perf_trace_counters.proto
+
// Begin of protos/perfetto/trace/ftrace/power.proto
message CpuFrequencyFtraceEvent {
@@ -9540,6 +9792,7 @@
SamsungTracingMarkWriteFtraceEvent samsung_tracing_mark_write = 484;
BinderCommandFtraceEvent binder_command = 485;
BinderReturnFtraceEvent binder_return = 486;
+ SchedSwitchWithCtrsFtraceEvent sched_switch_with_ctrs = 487;
}
}
@@ -13378,7 +13631,7 @@
// See the [Buffers and Dataflow](/docs/concepts/buffers.md) doc for details.
//
// Next reserved id: 14 (up to 15).
-// Next id: 96.
+// Next id: 99.
message TracePacket {
// The timestamp of the TracePacket.
// By default this timestamps refers to the trace clock (CLOCK_BOOTTIME on
@@ -13606,6 +13859,11 @@
// being present for a particular sequence does not necessarily imply data
// loss.
optional bool first_packet_on_sequence = 87;
+
+ // The machine ID for identifying trace packets in a multi-machine tracing
+ // session. Is emitted by the tracing service for producers running on a
+ // remote host (e.g. a VM guest). For more context: go/crosetto-vm-tracing.
+ optional uint32 machine_id = 98;
}
// End of protos/perfetto/trace/trace_packet.proto
diff --git a/protos/perfetto/trace/trace_packet.proto b/protos/perfetto/trace/trace_packet.proto
index 86a90fe..e8306b7 100644
--- a/protos/perfetto/trace/trace_packet.proto
+++ b/protos/perfetto/trace/trace_packet.proto
@@ -98,7 +98,7 @@
// See the [Buffers and Dataflow](/docs/concepts/buffers.md) doc for details.
//
// Next reserved id: 14 (up to 15).
-// Next id: 96.
+// Next id: 99.
message TracePacket {
// The timestamp of the TracePacket.
// By default this timestamps refers to the trace clock (CLOCK_BOOTTIME on
@@ -326,4 +326,9 @@
// being present for a particular sequence does not necessarily imply data
// loss.
optional bool first_packet_on_sequence = 87;
+
+ // The machine ID for identifying trace packets in a multi-machine tracing
+ // session. Is emitted by the tracing service for producers running on a
+ // remote host (e.g. a VM guest). For more context: go/crosetto-vm-tracing.
+ optional uint32 machine_id = 98;
}
diff --git a/protos/perfetto/trace_processor/serialization.proto b/protos/perfetto/trace_processor/serialization.proto
index 5890bc0..e79b7c9 100644
--- a/protos/perfetto/trace_processor/serialization.proto
+++ b/protos/perfetto/trace_processor/serialization.proto
@@ -45,30 +45,6 @@
optional bytes counts = 2;
optional uint32 size = 3;
}
- // A schema for serialization of any of the descendants of
- // |overlays::StorageOverlay|.
- message Overlay {
- // A schema for serialization of |overlays::ArrangementOverlay|.
- message ArrangementOverlay {
- optional bytes values = 1;
- }
-
- // A schema for serialization of |overlays::NullOverlay|.
- message NullOverlay {
- optional BitVector bit_vector = 1;
- }
-
- // A schema for serialization of |overlays::NullOverlay|.
- message SelectorOverlay {
- optional BitVector bit_vector = 1;
- }
-
- oneof data {
- ArrangementOverlay arrangement_overlay = 1;
- NullOverlay null_overlay = 2;
- SelectorOverlay selector_overlay = 3;
- }
- }
// A schema for serialization of any of the descendants of |storage::Storage|.
message Storage {
// Dummy storage should not contain any data. It's used to signify that
@@ -98,19 +74,38 @@
optional bool is_sorted = 2;
}
+ // A schema for serialization of |storage::NullStorage|.
+ message NullStorage {
+ optional BitVector bit_vector = 1;
+ optional Storage storage = 2;
+ }
+
+ // A schema for serialization of |storage::ArrangementStorage|.
+ message ArrangementStorage {
+ optional bytes values = 1;
+ optional Storage storage = 2;
+ }
+
+ // A schema for serialization of |storage::SelectorStorage|.
+ message SelectorStorage {
+ optional BitVector bit_vector = 1;
+ optional Storage storage = 2;
+ }
+
oneof data {
DummyStorage dummy_storage = 1;
IdStorage id_storage = 2;
NumericStorage numeric_storage = 3;
SetIdStorage set_id_storage = 4;
StringStorage string_storage = 5;
+ NullStorage null_storage = 6;
+ ArrangementStorage arrangement_storage = 7;
+ SelectorStorage selector_storage = 8;
}
}
// Name of the table this column is part of.
optional string table_name = 1;
optional string column_name = 2;
-
optional Storage storage = 3;
- repeated Overlay overlay = 4;
}
diff --git a/python/perfetto/prebuilts/manifests/trace_processor_shell.py b/python/perfetto/prebuilts/manifests/trace_processor_shell.py
index 2f881f5..0196c4b 100755
--- a/python/perfetto/prebuilts/manifests/trace_processor_shell.py
+++ b/python/perfetto/prebuilts/manifests/trace_processor_shell.py
@@ -1,15 +1,15 @@
-# This file has been generated by: tools/roll-prebuilts 6ba75cc5d93c39d4f86e2777709a460b30ce06fc
+# This file has been generated by: tools/roll-prebuilts v40.0
TRACE_PROCESSOR_SHELL_MANIFEST = [{
'arch':
'mac-amd64',
'file_name':
'trace_processor_shell',
'file_size':
- 9830664,
+ 9978200,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/mac-amd64/trace_processor_shell',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/mac-amd64/trace_processor_shell',
'sha256':
- 'd617f9237f77477a6e80065cbcfc84d6ce80505ee34851a0b435f0815aba2645',
+ 'f3e21eb29fb51cb2ea9b81b69132c5ae93ce3276c57ccd27fcf7c675306b4e41',
'platform':
'darwin',
'machine': ['x86_64']
@@ -19,11 +19,11 @@
'file_name':
'trace_processor_shell',
'file_size':
- 8328808,
+ 8493976,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/mac-arm64/trace_processor_shell',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/mac-arm64/trace_processor_shell',
'sha256':
- 'cc5b81618ddfa0a6eb63e0d418c0a52e302ca2617906fae6743d71f82c454611',
+ '84f35765141374b8d883813ac533e0c004cf72d1c6f05aef0c973364ff541eb9',
'platform':
'darwin',
'machine': ['arm64']
@@ -33,11 +33,11 @@
'file_name':
'trace_processor_shell',
'file_size':
- 9682088,
+ 9830856,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/linux-amd64/trace_processor_shell',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/linux-amd64/trace_processor_shell',
'sha256':
- '0beb26c1d744cb982630b23ce031a767d6ed7113b81dca0710f792111592ee9e',
+ 'b3dc0a9c641b84a57fa5d59637921ae2237e4f05b1778341a691df220faf0cd7',
'platform':
'linux',
'machine': ['x86_64']
@@ -47,11 +47,11 @@
'file_name':
'trace_processor_shell',
'file_size':
- 7087544,
+ 7231096,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/linux-arm/trace_processor_shell',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/linux-arm/trace_processor_shell',
'sha256':
- '4df289643b09261bd5718d6894e301023b4101e94e2dd81ead63037fb454054d',
+ 'a21252830fb1bbb7b3fd9665ce6e70920cffa6b1e72c16589c90896c002c3348',
'platform':
'linux',
'machine': ['armv6l', 'armv7l', 'armv8l']
@@ -61,11 +61,11 @@
'file_name':
'trace_processor_shell',
'file_size':
- 9090808,
+ 9238056,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/linux-arm64/trace_processor_shell',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/linux-arm64/trace_processor_shell',
'sha256':
- '9cb0ce22fba1929bef599d89a197a2ea718061840006c4122032cf0fc5fc0c90',
+ 'f77519ec19743ec2c22ed78fe3a20106a482a28d77c4154378af108c5f7bdd4a',
'platform':
'linux',
'machine': ['aarch64']
@@ -75,55 +75,55 @@
'file_name':
'trace_processor_shell',
'file_size':
- 6723512,
+ 6870968,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/android-arm/trace_processor_shell',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/android-arm/trace_processor_shell',
'sha256':
- 'c5949a736b1b5edb285f56c22e9af83e1d0ec6d331adaac77330a277d8bee07c'
+ '2c7055fb44085ec60ad8bb970d495c9c88070fce08902f11fcd44e0ae3369876'
}, {
'arch':
'android-arm64',
'file_name':
'trace_processor_shell',
'file_size':
- 8267112,
+ 8414568,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/android-arm64/trace_processor_shell',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/android-arm64/trace_processor_shell',
'sha256':
- '32475b5fe7e1af557eab0d898accb37c657bc4b2dd221135b55114e61bd8be39'
+ 'd8ca0dc2bab7ea604a6721f0ac0e2b433b43261f247c6c98c510dc17aafe5a72'
}, {
'arch':
'android-x86',
'file_name':
'trace_processor_shell',
'file_size':
- 9164668,
+ 9328508,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/android-x86/trace_processor_shell',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/android-x86/trace_processor_shell',
'sha256':
- '02aeff08c0c3e553c95c851401ade9aac6784ad2f19e312dabbb24801d02c0e5'
+ 'de6a6ea45769888e59a1678d37b6e355b27b834d34a0b9e4980a942d333b88cc'
}, {
'arch':
'android-x64',
'file_name':
'trace_processor_shell',
'file_size':
- 9430440,
+ 9577896,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/android-x64/trace_processor_shell',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/android-x64/trace_processor_shell',
'sha256':
- 'de75622f96f2551a7bbc28a0f063e0dfcc39241cd4fe09c39d0b2541d860a30a'
+ 'cd4b16c5f78a060934204737ba8b312e824ff7cc28f3732daf7d64e733a727f9'
}, {
'arch':
'windows-amd64',
'file_name':
'trace_processor_shell.exe',
'file_size':
- 9100288,
+ 9248256,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/windows-amd64/trace_processor_shell.exe',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/windows-amd64/trace_processor_shell.exe',
'sha256':
- 'f0065f1dfa3f8001959bf18f5cd30138aa58409e39a13ccdd52a1860384e34fb',
+ '26584b4bbab40f8b0ad991a869e7483f92d7223e1473b879a6ceafa49b76390a',
'platform':
'win32',
'machine': ['amd64']
diff --git a/python/perfetto/prebuilts/manifests/tracebox.py b/python/perfetto/prebuilts/manifests/tracebox.py
index a1fd44e..21698c1 100755
--- a/python/perfetto/prebuilts/manifests/tracebox.py
+++ b/python/perfetto/prebuilts/manifests/tracebox.py
@@ -1,15 +1,15 @@
-# This file has been generated by: tools/roll-prebuilts 6ba75cc5d93c39d4f86e2777709a460b30ce06fc
+# This file has been generated by: tools/roll-prebuilts v40.0
TRACEBOX_MANIFEST = [{
'arch':
'mac-amd64',
'file_name':
'tracebox',
'file_size':
- 1498680,
+ 1498816,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/mac-amd64/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/mac-amd64/tracebox',
'sha256':
- '57252aaf73b6a82cfb3bbc6cd68a9ec953f61296cf2c2d651125bb437dc50144',
+ '185014447d35357edbd20e7ce9924842a0d5c6576bd2257abae2ed48b65fd3b8',
'platform':
'darwin',
'machine': ['x86_64']
@@ -19,11 +19,11 @@
'file_name':
'tracebox',
'file_size':
- 1376136,
+ 1392776,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/mac-arm64/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/mac-arm64/tracebox',
'sha256':
- '5f37217af7d47b39624c62625847ec6b98db2ebd1a512e85921eb16bcb402b35',
+ '082bb50e64df5e232673eebb1cd8b0dd752a394105f600cb0262730833f6b7f3',
'platform':
'darwin',
'machine': ['arm64']
@@ -33,11 +33,11 @@
'file_name':
'tracebox',
'file_size':
- 2218840,
+ 2229096,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/linux-amd64/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/linux-amd64/tracebox',
'sha256':
- '89b1412e66b0a227cd8d16e6bf3d7416609c153d4b5c64d6e1a7c600870cd27b',
+ 'c99120caedb845e1c3fad4428263a683b44c357c76d65848dd8e437250066e38',
'platform':
'linux',
'machine': ['x86_64']
@@ -47,11 +47,11 @@
'file_name':
'tracebox',
'file_size':
- 1332292,
+ 1339796,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/linux-arm/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/linux-arm/tracebox',
'sha256':
- 'b5a3a8e0869b35bc9ceb06f3e4ca5bb6c1e1b1c5e6ea23cfed541e40a45ad96a',
+ '6732165916b74f0b820991d1aaed2086a6b56e91f6c604291efe6636f0bdda71',
'platform':
'linux',
'machine': ['armv6l', 'armv7l', 'armv8l']
@@ -61,11 +61,11 @@
'file_name':
'tracebox',
'file_size':
- 2147464,
+ 2157312,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/linux-arm64/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/linux-arm64/tracebox',
'sha256':
- '00fdbdfc5877352b9323b6ea1a119132b66e696941f380da117d0d47ae1baaf9',
+ '7d09865a6d7118e67d2acd0c56b2a94ce8bd5f614869d29a72fe633515ab1fbd',
'platform':
'linux',
'machine': ['aarch64']
@@ -75,11 +75,11 @@
'file_name':
'tracebox',
'file_size':
- 1230804,
+ 1247188,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/android-arm/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/android-arm/tracebox',
'sha256':
- '02ee157f995708e78f57d6e5e110054d2e2b407dbf2db120cc967c7c553081e7'
+ '4ecc192172ac2bca49557cbdbb1f7d660718d4fb4a7314fd19b2b2e52be8bc0c'
}, {
'arch':
'android-arm64',
@@ -88,9 +88,9 @@
'file_size':
1854120,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/android-arm64/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/android-arm64/tracebox',
'sha256':
- 'e0031963f623da25c387b78e20747e07829043732f5afe16cfdea9bad3c0f27c'
+ '1ca89113279d5c6a9ae273bde03b4d84373efe6923dc637cb840908f13b9639e'
}, {
'arch':
'android-x86',
@@ -99,9 +99,9 @@
'file_size':
1853356,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/android-x86/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/android-x86/tracebox',
'sha256':
- '6e9e4b7b0d3773ab5011e476eca883eeb0ab7538fc7d2cd4642b6abc01711ba9'
+ 'cf689a191c1252734ebbfda3106600da324610f761515cfbffbeac2ebdfee715'
}, {
'arch':
'android-x64',
@@ -110,7 +110,7 @@
'file_size':
2149032,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/android-x64/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/android-x64/tracebox',
'sha256':
- '4b494907a43e898047ce98271796464deb3010b6755cee8d9c8a6c341502979b'
+ '99e9ebdb5b5308d95551a4ad060d615d7defb6877c4061d21c783c45a71d372f'
}]
diff --git a/python/perfetto/prebuilts/manifests/traceconv.py b/python/perfetto/prebuilts/manifests/traceconv.py
index 7ada0fa..f01ef0a 100755
--- a/python/perfetto/prebuilts/manifests/traceconv.py
+++ b/python/perfetto/prebuilts/manifests/traceconv.py
@@ -1,15 +1,15 @@
-# This file has been generated by: tools/roll-prebuilts 6ba75cc5d93c39d4f86e2777709a460b30ce06fc
+# This file has been generated by: tools/roll-prebuilts v40.0
TRACECONV_MANIFEST = [{
'arch':
'mac-amd64',
'file_name':
'traceconv',
'file_size':
- 9020880,
+ 9184800,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/mac-amd64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/mac-amd64/traceconv',
'sha256':
- 'ae7903f9bb8a98b32fdf96c0124797cf9b4b58a9bcb45a05574d74d33b11ada9',
+ 'b651d0a5b5606c1c3e24723e94d8ecb233a01f0dfccc95a2c6a4e773cb8f52d7',
'platform':
'darwin',
'machine': ['x86_64']
@@ -19,11 +19,11 @@
'file_name':
'traceconv',
'file_size':
- 7580200,
+ 7761896,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/mac-arm64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/mac-arm64/traceconv',
'sha256':
- '619f31cd84a70fcb75e2a1cbe911f77feca0273ea0b1e706ae4be5ac020cdf7d',
+ '3b019f5ddd5293d3181f7c30f91dc7b08f3a2e83ebb3b52b8f3905dc5161747d',
'platform':
'darwin',
'machine': ['arm64']
@@ -33,11 +33,11 @@
'file_name':
'traceconv',
'file_size':
- 8773576,
+ 8928296,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/linux-amd64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/linux-amd64/traceconv',
'sha256':
- 'abc0b4191abe5106e1d4382bc0d238e53c39a83e1ba91237fbed5f789ef1c82b',
+ '830d20ffec266218d49f6b6c8efed4538bc59b51d8d2f735cbbb6a1435131b50',
'platform':
'linux',
'machine': ['x86_64']
@@ -47,11 +47,11 @@
'file_name':
'traceconv',
'file_size':
- 6620748,
+ 6770204,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/linux-arm/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/linux-arm/traceconv',
'sha256':
- 'f2dd9f1bfabea567ff20aedd0798e90093eff2bfdc15aacbfafe0abe52aa1fd1',
+ '93a9e5ccb94559b871af8f6da45f858aee01801b31776703892dcf3d7ea769b7',
'platform':
'linux',
'machine': ['armv6l', 'armv7l', 'armv8l']
@@ -61,11 +61,11 @@
'file_name':
'traceconv',
'file_size':
- 8240792,
+ 8393944,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/linux-arm64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/linux-arm64/traceconv',
'sha256':
- '76428eca01ced4b769241915fb5233b43b9b59e9062917e45d523db10f33e546',
+ '88a92ccbcd8e851673e018b7f599514daf05dde9b7e4de9641fa5629124abf12',
'platform':
'linux',
'machine': ['aarch64']
@@ -75,55 +75,55 @@
'file_name':
'traceconv',
'file_size':
- 6247672,
+ 6378744,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/android-arm/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/android-arm/traceconv',
'sha256':
- '3eb80bbd78c6210b73ef20654b9d80994747e552b3d342a8d2ec4aa58dabcc33'
+ '6cb7d30d656aa4f172e6724f105a56e249e7043ecf637c65e1e3868885535cff'
}, {
'arch':
'android-arm64',
'file_name':
'traceconv',
'file_size':
- 7545032,
+ 7692488,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/android-arm64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/android-arm64/traceconv',
'sha256':
- '30037aba74f7718f71273a83141373e623ddfe561294d01b41433dc9b572fee5'
+ '1668808efbdf8d5b116d4716d61d2bd002f71ce465206d3b83af4fcc7a4c19cd'
}, {
'arch':
'android-x86',
'file_name':
'traceconv',
'file_size':
- 8410300,
+ 8557756,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/android-x86/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/android-x86/traceconv',
'sha256':
- '9ad420368453699da12ce6359db514283e92b2caa2d415d9db61977cc79649a9'
+ '653733582cae0021eae0e1b5d8db387c1bae772d77b307f1e2111b78ec4ea67c'
}, {
'arch':
'android-x64',
'file_name':
'traceconv',
'file_size':
- 8544512,
+ 8708352,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/android-x64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/android-x64/traceconv',
'sha256':
- '60a62f8712186c5f984ff2fbc4ff8c47b6226b62a83b31f878e0597c8bb90cd8'
+ '7fc564ac581b81d79573f57dae027c47bd7a857ff0f89df984380c3c657d5876'
}, {
'arch':
'windows-amd64',
'file_name':
'traceconv.exe',
'file_size':
- 8049664,
+ 8204288,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/windows-amd64/traceconv.exe',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/windows-amd64/traceconv.exe',
'sha256':
- '9e89ccd0cdb466ea5fe960b71538b0ff8a2858b9e7ecdbcafa9ffe60839c9afc',
+ 'e33bad8061f08f9c3cfe6e91ef6f1696b6ac90d0799edcb57052f24888b436e2',
'platform':
'win32',
'machine': ['amd64']
diff --git a/python/tools/record_android_trace.py b/python/tools/record_android_trace.py
index 06a4fa7..7dbca53 100755
--- a/python/tools/record_android_trace.py
+++ b/python/tools/record_android_trace.py
@@ -431,7 +431,7 @@
fname = os.path.basename(path)
socketserver.TCPServer.allow_reuse_address = True
with socketserver.TCPServer(('127.0.0.1', PORT), HttpHandler) as httpd:
- address = f'{origin}/#!/?url=http://127.0.0.1:{PORT}/{fname}'
+ address = f'{origin}/#!/?url=http://127.0.0.1:{PORT}/{fname}&referrer=record_android_trace'
if open_browser:
webbrowser.open_new_tab(address)
else:
diff --git a/src/base/time.cc b/src/base/time.cc
index 3ea2343..e799542 100644
--- a/src/base/time.cc
+++ b/src/base/time.cc
@@ -79,7 +79,7 @@
// Make sure that at least 50 ms elapsed between the 2 readings. The first
// time that this function is called, we don't expect this to be the case.
- // Note: The longer the elapsed time between the 2 readings is, the morehttps://chromium-status.appspot.com/
+ // Note: The longer the elapsed time between the 2 readings is, the more
// accurate the computed TSC frequency will be. The 50 ms value was
// chosen because local benchmarks show that it allows us to get a
// stddev of less than 1 tick/us between multiple runs.
@@ -91,7 +91,8 @@
PERFETTO_CHECK(perf_counter_now >= perf_counter_initial);
const int64_t perf_counter_ticks = perf_counter_now - perf_counter_initial;
const double elapsed_time_seconds =
- perf_counter_ticks / static_cast<double>(perf_counter_frequency.QuadPart);
+ static_cast<double>(perf_counter_ticks) /
+ static_cast<double>(perf_counter_frequency.QuadPart);
constexpr double kMinimumEvaluationPeriodSeconds = 0.05;
if (elapsed_time_seconds < kMinimumEvaluationPeriodSeconds)
@@ -102,8 +103,9 @@
const uint64_t tsc_ticks = tsc_now - tsc_initial;
// Racing with another thread to write |tsc_ticks_per_second| is benign
// because both threads will write a valid result.
- tsc_ticks_per_second.store(tsc_ticks / elapsed_time_seconds,
- std::memory_order_relaxed);
+ tsc_ticks_per_second.store(
+ static_cast<double>(tsc_ticks) / elapsed_time_seconds,
+ std::memory_order_relaxed);
return tsc_ticks_per_second.load(std::memory_order_relaxed);
}
@@ -149,7 +151,8 @@
return TimeNanos();
// Return the CPU time of the current thread.
- const double thread_time_seconds = thread_cycle_time / tsc_ticks_per_second;
+ const double thread_time_seconds =
+ static_cast<double>(thread_cycle_time) / tsc_ticks_per_second;
constexpr int64_t kNanosecondsPerSecond = 1000 * 1000 * 1000;
return TimeNanos(
static_cast<int64_t>(thread_time_seconds * kNanosecondsPerSecond));
diff --git a/src/ipc/host_impl.cc b/src/ipc/host_impl.cc
index 029b450..0c862ee 100644
--- a/src/ipc/host_impl.cc
+++ b/src/ipc/host_impl.cc
@@ -21,6 +21,7 @@
#include <utility>
#include "perfetto/base/build_config.h"
+#include "perfetto/base/compiler.h"
#include "perfetto/base/logging.h"
#include "perfetto/base/task_runner.h"
#include "perfetto/base/time.h"
@@ -44,6 +45,47 @@
kUseTCPSocket ? base::SockFamily::kInet : base::SockFamily::kUnix;
base::CrashKey g_crash_key_uid("ipc_uid");
+
+base::MachineID GenerateMachineID(base::UnixSocket* sock,
+ const std::string& machine_id_hint) {
+ // The special value of base::kDefaultMachineID is reserved for local
+ // producers.
+ if (!sock->is_connected() || sock->family() == base::SockFamily::kUnix)
+ return base::kDefaultMachineID;
+
+ base::Hasher hasher;
+ // Use the hint from the client, or fallback to hostname if the client
+ // doesn't provide a hint.
+ if (!machine_id_hint.empty()) {
+ hasher.Update(machine_id_hint);
+ } else {
+ // Use the socket address without the port number part as the hint.
+ auto host_id = sock->GetSockAddr();
+ auto pos = std::string::npos;
+ switch (sock->family()) {
+ case base::SockFamily::kInet:
+ PERFETTO_FALLTHROUGH;
+ case base::SockFamily::kInet6:
+ PERFETTO_FALLTHROUGH;
+ case base::SockFamily::kVsock:
+ pos = host_id.rfind(":");
+ if (pos != std::string::npos)
+ host_id.resize(pos);
+ break;
+ case base::SockFamily::kUnspec:
+ PERFETTO_FALLTHROUGH;
+ case base::SockFamily::kUnix:
+ PERFETTO_DFATAL("Should be unreachable.");
+ return base::kDefaultMachineID;
+ }
+ hasher.Update(host_id);
+ }
+
+ // Take the lower 32-bit from the hash.
+ uint32_t digest = static_cast<uint32_t>(hasher.digest());
+ // Avoid the extremely unlikely case that the hasher digest happens to be 0.
+ return digest == base::kDefaultMachineID ? 1 : digest;
+}
} // namespace
uid_t HostImpl::ClientConnection::GetPosixPeerUid() const {
@@ -285,8 +327,8 @@
auto peer_uid = client->GetPosixPeerUid();
auto scoped_key = g_crash_key_uid.SetScoped(static_cast<int64_t>(peer_uid));
- service->client_info_ =
- ClientInfo(client->id, peer_uid, client->GetLinuxPeerPid());
+ service->client_info_ = ClientInfo(
+ client->id, peer_uid, client->GetLinuxPeerPid(), client->GetMachineID());
service->received_fd_ = &client->received_fd;
method.invoker(service, *decoded_req_args, std::move(deferred_reply));
service->received_fd_ = nullptr;
@@ -307,9 +349,12 @@
return;
}
- client->pid_override = req_frame.set_peer_identity().pid();
- client->uid_override =
- static_cast<uid_t>(req_frame.set_peer_identity().uid());
+ const auto& set_peer_identity = req_frame.set_peer_identity();
+ client->pid_override = set_peer_identity.pid();
+ client->uid_override = static_cast<uid_t>(set_peer_identity.uid());
+
+ client->machine_id = GenerateMachineID(client->sock.get(),
+ set_peer_identity.machine_id_hint());
}
void HostImpl::ReplyToMethodInvocation(ClientID client_id,
@@ -375,7 +420,8 @@
ClientID client_id = client->id;
ClientInfo client_info(client_id, client->GetPosixPeerUid(),
- client->GetLinuxPeerPid());
+ client->GetLinuxPeerPid(), client->GetMachineID());
+
clients_by_socket_.erase(it);
PERFETTO_DCHECK(clients_.count(client_id));
clients_.erase(client_id);
diff --git a/src/ipc/host_impl.h b/src/ipc/host_impl.h
index 8738459..c54a9e7 100644
--- a/src/ipc/host_impl.h
+++ b/src/ipc/host_impl.h
@@ -67,14 +67,19 @@
BufferedFrameDeserializer frame_deserializer;
base::ScopedFile received_fd;
std::function<bool(int)> send_fd_cb_fuchsia;
- // Peer identity set using IPCFrame sent by the client. These 2 fields
+ // Peer identity set using IPCFrame sent by the client. These 3 fields
// should be used only for non-AF_UNIX connections AF_UNIX connections
// should only rely on the peer identity obtained from the socket.
uid_t uid_override = base::kInvalidUid;
pid_t pid_override = base::kInvalidPid;
+ // |machine_id| is mapped from machine_id_hint (or socket hostname if
+ // |the client doesn't support machine_id_hint).
+ base::MachineID machine_id = base::kDefaultMachineID;
+
pid_t GetLinuxPeerPid() const;
uid_t GetPosixPeerUid() const;
+ base::MachineID GetMachineID() const { return machine_id; }
};
struct ExposedService {
ExposedService(ServiceID, const std::string&, std::unique_ptr<Service>);
diff --git a/src/ipc/host_impl_unittest.cc b/src/ipc/host_impl_unittest.cc
index c6e0404..927a5a6 100644
--- a/src/ipc/host_impl_unittest.cc
+++ b/src/ipc/host_impl_unittest.cc
@@ -15,11 +15,12 @@
*/
#include "src/ipc/host_impl.h"
-
+#include <sys/socket.h>
#include <memory>
#include "perfetto/ext/base/file_utils.h"
#include "perfetto/ext/base/scoped_file.h"
+#include "perfetto/ext/base/sys_types.h"
#include "perfetto/ext/base/temp_file.h"
#include "perfetto/ext/base/unix_socket.h"
#include "perfetto/ext/base/utils.h"
@@ -37,6 +38,7 @@
namespace ipc {
namespace {
+using ::perfetto::ipc::Frame;
using ::perfetto::ipc::gen::ReplyProto;
using ::perfetto::ipc::gen::RequestProto;
using ::testing::_;
@@ -95,6 +97,12 @@
base::SockType::kStream);
}
+ FakeClient(const char* sock_name, base::TaskRunner* task_runner) {
+ auto sock_family = base::GetSockFamily(sock_name);
+ sock_ = base::UnixSocket::Connect(sock_name, this, task_runner, sock_family,
+ base::SockType::kStream);
+ }
+
FakeClient(base::ScopedSocketHandle connected_socket,
base::TaskRunner* task_runner) {
sock_ = base::UnixSocket::AdoptConnected(std::move(connected_socket), this,
@@ -114,6 +122,21 @@
SendFrame(frame);
}
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
+ void SetPeerIdentity(uid_t uid,
+ pid_t pid,
+ const std::string& machine_id_hint) {
+ Frame ipc_frame;
+ ipc_frame.set_request_id(0);
+ auto* set_peer_identity = ipc_frame.mutable_set_peer_identity();
+ set_peer_identity->set_pid(pid);
+ set_peer_identity->set_uid(static_cast<int32_t>(uid));
+ set_peer_identity->set_machine_id_hint(machine_id_hint);
+ SendFrame(ipc_frame);
+ }
+#endif
+
void InvokeMethod(ServiceID service_id,
MethodID method_id,
const ProtoMessage& args,
@@ -530,6 +553,97 @@
EXPECT_CALL(*cli_, OnInvokeMethodReply(_)).WillOnce(Return());
task_runner_->RunUntilIdle();
}
+
+TEST_F(HostImplTest, SetPeerIdentityUnixSocket) {
+ FakeService* fake_service = new FakeService("FakeService");
+ ASSERT_TRUE(host_->ExposeService(std::unique_ptr<Service>(fake_service)));
+ // SetPeerIdentity must be the first message. Use getpid()+1/geteuid+1 to
+ // check that this message doesn't take effect for Unix socket.
+ cli_->SetPeerIdentity(geteuid() + 1, getpid() + 1, "test_machine_id_hint");
+
+ auto on_bind = task_runner_->CreateCheckpoint("on_bind");
+ cli_->BindService("FakeService");
+ EXPECT_CALL(*cli_, OnServiceBound(_)).WillOnce(InvokeWithoutArgs(on_bind));
+ task_runner_->RunUntilCheckpoint("on_bind");
+
+ RequestProto req_args;
+ req_args.set_data("foo");
+ cli_->InvokeMethod(cli_->last_bound_service_id_, 1, req_args);
+ EXPECT_CALL(*fake_service, OnFakeMethod1(_, _))
+ .WillOnce(
+ Invoke([fake_service](const RequestProto& req, DeferredBase* reply) {
+ ASSERT_EQ("foo", req.data());
+ std::unique_ptr<ReplyProto> reply_args(new ReplyProto());
+ reply_args->set_data("bar");
+ reply->Resolve(AsyncResult<ProtoMessage>(
+ std::unique_ptr<ProtoMessage>(reply_args.release())));
+ // Verifies the pid() and uid() values in ClientInfo.
+ const auto& client_info = fake_service->client_info();
+ ASSERT_EQ(client_info.uid(), getuid());
+ ASSERT_EQ(client_info.pid(), getpid());
+ ASSERT_EQ(client_info.machine_id(), base::kDefaultMachineID);
+ }));
+
+ EXPECT_CALL(*cli_, OnInvokeMethodReply(_)).WillOnce(Return());
+ task_runner_->RunUntilIdle();
+}
+
+TEST(HostImpl, SetPeerIdentityTcpSocket) {
+ std::unique_ptr<base::TestTaskRunner> task_runner(new base::TestTaskRunner());
+ std::unique_ptr<HostImpl> host_impl;
+ std::unique_ptr<FakeClient> cli;
+
+ auto tear_down = base::OnScopeExit([&]() {
+ task_runner->RunUntilIdle();
+ cli.reset();
+ host_impl.reset();
+ task_runner->RunUntilIdle();
+ task_runner.reset();
+ });
+
+ Host* host = Host::CreateInstance("127.0.0.1:0", task_runner.get()).release();
+ ASSERT_NE(nullptr, host);
+ host_impl.reset(static_cast<HostImpl*>(host));
+
+ auto sock_name = host_impl->sock()->GetSockAddr();
+ cli.reset(new FakeClient(sock_name.c_str(), task_runner.get()));
+
+ auto on_connect = task_runner->CreateCheckpoint("on_connect");
+ EXPECT_CALL(*cli, OnConnect()).WillOnce(Invoke(on_connect));
+ task_runner->RunUntilCheckpoint("on_connect");
+
+ FakeService* fake_service = new FakeService("FakeService");
+ ASSERT_TRUE(host->ExposeService(std::unique_ptr<Service>(fake_service)));
+ // Set peer identity with fake values.
+ cli->SetPeerIdentity(123, 456, "test_machine_id_hint");
+
+ auto on_bind = task_runner->CreateCheckpoint("on_bind");
+ cli->BindService("FakeService");
+ EXPECT_CALL(*cli, OnServiceBound(_)).WillOnce(InvokeWithoutArgs(on_bind));
+ task_runner->RunUntilCheckpoint("on_bind");
+
+ RequestProto req_args;
+ req_args.set_data("foo");
+ cli->InvokeMethod(cli->last_bound_service_id_, 1, req_args);
+ EXPECT_CALL(*fake_service, OnFakeMethod1(_, _))
+ .WillOnce(
+ Invoke([fake_service](const RequestProto& req, DeferredBase* reply) {
+ ASSERT_EQ("foo", req.data());
+ std::unique_ptr<ReplyProto> reply_args(new ReplyProto());
+ reply_args->set_data("bar");
+ reply->Resolve(AsyncResult<ProtoMessage>(
+ std::unique_ptr<ProtoMessage>(reply_args.release())));
+ // Verify peer identity.
+ const auto& client_info = fake_service->client_info();
+ ASSERT_EQ(client_info.uid(), 123u);
+ ASSERT_EQ(client_info.pid(), 456);
+ // ClientInfo contains non-default raw machine ID.
+ ASSERT_NE(client_info.machine_id(), base::kDefaultMachineID);
+ }));
+
+ EXPECT_CALL(*cli, OnInvokeMethodReply(_)).WillOnce(Return());
+ task_runner->RunUntilIdle();
+}
#endif // OS_WIN
// TODO(primiano): add the tests below in next CLs.
diff --git a/src/tools/ftrace_proto_gen/event_list b/src/tools/ftrace_proto_gen/event_list
index f2dcbb3..68bb2ba 100644
--- a/src/tools/ftrace_proto_gen/event_list
+++ b/src/tools/ftrace_proto_gen/event_list
@@ -481,3 +481,4 @@
samsung/tracing_mark_write
binder/binder_command
binder/binder_return
+perf_trace_counters/sched_switch_with_ctrs
diff --git a/src/trace_processor/BUILD.gn b/src/trace_processor/BUILD.gn
index b09ed17..b89512e 100644
--- a/src/trace_processor/BUILD.gn
+++ b/src/trace_processor/BUILD.gn
@@ -269,7 +269,6 @@
":top_level_unittests",
"containers:unittests",
"db:unittests",
- "db/overlays:unittests",
"db/storage:unittests",
"importers/android_bugreport:unittests",
"importers/common:unittests",
diff --git a/src/trace_processor/db/BUILD.gn b/src/trace_processor/db/BUILD.gn
index 067d768..604929d 100644
--- a/src/trace_processor/db/BUILD.gn
+++ b/src/trace_processor/db/BUILD.gn
@@ -44,7 +44,6 @@
"../util:glob",
"../util:regex",
"../util:util",
- "overlays",
"storage",
]
}
@@ -70,8 +69,8 @@
"../../base",
"../tables",
"../views",
- "overlays",
"storage",
+ "storage:fake_storage",
]
}
diff --git a/src/trace_processor/db/overlays/BUILD.gn b/src/trace_processor/db/overlays/BUILD.gn
deleted file mode 100644
index c2a16e5..0000000
--- a/src/trace_processor/db/overlays/BUILD.gn
+++ /dev/null
@@ -1,51 +0,0 @@
-# Copyright (C) 2023 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_tp_tables.gni")
-import("../../../../gn/test.gni")
-
-source_set("overlays") {
- sources = [
- "arrangement_overlay.cc",
- "arrangement_overlay.h",
- "null_overlay.cc",
- "null_overlay.h",
- "selector_overlay.cc",
- "selector_overlay.h",
- "storage_overlay.cc",
- "storage_overlay.h",
- "types.h",
- ]
- deps = [
- "../../../../gn:default_deps",
- "../../../../protos/perfetto/trace_processor:zero",
- "../../../base",
- "../../containers",
- "../storage",
- ]
-}
-
-perfetto_unittest_source_set("unittests") {
- testonly = true
- sources = [
- "arrangement_overlay_unittest.cc",
- "null_overlay_unittest.cc",
- "selector_overlay_unittest.cc",
- ]
- deps = [
- ":overlays",
- "../../../../gn:default_deps",
- "../../../../gn:gtest_and_gmock",
- ]
-}
diff --git a/src/trace_processor/db/overlays/arrangement_overlay.cc b/src/trace_processor/db/overlays/arrangement_overlay.cc
deleted file mode 100644
index 0709fb0..0000000
--- a/src/trace_processor/db/overlays/arrangement_overlay.cc
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "src/trace_processor/db/overlays/arrangement_overlay.h"
-#include <iterator>
-#include "perfetto/base/logging.h"
-#include "perfetto/ext/base/flat_hash_map.h"
-#include "protos/perfetto/trace_processor/serialization.pbzero.h"
-#include "src/trace_processor/containers/bit_vector.h"
-#include "src/trace_processor/db/overlays/types.h"
-
-namespace perfetto {
-namespace trace_processor {
-namespace overlays {
-
-using Range = RowMap::Range;
-
-StorageRange ArrangementOverlay::MapToStorageRange(TableRange t_range) const {
- PERFETTO_CHECK(t_range.range.end <= arrangement_->size());
- const auto [min, max] =
- std::minmax_element(arrangement_->data() + t_range.range.start,
- arrangement_->data() + t_range.range.end);
-
- return StorageRange(*min, *max + 1);
-}
-
-TableRangeOrBitVector ArrangementOverlay::MapToTableRangeOrBitVector(
- StorageRange s_range,
- OverlayOp) const {
- BitVector ret(static_cast<uint32_t>(arrangement_->size()), false);
- for (uint32_t i = 0; i < arrangement_->size(); ++i) {
- if (s_range.range.Contains((*arrangement_)[i]))
- ret.Set(i);
- }
- return TableRangeOrBitVector(std::move(ret));
-}
-
-TableBitVector ArrangementOverlay::MapToTableBitVector(StorageBitVector s_bv,
- OverlayOp) const {
- BitVector::Builder builder(static_cast<uint32_t>(arrangement_->size()));
- uint32_t cur_idx = 0;
-
- // Fast path: we compare as many groups of 64 elements as we can.
- // This should be very easy for the compiler to auto-vectorize.
- uint32_t fast_path_elements = builder.BitsInCompleteWordsUntilFull();
- for (uint32_t i = 0; i < fast_path_elements; i += BitVector::kBitsInWord) {
- uint64_t word = 0;
- // This part should be optimised by SIMD and is expected to be fast.
- for (uint32_t k = 0; k < BitVector::kBitsInWord; ++k, ++cur_idx) {
- bool comp_result = s_bv.bv.IsSet((*arrangement_)[cur_idx]);
- word |= static_cast<uint64_t>(comp_result) << k;
- }
- builder.AppendWord(word);
- }
-
- // Slow path: we compare <64 elements and append to fill the Builder.
- uint32_t back_elements = builder.BitsUntilFull();
- for (uint32_t i = 0; i < back_elements; ++i, ++cur_idx) {
- builder.Append(s_bv.bv.IsSet((*arrangement_)[cur_idx]));
- }
- return TableBitVector{std::move(builder).Build()};
-}
-
-BitVector ArrangementOverlay::IsStorageLookupRequired(
- OverlayOp,
- const TableIndexVector& t_iv) const {
- return BitVector(t_iv.size(), true);
-}
-
-StorageIndexVector ArrangementOverlay::MapToStorageIndexVector(
- TableIndexVector t_iv) const {
- std::vector<uint32_t> ret;
- for (const auto& i : t_iv.indices) {
- ret.push_back((*arrangement_)[i]);
- }
- return StorageIndexVector{ret};
-}
-
-BitVector ArrangementOverlay::IndexSearch(OverlayOp,
- const TableIndexVector&) const {
- PERFETTO_FATAL("IndexSearch should not be called inside ArrangementOverlay");
-}
-
-CostEstimatePerRow ArrangementOverlay::EstimateCostPerRow(OverlayOp) const {
- CostEstimatePerRow estimate;
- // Cost of std::min and std::max
- estimate.to_storage_range = 20;
- // Free
- estimate.to_table_bit_vector = 0;
- // Cost of creating trivial vector of 1s
- estimate.is_storage_search_required = 0;
- // Cost of a lookup inside |arrangement_|
- estimate.map_to_storage_index_vector = 10;
- // Shouldn't be called
- estimate.index_search = 0;
-
- return estimate;
-}
-
-void ArrangementOverlay::Serialize(OverlayProto* msg) const {
- PERFETTO_CHECK(arrangement_);
- auto* arrangement_msg = msg->set_arrangement_overlay();
- arrangement_msg->set_values(
- reinterpret_cast<const uint8_t*>(arrangement_->data()),
- sizeof(uint32_t) * arrangement_->size());
-}
-
-} // namespace overlays
-} // namespace trace_processor
-} // namespace perfetto
diff --git a/src/trace_processor/db/overlays/arrangement_overlay.h b/src/trace_processor/db/overlays/arrangement_overlay.h
deleted file mode 100644
index f0040d3..0000000
--- a/src/trace_processor/db/overlays/arrangement_overlay.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef SRC_TRACE_PROCESSOR_DB_OVERLAYS_ARRANGEMENT_OVERLAY_H_
-#define SRC_TRACE_PROCESSOR_DB_OVERLAYS_ARRANGEMENT_OVERLAY_H_
-
-#include "src/trace_processor/db/overlays/storage_overlay.h"
-
-namespace perfetto {
-namespace trace_processor {
-namespace overlays {
-
-// Overlay responsible for arranging the elements of Storage. It deals with
-// duplicates, permutations and selection. For selection only it's more
-// efficient to use `SelectorOverlay`.
-class ArrangementOverlay : public StorageOverlay {
- public:
- explicit ArrangementOverlay(const std::vector<uint32_t>* arrangement)
- : arrangement_(std::move(arrangement)) {}
-
- StorageRange MapToStorageRange(TableRange) const override;
-
- TableRangeOrBitVector MapToTableRangeOrBitVector(StorageRange,
- OverlayOp) const override;
-
- TableBitVector MapToTableBitVector(StorageBitVector,
- OverlayOp) const override;
-
- BitVector IsStorageLookupRequired(OverlayOp,
- const TableIndexVector&) const override;
-
- StorageIndexVector MapToStorageIndexVector(TableIndexVector) const override;
-
- BitVector IndexSearch(OverlayOp, const TableIndexVector&) const override;
-
- CostEstimatePerRow EstimateCostPerRow(OverlayOp) const override;
-
- void Serialize(OverlayProto*) const override;
-
- private:
- const std::vector<uint32_t>* arrangement_;
-};
-
-} // namespace overlays
-} // namespace trace_processor
-} // namespace perfetto
-
-#endif // SRC_TRACE_PROCESSOR_DB_OVERLAYS_ARRANGEMENT_OVERLAY_H_
diff --git a/src/trace_processor/db/overlays/arrangement_overlay_unittest.cc b/src/trace_processor/db/overlays/arrangement_overlay_unittest.cc
deleted file mode 100644
index 1418bab..0000000
--- a/src/trace_processor/db/overlays/arrangement_overlay_unittest.cc
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "src/trace_processor/db/overlays/arrangement_overlay.h"
-#include "test/gtest_and_gmock.h"
-
-namespace perfetto {
-namespace trace_processor {
-namespace overlays {
-namespace {
-
-TEST(ArrangementOverlay, MapToStorageRangeFirst) {
- std::vector<uint32_t> arrangement{1, 1, 2, 2, 3, 3, 4, 4, 1, 1};
- ArrangementOverlay overlay(&arrangement);
- StorageRange r = overlay.MapToStorageRange(TableRange(2, 4));
-
- ASSERT_EQ(r.range.start, 2u);
- ASSERT_EQ(r.range.end, 3u);
-}
-
-TEST(ArrangementOverlay, MapToStorageRangeSecond) {
- std::vector<uint32_t> arrangement{1, 1, 2, 2, 3, 3, 4, 4, 1, 1};
- ArrangementOverlay overlay(&arrangement);
- StorageRange r = overlay.MapToStorageRange(TableRange(5, 10));
-
- ASSERT_EQ(r.range.start, 1u);
- ASSERT_EQ(r.range.end, 5u);
-}
-
-TEST(ArrangementOverlay, MapToTableBitVector) {
- std::vector<uint32_t> arrangement{1, 1, 2, 2, 3, 3, 4, 4, 1, 1};
- ArrangementOverlay overlay(&arrangement);
-
- BitVector storage_bv{0, 1, 0, 1, 0};
-
- // Table bv:
- // 1, 1, 0, 0, 1, 1, 0, 0, 1, 1
- TableBitVector table_bv =
- overlay.MapToTableBitVector({std::move(storage_bv)}, OverlayOp::kOther);
-
- ASSERT_EQ(table_bv.bv.size(), 10u);
- ASSERT_EQ(table_bv.bv.CountSetBits(), 6u);
-
- ASSERT_TRUE(table_bv.bv.IsSet(0));
- ASSERT_TRUE(table_bv.bv.IsSet(1));
- ASSERT_TRUE(table_bv.bv.IsSet(4));
- ASSERT_TRUE(table_bv.bv.IsSet(5));
- ASSERT_TRUE(table_bv.bv.IsSet(8));
- ASSERT_TRUE(table_bv.bv.IsSet(9));
-}
-
-TEST(ArrangementOverlay, IsStorageLookupRequired) {
- std::vector<uint32_t> arrangement{0, 1, 1, 0, 0, 1, 1, 0};
- ArrangementOverlay overlay(&arrangement);
-
- std::vector<uint32_t> table_idx{0, 1, 2};
- BitVector lookup_bv =
- overlay.IsStorageLookupRequired(OverlayOp::kIsNull, {table_idx});
-
- ASSERT_EQ(lookup_bv.size(), 3u);
-}
-
-TEST(ArrangementOverlay, MapToStorageIndexVector) {
- std::vector<uint32_t> arrangement{1, 1, 2, 2, 3, 3, 4, 4, 1, 1};
- ArrangementOverlay overlay(&arrangement);
-
- std::vector<uint32_t> table_idx{1, 3, 7};
- StorageIndexVector storage_iv = overlay.MapToStorageIndexVector({table_idx});
-
- std::vector<uint32_t> res{1, 2, 4};
- ASSERT_EQ(storage_iv.indices, res);
-}
-
-} // namespace
-} // namespace overlays
-} // namespace trace_processor
-} // namespace perfetto
diff --git a/src/trace_processor/db/overlays/null_overlay.cc b/src/trace_processor/db/overlays/null_overlay.cc
deleted file mode 100644
index 0b86623..0000000
--- a/src/trace_processor/db/overlays/null_overlay.cc
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "src/trace_processor/db/overlays/null_overlay.h"
-#include "perfetto/ext/base/flat_hash_map.h"
-#include "protos/perfetto/trace_processor/serialization.pbzero.h"
-#include "src/trace_processor/containers/bit_vector.h"
-#include "src/trace_processor/db/overlays/types.h"
-
-namespace perfetto {
-namespace trace_processor {
-namespace overlays {
-
-using Range = RowMap::Range;
-
-StorageRange NullOverlay::MapToStorageRange(TableRange t_range) const {
- uint32_t start = non_null_->CountSetBits(t_range.range.start);
- uint32_t end = non_null_->CountSetBits(t_range.range.end);
-
- return StorageRange(start, end);
-}
-
-TableRangeOrBitVector NullOverlay::MapToTableRangeOrBitVector(
- StorageRange s_range,
- OverlayOp op) const {
- PERFETTO_DCHECK(s_range.range.end <= non_null_->CountSetBits());
-
- BitVector range_to_bv(s_range.range.start, false);
- range_to_bv.Resize(s_range.range.end, true);
-
- return TableRangeOrBitVector(
- MapToTableBitVector(StorageBitVector{std::move(range_to_bv)}, op).bv);
-}
-
-TableBitVector NullOverlay::MapToTableBitVector(StorageBitVector s_bv,
- OverlayOp op) const {
- BitVector res = non_null_->Copy();
- res.UpdateSetBits(s_bv.bv);
-
- if (op != OverlayOp::kIsNull)
- return {std::move(res)};
-
- BitVector not_non_null = non_null_->Copy();
- not_non_null.Not();
-
- if (res.CountSetBits() == 0)
- return {std::move(not_non_null)};
-
- res.Or(not_non_null);
- return {std::move(res)};
-}
-
-BitVector NullOverlay::IsStorageLookupRequired(
- OverlayOp op,
- const TableIndexVector& t_iv) const {
- PERFETTO_DCHECK(t_iv.indices.size() <= non_null_->size());
-
- if (op != OverlayOp::kOther)
- return BitVector(t_iv.size(), false);
-
- BitVector in_storage(static_cast<uint32_t>(t_iv.indices.size()), false);
-
- // For each index in TableIndexVector check whether this index is in storage.
- for (uint32_t i = 0; i < t_iv.indices.size(); ++i) {
- if (non_null_->IsSet(t_iv.indices[i]))
- in_storage.Set(i);
- }
-
- return in_storage;
-}
-
-StorageIndexVector NullOverlay::MapToStorageIndexVector(
- TableIndexVector t_iv_with_idx_in_storage) const {
- PERFETTO_DCHECK(t_iv_with_idx_in_storage.indices.size() <=
- non_null_->CountSetBits());
-
- std::vector<uint32_t> storage_index_vector;
- storage_index_vector.reserve(t_iv_with_idx_in_storage.indices.size());
- for (auto t_idx : t_iv_with_idx_in_storage.indices) {
- storage_index_vector.push_back(non_null_->CountSetBits(t_idx));
- }
-
- return StorageIndexVector({std::move(storage_index_vector)});
-}
-
-BitVector NullOverlay::IndexSearch(
- OverlayOp op,
- const TableIndexVector& t_iv_overlay_idx) const {
- if (op == OverlayOp::kOther)
- return BitVector(t_iv_overlay_idx.size(), false);
-
- BitVector res(static_cast<uint32_t>(t_iv_overlay_idx.indices.size()), false);
- if (op == OverlayOp::kIsNull) {
- for (uint32_t i = 0; i < res.size(); ++i) {
- if (!non_null_->IsSet(t_iv_overlay_idx.indices[i]))
- res.Set(i);
- }
- return res;
- }
-
- PERFETTO_DCHECK(op == OverlayOp::kIsNotNull);
- for (uint32_t i = 0; i < res.size(); ++i) {
- if (non_null_->IsSet(t_iv_overlay_idx.indices[i]))
- res.Set(i);
- }
- return res;
-}
-
-CostEstimatePerRow NullOverlay::EstimateCostPerRow(OverlayOp op) const {
- // TODO(b/283763282): Replace with benchmarked data.
- CostEstimatePerRow res;
-
- // Two |BitVector::CountSetBits| calls.
- res.to_storage_range = 100;
-
- // Cost of |BitVector::UpdateSetBits|
- res.to_table_bit_vector = 100;
-
- if (op == OverlayOp::kOther) {
- // Cost of |BitVector::IsSet| and |BitVector::Set|
- res.is_storage_search_required = 10;
-
- // Cost of iterating all set bits and looping the index vector divided by
- // number of indices.
- res.map_to_storage_index_vector = 100;
-
- // Won't be called.
- res.index_search = 0;
- } else {
- // Cost of creating trivial BitVector.
- res.is_storage_search_required = 0;
-
- // Won't be called
- res.map_to_storage_index_vector = 0;
-
- // Cost of calling |BitVector::IsSet|
- res.index_search = 10;
- }
-
- return res;
-}
-
-void NullOverlay::Serialize(OverlayProto* message) const {
- auto* bv_message = message->set_null_overlay()->set_bit_vector();
- non_null_->Serialize(bv_message);
-}
-
-} // namespace overlays
-} // namespace trace_processor
-} // namespace perfetto
diff --git a/src/trace_processor/db/overlays/null_overlay.h b/src/trace_processor/db/overlays/null_overlay.h
deleted file mode 100644
index 4d99a0f..0000000
--- a/src/trace_processor/db/overlays/null_overlay.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef SRC_TRACE_PROCESSOR_DB_OVERLAYS_NULL_OVERLAY_H_
-#define SRC_TRACE_PROCESSOR_DB_OVERLAYS_NULL_OVERLAY_H_
-
-#include "src/trace_processor/db/overlays/storage_overlay.h"
-#include "src/trace_processor/db/overlays/types.h"
-
-namespace perfetto {
-namespace trace_processor {
-namespace overlays {
-
-// Introduces the layer of nullability - spreads out the storage with nulls
-// using BitVector.
-class NullOverlay : public StorageOverlay {
- public:
- explicit NullOverlay(const BitVector* null) : non_null_(std::move(null)) {}
-
- StorageRange MapToStorageRange(TableRange) const override;
-
- TableRangeOrBitVector MapToTableRangeOrBitVector(StorageRange,
- OverlayOp) const override;
-
- TableBitVector MapToTableBitVector(StorageBitVector,
- OverlayOp) const override;
-
- BitVector IsStorageLookupRequired(OverlayOp,
- const TableIndexVector&) const override;
-
- StorageIndexVector MapToStorageIndexVector(TableIndexVector) const override;
-
- BitVector IndexSearch(OverlayOp, const TableIndexVector&) const override;
-
- CostEstimatePerRow EstimateCostPerRow(OverlayOp) const override;
-
- void Serialize(OverlayProto*) const override;
-
- private:
- // Non null data in the overlay.
- const BitVector* non_null_;
-};
-
-} // namespace overlays
-} // namespace trace_processor
-} // namespace perfetto
-
-#endif // SRC_TRACE_PROCESSOR_DB_OVERLAYS_NULL_OVERLAY_H_
diff --git a/src/trace_processor/db/overlays/null_overlay_unittest.cc b/src/trace_processor/db/overlays/null_overlay_unittest.cc
deleted file mode 100644
index aff9474..0000000
--- a/src/trace_processor/db/overlays/null_overlay_unittest.cc
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "src/trace_processor/db/overlays/null_overlay.h"
-#include "test/gtest_and_gmock.h"
-
-namespace perfetto {
-namespace trace_processor {
-namespace overlays {
-namespace {
-
-TEST(NullOverlay, MapToStorageRangeOutsideBoundary) {
- BitVector bv{0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0};
- NullOverlay overlay(&bv);
- StorageRange r = overlay.MapToStorageRange(TableRange(1, 6));
-
- ASSERT_EQ(r.range.start, 0u);
- ASSERT_EQ(r.range.end, 2u);
-}
-
-TEST(NullOverlay, MapToStorageRangeOnBoundary) {
- BitVector bv{0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0};
- NullOverlay overlay(&bv);
- StorageRange r = overlay.MapToStorageRange(TableRange(3, 8));
-
- ASSERT_EQ(r.range.start, 1u);
- ASSERT_EQ(r.range.end, 4u);
-}
-
-TEST(NullOverlay, MapToTableRangeOutsideBoundary) {
- BitVector bv{0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0};
- NullOverlay overlay(&bv);
- auto r =
- overlay.MapToTableRangeOrBitVector(StorageRange(1, 3), OverlayOp::kOther);
-
- // All set bits between |bv| index 3 and 6.
- ASSERT_EQ(std::move(r).TakeIfBitVector().CountSetBits(), 2u);
-}
-
-TEST(NullOverlay, MapToTableRangeOnBoundary) {
- BitVector bv{0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0};
- NullOverlay overlay(&bv);
- auto r =
- overlay.MapToTableRangeOrBitVector(StorageRange(0, 5), OverlayOp::kOther);
-
- ASSERT_EQ(std::move(r).TakeIfBitVector().CountSetBits(), 5u);
-}
-
-TEST(NullOverlay, MapToTableBitVector) {
- BitVector bv{0, 1, 1, 0, 0, 1, 1, 0};
- NullOverlay overlay(&bv);
-
- BitVector storage_bv{0, 1, 0, 1};
- TableBitVector table_bv =
- overlay.MapToTableBitVector({std::move(storage_bv)}, OverlayOp::kOther);
-
- ASSERT_EQ(table_bv.bv.CountSetBits(), 2u);
- ASSERT_TRUE(table_bv.bv.IsSet(2));
- ASSERT_TRUE(table_bv.bv.IsSet(6));
-}
-
-TEST(NullOverlay, MapToTableBitVectorIsNull) {
- BitVector bv{0, 1, 1, 0, 0, 1, 1, 0};
- NullOverlay overlay(&bv);
-
- BitVector storage_bv{0, 1, 0, 1};
- TableBitVector table_bv =
- overlay.MapToTableBitVector({std::move(storage_bv)}, OverlayOp::kIsNull);
-
- // Result is all of the zeroes from |bv| and set bits from |storage_bv|
- // 1, 0, 1, 1, 1, 0, 1, 1
-
- ASSERT_EQ(table_bv.bv.CountSetBits(), 6u);
- ASSERT_FALSE(table_bv.bv.IsSet(1));
- ASSERT_FALSE(table_bv.bv.IsSet(5));
-}
-
-TEST(NullOverlay, IsStorageLookupRequiredNullOp) {
- BitVector bv{0, 1, 1, 0, 0, 1, 1, 0};
- NullOverlay overlay(&bv);
-
- std::vector<uint32_t> table_idx{0, 2, 4, 6};
- BitVector lookup_bv =
- overlay.IsStorageLookupRequired(OverlayOp::kIsNull, {table_idx});
-
- ASSERT_EQ(lookup_bv.CountSetBits(), 0u);
-}
-
-TEST(NullOverlay, IsStorageLookupRequiredOtherOp) {
- BitVector bv{0, 1, 1, 0, 0, 1, 1, 0};
- NullOverlay overlay(&bv);
-
- std::vector<uint32_t> table_idx{0, 2, 4, 6};
- BitVector lookup_bv =
- overlay.IsStorageLookupRequired(OverlayOp::kOther, {table_idx});
-
- ASSERT_EQ(lookup_bv.size(), 4u);
- ASSERT_EQ(lookup_bv.CountSetBits(), 2u);
- ASSERT_TRUE(lookup_bv.IsSet(1));
- ASSERT_TRUE(lookup_bv.IsSet(3));
-}
-
-TEST(NullOverlay, MapToStorageIndexVector) {
- BitVector bv{0, 1, 1, 0, 0, 1, 1, 0};
- NullOverlay overlay(&bv);
-
- std::vector<uint32_t> table_idx{1, 5, 2};
- StorageIndexVector storage_iv = overlay.MapToStorageIndexVector({table_idx});
-
- std::vector<uint32_t> res{0, 2, 1};
- ASSERT_EQ(storage_iv.indices, res);
-}
-
-TEST(NullOverlay, IndexSearchOtherOp) {
- BitVector bv{0, 1, 1, 0, 0, 1, 1, 0};
- NullOverlay overlay(&bv);
-
- std::vector<uint32_t> table_idx{0, 3, 4};
- BitVector idx_search_bv = overlay.IndexSearch(OverlayOp::kOther, {table_idx});
-
- ASSERT_EQ(idx_search_bv.CountSetBits(), 0u);
-}
-
-TEST(NullOverlay, IndexSearchIsNullOp) {
- BitVector bv{0, 1, 1, 0, 0, 1, 1, 0};
- NullOverlay overlay(&bv);
-
- std::vector<uint32_t> table_idx{0, 3, 4};
- BitVector idx_search_bv =
- overlay.IndexSearch(OverlayOp::kIsNull, {table_idx});
-
- ASSERT_EQ(idx_search_bv.size(), 3u);
- ASSERT_EQ(idx_search_bv.CountSetBits(), 3u);
-}
-
-TEST(NullOverlay, IndexSearchIsNotNullOp) {
- BitVector bv{0, 1, 1, 0, 0, 1, 1, 0};
- NullOverlay overlay(&bv);
-
- std::vector<uint32_t> table_idx{0, 3, 4};
- BitVector idx_search_bv =
- overlay.IndexSearch(OverlayOp::kIsNotNull, {table_idx});
-
- ASSERT_EQ(idx_search_bv.size(), 3u);
- ASSERT_EQ(idx_search_bv.CountSetBits(), 0u);
-}
-
-} // namespace
-} // namespace overlays
-} // namespace trace_processor
-} // namespace perfetto
diff --git a/src/trace_processor/db/overlays/selector_overlay.cc b/src/trace_processor/db/overlays/selector_overlay.cc
deleted file mode 100644
index 1773bd6..0000000
--- a/src/trace_processor/db/overlays/selector_overlay.cc
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "src/trace_processor/db/overlays/selector_overlay.h"
-#include "protos/perfetto/trace_processor/serialization.pbzero.h"
-#include "src/trace_processor/containers/bit_vector.h"
-#include "src/trace_processor/db/overlays/types.h"
-
-namespace perfetto {
-namespace trace_processor {
-namespace overlays {
-
-using Range = RowMap::Range;
-
-StorageRange SelectorOverlay::MapToStorageRange(TableRange t_range) const {
- // Table data is smaller than Storage, so we need to expand the data.
- return StorageRange{
- Range(selected_->IndexOfNthSet(t_range.range.start),
- selected_->IndexOfNthSet(t_range.range.end - 1) + 1)};
-}
-
-TableRangeOrBitVector SelectorOverlay::MapToTableRangeOrBitVector(
- StorageRange s_range,
- OverlayOp) const {
- if (s_range.range.size() == 0)
- return TableRangeOrBitVector(Range());
-
- uint32_t start = selected_->CountSetBits(s_range.range.start);
- uint32_t end = selected_->CountSetBits(s_range.range.end);
-
- return TableRangeOrBitVector(Range(start, end));
-}
-
-TableBitVector SelectorOverlay::MapToTableBitVector(StorageBitVector s_bv,
- OverlayOp) const {
- PERFETTO_DCHECK(s_bv.bv.size() <= selected_->size());
- BitVector res(selected_->CountSetBits());
- // TODO(b/283763282): Implement this variation of |UpdateSetBits| in
- // BitVector.
- for (auto it = selected_->IterateSetBits(); it && it.index() < s_bv.bv.size();
- it.Next()) {
- if (s_bv.bv.IsSet(it.index()))
- res.Set(it.ordinal());
- }
- return TableBitVector({std::move(res)});
-}
-
-BitVector SelectorOverlay::IsStorageLookupRequired(
- OverlayOp,
- const TableIndexVector& t_iv) const {
- return BitVector(static_cast<uint32_t>(t_iv.indices.size()), true);
-}
-
-StorageIndexVector SelectorOverlay::MapToStorageIndexVector(
- TableIndexVector t_iv) const {
- PERFETTO_DCHECK(t_iv.indices.empty() ||
- *std::max_element(t_iv.indices.begin(), t_iv.indices.end()) <=
- selected_->size());
- // To go from TableIndexVector to StorageIndexVector we need to find index in
- // |selector_| by looking only into set bits.
- std::vector<uint32_t> s_iv;
- s_iv.reserve(t_iv.indices.size());
- for (auto t_idx : t_iv.indices) {
- s_iv.push_back(selected_->IndexOfNthSet(t_idx));
- }
-
- return StorageIndexVector({std::move(s_iv)});
-}
-
-BitVector SelectorOverlay::IndexSearch(OverlayOp,
- const TableIndexVector&) const {
- // |t_iv| doesn't contain any values that are null in |selected_| as other
- // overlays are not able to access them. This function should not be called.
- PERFETTO_FATAL("Should not be called in SelectorOverlay.");
-}
-
-CostEstimatePerRow SelectorOverlay::EstimateCostPerRow(OverlayOp) const {
- CostEstimatePerRow estimate;
- // Cost of two |IndexOfNthSet|
- estimate.to_storage_range = 20;
- // Cost of iterating over all selected bits and calling |IsSet| each time (and
- // |Set| if true)
- estimate.to_table_bit_vector = 100;
- // Cost of creating trivial vector of 1s
- estimate.is_storage_search_required = 0;
- // Cost of |IndexOfNthSet| for each row
- estimate.map_to_storage_index_vector = 10;
- // Shouldn't be called
- estimate.index_search = 0;
-
- return estimate;
-}
-
-void SelectorOverlay::Serialize(OverlayProto* msg) const {
- auto* bv_message = msg->set_selector_overlay()->set_bit_vector();
- selected_->Serialize(bv_message);
-}
-
-} // namespace overlays
-} // namespace trace_processor
-} // namespace perfetto
diff --git a/src/trace_processor/db/overlays/selector_overlay.h b/src/trace_processor/db/overlays/selector_overlay.h
deleted file mode 100644
index 9ad87ce..0000000
--- a/src/trace_processor/db/overlays/selector_overlay.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef SRC_TRACE_PROCESSOR_DB_OVERLAYS_SELECTOR_OVERLAY_H_
-#define SRC_TRACE_PROCESSOR_DB_OVERLAYS_SELECTOR_OVERLAY_H_
-
-#include "src/trace_processor/db/overlays/storage_overlay.h"
-#include "src/trace_processor/db/overlays/types.h"
-
-namespace perfetto {
-namespace trace_processor {
-namespace overlays {
-
-// Overlay responsible for selecting specific rows from Storage.
-class SelectorOverlay : public StorageOverlay {
- public:
- explicit SelectorOverlay(const BitVector* selected) : selected_(selected) {}
-
- StorageRange MapToStorageRange(TableRange) const override;
-
- TableRangeOrBitVector MapToTableRangeOrBitVector(StorageRange,
- OverlayOp) const override;
-
- TableBitVector MapToTableBitVector(StorageBitVector,
- OverlayOp) const override;
-
- BitVector IsStorageLookupRequired(OverlayOp,
- const TableIndexVector&) const override;
-
- StorageIndexVector MapToStorageIndexVector(TableIndexVector) const override;
-
- BitVector IndexSearch(OverlayOp, const TableIndexVector&) const override;
-
- CostEstimatePerRow EstimateCostPerRow(OverlayOp) const override;
-
- void Serialize(OverlayProto*) const override;
-
- private:
- const BitVector* selected_;
-};
-
-} // namespace overlays
-} // namespace trace_processor
-} // namespace perfetto
-
-#endif // SRC_TRACE_PROCESSOR_DB_OVERLAYS_SELECTOR_OVERLAY_H_
diff --git a/src/trace_processor/db/overlays/selector_overlay_unittest.cc b/src/trace_processor/db/overlays/selector_overlay_unittest.cc
deleted file mode 100644
index 28b4f02..0000000
--- a/src/trace_processor/db/overlays/selector_overlay_unittest.cc
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "src/trace_processor/db/overlays/selector_overlay.h"
-#include "src/trace_processor/db/overlays/types.h"
-#include "test/gtest_and_gmock.h"
-
-namespace perfetto {
-namespace trace_processor {
-namespace overlays {
-namespace {
-
-TEST(SelectorOverlay, MapToStorageRangeFirst) {
- BitVector selector{0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1};
- SelectorOverlay overlay(&selector);
- StorageRange r = overlay.MapToStorageRange(TableRange(1, 4));
-
- ASSERT_EQ(r.range.start, 4u);
- ASSERT_EQ(r.range.end, 8u);
-}
-
-TEST(SelectorOverlay, MapToStorageRangeSecond) {
- BitVector selector{0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0};
- SelectorOverlay overlay(&selector);
- StorageRange r = overlay.MapToStorageRange(TableRange(1, 3));
-
- ASSERT_EQ(r.range.start, 4u);
- ASSERT_EQ(r.range.end, 7u);
-}
-
-TEST(SelectorOverlay, MapToTableRangeFirst) {
- BitVector selector{0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1};
- SelectorOverlay overlay(&selector);
- auto r =
- overlay.MapToTableRangeOrBitVector(StorageRange(2, 5), OverlayOp::kOther);
-
- Range range = std::move(r).TakeIfRange();
- ASSERT_EQ(range.start, 1u);
- ASSERT_EQ(range.end, 3u);
-}
-
-TEST(SelectorOverlay, MapToTableRangeSecond) {
- BitVector selector{0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0};
- SelectorOverlay overlay(&selector);
- auto r = overlay.MapToTableRangeOrBitVector(StorageRange(0, 10),
- OverlayOp::kOther);
-
- Range range = std::move(r).TakeIfRange();
- ASSERT_EQ(range.start, 0u);
- ASSERT_EQ(range.end, 6u);
-}
-
-TEST(SelectorOverlay, MapToTableBitVector) {
- BitVector selector{0, 1, 1, 0, 0, 1, 1, 0};
- SelectorOverlay overlay(&selector);
-
- BitVector storage_bv{1, 0, 1, 0, 1, 0, 1, 0};
- TableBitVector table_bv =
- overlay.MapToTableBitVector({std::move(storage_bv)}, OverlayOp::kOther);
-
- ASSERT_EQ(table_bv.bv.size(), 4u);
- ASSERT_EQ(table_bv.bv.CountSetBits(), 2u);
- ASSERT_TRUE(table_bv.bv.IsSet(1));
- ASSERT_TRUE(table_bv.bv.IsSet(3));
-}
-
-TEST(SelectorOverlay, IsStorageLookupRequired) {
- BitVector selector{0, 1, 1, 0, 0, 1, 1, 0};
- SelectorOverlay overlay(&selector);
-
- std::vector<uint32_t> table_idx{0, 1, 2};
- BitVector lookup_bv =
- overlay.IsStorageLookupRequired(OverlayOp::kIsNull, {table_idx});
-
- ASSERT_EQ(lookup_bv.size(), 3u);
-}
-
-TEST(SelectorOverlay, MapToStorageIndexVector) {
- BitVector selector{0, 1, 1, 0, 0, 1, 1, 0};
- SelectorOverlay overlay(&selector);
-
- std::vector<uint32_t> table_idx{1, 3, 2};
- StorageIndexVector storage_iv = overlay.MapToStorageIndexVector({table_idx});
-
- std::vector<uint32_t> res{2, 6, 5};
- ASSERT_EQ(storage_iv.indices, res);
-}
-
-} // namespace
-} // namespace overlays
-} // namespace trace_processor
-} // namespace perfetto
diff --git a/src/trace_processor/db/overlays/storage_overlay.cc b/src/trace_processor/db/overlays/storage_overlay.cc
deleted file mode 100644
index 56897f2..0000000
--- a/src/trace_processor/db/overlays/storage_overlay.cc
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "src/trace_processor/db/overlays/storage_overlay.h"
-
-namespace perfetto {
-namespace trace_processor {
-namespace overlays {
-
-StorageOverlay::~StorageOverlay() = default;
-
-} // namespace overlays
-} // namespace trace_processor
-} // namespace perfetto
diff --git a/src/trace_processor/db/overlays/storage_overlay.h b/src/trace_processor/db/overlays/storage_overlay.h
deleted file mode 100644
index 753ff55..0000000
--- a/src/trace_processor/db/overlays/storage_overlay.h
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef SRC_TRACE_PROCESSOR_DB_OVERLAYS_STORAGE_OVERLAY_H_
-#define SRC_TRACE_PROCESSOR_DB_OVERLAYS_STORAGE_OVERLAY_H_
-
-#include "src/trace_processor/db/overlays/types.h"
-
-namespace perfetto {
-
-namespace protos::pbzero {
-class SerializedColumn_Overlay;
-}
-
-namespace trace_processor {
-namespace overlays {
-
-// Abstract class which is layered on top of Storage transforming how the
-// storage should be interpreted. The main purpose of this class is to be
-// responsible for for mapping between table indices and storage indices (i.e.
-// in both directions).
-//
-// Overlays are designed to be "layered" on top of each other (i.e. the mapping
-// algorithms compose). To make it easier to reason about this class, we
-// ignore any other overlays and assume we are mapping directly between table
-// indices and storage indices. i.e. even if "table indices" we are working with
-// come from another overlay, we still consider them as having come from the
-// table and vice versa for "storage indices".
-//
-// The core functions in this class work with input and output arguments which
-// use the same data structure but have different semantics (i.e. input might
-// be in terms of storage indices and output might be in terms of table
-// indices).
-//
-// For this reason, we use the defined wrapper structs which "tag" the data
-// structure with the semantics.
-class StorageOverlay {
- public:
- using OverlayProto = protos::pbzero::SerializedColumn_Overlay;
- virtual ~StorageOverlay();
-
- // Maps a range of indices in table space to an equivalent range of
- // indices in the storage space.
- virtual StorageRange MapToStorageRange(TableRange) const = 0;
-
- // Returns the smallest Range or BitVector containing all of the elements
- // matching the OverlayOp.
- virtual TableRangeOrBitVector MapToTableRangeOrBitVector(StorageRange,
- OverlayOp) const = 0;
-
- // Maps a BitVector of indices in storage space to an equivalent range of
- // indices in the table space.
- virtual TableBitVector MapToTableBitVector(StorageBitVector,
- OverlayOp) const = 0;
-
- // Returns a BitVector where each boolean indicates if the corresponding index
- // in |indices| needs to be mapped and searched in the storage or if the
- // overlay can provide the answer without storage lookup.
- virtual BitVector IsStorageLookupRequired(OverlayOp,
- const TableIndexVector&) const = 0;
-
- // Maps a vector of indices in the table space with an equivalent range
- // of indices in the storage space.
- //
- // Note: callers must call |IsStorageSearchRequired| first and only call
- // this method with indices where |IsStorageSearchRequired| returned true.
- // Passing indices here which are not mappable is undefined behaviour.
- virtual StorageIndexVector MapToStorageIndexVector(
- TableIndexVector) const = 0;
-
- // Given a vector of indices given in table space, returns whether the index
- // matches the operation given by |op|.
- //
- // Note: callers must call |IsStorageSearchRequired| first and only call
- // this method with indices where |IsStorageSearchRequired| returned false.
- // Passing indices here which are not searchable is undefined behaviour.
- virtual BitVector IndexSearch(OverlayOp, const TableIndexVector&) const = 0;
-
- // Estimates the per-row costs of the methods of this class. Allows for
- // deciding which algorithm to use to search/sort the storage.
- virtual CostEstimatePerRow EstimateCostPerRow(OverlayOp) const = 0;
-
- // Serializes the contents of the overlay.
- virtual void Serialize(OverlayProto*) const = 0;
-};
-
-} // namespace overlays
-} // namespace trace_processor
-} // namespace perfetto
-
-#endif // SRC_TRACE_PROCESSOR_DB_OVERLAYS_STORAGE_OVERLAY_H_
diff --git a/src/trace_processor/db/overlays/types.h b/src/trace_processor/db/overlays/types.h
deleted file mode 100644
index 8975084..0000000
--- a/src/trace_processor/db/overlays/types.h
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#ifndef SRC_TRACE_PROCESSOR_DB_OVERLAYS_TYPES_H_
-#define SRC_TRACE_PROCESSOR_DB_OVERLAYS_TYPES_H_
-
-#include "perfetto/base/logging.h"
-#include "src/trace_processor/containers/bit_vector.h"
-#include "src/trace_processor/db/storage/types.h"
-
-namespace perfetto {
-namespace trace_processor {
-namespace overlays {
-
-using Range = RowMap::Range;
-
-// A range of indices in the table space.
-struct TableRange {
- TableRange(uint32_t start, uint32_t end) : range(start, end) {}
- explicit TableRange(Range r) : range(r) {}
-
- Range range;
-};
-
-// A range of indices in the storage space.
-struct StorageRange {
- StorageRange(uint32_t start, uint32_t end) : range(start, end) {}
- explicit StorageRange(Range r) : range(r) {}
-
- Range range;
-};
-
-// A BitVector with set bits corresponding to indices in the table space.
-struct TableBitVector {
- BitVector bv;
-};
-
-// A BitVector with set bits corresponding to indices in the table space.
-struct StorageBitVector {
- BitVector bv;
-};
-
-// RangeOrBitVector of indices in the table space.
-struct TableRangeOrBitVector {
- explicit TableRangeOrBitVector(Range range) : val(range) {}
- explicit TableRangeOrBitVector(BitVector bv) : val(std::move(bv)) {}
- explicit TableRangeOrBitVector(RangeOrBitVector r_or_bv)
- : val(std::move(r_or_bv)) {}
-
- bool IsRange() const { return val.IsRange(); }
- bool IsBitVector() const { return val.IsBitVector(); }
-
- BitVector TakeIfBitVector() && { return std::move(val).TakeIfBitVector(); }
- Range TakeIfRange() && { return std::move(val).TakeIfRange(); }
-
- RangeOrBitVector val = RangeOrBitVector(Range());
-};
-
-// Represents a vector of indices in the table space.
-struct TableIndexVector {
- std::vector<uint32_t> indices;
-
- uint32_t size() const { return static_cast<uint32_t>(indices.size()); }
-};
-
-// Represents a vector of indices in the storage space.
-struct StorageIndexVector {
- std::vector<uint32_t> indices;
-
- uint32_t size() const { return static_cast<uint32_t>(indices.size()); }
-};
-
-// A subset of FilterOp containing operations which can be handled by
-// overlays.
-enum class OverlayOp {
- kIsNull,
- kIsNotNull,
- kOther,
-};
-
-inline OverlayOp FilterOpToOverlayOp(FilterOp op) {
- if (op == FilterOp::kIsNull) {
- return OverlayOp::kIsNull;
- }
- if (op == FilterOp::kIsNotNull) {
- return OverlayOp::kIsNotNull;
- }
- return OverlayOp::kOther;
-}
-
-// Contains estimates of the cost for each of method in this class per row.
-struct CostEstimatePerRow {
- uint32_t to_storage_range;
- uint32_t to_table_bit_vector;
- uint32_t is_storage_search_required;
- uint32_t map_to_storage_index_vector;
- uint32_t index_search;
-};
-
-} // namespace overlays
-} // namespace trace_processor
-} // namespace perfetto
-
-#endif // SRC_TRACE_PROCESSOR_DB_OVERLAYS_TYPES_H_
diff --git a/src/trace_processor/db/query_executor.cc b/src/trace_processor/db/query_executor.cc
index 21e4c7c..1151079 100644
--- a/src/trace_processor/db/query_executor.cc
+++ b/src/trace_processor/db/query_executor.cc
@@ -25,15 +25,13 @@
#include "perfetto/base/logging.h"
#include "perfetto/ext/base/status_or.h"
#include "src/trace_processor/containers/string_pool.h"
-#include "src/trace_processor/db/overlays/arrangement_overlay.h"
-#include "src/trace_processor/db/overlays/null_overlay.h"
-#include "src/trace_processor/db/overlays/selector_overlay.h"
-#include "src/trace_processor/db/overlays/storage_overlay.h"
-#include "src/trace_processor/db/overlays/types.h"
#include "src/trace_processor/db/query_executor.h"
+#include "src/trace_processor/db/storage/arrangement_storage.h"
#include "src/trace_processor/db/storage/dummy_storage.h"
#include "src/trace_processor/db/storage/id_storage.h"
+#include "src/trace_processor/db/storage/null_storage.h"
#include "src/trace_processor/db/storage/numeric_storage.h"
+#include "src/trace_processor/db/storage/selector_storage.h"
#include "src/trace_processor/db/storage/set_id_storage.h"
#include "src/trace_processor/db/storage/string_storage.h"
#include "src/trace_processor/db/storage/types.h"
@@ -45,96 +43,25 @@
namespace {
using Range = RowMap::Range;
-using OverlayOp = overlays::OverlayOp;
-using StorageRange = overlays::StorageRange;
-using TableRange = overlays::TableRange;
using Storage = storage::Storage;
-using StorageOverlay = overlays::StorageOverlay;
-using TableIndexVector = overlays::TableIndexVector;
-using StorageIndexVector = overlays::StorageIndexVector;
-using TableBitVector = overlays::TableBitVector;
-using StorageBitVector = overlays::StorageBitVector;
-using OverlaysVec = base::SmallVector<const overlays::StorageOverlay*,
- QueryExecutor::kMaxOverlayCount>;
-// Helper struct to simplify operations on |global| and |current| sets of
-// indices. Having this coupling enables efficient implementation of
-// IndexedColumnFilter.
-struct IndexFilterHelper {
- explicit IndexFilterHelper(std::vector<uint32_t> indices) {
- current_ = indices;
- global_ = std::move(indices);
- }
-
- // Removes pairs of elements that are not set in the |bv| and returns
- // Indices made of them.
- static std::pair<IndexFilterHelper, IndexFilterHelper> Partition(
- IndexFilterHelper indices,
- const BitVector& bv) {
- if (bv.CountSetBits() == 0) {
- return {IndexFilterHelper(), indices};
- }
-
- IndexFilterHelper set_partition;
- IndexFilterHelper non_set_partition;
- for (auto it = bv.IterateAllBits(); it; it.Next()) {
- uint32_t idx = it.index();
- if (it.IsSet()) {
- set_partition.PushBack({indices.current_[idx], indices.global_[idx]});
- } else {
- non_set_partition.PushBack(
- {indices.current_[idx], indices.global_[idx]});
- }
- }
- return {set_partition, non_set_partition};
- }
-
- // Removes pairs of elements that are not set in the |bv|. Returns count of
- // removed elements.
- uint32_t KeepAtSet(BitVector filter_nulls) {
- PERFETTO_DCHECK(filter_nulls.size() == current_.size() ||
- filter_nulls.CountSetBits() == 0);
- uint32_t count_removed =
- static_cast<uint32_t>(current_.size()) - filter_nulls.CountSetBits();
-
- uint32_t i = 0;
- auto filter = [&i, &filter_nulls](uint32_t) {
- return !filter_nulls.IsSet(i++);
- };
-
- auto current_it = std::remove_if(current_.begin(), current_.end(), filter);
- current_.erase(current_it, current_.end());
-
- i = 0;
- auto global_it = std::remove_if(global_.begin(), global_.end(), filter);
- global_.erase(global_it, global_.end());
-
- return count_removed;
- }
-
- std::vector<uint32_t>& current() { return current_; }
-
- std::vector<uint32_t>& global() { return global_; }
-
- private:
- IndexFilterHelper() = default;
-
- void PushBack(std::pair<uint32_t, uint32_t> cur_and_global_idx) {
- current_.push_back(cur_and_global_idx.first);
- global_.push_back(cur_and_global_idx.second);
- }
-
- std::vector<uint32_t> current_;
- std::vector<uint32_t> global_;
-};
} // namespace
void QueryExecutor::FilterColumn(const Constraint& c,
- const SimpleColumn& col,
+ const storage::Storage& storage,
RowMap* rm) {
+ // Shortcut of empty row map.
if (rm->empty())
return;
+ // Comparison of NULL with any operation apart from |IS_NULL| and
+ // |IS_NOT_NULL| should return no rows.
+ if (c.value.is_null() && c.op != FilterOp::kIsNull &&
+ c.op != FilterOp::kIsNotNull) {
+ rm->Clear();
+ return;
+ }
+
uint32_t rm_size = rm->size();
uint32_t rm_first = rm->Get(0);
uint32_t rm_last = rm->Get(rm_size - 1);
@@ -146,43 +73,22 @@
bool disallows_index_search = rm->IsRange();
bool prefers_index_search =
rm->IsIndexVector() || rm_size < 1024 || rm_size * 10 < range_size;
+
if (!disallows_index_search && prefers_index_search) {
- *rm = IndexSearch(c, col, rm);
+ IndexSearch(c, storage, rm);
return;
}
- LinearSearch(c, col, rm);
+ LinearSearch(c, storage, rm);
}
void QueryExecutor::LinearSearch(const Constraint& c,
- const SimpleColumn& col,
+ const storage::Storage& storage,
RowMap* rm) {
// TODO(b/283763282): Align these to word boundaries.
- TableRange bounds{Range(rm->Get(0), rm->Get(rm->size() - 1) + 1)};
-
- // Translate the bounds to the storage level.
- for (const auto& overlay : col.overlays) {
- bounds = TableRange({overlay->MapToStorageRange(bounds).range});
- }
+ Range bounds(rm->Get(0), rm->Get(rm->size() - 1) + 1);
// Search the storage.
- overlays::TableRangeOrBitVector res(
- col.storage->Search(c.op, c.value, bounds.range));
-
- // Translate the result to global level.
- OverlayOp op = overlays::FilterOpToOverlayOp(c.op);
- for (uint32_t i = 0; i < col.overlays.size(); ++i) {
- uint32_t rev_i = static_cast<uint32_t>(col.overlays.size()) - 1 - i;
-
- if (res.IsBitVector()) {
- TableBitVector t_bv = col.overlays[rev_i]->MapToTableBitVector(
- StorageBitVector{std::move(res).TakeIfBitVector()}, op);
- res.val = RangeOrBitVector(std::move(t_bv.bv));
- } else {
- res = col.overlays[rev_i]->MapToTableRangeOrBitVector(
- StorageRange(std::move(res).TakeIfRange()), op);
- }
- }
-
+ RangeOrBitVector res = storage.Search(c.op, c.value, bounds);
if (rm->IsRange()) {
if (res.IsRange()) {
Range range = std::move(res).TakeIfRange();
@@ -203,75 +109,44 @@
rm->Intersect(RowMap(std::move(res).TakeIfBitVector()));
}
-RowMap QueryExecutor::IndexSearch(const Constraint& c,
- const SimpleColumn& col,
- RowMap* rm) {
+void QueryExecutor::IndexSearch(const Constraint& c,
+ const storage::Storage& storage,
+ RowMap* rm) {
// Create outmost TableIndexVector.
std::vector<uint32_t> table_indices = std::move(*rm).TakeAsIndexVector();
- // Datastructures for storing data across overlays.
- IndexFilterHelper to_filter(std::move(table_indices));
- std::vector<uint32_t> matched;
- uint32_t count_removed = 0;
- uint32_t count_starting_indices =
- static_cast<uint32_t>(to_filter.current().size());
+ RangeOrBitVector matched = storage.IndexSearch(
+ c.op, c.value, table_indices.data(),
+ static_cast<uint32_t>(table_indices.size()), false /* sorted */);
- // Fetch the list of indices that require storage lookup and deal with all
- // of the indices that can be compared before it.
- OverlayOp op = overlays::FilterOpToOverlayOp(c.op);
- for (const auto& overlay : col.overlays) {
- BitVector partition =
- overlay->IsStorageLookupRequired(op, {to_filter.current()});
-
- // Most overlays don't require partitioning.
- if (partition.CountSetBits() == partition.size()) {
- to_filter.current() =
- overlay->MapToStorageIndexVector({to_filter.current()}).indices;
- continue;
- }
-
- // Separate indices that don't require storage lookup. Those can be dealt
- // with in each pass.
- auto [storage_lookup, no_storage_lookup] =
- IndexFilterHelper::Partition(to_filter, partition);
- to_filter = storage_lookup;
-
- // Erase the values which don't match the constraint and add the
- // remaining ones to the result.
- BitVector valid_bv =
- overlay->IndexSearch(op, {no_storage_lookup.current()});
- count_removed += no_storage_lookup.KeepAtSet(std::move(valid_bv));
- matched.insert(matched.end(), no_storage_lookup.global().begin(),
- no_storage_lookup.global().end());
-
- // Update the current indices to the next storage overlay.
- to_filter.current() =
- overlay->MapToStorageIndexVector({to_filter.current()}).indices;
+ if (matched.IsBitVector()) {
+ BitVector res = std::move(matched).TakeIfBitVector();
+ uint32_t i = 0;
+ table_indices.erase(
+ std::remove_if(table_indices.begin(), table_indices.end(),
+ [&i, &res](uint32_t) { return !res.IsSet(i++); }),
+ table_indices.end());
+ *rm = RowMap(std::move(table_indices));
+ return;
}
- RangeOrBitVector matched_in_storage = col.storage->IndexSearch(
- c.op, c.value, to_filter.current().data(),
- static_cast<uint32_t>(to_filter.current().size()));
-
+ Range res = std::move(matched).TakeIfRange();
+ if (res.size() == 0) {
+ rm->Clear();
+ return;
+ }
+ if (res.size() == table_indices.size()) {
+ return;
+ }
// TODO(b/283763282): Remove after implementing extrinsic binary search.
- PERFETTO_DCHECK(matched_in_storage.IsBitVector());
-
- count_removed +=
- to_filter.KeepAtSet(std::move(matched_in_storage).TakeIfBitVector());
- matched.insert(matched.end(), to_filter.global().begin(),
- to_filter.global().end());
-
- PERFETTO_CHECK(count_starting_indices == matched.size() + count_removed);
-
- std::sort(matched.begin(), matched.end());
- return RowMap(std::move(matched));
+ PERFETTO_FATAL("Extrinsic binary search is not implemented.");
}
RowMap QueryExecutor::FilterLegacy(const Table* table,
const std::vector<Constraint>& c_vec) {
RowMap rm(0, table->row_count());
for (const auto& c : c_vec) {
- if (rm.size() == 0) {
+ if (rm.empty()) {
return rm;
}
const Column& col = table->columns()[c.col_idx];
@@ -286,9 +161,9 @@
col.overlay().row_map().IsRange());
// Mismatched types.
- use_legacy = use_legacy || (overlays::FilterOpToOverlayOp(c.op) ==
- overlays::OverlayOp::kOther &&
- col.type() != c.value.type);
+ use_legacy = use_legacy ||
+ (c.op != FilterOp::kIsNull && c.op != FilterOp::kIsNotNull &&
+ col.type() != c.value.type && !c.value.is_null());
// Dense columns.
use_legacy = use_legacy || col.IsDense();
@@ -302,108 +177,92 @@
continue;
}
- // String columns are inherently nullable: null values are signified with
- // Id::Null().
- PERFETTO_CHECK(
- !(col.col_type() == ColumnType::kString && col.IsNullable()));
-
- SimpleColumn s_col{OverlaysVec(), nullptr};
-
// Create storage
std::unique_ptr<Storage> storage;
if (col.IsSetId()) {
if (col.IsNullable()) {
- storage.reset(new storage::SetIdStorage(
- &col.storage<std::optional<uint32_t>>().non_null_vector()));
+ storage = std::make_unique<storage::SetIdStorage>(
+ &col.storage<std::optional<uint32_t>>().non_null_vector());
} else {
- storage.reset(
- new storage::SetIdStorage(&col.storage<uint32_t>().vector()));
+ storage = std::make_unique<storage::SetIdStorage>(
+ &col.storage<uint32_t>().vector());
}
} else {
switch (col.col_type()) {
case ColumnType::kDummy:
- storage.reset(new storage::DummyStorage());
+ storage = std::make_unique<storage::DummyStorage>();
break;
case ColumnType::kId:
- storage.reset(new storage::IdStorage(column_size));
+ storage = std::make_unique<storage::IdStorage>(column_size);
break;
case ColumnType::kString:
- storage.reset(new storage::StringStorage(
+ storage = std::make_unique<storage::StringStorage>(
table->string_pool(), &col.storage<StringPool::Id>().vector(),
- col.IsSorted()));
+ col.IsSorted());
break;
case ColumnType::kInt64:
if (col.IsNullable()) {
- storage.reset(new storage::NumericStorage<int64_t>(
+ storage = std::make_unique<storage::NumericStorage<int64_t>>(
&col.storage<std::optional<int64_t>>().non_null_vector(),
- col.col_type(), col.IsSorted()));
+ col.col_type(), col.IsSorted());
} else {
- storage.reset(new storage::NumericStorage<int64_t>(
+ storage = std::make_unique<storage::NumericStorage<int64_t>>(
&col.storage<int64_t>().vector(), col.col_type(),
- col.IsSorted()));
+ col.IsSorted());
}
break;
case ColumnType::kUint32:
if (col.IsNullable()) {
- storage.reset(new storage::NumericStorage<uint32_t>(
+ storage = std::make_unique<storage::NumericStorage<uint32_t>>(
&col.storage<std::optional<uint32_t>>().non_null_vector(),
- col.col_type(), col.IsSorted()));
-
+ col.col_type(), col.IsSorted());
} else {
- storage.reset(new storage::NumericStorage<uint32_t>(
+ storage = std::make_unique<storage::NumericStorage<uint32_t>>(
&col.storage<uint32_t>().vector(), col.col_type(),
- col.IsSorted()));
+ col.IsSorted());
}
break;
case ColumnType::kInt32:
if (col.IsNullable()) {
- storage.reset(new storage::NumericStorage<int32_t>(
+ storage = std::make_unique<storage::NumericStorage<int32_t>>(
&col.storage<std::optional<int32_t>>().non_null_vector(),
- col.col_type(), col.IsSorted()));
-
+ col.col_type(), col.IsSorted());
} else {
- storage.reset(new storage::NumericStorage<int32_t>(
+ storage = std::make_unique<storage::NumericStorage<int32_t>>(
&col.storage<int32_t>().vector(), col.col_type(),
- col.IsSorted()));
+ col.IsSorted());
}
break;
case ColumnType::kDouble:
if (col.IsNullable()) {
- storage.reset(new storage::NumericStorage<double_t>(
- &col.storage<std::optional<double_t>>().non_null_vector(),
- col.col_type(), col.IsSorted()));
-
+ storage = std::make_unique<storage::NumericStorage<double>>(
+ &col.storage<std::optional<double>>().non_null_vector(),
+ col.col_type(), col.IsSorted());
} else {
- storage.reset(new storage::NumericStorage<double_t>(
- &col.storage<double_t>().vector(), col.col_type(),
- col.IsSorted()));
+ storage = std::make_unique<storage::NumericStorage<double>>(
+ &col.storage<double>().vector(), col.col_type(),
+ col.IsSorted());
}
}
}
- s_col.storage = storage.get();
-
- // Create cEngine overlays based on col.overlay()
- overlays::SelectorOverlay selector_overlay(
- col.overlay().row_map().GetIfBitVector());
- if (col.overlay().size() != column_size &&
- col.overlay().row_map().IsBitVector())
- s_col.overlays.emplace_back(&selector_overlay);
-
- overlays::ArrangementOverlay arrangement_overlay(
- col.overlay().row_map().GetIfIndexVector());
- if (col.overlay().row_map().IsIndexVector())
- s_col.overlays.emplace_back(&arrangement_overlay);
-
- // Add nullability
- BitVector null_bv;
- overlays::NullOverlay null_overlay(
- col.IsNullable() ? col.storage_base().bv() : &null_bv);
- if (col.IsNullable())
- s_col.overlays.emplace_back(&null_overlay);
-
+ if (col.IsNullable()) {
+ // String columns are inherently nullable: null values are signified
+ // with Id::Null().
+ PERFETTO_CHECK(col.col_type() != ColumnType::kString);
+ storage = std::make_unique<storage::NullStorage>(std::move(storage),
+ col.storage_base().bv());
+ }
+ if (col.overlay().row_map().IsIndexVector()) {
+ storage = std::make_unique<storage::ArrangementStorage>(
+ std::move(storage), col.overlay().row_map().GetIfIndexVector());
+ }
+ if (col.overlay().row_map().IsBitVector()) {
+ storage = std::make_unique<storage::SelectorStorage>(
+ std::move(storage), col.overlay().row_map().GetIfBitVector());
+ }
uint32_t pre_count = rm.size();
- FilterColumn(c, s_col, &rm);
+ FilterColumn(c, *storage.get(), &rm);
PERFETTO_DCHECK(rm.size() <= pre_count);
}
return rm;
diff --git a/src/trace_processor/db/query_executor.h b/src/trace_processor/db/query_executor.h
index fd566a6..013dbf2 100644
--- a/src/trace_processor/db/query_executor.h
+++ b/src/trace_processor/db/query_executor.h
@@ -24,8 +24,6 @@
#include "src/trace_processor/containers/bit_vector.h"
#include "src/trace_processor/containers/row_map.h"
#include "src/trace_processor/db/column.h"
-#include "src/trace_processor/db/overlays/storage_overlay.h"
-#include "src/trace_processor/db/overlays/types.h"
#include "src/trace_processor/db/storage/storage.h"
namespace perfetto {
@@ -37,22 +35,16 @@
public:
static constexpr uint32_t kMaxOverlayCount = 8;
- // Overlay-based definition of the column.
- struct SimpleColumn {
- base::SmallVector<const overlays::StorageOverlay*, kMaxOverlayCount>
- overlays;
- const storage::Storage* storage;
- };
-
// |row_count| is the size of the last overlay.
- QueryExecutor(const std::vector<SimpleColumn>& columns, uint32_t row_count)
+ QueryExecutor(const std::vector<storage::Storage*>& columns,
+ uint32_t row_count)
: columns_(columns), row_count_(row_count) {}
// Apply all the constraints on the data and return the filtered RowMap.
RowMap Filter(const std::vector<Constraint>& cs) {
RowMap rm(0, row_count_);
for (const auto& c : cs) {
- FilterColumn(c, columns_[c.col_idx], &rm);
+ FilterColumn(c, *columns_[c.col_idx], &rm);
}
return rm;
}
@@ -72,31 +64,31 @@
// Used only in unittests. Exposes private function.
static void BoundedColumnFilterForTesting(const Constraint& c,
- const SimpleColumn& col,
+ const storage::Storage& col,
RowMap* rm) {
LinearSearch(c, col, rm);
}
// Used only in unittests. Exposes private function.
- static RowMap IndexedColumnFilterForTesting(const Constraint& c,
- const SimpleColumn& col,
- RowMap* rm) {
- return IndexSearch(c, col, rm);
+ static void IndexedColumnFilterForTesting(const Constraint& c,
+ const storage::Storage& col,
+ RowMap* rm) {
+ IndexSearch(c, col, rm);
}
private:
// Updates RowMap with result of filtering single column using the Constraint.
- static void FilterColumn(const Constraint&, const SimpleColumn&, RowMap*);
+ static void FilterColumn(const Constraint&, const storage::Storage&, RowMap*);
// Filters the column using Range algorithm - tries to find the smallest Range
// to filter the storage with.
- static void LinearSearch(const Constraint&, const SimpleColumn&, RowMap*);
+ static void LinearSearch(const Constraint&, const storage::Storage&, RowMap*);
// Filters the column using Index algorithm - finds the indices to filter the
// storage with.
- static RowMap IndexSearch(const Constraint&, const SimpleColumn&, RowMap*);
+ static void IndexSearch(const Constraint&, const storage::Storage&, RowMap*);
- std::vector<SimpleColumn> columns_;
+ std::vector<storage::Storage*> columns_;
// Number of rows in the outmost overlay.
uint32_t row_count_ = 0;
diff --git a/src/trace_processor/db/query_executor_unittest.cc b/src/trace_processor/db/query_executor_unittest.cc
index 73f88d2..95ce5ef 100644
--- a/src/trace_processor/db/query_executor_unittest.cc
+++ b/src/trace_processor/db/query_executor_unittest.cc
@@ -15,12 +15,15 @@
*/
#include "src/trace_processor/db/query_executor.h"
-#include "src/trace_processor/db/overlays/arrangement_overlay.h"
-#include "src/trace_processor/db/overlays/null_overlay.h"
-#include "src/trace_processor/db/overlays/selector_overlay.h"
+
+#include "src/trace_processor/db/storage/arrangement_storage.h"
+#include "src/trace_processor/db/storage/fake_storage.h"
#include "src/trace_processor/db/storage/id_storage.h"
+#include "src/trace_processor/db/storage/null_storage.h"
#include "src/trace_processor/db/storage/numeric_storage.h"
+#include "src/trace_processor/db/storage/selector_storage.h"
#include "src/trace_processor/db/storage/set_id_storage.h"
+#include "src/trace_processor/db/storage/storage.h"
#include "src/trace_processor/db/storage/string_storage.h"
#include "test/gtest_and_gmock.h"
@@ -28,26 +31,22 @@
namespace trace_processor {
namespace {
-using OverlaysVec = base::SmallVector<const overlays::StorageOverlay*,
- QueryExecutor::kMaxOverlayCount>;
-using SimpleColumn = QueryExecutor::SimpleColumn;
+using testing::ElementsAre;
using IdStorage = storage::IdStorage;
using SetIdStorage = storage::SetIdStorage;
using StringStorage = storage::StringStorage;
-
-using ArrangementOverlay = overlays::ArrangementOverlay;
-using NullOverlay = overlays::NullOverlay;
-using SelectorOverlay = overlays::SelectorOverlay;
+using NullStorage = storage::NullStorage;
+using ArrangementStorage = storage::ArrangementStorage;
+using SelectorStorage = storage::SelectorStorage;
TEST(QueryExecutor, OnlyStorageRange) {
std::vector<int64_t> storage_data{1, 2, 3, 4, 5};
storage::NumericStorage<int64_t> storage(&storage_data, ColumnType::kInt64);
- SimpleColumn col{OverlaysVec(), &storage};
Constraint c{0, FilterOp::kGe, SqlValue::Long(3)};
RowMap rm(0, 5);
- QueryExecutor::BoundedColumnFilterForTesting(c, col, &rm);
+ QueryExecutor::BoundedColumnFilterForTesting(c, storage, &rm);
ASSERT_EQ(rm.size(), 3u);
ASSERT_EQ(rm.Get(0), 2u);
@@ -56,11 +55,10 @@
TEST(QueryExecutor, OnlyStorageRangeIsNull) {
std::vector<int64_t> storage_data{1, 2, 3, 4, 5};
storage::NumericStorage<int64_t> storage(&storage_data, ColumnType::kInt64);
- SimpleColumn col{OverlaysVec(), &storage};
- Constraint c{0, FilterOp::kIsNull, SqlValue::Long(3)};
+ Constraint c{0, FilterOp::kIsNull, SqlValue()};
RowMap rm(0, 5);
- QueryExecutor::BoundedColumnFilterForTesting(c, col, &rm);
+ QueryExecutor::BoundedColumnFilterForTesting(c, storage, &rm);
ASSERT_EQ(rm.size(), 0u);
}
@@ -73,64 +71,56 @@
[](int64_t n) { return n % 5; });
storage::NumericStorage<int64_t> storage(&storage_data, ColumnType::kInt64);
- SimpleColumn col{OverlaysVec(), &storage};
Constraint c{0, FilterOp::kLt, SqlValue::Long(2)};
RowMap rm(0, 10);
- RowMap res = QueryExecutor::IndexedColumnFilterForTesting(c, col, &rm);
+ QueryExecutor::IndexedColumnFilterForTesting(c, storage, &rm);
- ASSERT_EQ(res.size(), 4u);
- ASSERT_EQ(res.Get(0), 0u);
- ASSERT_EQ(res.Get(1), 1u);
- ASSERT_EQ(res.Get(2), 5u);
- ASSERT_EQ(res.Get(3), 6u);
+ ASSERT_EQ(rm.size(), 4u);
+ ASSERT_EQ(rm.Get(0), 0u);
+ ASSERT_EQ(rm.Get(1), 1u);
+ ASSERT_EQ(rm.Get(2), 5u);
+ ASSERT_EQ(rm.Get(3), 6u);
}
TEST(QueryExecutor, OnlyStorageIndexIsNull) {
std::vector<int64_t> storage_data{1, 2, 3, 4, 5};
storage::NumericStorage<int64_t> storage(&storage_data, ColumnType::kInt64);
- SimpleColumn col{OverlaysVec(), &storage};
- Constraint c{0, FilterOp::kIsNull, SqlValue::Long(3)};
+ Constraint c{0, FilterOp::kIsNull, SqlValue()};
RowMap rm(0, 5);
- RowMap res = QueryExecutor::IndexedColumnFilterForTesting(c, col, &rm);
+ QueryExecutor::IndexedColumnFilterForTesting(c, storage, &rm);
- ASSERT_EQ(res.size(), 0u);
+ ASSERT_EQ(rm.size(), 0u);
}
-TEST(QueryExecutor, NullOverlayBounds) {
+TEST(QueryExecutor, NullBounds) {
std::vector<int64_t> storage_data(5);
std::iota(storage_data.begin(), storage_data.end(), 0);
- storage::NumericStorage<int64_t> storage(&storage_data, ColumnType::kInt64);
+ auto numeric = std::make_unique<storage::NumericStorage<int64_t>>(
+ &storage_data, ColumnType::kInt64);
BitVector bv{1, 1, 0, 1, 1, 0, 0, 0, 1, 0};
- overlays::NullOverlay overlay(&bv);
- OverlaysVec overlays_vec;
- overlays_vec.emplace_back(&overlay);
-
- SimpleColumn col{overlays_vec, &storage};
+ storage::NullStorage storage(std::move(numeric), &bv);
Constraint c{0, FilterOp::kGe, SqlValue::Long(3)};
RowMap rm(0, 10);
- QueryExecutor::BoundedColumnFilterForTesting(c, col, &rm);
+ QueryExecutor::BoundedColumnFilterForTesting(c, storage, &rm);
ASSERT_EQ(rm.size(), 2u);
ASSERT_EQ(rm.Get(0), 4u);
ASSERT_EQ(rm.Get(1), 8u);
}
-TEST(QueryExecutor, NullOverlayRangeIsNull) {
+TEST(QueryExecutor, NullRangeIsNull) {
std::vector<int64_t> storage_data(5);
std::iota(storage_data.begin(), storage_data.end(), 0);
- storage::NumericStorage<int64_t> storage(&storage_data, ColumnType::kInt64);
+ auto numeric = std::make_unique<storage::NumericStorage<int64_t>>(
+ &storage_data, ColumnType::kInt64);
BitVector bv{1, 1, 0, 1, 1, 0, 0, 0, 1, 0};
- overlays::NullOverlay overlay(&bv);
- OverlaysVec overlays_vec;
- overlays_vec.emplace_back(&overlay);
+ storage::NullStorage storage(std::move(numeric), &bv);
- SimpleColumn col{overlays_vec, &storage};
-
- Constraint c{0, FilterOp::kIsNull, SqlValue::Long(3)};
+ Constraint c{0, FilterOp::kIsNull, SqlValue()};
RowMap rm(0, 10);
- QueryExecutor::BoundedColumnFilterForTesting(c, col, &rm);
+ QueryExecutor::BoundedColumnFilterForTesting(c, storage, &rm);
ASSERT_EQ(rm.size(), 5u);
ASSERT_EQ(rm.Get(0), 2u);
@@ -140,163 +130,174 @@
ASSERT_EQ(rm.Get(4), 9u);
}
-TEST(QueryExecutor, NullOverlayIndex) {
+TEST(QueryExecutor, NullIndex) {
std::vector<int64_t> storage_data(6);
std::iota(storage_data.begin(), storage_data.end(), 0);
std::transform(storage_data.begin(), storage_data.end(), storage_data.begin(),
[](int64_t n) { return n % 3; });
- storage::NumericStorage<int64_t> storage(&storage_data, ColumnType::kInt64);
+ auto numeric = std::make_unique<storage::NumericStorage<int64_t>>(
+ &storage_data, ColumnType::kInt64);
BitVector bv{1, 1, 0, 1, 1, 0, 1, 0, 0, 1};
- NullOverlay overlay(&bv);
- OverlaysVec overlays_vec;
- overlays_vec.emplace_back(&overlay);
-
- SimpleColumn col{overlays_vec, &storage};
+ storage::NullStorage storage(std::move(numeric), &bv);
Constraint c{0, FilterOp::kGe, SqlValue::Long(1)};
RowMap rm(0, 10);
- RowMap res = QueryExecutor::IndexedColumnFilterForTesting(c, col, &rm);
+ QueryExecutor::IndexedColumnFilterForTesting(c, storage, &rm);
- ASSERT_EQ(res.size(), 4u);
- ASSERT_EQ(res.Get(0), 1u);
- ASSERT_EQ(res.Get(1), 3u);
- ASSERT_EQ(res.Get(2), 6u);
- ASSERT_EQ(res.Get(3), 9u);
+ ASSERT_EQ(rm.size(), 4u);
+ ASSERT_EQ(rm.Get(0), 1u);
+ ASSERT_EQ(rm.Get(1), 3u);
+ ASSERT_EQ(rm.Get(2), 6u);
+ ASSERT_EQ(rm.Get(3), 9u);
}
-TEST(QueryExecutor, NullOverlayIndexIsNull) {
+TEST(QueryExecutor, NullIndexIsNull) {
std::vector<int64_t> storage_data(5);
std::iota(storage_data.begin(), storage_data.end(), 0);
- storage::NumericStorage<int64_t> storage(&storage_data, ColumnType::kInt64);
+ auto numeric = std::make_unique<storage::NumericStorage<int64_t>>(
+ &storage_data, ColumnType::kInt64);
+
BitVector bv{1, 1, 0, 1, 1, 0, 0, 0, 1, 0};
- overlays::NullOverlay overlay(&bv);
- OverlaysVec overlays_vec;
- overlays_vec.emplace_back(&overlay);
+ storage::NullStorage storage(std::move(numeric), &bv);
- SimpleColumn col{overlays_vec, &storage};
-
- Constraint c{0, FilterOp::kIsNull, SqlValue::Long(3)};
+ Constraint c{0, FilterOp::kIsNull, SqlValue()};
RowMap rm(0, 10);
- RowMap res = QueryExecutor::IndexedColumnFilterForTesting(c, col, &rm);
+ QueryExecutor::IndexedColumnFilterForTesting(c, storage, &rm);
- ASSERT_EQ(res.size(), 5u);
- ASSERT_EQ(res.Get(0), 2u);
- ASSERT_EQ(res.Get(1), 5u);
- ASSERT_EQ(res.Get(2), 6u);
- ASSERT_EQ(res.Get(3), 7u);
- ASSERT_EQ(res.Get(4), 9u);
+ ASSERT_EQ(rm.size(), 5u);
+ ASSERT_EQ(rm.Get(0), 2u);
+ ASSERT_EQ(rm.Get(1), 5u);
+ ASSERT_EQ(rm.Get(2), 6u);
+ ASSERT_EQ(rm.Get(3), 7u);
+ ASSERT_EQ(rm.Get(4), 9u);
}
-TEST(QueryExecutor, SelectorOverlayBounds) {
+TEST(QueryExecutor, SelectorStorageBounds) {
std::vector<int64_t> storage_data(5);
std::iota(storage_data.begin(), storage_data.end(), 0);
- storage::NumericStorage<int64_t> storage(&storage_data, ColumnType::kInt64);
+ auto numeric = std::make_unique<storage::NumericStorage<int64_t>>(
+ &storage_data, ColumnType::kInt64);
BitVector bv{1, 1, 0, 0, 1};
- SelectorOverlay overlay(&bv);
- OverlaysVec overlays_vec;
- overlays_vec.emplace_back(&overlay);
-
- SimpleColumn col{overlays_vec, &storage};
+ SelectorStorage storage(std::move(numeric), &bv);
Constraint c{0, FilterOp::kGt, SqlValue::Long(1)};
RowMap rm(0, 3);
- QueryExecutor::BoundedColumnFilterForTesting(c, col, &rm);
+ QueryExecutor::BoundedColumnFilterForTesting(c, storage, &rm);
- ASSERT_EQ(rm.size(), 1u);
- ASSERT_EQ(rm.Get(0), 2u);
+ ASSERT_THAT(rm.GetAllIndices(), ElementsAre(2u));
}
-TEST(QueryExecutor, SelectorOverlayIndex) {
+TEST(QueryExecutor, SelectorStorageIndex) {
std::vector<int64_t> storage_data(10);
std::iota(storage_data.begin(), storage_data.end(), 0);
std::transform(storage_data.begin(), storage_data.end(), storage_data.begin(),
[](int64_t n) { return n % 5; });
- storage::NumericStorage<int64_t> storage(&storage_data, ColumnType::kInt64);
+ auto numeric = std::make_unique<storage::NumericStorage<int64_t>>(
+ &storage_data, ColumnType::kInt64);
BitVector bv{1, 1, 0, 1, 1, 0, 1, 0, 0, 1};
- SelectorOverlay overlay(&bv);
- OverlaysVec overlays_vec;
- overlays_vec.emplace_back(&overlay);
-
- SimpleColumn col{overlays_vec, &storage};
+ SelectorStorage storage(std::move(numeric), &bv);
Constraint c{0, FilterOp::kGe, SqlValue::Long(2)};
RowMap rm(0, 6);
- RowMap res = QueryExecutor::IndexedColumnFilterForTesting(c, col, &rm);
+ QueryExecutor::IndexedColumnFilterForTesting(c, storage, &rm);
- ASSERT_EQ(res.size(), 3u);
- ASSERT_EQ(res.Get(0), 2u);
- ASSERT_EQ(res.Get(1), 3u);
- ASSERT_EQ(res.Get(2), 5u);
+ ASSERT_THAT(rm.GetAllIndices(), ElementsAre(2u, 3u, 5u));
}
-TEST(QueryExecutor, ArrangementOverlayBounds) {
+TEST(QueryExecutor, ArrangementStorageBounds) {
std::vector<int64_t> storage_data(5);
std::iota(storage_data.begin(), storage_data.end(), 0);
- storage::NumericStorage<int64_t> storage(&storage_data, ColumnType::kInt64);
+ auto numeric = std::make_unique<storage::NumericStorage<int64_t>>(
+ &storage_data, ColumnType::kInt64);
std::vector<uint32_t> arrangement{4, 1, 2, 2, 3};
- overlays::ArrangementOverlay overlay(&arrangement);
- OverlaysVec overlays_vec;
- overlays_vec.emplace_back(&overlay);
-
- SimpleColumn col{overlays_vec, &storage};
+ storage::ArrangementStorage storage(std::move(numeric), &arrangement);
Constraint c{0, FilterOp::kGe, SqlValue::Long(3)};
RowMap rm(0, 5);
- QueryExecutor::BoundedColumnFilterForTesting(c, col, &rm);
+ QueryExecutor::BoundedColumnFilterForTesting(c, storage, &rm);
- ASSERT_EQ(rm.size(), 2u);
- ASSERT_EQ(rm.Get(0), 0u);
- ASSERT_EQ(rm.Get(1), 4u);
+ ASSERT_THAT(rm.GetAllIndices(), ElementsAre(0u, 4u));
}
-TEST(QueryExecutor, ArrangmentOverlayIndex) {
- std::vector<int64_t> storage_data(5);
- std::iota(storage_data.begin(), storage_data.end(), 0);
- storage::NumericStorage<int64_t> storage(&storage_data, ColumnType::kInt64);
+TEST(QueryExecutor, ArrangementStorageSubsetInputRange) {
+ std::unique_ptr<storage::Storage> fake =
+ storage::FakeStorage::SearchSubset(5u, RowMap::Range(2u, 4u));
std::vector<uint32_t> arrangement{4, 1, 2, 2, 3};
- overlays::ArrangementOverlay overlay(&arrangement);
- OverlaysVec overlays_vec;
- overlays_vec.emplace_back(&overlay);
+ storage::ArrangementStorage storage(std::move(fake), &arrangement);
- SimpleColumn col{overlays_vec, &storage};
+ Constraint c{0, FilterOp::kGe, SqlValue::Long(0u)};
+ RowMap rm(1, 3);
+ QueryExecutor::BoundedColumnFilterForTesting(c, storage, &rm);
+
+ ASSERT_THAT(rm.GetAllIndices(), ElementsAre(2u));
+}
+
+TEST(QueryExecutor, ArrangementStorageSubsetInputBitvector) {
+ std::unique_ptr<storage::Storage> fake =
+ storage::FakeStorage::SearchSubset(5u, BitVector({0, 0, 1, 1, 0}));
+
+ std::vector<uint32_t> arrangement{4, 1, 2, 2, 3};
+ storage::ArrangementStorage storage(std::move(fake), &arrangement);
+
+ Constraint c{0, FilterOp::kGe, SqlValue::Long(0u)};
+ RowMap rm(1, 3);
+ QueryExecutor::BoundedColumnFilterForTesting(c, storage, &rm);
+
+ ASSERT_THAT(rm.GetAllIndices(), ElementsAre(2u));
+}
+
+TEST(QueryExecutor, ArrangementStorageIndex) {
+ std::vector<int64_t> storage_data(5);
+ std::iota(storage_data.begin(), storage_data.end(), 0);
+ auto numeric = std::make_unique<storage::NumericStorage<int64_t>>(
+ &storage_data, ColumnType::kInt64);
+
+ std::vector<uint32_t> arrangement{4, 1, 2, 2, 3};
+ storage::ArrangementStorage storage(std::move(numeric), &arrangement);
Constraint c{0, FilterOp::kGe, SqlValue::Long(3)};
RowMap rm(0, 5);
- RowMap res = QueryExecutor::IndexedColumnFilterForTesting(c, col, &rm);
+ QueryExecutor::IndexedColumnFilterForTesting(c, storage, &rm);
- ASSERT_EQ(res.size(), 2u);
- ASSERT_EQ(res.Get(0), 0u);
- ASSERT_EQ(res.Get(1), 4u);
+ ASSERT_THAT(rm.GetAllIndices(), ElementsAre(0u, 4u));
+}
+
+TEST(QueryExecutor, MismatchedTypeNullWithOtherOperations) {
+ std::vector<int64_t> storage_data{0, 1, 2, 3, 0, 1, 2, 3};
+ storage::NumericStorage<int64_t> storage(&storage_data, ColumnType::kInt64);
+
+ // Filter.
+ Constraint c{0, FilterOp::kGe, SqlValue()};
+ QueryExecutor exec({&storage}, 6);
+ RowMap res = exec.Filter({c});
+
+ ASSERT_TRUE(res.empty());
}
TEST(QueryExecutor, SingleConstraintWithNullAndSelector) {
std::vector<int64_t> storage_data{0, 1, 2, 3, 0, 1, 2, 3};
- storage::NumericStorage<int64_t> storage(&storage_data, ColumnType::kInt64);
+ auto numeric = std::make_unique<storage::NumericStorage<int64_t>>(
+ &storage_data, ColumnType::kInt64);
// Current vector
// 0, 1, NULL, 2, 3, 0, NULL, NULL, 1, 2, 3, NULL
BitVector null_bv{1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0};
- NullOverlay null_overlay(&null_bv);
+ auto null =
+ std::make_unique<storage::NullStorage>(std::move(numeric), &null_bv);
// Final vector
// 0, NULL, 3, NULL, 1, 3
BitVector selector_bv{1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0};
- SelectorOverlay selector_overlay(&selector_bv);
-
- // Create the column.
- OverlaysVec overlays_vec;
- overlays_vec.emplace_back(&selector_overlay);
- overlays_vec.emplace_back(&null_overlay);
- SimpleColumn col{overlays_vec, &storage};
+ SelectorStorage storage(std::move(null), &selector_bv);
// Filter.
Constraint c{0, FilterOp::kGe, SqlValue::Long(2)};
- QueryExecutor exec({col}, 6);
+ QueryExecutor exec({&storage}, 6);
RowMap res = exec.Filter({c});
ASSERT_EQ(res.size(), 2u);
@@ -306,27 +307,23 @@
TEST(QueryExecutor, SingleConstraintWithNullAndArrangement) {
std::vector<int64_t> storage_data{0, 1, 2, 3, 0, 1, 2, 3};
- storage::NumericStorage<int64_t> storage(&storage_data, ColumnType::kInt64);
+ auto numeric = std::make_unique<storage::NumericStorage<int64_t>>(
+ &storage_data, ColumnType::kInt64);
// Current vector
// 0, 1, NULL, 2, 3, 0, NULL, NULL, 1, 2, 3, NULL
BitVector null_bv{1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0};
- NullOverlay null_overlay(&null_bv);
+ auto null =
+ std::make_unique<storage::NullStorage>(std::move(numeric), &null_bv);
// Final vector
// NULL, 3, NULL, NULL, 3, NULL
std::vector<uint32_t> arrangement{2, 4, 6, 2, 4, 6};
- ArrangementOverlay arrangement_overlay(&arrangement);
-
- // Create the column.
- OverlaysVec overlays_vec;
- overlays_vec.emplace_back(&arrangement_overlay);
- overlays_vec.emplace_back(&null_overlay);
- SimpleColumn col{overlays_vec, &storage};
+ ArrangementStorage storage(std::move(null), &arrangement);
// Filter.
Constraint c{0, FilterOp::kGe, SqlValue::Long(1)};
- QueryExecutor exec({col}, 6);
+ QueryExecutor exec({&storage}, 6);
RowMap res = exec.Filter({c});
ASSERT_EQ(res.size(), 2u);
@@ -336,27 +333,23 @@
TEST(QueryExecutor, IsNullWithSelector) {
std::vector<int64_t> storage_data{0, 1, 2, 3, 0, 1, 2, 3};
- storage::NumericStorage<int64_t> storage(&storage_data, ColumnType::kInt64);
+ auto numeric = std::make_unique<storage::NumericStorage<int64_t>>(
+ &storage_data, ColumnType::kInt64);
// Current vector
// 0, 1, NULL, 2, 3, 0, NULL, NULL, 1, 2, 3, NULL
BitVector null_bv{1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0};
- NullOverlay null_overlay(&null_bv);
+ auto null =
+ std::make_unique<storage::NullStorage>(std::move(numeric), &null_bv);
// Final vector
// 0, NULL, 3, NULL, 1, 3
BitVector selector_bv{1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0};
- SelectorOverlay selector_overlay(&selector_bv);
-
- // Create the column.
- OverlaysVec overlays_vec;
- overlays_vec.emplace_back(&selector_overlay);
- overlays_vec.emplace_back(&null_overlay);
- SimpleColumn col{overlays_vec, &storage};
+ SelectorStorage storage(std::move(null), &selector_bv);
// Filter.
- Constraint c{0, FilterOp::kIsNull, SqlValue::Long(0)};
- QueryExecutor exec({col}, 6);
+ Constraint c{0, FilterOp::kIsNull, SqlValue()};
+ QueryExecutor exec({&storage}, 6);
RowMap res = exec.Filter({c});
ASSERT_EQ(res.size(), 2u);
@@ -366,26 +359,21 @@
TEST(QueryExecutor, BinarySearch) {
std::vector<int64_t> storage_data{0, 1, 2, 3, 4, 5, 6};
- storage::NumericStorage<int64_t> storage(&storage_data, ColumnType::kInt64,
- true);
+ auto numeric = std::make_unique<storage::NumericStorage<int64_t>>(
+ &storage_data, ColumnType::kInt64, true);
// Add nulls - {0, 1, NULL, NULL, 2, 3, NULL, NULL, 4, 5, 6, NULL}
BitVector null_bv{1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0};
- NullOverlay null_overlay(&null_bv);
+ auto null =
+ std::make_unique<storage::NullStorage>(std::move(numeric), &null_bv);
// Final vector {1, NULL, 3, NULL, 5, NULL}.
BitVector selector_bv{0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1};
- SelectorOverlay selector_overlay(&selector_bv);
-
- // Create the column.
- OverlaysVec overlays_vec;
- overlays_vec.emplace_back(&selector_overlay);
- overlays_vec.emplace_back(&null_overlay);
- SimpleColumn col{overlays_vec, &storage};
+ SelectorStorage storage(std::move(null), &selector_bv);
// Filter.
Constraint c{0, FilterOp::kGe, SqlValue::Long(3)};
- QueryExecutor exec({col}, 6);
+ QueryExecutor exec({&storage}, 6);
RowMap res = exec.Filter({c});
ASSERT_EQ(res.size(), 2u);
@@ -395,26 +383,21 @@
TEST(QueryExecutor, BinarySearchIsNull) {
std::vector<int64_t> storage_data{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
- storage::NumericStorage<int64_t> storage(&storage_data, ColumnType::kInt64,
- true);
+ auto numeric = std::make_unique<storage::NumericStorage<int64_t>>(
+ &storage_data, ColumnType::kInt64, true);
// Select 6 elements from storage, resulting in a vector {0, 1, 3, 4, 6, 7}.
BitVector selector_bv{1, 1, 0, 1, 1, 0, 1, 1, 0, 0};
- SelectorOverlay selector_overlay(&selector_bv);
+ auto selector =
+ std::make_unique<SelectorStorage>(std::move(numeric), &selector_bv);
// Add nulls, final vector {NULL, NULL, NULL 0, 1, 3, 4, 6, 7}.
BitVector null_bv{0, 0, 0, 1, 1, 1, 1, 1, 1};
- NullOverlay null_overlay(&null_bv);
-
- // Create the column.
- OverlaysVec overlays_vec;
- overlays_vec.emplace_back(&null_overlay);
- overlays_vec.emplace_back(&selector_overlay);
- SimpleColumn col{overlays_vec, &storage};
+ storage::NullStorage storage(std::move(selector), &null_bv);
// Filter.
- Constraint c{0, FilterOp::kIsNull, SqlValue::Long(0)};
- QueryExecutor exec({col}, 9);
+ Constraint c{0, FilterOp::kIsNull, SqlValue()};
+ QueryExecutor exec({&storage}, 9);
RowMap res = exec.Filter({c});
ASSERT_EQ(res.size(), 3u);
@@ -425,25 +408,20 @@
TEST(QueryExecutor, SetIdStorage) {
std::vector<uint32_t> storage_data{0, 0, 0, 3, 3, 3, 6, 6, 6, 9, 9, 9};
- SetIdStorage storage(&storage_data);
+ auto numeric = std::make_unique<storage::SetIdStorage>(&storage_data);
// Select 6 elements from storage, resulting in a vector {0, 3, 3, 6, 9, 9}.
BitVector selector_bv{0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1};
- SelectorOverlay selector_overlay(&selector_bv);
+ auto selector =
+ std::make_unique<SelectorStorage>(std::move(numeric), &selector_bv);
// Add nulls - vector (size 10) {NULL, 0, 3, NULL, 3, 6, NULL, 9, 9, NULL}.
BitVector null_bv{0, 1, 1, 0, 1, 1, 0, 1, 1, 0};
- NullOverlay null_overlay(&null_bv);
-
- // Create the column.
- OverlaysVec overlays_vec;
- overlays_vec.emplace_back(&null_overlay);
- overlays_vec.emplace_back(&selector_overlay);
- SimpleColumn col{overlays_vec, &storage};
+ storage::NullStorage storage(std::move(selector), &null_bv);
// Filter.
- Constraint c{0, FilterOp::kIsNull, SqlValue::Long(0)};
- QueryExecutor exec({col}, 10);
+ Constraint c{0, FilterOp::kIsNull, SqlValue()};
+ QueryExecutor exec({&storage}, 10);
RowMap res = exec.Filter({c});
ASSERT_EQ(res.size(), 4u);
@@ -458,12 +436,9 @@
storage::NumericStorage<int64_t> storage(&storage_data, ColumnType::kInt64,
true);
- OverlaysVec overlays_vec;
- SimpleColumn col{overlays_vec, &storage};
-
// Filter.
Constraint c{0, FilterOp::kNe, SqlValue::Long(5)};
- QueryExecutor exec({col}, 10);
+ QueryExecutor exec({&storage}, 10);
RowMap res = exec.Filter({c});
ASSERT_EQ(res.size(), 9u);
@@ -471,12 +446,10 @@
TEST(QueryExecutor, IdSearchIsNull) {
IdStorage storage(5);
- OverlaysVec overlays_vec;
- SimpleColumn col{overlays_vec, &storage};
// Filter.
- Constraint c{0, FilterOp::kIsNull, SqlValue::Long(0)};
- QueryExecutor exec({col}, 5);
+ Constraint c{0, FilterOp::kIsNull, SqlValue()};
+ QueryExecutor exec({&storage}, 5);
RowMap res = exec.Filter({c});
ASSERT_EQ(res.size(), 0u);
@@ -484,12 +457,10 @@
TEST(QueryExecutor, IdSearchIsNotNull) {
IdStorage storage(5);
- OverlaysVec overlays_vec;
- SimpleColumn col{overlays_vec, &storage};
// Filter.
- Constraint c{0, FilterOp::kIsNotNull, SqlValue::Long(0)};
- QueryExecutor exec({col}, 5);
+ Constraint c{0, FilterOp::kIsNotNull, SqlValue()};
+ QueryExecutor exec({&storage}, 5);
RowMap res = exec.Filter({c});
ASSERT_EQ(res.size(), 5u);
@@ -497,12 +468,10 @@
TEST(QueryExecutor, IdSearchNotEq) {
IdStorage storage(5);
- OverlaysVec overlays_vec;
- SimpleColumn col{overlays_vec, &storage};
// Filter.
Constraint c{0, FilterOp::kNe, SqlValue::Long(3)};
- QueryExecutor exec({col}, 5);
+ QueryExecutor exec({&storage}, 5);
RowMap res = exec.Filter({c});
ASSERT_EQ(res.size(), 4u);
@@ -517,20 +486,15 @@
ids.push_back(pool.InternString(base::StringView(string)));
}
ids.insert(ids.begin() + 3, StringPool::Id::Null());
- StringStorage storage(&pool, &ids);
+ auto string = std::make_unique<StringStorage>(&pool, &ids);
// Final vec {"cheese", "pasta", "NULL", "pierogi", "fries"}.
BitVector selector_bv{1, 1, 0, 1, 1, 0, 1};
- SelectorOverlay selector_overlay(&selector_bv);
-
- // Create the column.
- OverlaysVec overlays_vec;
- overlays_vec.emplace_back(&selector_overlay);
- SimpleColumn col{overlays_vec, &storage};
+ SelectorStorage storage(std::move(string), &selector_bv);
// Filter.
- Constraint c{0, FilterOp::kIsNull, SqlValue::Long(0)};
- QueryExecutor exec({col}, 5);
+ Constraint c{0, FilterOp::kIsNull, SqlValue()};
+ QueryExecutor exec({&storage}, 5);
RowMap res = exec.Filter({c});
ASSERT_EQ(res.size(), 1u);
@@ -545,20 +509,15 @@
for (const auto& string : strings) {
ids.push_back(pool.InternString(base::StringView(string)));
}
- StringStorage storage(&pool, &ids, true);
+ auto string = std::make_unique<StringStorage>(&pool, &ids, true);
// Final vec {"apple", "burger", "doughnut", "eggplant"}.
BitVector selector_bv{1, 1, 0, 1, 1, 0};
- SelectorOverlay selector_overlay(&selector_bv);
-
- // Create the column.
- OverlaysVec overlays_vec;
- overlays_vec.emplace_back(&selector_overlay);
- SimpleColumn col{overlays_vec, &storage};
+ SelectorStorage storage(std::move(string), &selector_bv);
// Filter.
Constraint c{0, FilterOp::kGe, SqlValue::String("camembert")};
- QueryExecutor exec({col}, 4);
+ QueryExecutor exec({&storage}, 4);
RowMap res = exec.Filter({c});
ASSERT_EQ(res.size(), 2u);
@@ -573,20 +532,15 @@
for (const auto& string : strings) {
ids.push_back(pool.InternString(base::StringView(string)));
}
- StringStorage storage(&pool, &ids, true);
+ auto string = std::make_unique<StringStorage>(&pool, &ids, true);
// Final vec {"apple", "burger", "doughnut", "eggplant"}.
BitVector selector_bv{1, 1, 0, 1, 1, 0};
- SelectorOverlay selector_overlay(&selector_bv);
-
- // Create the column.
- OverlaysVec overlays_vec;
- overlays_vec.emplace_back(&selector_overlay);
- SimpleColumn col{overlays_vec, &storage};
+ SelectorStorage storage(std::move(string), &selector_bv);
// Filter.
Constraint c{0, FilterOp::kNe, SqlValue::String("doughnut")};
- QueryExecutor exec({col}, 4);
+ QueryExecutor exec({&storage}, 4);
RowMap res = exec.Filter({c});
ASSERT_EQ(res.size(), 3u);
@@ -603,20 +557,15 @@
ids.push_back(pool.InternString(base::StringView(string)));
}
ids.insert(ids.begin() + 3, StringPool::Id::Null());
- StringStorage storage(&pool, &ids);
+ auto string = std::make_unique<StringStorage>(&pool, &ids);
// Final vec {"cheese", "pasta", "NULL", "pierogi", "fries"}.
BitVector selector_bv{1, 1, 0, 1, 1, 0, 1};
- SelectorOverlay selector_overlay(&selector_bv);
-
- // Create the column.
- OverlaysVec overlays_vec;
- overlays_vec.emplace_back(&selector_overlay);
- SimpleColumn col{overlays_vec, &storage};
+ SelectorStorage storage(std::move(string), &selector_bv);
// Filter.
Constraint c{0, FilterOp::kRegex, SqlValue::String("p.*")};
- QueryExecutor exec({col}, 5);
+ QueryExecutor exec({&storage}, 5);
RowMap res = exec.Filter({c});
ASSERT_EQ(res.size(), 2u);
@@ -633,20 +582,15 @@
ids.push_back(pool.InternString(base::StringView(string)));
}
ids.insert(ids.begin() + 3, StringPool::Id::Null());
- StringStorage storage(&pool, &ids);
+ auto string = std::make_unique<StringStorage>(&pool, &ids);
// Final vec {"cheese", "pasta", "NULL", "pierogi", "fries"}.
BitVector selector_bv{1, 1, 0, 1, 1, 0, 1};
- SelectorOverlay selector_overlay(&selector_bv);
-
- // Create the column.
- OverlaysVec overlays_vec;
- overlays_vec.emplace_back(&selector_overlay);
- SimpleColumn col{overlays_vec, &storage};
+ SelectorStorage storage(std::move(string), &selector_bv);
// Filter.
Constraint c{0, FilterOp::kRegex, SqlValue::Long(4)};
- QueryExecutor exec({col}, 5);
+ QueryExecutor exec({&storage}, 5);
RowMap res = exec.Filter({c});
ASSERT_EQ(res.size(), 0u);
diff --git a/src/trace_processor/db/storage/BUILD.gn b/src/trace_processor/db/storage/BUILD.gn
index 3b90470..55b7eb8 100644
--- a/src/trace_processor/db/storage/BUILD.gn
+++ b/src/trace_processor/db/storage/BUILD.gn
@@ -16,12 +16,18 @@
source_set("storage") {
sources = [
+ "arrangement_storage.cc",
+ "arrangement_storage.h",
"dummy_storage.cc",
"dummy_storage.h",
"id_storage.cc",
"id_storage.h",
+ "null_storage.cc",
+ "null_storage.h",
"numeric_storage.cc",
"numeric_storage.h",
+ "selector_storage.cc",
+ "selector_storage.h",
"set_id_storage.cc",
"set_id_storage.h",
"storage.cc",
@@ -43,17 +49,36 @@
]
}
-perfetto_unittest_source_set("unittests") {
+perfetto_unittest_source_set("fake_storage") {
testonly = true
sources = [
- "id_storage_unittest.cc",
- "numeric_storage_unittest.cc",
- "set_id_storage_unittest.cc",
- "string_storage_unittest.cc",
+ "fake_storage.cc",
+ "fake_storage.h",
]
deps = [
":storage",
"../../../../gn:default_deps",
"../../../../gn:gtest_and_gmock",
+ "../../containers",
+ ]
+}
+
+perfetto_unittest_source_set("unittests") {
+ testonly = true
+ sources = [
+ "arrangement_storage_unittest.cc",
+ "id_storage_unittest.cc",
+ "null_storage_unittest.cc",
+ "numeric_storage_unittest.cc",
+ "selector_storage_unittest.cc",
+ "set_id_storage_unittest.cc",
+ "string_storage_unittest.cc",
+ ]
+ deps = [
+ ":fake_storage",
+ ":storage",
+ "../../../../gn:default_deps",
+ "../../../../gn:gtest_and_gmock",
+ "../../containers",
]
}
diff --git a/src/trace_processor/db/storage/arrangement_storage.cc b/src/trace_processor/db/storage/arrangement_storage.cc
new file mode 100644
index 0000000..fac7f68
--- /dev/null
+++ b/src/trace_processor/db/storage/arrangement_storage.cc
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "src/trace_processor/db/storage/arrangement_storage.h"
+
+#include <algorithm>
+#include <cstdint>
+#include <vector>
+
+#include "protos/perfetto/trace_processor/serialization.pbzero.h"
+#include "src/trace_processor/containers/bit_vector.h"
+#include "src/trace_processor/tp_metatrace.h"
+
+namespace perfetto {
+namespace trace_processor {
+namespace storage {
+namespace {
+
+using Range = RowMap::Range;
+
+} // namespace
+
+ArrangementStorage::ArrangementStorage(std::unique_ptr<Storage> inner,
+ const std::vector<uint32_t>* arrangement)
+ : inner_(std::move(inner)), arrangement_(arrangement) {
+ PERFETTO_DCHECK(*std::max_element(arrangement->begin(), arrangement->end()) <=
+ inner_->size());
+}
+
+Storage::SearchValidationResult ArrangementStorage::ValidateSearchConstraints(
+ SqlValue sql_val,
+ FilterOp op) const {
+ return inner_->ValidateSearchConstraints(sql_val, op);
+}
+
+RangeOrBitVector ArrangementStorage::Search(FilterOp op,
+ SqlValue sql_val,
+ Range in) const {
+ PERFETTO_TP_TRACE(metatrace::Category::DB, "ArrangementStorage::Search");
+
+ const auto& arrangement = *arrangement_;
+ PERFETTO_DCHECK(in.end <= arrangement.size());
+ const auto [min_i, max_i] =
+ std::minmax_element(arrangement.begin() + static_cast<int32_t>(in.start),
+ arrangement.begin() + static_cast<int32_t>(in.end));
+
+ auto storage_result = inner_->Search(op, sql_val, Range(*min_i, *max_i + 1));
+ BitVector::Builder builder(in.end, in.start);
+ if (storage_result.IsRange()) {
+ Range storage_range = std::move(storage_result).TakeIfRange();
+ for (uint32_t i = in.start; i < in.end; ++i) {
+ builder.Append(storage_range.Contains(arrangement[i]));
+ }
+ } else {
+ BitVector storage_bitvector = std::move(storage_result).TakeIfBitVector();
+ PERFETTO_DCHECK(storage_bitvector.size() == *max_i + 1);
+
+ // After benchmarking, it turns out this complexity *is* actually worthwhile
+ // and has a noticable impact on the performance of this function in real
+ // world tables.
+
+ // Fast path: we compare as many groups of 64 elements as we can.
+ // This should be very easy for the compiler to auto-vectorize.
+ const uint32_t* arrangement_idx = arrangement.data() + in.start;
+ uint32_t fast_path_elements = builder.BitsInCompleteWordsUntilFull();
+ for (uint32_t i = 0; i < fast_path_elements; i += BitVector::kBitsInWord) {
+ uint64_t word = 0;
+ // This part should be optimised by SIMD and is expected to be fast.
+ for (uint32_t k = 0; k < BitVector::kBitsInWord; ++k, ++arrangement_idx) {
+ bool comp_result = storage_bitvector.IsSet(*arrangement_idx);
+ word |= static_cast<uint64_t>(comp_result) << k;
+ }
+ builder.AppendWord(word);
+ }
+
+ // Slow path: we compare <64 elements and append to fill the Builder.
+ uint32_t back_elements = builder.BitsUntilFull();
+ for (uint32_t i = 0; i < back_elements; ++i, ++arrangement_idx) {
+ builder.Append(storage_bitvector.IsSet(*arrangement_idx));
+ }
+ }
+ return RangeOrBitVector(std::move(builder).Build());
+}
+
+RangeOrBitVector ArrangementStorage::IndexSearch(FilterOp op,
+ SqlValue sql_val,
+ uint32_t* indices,
+ uint32_t indices_size,
+ bool sorted) const {
+ PERFETTO_TP_TRACE(metatrace::Category::DB, "ArrangementStorage::IndexSearch");
+
+ std::vector<uint32_t> storage_iv;
+ for (uint32_t* it = indices; it != indices + indices_size; ++it) {
+ storage_iv.push_back((*arrangement_)[*it]);
+ }
+ return inner_->IndexSearch(op, sql_val, storage_iv.data(),
+ static_cast<uint32_t>(storage_iv.size()), sorted);
+}
+
+void ArrangementStorage::StableSort(uint32_t*, uint32_t) const {
+ // TODO(b/307482437): Implement.
+ PERFETTO_FATAL("Not implemented");
+}
+
+void ArrangementStorage::Sort(uint32_t*, uint32_t) const {
+ // TODO(b/307482437): Implement.
+ PERFETTO_FATAL("Not implemented");
+}
+
+void ArrangementStorage::Serialize(StorageProto* storage) const {
+ auto* arrangement_storage = storage->set_arrangement_storage();
+ arrangement_storage->set_values(
+ reinterpret_cast<const uint8_t*>(arrangement_->data()),
+ sizeof(uint32_t) * arrangement_->size());
+ inner_->Serialize(arrangement_storage->set_storage());
+}
+
+} // namespace storage
+} // namespace trace_processor
+} // namespace perfetto
diff --git a/src/trace_processor/db/storage/arrangement_storage.h b/src/trace_processor/db/storage/arrangement_storage.h
new file mode 100644
index 0000000..97a944e
--- /dev/null
+++ b/src/trace_processor/db/storage/arrangement_storage.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SRC_TRACE_PROCESSOR_DB_STORAGE_ARRANGEMENT_STORAGE_H_
+#define SRC_TRACE_PROCESSOR_DB_STORAGE_ARRANGEMENT_STORAGE_H_
+
+#include <memory>
+#include "src/trace_processor/db/storage/storage.h"
+
+namespace perfetto {
+namespace trace_processor {
+namespace storage {
+
+// Storage responsible for rearranging the elements of another Storage. It deals
+// with duplicates, permutations and selection; for selection only, it's more
+// efficient to use `SelectorStorage`.
+class ArrangementStorage : public Storage {
+ public:
+ explicit ArrangementStorage(std::unique_ptr<Storage> inner,
+ const std::vector<uint32_t>* arrangement);
+
+ Storage::SearchValidationResult ValidateSearchConstraints(SqlValue, FilterOp)
+ const override;
+
+ RangeOrBitVector Search(FilterOp op,
+ SqlValue value,
+ RowMap::Range range) const override;
+
+ RangeOrBitVector IndexSearch(FilterOp op,
+ SqlValue value,
+ uint32_t* indices,
+ uint32_t indices_count,
+ bool sorted) const override;
+
+ void StableSort(uint32_t* rows, uint32_t rows_size) const override;
+
+ void Sort(uint32_t* rows, uint32_t rows_size) const override;
+
+ void Serialize(StorageProto*) const override;
+
+ uint32_t size() const override {
+ return static_cast<uint32_t>(arrangement_->size());
+ }
+
+ private:
+ std::unique_ptr<Storage> inner_;
+ const std::vector<uint32_t>* arrangement_;
+};
+
+} // namespace storage
+} // namespace trace_processor
+} // namespace perfetto
+
+#endif // SRC_TRACE_PROCESSOR_DB_STORAGE_ARRANGEMENT_STORAGE_H_
diff --git a/src/trace_processor/db/storage/arrangement_storage_unittest.cc b/src/trace_processor/db/storage/arrangement_storage_unittest.cc
new file mode 100644
index 0000000..f7b30f1
--- /dev/null
+++ b/src/trace_processor/db/storage/arrangement_storage_unittest.cc
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "src/trace_processor/db/storage/arrangement_storage.h"
+
+#include "src/trace_processor/db/storage/fake_storage.h"
+#include "src/trace_processor/db/storage/types.h"
+#include "test/gtest_and_gmock.h"
+
+namespace perfetto {
+namespace trace_processor {
+namespace storage {
+namespace {
+
+using testing::ElementsAre;
+using testing::IsEmpty;
+
+using Range = RowMap::Range;
+
+std::vector<uint32_t> ToIndexVector(RangeOrBitVector& r_or_bv) {
+ RowMap rm;
+ if (r_or_bv.IsBitVector()) {
+ rm = RowMap(std::move(r_or_bv).TakeIfBitVector());
+ } else {
+ Range range = std::move(r_or_bv).TakeIfRange();
+ rm = RowMap(range.start, range.end);
+ }
+ return rm.GetAllIndices();
+}
+
+TEST(ArrangementStorage, SearchAll) {
+ std::vector<uint32_t> arrangement{1, 1, 2, 2, 3, 3, 4, 4, 1, 1};
+ ArrangementStorage storage(FakeStorage::SearchAll(5), &arrangement);
+
+ auto res =
+ storage.Search(FilterOp::kGe, SqlValue::Long(0u), RowMap::Range(2, 4));
+ ASSERT_THAT(ToIndexVector(res), ElementsAre(2u, 3u));
+}
+
+TEST(ArrangementStorage, SearchNone) {
+ std::vector<uint32_t> arrangement{1, 1, 2, 2, 3, 3, 4, 4, 1, 1};
+ ArrangementStorage storage(FakeStorage::SearchNone(5), &arrangement);
+
+ auto res =
+ storage.Search(FilterOp::kGe, SqlValue::Long(0u), RowMap::Range(2, 4));
+ ASSERT_THAT(ToIndexVector(res), IsEmpty());
+}
+
+TEST(ArrangementStorage, DISABLED_SearchLimited) {
+ std::vector<uint32_t> arrangement{1, 1, 2, 2, 3, 3, 4, 4, 1, 1};
+ ArrangementStorage storage(FakeStorage::SearchSubset(5, Range(4, 5)),
+ &arrangement);
+
+ auto res = storage.Search(FilterOp::kGe, SqlValue::Long(0u), Range(2, 7));
+ ASSERT_THAT(ToIndexVector(res), ElementsAre(6u));
+}
+
+TEST(ArrangementStorage, SearchBitVector) {
+ std::vector<uint32_t> arrangement{1, 1, 2, 2, 3, 3, 4, 4, 1, 1};
+ ArrangementStorage storage(
+ FakeStorage::SearchSubset(5, BitVector({0, 1, 0, 1, 0})), &arrangement);
+
+ // Table bv:
+ // 1, 1, 0, 0, 1, 1, 0, 0, 1, 1
+ auto res = storage.Search(FilterOp::kGe, SqlValue::Long(0u), Range(0, 10));
+ ASSERT_THAT(ToIndexVector(res), ElementsAre(0, 1, 4, 5, 8, 9));
+}
+
+TEST(ArrangementStorage, IndexSearch) {
+ std::vector<uint32_t> arrangement{1, 1, 2, 2, 3, 3, 4, 4, 1, 1};
+ ArrangementStorage storage(
+ FakeStorage::SearchSubset(5, BitVector({0, 1, 0, 1, 0})), &arrangement);
+
+ std::vector<uint32_t> table_idx{7u, 1u, 3u};
+ RangeOrBitVector res =
+ storage.IndexSearch(FilterOp::kGe, SqlValue::Long(0u), table_idx.data(),
+ static_cast<uint32_t>(table_idx.size()), false);
+
+ ASSERT_THAT(ToIndexVector(res), ElementsAre(1u));
+}
+
+} // namespace
+} // namespace storage
+} // namespace trace_processor
+} // namespace perfetto
diff --git a/src/trace_processor/db/storage/dummy_storage.cc b/src/trace_processor/db/storage/dummy_storage.cc
index 4c6eb05..b4f0be5 100644
--- a/src/trace_processor/db/storage/dummy_storage.cc
+++ b/src/trace_processor/db/storage/dummy_storage.cc
@@ -21,6 +21,12 @@
namespace trace_processor {
namespace storage {
+DummyStorage::SearchValidationResult DummyStorage::ValidateSearchConstraints(
+ SqlValue,
+ FilterOp) const {
+ PERFETTO_FATAL("Shouldn't be called");
+}
+
RangeOrBitVector DummyStorage::Search(FilterOp, SqlValue, RowMap::Range) const {
PERFETTO_FATAL("Shouldn't be called");
}
diff --git a/src/trace_processor/db/storage/dummy_storage.h b/src/trace_processor/db/storage/dummy_storage.h
index 8d76d2f..7fd3a40 100644
--- a/src/trace_processor/db/storage/dummy_storage.h
+++ b/src/trace_processor/db/storage/dummy_storage.h
@@ -36,6 +36,9 @@
RangeOrBitVector Search(FilterOp, SqlValue, RowMap::Range) const override;
+ SearchValidationResult ValidateSearchConstraints(SqlValue,
+ FilterOp) const override;
+
RangeOrBitVector IndexSearch(FilterOp,
SqlValue,
uint32_t*,
diff --git a/src/trace_processor/db/storage/fake_storage.cc b/src/trace_processor/db/storage/fake_storage.cc
new file mode 100644
index 0000000..fd9ac2c
--- /dev/null
+++ b/src/trace_processor/db/storage/fake_storage.cc
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "src/trace_processor/db/storage/fake_storage.h"
+#include "src/trace_processor/containers/bit_vector.h"
+#include "src/trace_processor/containers/row_map.h"
+#include "src/trace_processor/db/storage/storage.h"
+#include "src/trace_processor/db/storage/types.h"
+
+namespace perfetto {
+namespace trace_processor {
+namespace storage {
+
+FakeStorage::FakeStorage(uint32_t size, SearchStrategy strategy)
+ : size_(size), strategy_(strategy) {}
+
+FakeStorage::SearchValidationResult FakeStorage::ValidateSearchConstraints(
+ SqlValue,
+ FilterOp) const {
+ return SearchValidationResult::kOk;
+}
+
+RangeOrBitVector FakeStorage::Search(FilterOp,
+ SqlValue,
+ RowMap::Range in) const {
+ switch (strategy_) {
+ case kAll:
+ return RangeOrBitVector(in);
+ case kNone:
+ return RangeOrBitVector(RowMap::Range());
+ case kRange:
+ return RangeOrBitVector(RowMap::Range(std::max(in.start, range_.start),
+ std::min(in.end, range_.end)));
+ case kBitVector:
+ return RangeOrBitVector{bit_vector_.IntersectRange(in.start, in.end)};
+ }
+ PERFETTO_FATAL("For GCC");
+}
+
+RangeOrBitVector FakeStorage::IndexSearch(FilterOp,
+ SqlValue,
+ uint32_t* indices,
+ uint32_t indices_size,
+ bool) const {
+ switch (strategy_) {
+ case kAll:
+ return RangeOrBitVector(RowMap::Range(0, indices_size));
+ case kNone:
+ return RangeOrBitVector(RowMap::Range());
+ case kRange:
+ case kBitVector: {
+ BitVector::Builder builder(indices_size);
+ for (uint32_t* it = indices; it != indices + indices_size; ++it) {
+ bool in_range = strategy_ == kRange && range_.Contains(*it);
+ bool in_bv = strategy_ == kBitVector && bit_vector_.IsSet(*it);
+ builder.Append(in_range || in_bv);
+ }
+ return RangeOrBitVector(std::move(builder).Build());
+ }
+ }
+ PERFETTO_FATAL("For GCC");
+}
+
+void FakeStorage::StableSort(uint32_t*, uint32_t) const {
+ // TODO(b/307482437): Implement.
+ PERFETTO_FATAL("Not implemented");
+}
+
+void FakeStorage::Sort(uint32_t*, uint32_t) const {
+ // TODO(b/307482437): Implement.
+ PERFETTO_FATAL("Not implemented");
+}
+
+void FakeStorage::Serialize(StorageProto*) const {
+ // FakeStorage doesn't really make sense to serialize.
+ PERFETTO_FATAL("Not implemented");
+}
+
+} // namespace storage
+} // namespace trace_processor
+} // namespace perfetto
diff --git a/src/trace_processor/db/storage/fake_storage.h b/src/trace_processor/db/storage/fake_storage.h
new file mode 100644
index 0000000..2320269
--- /dev/null
+++ b/src/trace_processor/db/storage/fake_storage.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SRC_TRACE_PROCESSOR_DB_STORAGE_FAKE_STORAGE_H_
+#define SRC_TRACE_PROCESSOR_DB_STORAGE_FAKE_STORAGE_H_
+
+#include <memory>
+#include "src/trace_processor/containers/row_map.h"
+#include "src/trace_processor/db/storage/storage.h"
+#include "src/trace_processor/db/storage/types.h"
+
+namespace perfetto {
+namespace trace_processor {
+namespace storage {
+
+// Fake implementation of Storage for use in tests.
+class FakeStorage final : public Storage {
+ public:
+ SearchValidationResult ValidateSearchConstraints(SqlValue,
+ FilterOp) const override;
+
+ RangeOrBitVector Search(FilterOp op,
+ SqlValue value,
+ RowMap::Range range) const override;
+
+ RangeOrBitVector IndexSearch(FilterOp op,
+ SqlValue value,
+ uint32_t* indices,
+ uint32_t indices_count,
+ bool sorted) const override;
+
+ void StableSort(uint32_t* rows, uint32_t rows_size) const override;
+
+ void Sort(uint32_t* rows, uint32_t rows_size) const override;
+
+ void Serialize(StorageProto*) const override;
+
+ static std::unique_ptr<Storage> SearchAll(uint32_t size) {
+ return std::unique_ptr<Storage>(
+ new FakeStorage(size, SearchStrategy::kAll));
+ }
+
+ static std::unique_ptr<Storage> SearchNone(uint32_t size) {
+ return std::unique_ptr<Storage>(
+ new FakeStorage(size, SearchStrategy::kNone));
+ }
+
+ static std::unique_ptr<Storage> SearchSubset(uint32_t size, RowMap::Range r) {
+ std::unique_ptr<FakeStorage> storage(
+ new FakeStorage(size, SearchStrategy::kRange));
+ storage->range_ = r;
+ return std::move(storage);
+ }
+
+ static std::unique_ptr<Storage> SearchSubset(uint32_t size, BitVector bv) {
+ std::unique_ptr<FakeStorage> storage(
+ new FakeStorage(size, SearchStrategy::kBitVector));
+ storage->bit_vector_ = std::move(bv);
+ return std::move(storage);
+ }
+
+ uint32_t size() const override { return size_; }
+
+ private:
+ enum SearchStrategy { kNone, kAll, kRange, kBitVector };
+ FakeStorage(uint32_t size, SearchStrategy strategy);
+
+ uint32_t size_ = 0;
+ SearchStrategy strategy_ = SearchStrategy::kNone;
+ RowMap::Range range_;
+ BitVector bit_vector_;
+};
+
+} // namespace storage
+} // namespace trace_processor
+} // namespace perfetto
+
+#endif // SRC_TRACE_PROCESSOR_DB_STORAGE_FAKE_STORAGE_H_
diff --git a/src/trace_processor/db/storage/id_storage.cc b/src/trace_processor/db/storage/id_storage.cc
index 53e85a8..bec9b041 100644
--- a/src/trace_processor/db/storage/id_storage.cc
+++ b/src/trace_processor/db/storage/id_storage.cc
@@ -16,12 +16,15 @@
#include "src/trace_processor/db/storage/id_storage.h"
+#include <optional>
+
#include "perfetto/base/logging.h"
-#include "perfetto/trace_processor/basic_types.h"
+#include "perfetto/public/compiler.h"
#include "protos/perfetto/trace_processor/serialization.pbzero.h"
#include "src/trace_processor/containers/bit_vector.h"
#include "src/trace_processor/containers/row_map.h"
#include "src/trace_processor/db/storage/types.h"
+#include "src/trace_processor/db/storage/utils.h"
#include "src/trace_processor/tp_metatrace.h"
namespace perfetto {
@@ -68,33 +71,112 @@
}
return RangeOrBitVector(std::move(builder).Build());
}
+
} // namespace
+IdStorage::SearchValidationResult IdStorage::ValidateSearchConstraints(
+ SqlValue val,
+ FilterOp op) const {
+ // NULL checks.
+ if (PERFETTO_UNLIKELY(val.is_null())) {
+ if (op == FilterOp::kIsNotNull) {
+ return SearchValidationResult::kAllData;
+ }
+ if (op == FilterOp::kIsNull) {
+ return SearchValidationResult::kNoData;
+ }
+ PERFETTO_DFATAL(
+ "Invalid filter operation. NULL should only be compared with 'IS NULL' "
+ "and 'IS NOT NULL'");
+ return SearchValidationResult::kNoData;
+ }
+
+ // FilterOp checks. Switch so that we get a warning if new FilterOp is not
+ // handled.
+ switch (op) {
+ case FilterOp::kEq:
+ case FilterOp::kNe:
+ case FilterOp::kLt:
+ case FilterOp::kLe:
+ case FilterOp::kGt:
+ case FilterOp::kGe:
+ break;
+ case FilterOp::kIsNull:
+ case FilterOp::kIsNotNull:
+ PERFETTO_FATAL("Invalid constraint");
+ case FilterOp::kGlob:
+ case FilterOp::kRegex:
+ return SearchValidationResult::kNoData;
+ }
+
+ // Type checks.
+ switch (val.type) {
+ case SqlValue::kNull:
+ case SqlValue::kLong:
+ case SqlValue::kDouble:
+ break;
+ case SqlValue::kString:
+ // Any string is always more than any numeric.
+ if (op == FilterOp::kLt || op == FilterOp::kLe) {
+ return Storage::SearchValidationResult::kAllData;
+ }
+ return Storage::SearchValidationResult::kNoData;
+ case SqlValue::kBytes:
+ return Storage::SearchValidationResult::kNoData;
+ }
+
+ // TODO(b/307482437): Remove after adding support for double
+ PERFETTO_CHECK(val.type != SqlValue::kDouble);
+
+ // Bounds of the value.
+ if (PERFETTO_UNLIKELY(val.AsLong() > std::numeric_limits<uint32_t>::max())) {
+ if (op == FilterOp::kLe || op == FilterOp::kLt || op == FilterOp::kNe) {
+ return SearchValidationResult::kAllData;
+ }
+ return SearchValidationResult::kNoData;
+ }
+ if (PERFETTO_UNLIKELY(val.AsLong() < std::numeric_limits<uint32_t>::min())) {
+ if (op == FilterOp::kGe || op == FilterOp::kGt || op == FilterOp::kNe) {
+ return SearchValidationResult::kAllData;
+ }
+ return SearchValidationResult::kNoData;
+ }
+
+ return SearchValidationResult::kOk;
+}
+
RangeOrBitVector IdStorage::Search(FilterOp op,
SqlValue sql_val,
- RowMap::Range range) const {
+ RowMap::Range search_range) const {
PERFETTO_TP_TRACE(metatrace::Category::DB, "IdStorage::Search",
- [&range, op](metatrace::Record* r) {
- r->AddArg("Start", std::to_string(range.start));
- r->AddArg("End", std::to_string(range.end));
+ [&search_range, op](metatrace::Record* r) {
+ r->AddArg("Start", std::to_string(search_range.start));
+ r->AddArg("End", std::to_string(search_range.end));
r->AddArg("Op",
std::to_string(static_cast<uint32_t>(op)));
});
+ PERFETTO_DCHECK(search_range.end <= size_);
+
+ // After this switch we assume the search is valid.
+ switch (ValidateSearchConstraints(sql_val, op)) {
+ case SearchValidationResult::kOk:
+ break;
+ case SearchValidationResult::kAllData:
+ return RangeOrBitVector(search_range);
+ case SearchValidationResult::kNoData:
+ return RangeOrBitVector(Range());
+ }
+
+ uint32_t val = static_cast<uint32_t>(sql_val.AsLong());
if (op == FilterOp::kNe) {
- if (sql_val.AsLong() > std::numeric_limits<uint32_t>::max() ||
- sql_val.AsLong() < std::numeric_limits<uint32_t>::min())
- return RangeOrBitVector(Range(0, size_));
-
- uint32_t val = static_cast<uint32_t>(sql_val.AsLong());
- BitVector ret(range.start, false);
- ret.Resize(range.end, true);
+ BitVector ret(search_range.start, false);
+ ret.Resize(search_range.end, true);
ret.Resize(size_, false);
-
ret.Clear(val);
return RangeOrBitVector(std::move(ret));
}
- return RangeOrBitVector(BinarySearchIntrinsic(op, sql_val, range));
+ return RangeOrBitVector(BinarySearchIntrinsic(op, val, search_range));
}
RangeOrBitVector IdStorage::IndexSearch(FilterOp op,
@@ -108,29 +190,17 @@
r->AddArg("Op",
std::to_string(static_cast<uint32_t>(op)));
});
- // Validate sql_val
- if (PERFETTO_UNLIKELY(sql_val.is_null())) {
- if (op == FilterOp::kIsNotNull) {
- return RangeOrBitVector(Range(indices_size, true));
- }
- return RangeOrBitVector(Range());
+
+ // After this switch we assume the search is valid.
+ switch (ValidateSearchConstraints(sql_val, op)) {
+ case SearchValidationResult::kOk:
+ break;
+ case SearchValidationResult::kAllData:
+ return RangeOrBitVector(Range(0, indices_size));
+ case SearchValidationResult::kNoData:
+ return RangeOrBitVector(Range());
}
- if (PERFETTO_UNLIKELY(sql_val.AsLong() >
- std::numeric_limits<uint32_t>::max())) {
- if (op == FilterOp::kLe || op == FilterOp::kLt) {
- return RangeOrBitVector(Range(indices_size, true));
- }
- return RangeOrBitVector(Range());
- }
-
- if (PERFETTO_UNLIKELY(sql_val.AsLong() <
- std::numeric_limits<uint32_t>::min())) {
- if (op == FilterOp::kGe || op == FilterOp::kGt) {
- return RangeOrBitVector(Range(indices_size, true));
- }
- return RangeOrBitVector(Range());
- }
uint32_t val = static_cast<uint32_t>(sql_val.AsLong());
switch (op) {
@@ -153,46 +223,15 @@
return IndexSearchWithComparator(val, indices, indices_size,
std::greater_equal<uint32_t>());
case FilterOp::kIsNotNull:
- return RangeOrBitVector(Range(indices_size, true));
case FilterOp::kIsNull:
case FilterOp::kGlob:
case FilterOp::kRegex:
- return RangeOrBitVector(Range());
+ PERFETTO_FATAL("Invalid filter operation");
}
PERFETTO_FATAL("FilterOp not matched");
}
-Range IdStorage::BinarySearchIntrinsic(FilterOp op,
- SqlValue sql_val,
- Range range) const {
- PERFETTO_DCHECK(range.end <= size_);
-
- // Validate sql_value
- if (PERFETTO_UNLIKELY(sql_val.is_null())) {
- if (op == FilterOp::kIsNotNull) {
- return range;
- }
- return Range();
- }
-
- if (PERFETTO_UNLIKELY(sql_val.AsLong() >
- std::numeric_limits<uint32_t>::max())) {
- if (op == FilterOp::kLe || op == FilterOp::kLt) {
- return range;
- }
- return Range();
- }
-
- if (PERFETTO_UNLIKELY(sql_val.AsLong() <
- std::numeric_limits<uint32_t>::min())) {
- if (op == FilterOp::kGe || op == FilterOp::kGt) {
- return range;
- }
- return Range();
- }
-
- uint32_t val = static_cast<uint32_t>(sql_val.AsLong());
-
+Range IdStorage::BinarySearchIntrinsic(FilterOp op, Id val, Range range) const {
switch (op) {
case FilterOp::kEq:
return Range(val, val + (range.start <= val && val < range.end));
@@ -205,13 +244,11 @@
case FilterOp::kGt:
return RowMap::Range(std::max(val + 1, range.start), range.end);
case FilterOp::kIsNotNull:
- return range;
case FilterOp::kNe:
- PERFETTO_FATAL("Shouldn't be called");
case FilterOp::kIsNull:
case FilterOp::kGlob:
case FilterOp::kRegex:
- return RowMap::Range();
+ PERFETTO_FATAL("Invalid filter operation");
}
PERFETTO_FATAL("FilterOp not matched");
}
diff --git a/src/trace_processor/db/storage/id_storage.h b/src/trace_processor/db/storage/id_storage.h
index e797028..475c29b 100644
--- a/src/trace_processor/db/storage/id_storage.h
+++ b/src/trace_processor/db/storage/id_storage.h
@@ -16,6 +16,10 @@
#ifndef SRC_TRACE_PROCESSOR_DB_STORAGE_ID_STORAGE_H_
#define SRC_TRACE_PROCESSOR_DB_STORAGE_ID_STORAGE_H_
+#include "perfetto/base/status.h"
+#include "perfetto/ext/base/status_or.h"
+#include "perfetto/trace_processor/basic_types.h"
+#include "src/trace_processor/containers/bit_vector.h"
#include "src/trace_processor/containers/row_map.h"
#include "src/trace_processor/db/storage/storage.h"
#include "src/trace_processor/db/storage/types.h"
@@ -34,6 +38,9 @@
public:
explicit IdStorage(uint32_t size) : size_(size) {}
+ SearchValidationResult ValidateSearchConstraints(SqlValue,
+ FilterOp) const override;
+
RangeOrBitVector Search(FilterOp op,
SqlValue value,
RowMap::Range range) const override;
@@ -53,9 +60,11 @@
uint32_t size() const override { return size_; }
private:
- BitVector IndexSearch(FilterOp, SqlValue, uint32_t*, uint32_t) const;
+ using Id = uint32_t;
+
+ BitVector IndexSearch(FilterOp, Id, uint32_t*, uint32_t) const;
RowMap::Range BinarySearchIntrinsic(FilterOp op,
- SqlValue val,
+ Id,
RowMap::Range search_range) const;
const uint32_t size_ = 0;
diff --git a/src/trace_processor/db/storage/id_storage_unittest.cc b/src/trace_processor/db/storage/id_storage_unittest.cc
index 13229e3..2262c43 100644
--- a/src/trace_processor/db/storage/id_storage_unittest.cc
+++ b/src/trace_processor/db/storage/id_storage_unittest.cc
@@ -14,17 +14,100 @@
* limitations under the License.
*/
#include "src/trace_processor/db/storage/id_storage.h"
+#include <limits>
#include "src/trace_processor/db/storage/types.h"
#include "test/gtest_and_gmock.h"
namespace perfetto {
namespace trace_processor {
+
+inline bool operator==(const RowMap::Range& a, const RowMap::Range& b) {
+ return std::tie(a.start, a.end) == std::tie(b.start, b.end);
+}
+
namespace storage {
namespace {
using Range = RowMap::Range;
+TEST(IdStorageUnittest, InvalidSearchConstraints) {
+ IdStorage storage(100);
+ Range test_range(10, 20);
+ Range empty_range;
+
+ // NULL checks
+ SqlValue val;
+ val.type = SqlValue::kNull;
+ Range search_result =
+ storage.Search(FilterOp::kIsNull, val, test_range).TakeIfRange();
+ ASSERT_EQ(search_result, empty_range);
+ search_result =
+ storage.Search(FilterOp::kIsNotNull, val, test_range).TakeIfRange();
+ ASSERT_EQ(search_result, test_range);
+
+ // FilterOp checks
+ search_result =
+ storage.Search(FilterOp::kGlob, SqlValue::Long(15), test_range)
+ .TakeIfRange();
+ ASSERT_EQ(search_result, empty_range);
+ search_result =
+ storage.Search(FilterOp::kRegex, SqlValue::Long(15), test_range)
+ .TakeIfRange();
+ ASSERT_EQ(search_result, empty_range);
+
+ // Type checks
+ search_result =
+ storage.Search(FilterOp::kGe, SqlValue::String("cheese"), test_range)
+ .TakeIfRange();
+ ASSERT_EQ(search_result, empty_range);
+
+ // Value bounds
+ SqlValue max_val = SqlValue::Long(
+ static_cast<int64_t>(std::numeric_limits<uint32_t>::max()) + 10);
+ search_result =
+ storage.Search(FilterOp::kGe, max_val, test_range).TakeIfRange();
+ ASSERT_EQ(search_result, empty_range);
+ search_result =
+ storage.Search(FilterOp::kGt, max_val, test_range).TakeIfRange();
+ ASSERT_EQ(search_result, empty_range);
+ search_result =
+ storage.Search(FilterOp::kEq, max_val, test_range).TakeIfRange();
+ ASSERT_EQ(search_result, empty_range);
+
+ search_result =
+ storage.Search(FilterOp::kLe, max_val, test_range).TakeIfRange();
+ ASSERT_EQ(search_result, test_range);
+ search_result =
+ storage.Search(FilterOp::kLt, max_val, test_range).TakeIfRange();
+ ASSERT_EQ(search_result, test_range);
+ search_result =
+ storage.Search(FilterOp::kNe, max_val, test_range).TakeIfRange();
+ ASSERT_EQ(search_result, test_range);
+
+ SqlValue min_val = SqlValue::Long(
+ static_cast<int64_t>(std::numeric_limits<uint32_t>::min()) - 1);
+ search_result =
+ storage.Search(FilterOp::kGe, min_val, test_range).TakeIfRange();
+ ASSERT_EQ(search_result, test_range);
+ search_result =
+ storage.Search(FilterOp::kGt, min_val, test_range).TakeIfRange();
+ ASSERT_EQ(search_result, test_range);
+ search_result =
+ storage.Search(FilterOp::kNe, min_val, test_range).TakeIfRange();
+ ASSERT_EQ(search_result, test_range);
+
+ search_result =
+ storage.Search(FilterOp::kLe, min_val, test_range).TakeIfRange();
+ ASSERT_EQ(search_result, empty_range);
+ search_result =
+ storage.Search(FilterOp::kLt, min_val, test_range).TakeIfRange();
+ ASSERT_EQ(search_result, empty_range);
+ search_result =
+ storage.Search(FilterOp::kEq, min_val, test_range).TakeIfRange();
+ ASSERT_EQ(search_result, empty_range);
+}
+
TEST(IdStorageUnittest, BinarySearchIntrinsicEqSimple) {
IdStorage storage(100);
Range range = storage.Search(FilterOp::kEq, SqlValue::Long(15), Range(10, 20))
@@ -100,7 +183,7 @@
IdStorage storage(100);
Range r = storage.Search(FilterOp::kNe, SqlValue::Long(-1), Range(30, 70))
.TakeIfRange();
- ASSERT_EQ(r.size(), 100u);
+ ASSERT_EQ(r.size(), 40u);
}
TEST(IdStorageUnittest, Sort) {
diff --git a/src/trace_processor/db/storage/null_storage.cc b/src/trace_processor/db/storage/null_storage.cc
new file mode 100644
index 0000000..6de2759
--- /dev/null
+++ b/src/trace_processor/db/storage/null_storage.cc
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "src/trace_processor/db/storage/null_storage.h"
+
+#include <cstdint>
+#include <variant>
+
+#include "protos/perfetto/trace_processor/serialization.pbzero.h"
+#include "src/trace_processor/containers/bit_vector.h"
+#include "src/trace_processor/containers/row_map.h"
+#include "src/trace_processor/db/storage/types.h"
+#include "src/trace_processor/tp_metatrace.h"
+
+namespace perfetto {
+namespace trace_processor {
+namespace storage {
+namespace {
+
+using Range = RowMap::Range;
+
+RangeOrBitVector ReconcileStorageResult(FilterOp op,
+ const BitVector& non_null,
+ RangeOrBitVector storage_result,
+ Range in_range) {
+ PERFETTO_CHECK(in_range.end <= non_null.size());
+
+ // Reconcile the results of the Search operation with the non-null indices
+ // to ensure only those positions are set.
+ BitVector res;
+ if (storage_result.IsRange()) {
+ Range range = std::move(storage_result).TakeIfRange();
+ if (range.size() > 0) {
+ res = non_null.IntersectRange(non_null.IndexOfNthSet(range.start),
+ non_null.IndexOfNthSet(range.end - 1) + 1);
+
+ // We should always have at least as many elements as the input range
+ // itself.
+ PERFETTO_CHECK(res.size() <= in_range.end);
+ }
+ } else {
+ res = non_null.Copy();
+ res.UpdateSetBits(std::move(storage_result).TakeIfBitVector());
+ }
+
+ // Ensure that |res| exactly matches the size which we need to return,
+ // padding with zeros or truncating if necessary.
+ res.Resize(in_range.end, false);
+
+ // For the IS NULL constraint, we also need to include all the null indices
+ // themselves.
+ if (PERFETTO_UNLIKELY(op == FilterOp::kIsNull)) {
+ BitVector null = non_null.IntersectRange(in_range.start, in_range.end);
+ null.Resize(in_range.end, false);
+ null.Not();
+ res.Or(null);
+ }
+ return RangeOrBitVector(std::move(res));
+}
+
+} // namespace
+
+Storage::SearchValidationResult NullStorage::ValidateSearchConstraints(
+ SqlValue sql_val,
+ FilterOp op) const {
+ return storage_->ValidateSearchConstraints(sql_val, op);
+}
+
+NullStorage::NullStorage(std::unique_ptr<Storage> storage,
+ const BitVector* non_null)
+ : storage_(std::move(storage)), non_null_(non_null) {
+ PERFETTO_DCHECK(non_null_->CountSetBits() <= storage_->size());
+}
+
+RangeOrBitVector NullStorage::Search(FilterOp op,
+ SqlValue sql_val,
+ RowMap::Range in) const {
+ PERFETTO_TP_TRACE(metatrace::Category::DB, "NullStorage::Search");
+
+ // Figure out the bounds of the indices in the underlying storage and search
+ // it.
+ uint32_t start = non_null_->CountSetBits(in.start);
+ uint32_t end = non_null_->CountSetBits(in.end);
+ return ReconcileStorageResult(
+ op, *non_null_, storage_->Search(op, sql_val, RowMap::Range(start, end)),
+ in);
+}
+
+RangeOrBitVector NullStorage::IndexSearch(FilterOp op,
+ SqlValue sql_val,
+ uint32_t* indices,
+ uint32_t indices_size,
+ bool sorted) const {
+ PERFETTO_TP_TRACE(metatrace::Category::DB, "NullStorage::IndexSearch");
+
+ BitVector::Builder storage_non_null(indices_size);
+ std::vector<uint32_t> storage_iv;
+ storage_iv.reserve(indices_size);
+ for (uint32_t* it = indices; it != indices + indices_size; it++) {
+ bool is_non_null = non_null_->IsSet(*it);
+ if (is_non_null) {
+ storage_iv.push_back(non_null_->CountSetBits(*it));
+ }
+ storage_non_null.Append(is_non_null);
+ }
+ RangeOrBitVector range_or_bv =
+ storage_->IndexSearch(op, sql_val, storage_iv.data(),
+ static_cast<uint32_t>(storage_iv.size()), sorted);
+ return ReconcileStorageResult(op, std::move(storage_non_null).Build(),
+ std::move(range_or_bv), Range(0, indices_size));
+}
+
+void NullStorage::StableSort(uint32_t*, uint32_t) const {
+ // TODO(b/307482437): Implement.
+ PERFETTO_FATAL("Not implemented");
+}
+
+void NullStorage::Sort(uint32_t*, uint32_t) const {
+ // TODO(b/307482437): Implement.
+ PERFETTO_FATAL("Not implemented");
+}
+
+void NullStorage::Serialize(StorageProto* storage) const {
+ auto* null_storage = storage->set_null_storage();
+ non_null_->Serialize(null_storage->set_bit_vector());
+ storage_->Serialize(null_storage->set_storage());
+}
+
+} // namespace storage
+} // namespace trace_processor
+} // namespace perfetto
diff --git a/src/trace_processor/db/storage/null_storage.h b/src/trace_processor/db/storage/null_storage.h
new file mode 100644
index 0000000..3087749
--- /dev/null
+++ b/src/trace_processor/db/storage/null_storage.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SRC_TRACE_PROCESSOR_DB_STORAGE_NULL_STORAGE_H_
+#define SRC_TRACE_PROCESSOR_DB_STORAGE_NULL_STORAGE_H_
+
+#include <memory>
+#include <variant>
+
+#include "src/trace_processor/containers/bit_vector.h"
+#include "src/trace_processor/db/storage/storage.h"
+#include "src/trace_processor/db/storage/types.h"
+
+namespace perfetto {
+namespace trace_processor {
+namespace storage {
+
+// Storage which introduces the layer of nullability. Specifically, spreads out
+// the storage with nulls using a BitVector.
+class NullStorage : public Storage {
+ public:
+ NullStorage(std::unique_ptr<Storage> storage, const BitVector* non_null);
+
+ SearchValidationResult ValidateSearchConstraints(SqlValue,
+ FilterOp) const override;
+
+ RangeOrBitVector Search(FilterOp op,
+ SqlValue value,
+ RowMap::Range range) const override;
+
+ RangeOrBitVector IndexSearch(FilterOp op,
+ SqlValue value,
+ uint32_t* indices,
+ uint32_t indices_count,
+ bool sorted) const override;
+
+ void StableSort(uint32_t* rows, uint32_t rows_size) const override;
+
+ void Sort(uint32_t* rows, uint32_t rows_size) const override;
+
+ void Serialize(StorageProto*) const override;
+
+ uint32_t size() const override { return non_null_->size(); }
+
+ private:
+ std::unique_ptr<Storage> storage_ = nullptr;
+ const BitVector* non_null_ = nullptr;
+};
+
+} // namespace storage
+} // namespace trace_processor
+} // namespace perfetto
+
+#endif // SRC_TRACE_PROCESSOR_DB_STORAGE_NULL_STORAGE_H_
diff --git a/src/trace_processor/db/storage/null_storage_unittest.cc b/src/trace_processor/db/storage/null_storage_unittest.cc
new file mode 100644
index 0000000..daa235f
--- /dev/null
+++ b/src/trace_processor/db/storage/null_storage_unittest.cc
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "src/trace_processor/db/storage/null_storage.h"
+
+#include <memory>
+#include <vector>
+
+#include "src/trace_processor/containers/bit_vector.h"
+#include "src/trace_processor/containers/row_map.h"
+#include "src/trace_processor/db/storage/fake_storage.h"
+#include "src/trace_processor/db/storage/numeric_storage.h"
+#include "src/trace_processor/db/storage/types.h"
+#include "test/gtest_and_gmock.h"
+
+namespace perfetto {
+namespace trace_processor {
+namespace storage {
+namespace {
+
+using testing::ElementsAre;
+using testing::IsEmpty;
+using Range = RowMap::Range;
+
+std::vector<uint32_t> ToIndexVector(RangeOrBitVector& r_or_bv) {
+ RowMap rm;
+ if (r_or_bv.IsBitVector()) {
+ rm = RowMap(std::move(r_or_bv).TakeIfBitVector());
+ } else {
+ Range range = std::move(r_or_bv).TakeIfRange();
+ rm = RowMap(range.start, range.end);
+ }
+ return rm.GetAllIndices();
+}
+
+TEST(NullStorage, SearchInputInsideBoundary) {
+ BitVector bv{0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0};
+ NullStorage storage(FakeStorage::SearchAll(4u), &bv);
+
+ auto res = storage.Search(FilterOp::kGt, SqlValue::Long(0), Range(1, 6));
+ ASSERT_THAT(ToIndexVector(res), ElementsAre(3, 4));
+}
+
+TEST(NullStorage, SearchInputOutsideBoundary) {
+ BitVector bv{0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0};
+ NullStorage storage(FakeStorage::SearchAll(5u), &bv);
+
+ auto res = storage.Search(FilterOp::kGt, SqlValue::Long(0), Range(3, 8));
+ ASSERT_THAT(ToIndexVector(res), ElementsAre(3, 4, 7));
+}
+
+TEST(NullStorage, SubsetResultOutsideBoundary) {
+ BitVector bv{0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0};
+ NullStorage storage(FakeStorage::SearchSubset(5u, RowMap::Range(1, 3)), &bv);
+
+ auto res = storage.Search(FilterOp::kGt, SqlValue::Long(0), Range(0, 11));
+ ASSERT_THAT(ToIndexVector(res), ElementsAre(3, 4));
+}
+
+TEST(NullStorage, SubsetResultOnBoundary) {
+ BitVector bv{0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0};
+ NullStorage storage(FakeStorage::SearchAll(5u), &bv);
+
+ auto res = storage.Search(FilterOp::kGt, SqlValue::Long(0), Range(0, 11));
+ ASSERT_THAT(ToIndexVector(res), ElementsAre(1, 3, 4, 7, 8));
+}
+
+TEST(NullStorage, BitVectorSubset) {
+ BitVector bv{0, 1, 1, 0, 0, 1, 1, 0};
+ NullStorage storage(FakeStorage::SearchSubset(4u, BitVector{0, 1, 0, 1}),
+ &bv);
+
+ auto res = storage.Search(FilterOp::kGt, SqlValue::Long(0), Range(0, 8));
+ ASSERT_THAT(ToIndexVector(res), ElementsAre(2, 6));
+}
+
+TEST(NullStorage, BitVectorSubsetIsNull) {
+ BitVector bv{0, 1, 1, 0, 0, 1, 1, 0};
+ NullStorage storage(FakeStorage::SearchSubset(4u, BitVector{0, 1, 0, 1}),
+ &bv);
+
+ auto res = storage.Search(FilterOp::kIsNull, SqlValue(), Range(0, 8));
+ ASSERT_THAT(ToIndexVector(res), ElementsAre(0, 2, 3, 4, 6, 7));
+}
+
+TEST(NullStorage, IndexSearchAllElements) {
+ BitVector bv{0, 1, 1, 0, 0, 1, 1, 0};
+ NullStorage storage(FakeStorage::SearchAll(4u), &bv);
+
+ std::vector<uint32_t> table_idx{1, 5, 2};
+ auto res =
+ storage.IndexSearch(FilterOp::kGt, SqlValue::Long(0), table_idx.data(),
+ uint32_t(table_idx.size()), false);
+ ASSERT_THAT(ToIndexVector(res), ElementsAre(0, 1, 2));
+}
+
+TEST(NullStorage, IndexSearchPartialElements) {
+ BitVector bv{0, 1, 1, 0, 0, 1, 1, 0};
+ NullStorage storage(FakeStorage::SearchAll(4u), &bv);
+
+ std::vector<uint32_t> table_idx{1, 4, 2};
+ auto res =
+ storage.IndexSearch(FilterOp::kGt, SqlValue::Long(0), table_idx.data(),
+ uint32_t(table_idx.size()), false);
+ ASSERT_THAT(ToIndexVector(res), ElementsAre(0, 2));
+}
+
+TEST(NullStorage, IndexSearchIsNullOpEmptyRes) {
+ BitVector bv{0, 1, 1, 0, 0, 1, 1, 0};
+ NullStorage storage(FakeStorage::SearchNone(4u), &bv);
+
+ std::vector<uint32_t> table_idx{0, 3, 5, 4, 2};
+ auto res =
+ storage.IndexSearch(FilterOp::kIsNull, SqlValue(), table_idx.data(),
+ uint32_t(table_idx.size()), false);
+ ASSERT_THAT(ToIndexVector(res), ElementsAre(0, 1, 3));
+}
+
+TEST(NullStorage, IndexSearchIsNullOp) {
+ BitVector bv{0, 1, 1, 0, 0, 1, 1, 0};
+ NullStorage storage(FakeStorage::SearchSubset(4u, Range(2, 3)), &bv);
+
+ std::vector<uint32_t> table_idx{0, 3, 2, 4, 5};
+ auto res =
+ storage.IndexSearch(FilterOp::kIsNull, SqlValue(), table_idx.data(),
+ uint32_t(table_idx.size()), false);
+ ASSERT_THAT(ToIndexVector(res), ElementsAre(0, 1, 3, 4));
+}
+
+TEST(NullStorage, IndexSearchIsNotNullOp) {
+ BitVector bv{0, 1, 1, 0, 0, 1, 1, 0};
+ NullStorage storage(FakeStorage::SearchAll(4u), &bv);
+
+ std::vector<uint32_t> table_idx{0, 3, 4};
+ auto res =
+ storage.IndexSearch(FilterOp::kIsNotNull, SqlValue(), table_idx.data(),
+ uint32_t(table_idx.size()), false);
+ ASSERT_THAT(ToIndexVector(res), IsEmpty());
+}
+
+} // namespace
+} // namespace storage
+} // namespace trace_processor
+} // namespace perfetto
diff --git a/src/trace_processor/db/storage/numeric_storage.cc b/src/trace_processor/db/storage/numeric_storage.cc
index ae09477..0b792de 100644
--- a/src/trace_processor/db/storage/numeric_storage.cc
+++ b/src/trace_processor/db/storage/numeric_storage.cc
@@ -17,12 +17,17 @@
#include "src/trace_processor/db/storage/numeric_storage.h"
+#include <cmath>
#include <cstddef>
#include <string>
+#include "perfetto/base/compiler.h"
+#include "perfetto/base/logging.h"
+#include "perfetto/public/compiler.h"
#include "protos/perfetto/trace_processor/serialization.pbzero.h"
#include "src/trace_processor/containers/bit_vector.h"
#include "src/trace_processor/containers/row_map.h"
+#include "src/trace_processor/db/storage/storage.h"
#include "src/trace_processor/db/storage/types.h"
#include "src/trace_processor/db/storage/utils.h"
#include "src/trace_processor/tp_metatrace.h"
@@ -32,7 +37,7 @@
namespace storage {
namespace {
-// All viable numeric values for ColumnTypes.
+using Range = RowMap::Range;
using NumericValue = std::variant<uint32_t, int32_t, int64_t, double_t>;
// Using the fact that binary operators in std are operators() of classes, we
@@ -46,33 +51,22 @@
std::equal_to<T>,
std::not_equal_to<T>>;
-// Based on SqlValue and ColumnType, casts SqlValue to proper type, returns
-// std::nullopt if SqlValue can't be cast and should be considered invalid for
-// comparison.
-inline std::optional<NumericValue> GetNumericTypeVariant(ColumnType type,
- SqlValue val) {
- if (val.is_null())
- return std::nullopt;
-
+// Based on SqlValue and ColumnType, casts SqlValue to proper type. Assumes the
+// |val| and |type| are correct.
+inline NumericValue GetNumericTypeVariant(ColumnType type, SqlValue val) {
switch (type) {
case ColumnType::kDouble:
return val.AsDouble();
case ColumnType::kInt64:
return val.AsLong();
case ColumnType::kInt32:
- if (val.AsLong() > std::numeric_limits<int32_t>::max() ||
- val.AsLong() < std::numeric_limits<int32_t>::min())
- return std::nullopt;
return static_cast<int32_t>(val.AsLong());
case ColumnType::kUint32:
- if (val.AsLong() > std::numeric_limits<uint32_t>::max() ||
- val.AsLong() < std::numeric_limits<uint32_t>::min())
- return std::nullopt;
return static_cast<uint32_t>(val.AsLong());
case ColumnType::kString:
case ColumnType::kDummy:
case ColumnType::kId:
- return std::nullopt;
+ PERFETTO_FATAL("Invalid type");
}
PERFETTO_FATAL("For GCC");
}
@@ -201,73 +195,198 @@
} // namespace
+NumericStorageBase::SearchValidationResult
+NumericStorageBase::ValidateSearchConstraints(SqlValue val, FilterOp op) const {
+ // NULL checks.
+ if (PERFETTO_UNLIKELY(val.is_null())) {
+ if (op == FilterOp::kIsNotNull) {
+ return SearchValidationResult::kAllData;
+ }
+ if (op == FilterOp::kIsNull) {
+ return SearchValidationResult::kNoData;
+ }
+ PERFETTO_FATAL(
+ "Invalid path. NULL should only be compared with 'IS NULL' and 'IS NOT "
+ "NULL'");
+ }
+
+ // FilterOp checks. Switch so that we get a warning if new FilterOp is not
+ // handled.
+ switch (op) {
+ case FilterOp::kEq:
+ case FilterOp::kNe:
+ case FilterOp::kLt:
+ case FilterOp::kLe:
+ case FilterOp::kGt:
+ case FilterOp::kGe:
+ break;
+ case FilterOp::kIsNull:
+ case FilterOp::kIsNotNull:
+ PERFETTO_FATAL("Invalid constraint");
+ case FilterOp::kGlob:
+ case FilterOp::kRegex:
+ return SearchValidationResult::kNoData;
+ }
+
+ // Type checks.
+ switch (val.type) {
+ case SqlValue::kNull:
+ case SqlValue::kLong:
+ case SqlValue::kDouble:
+ break;
+ case SqlValue::kString:
+ // Any string is always more than any numeric.
+ if (op == FilterOp::kLt || op == FilterOp::kLe) {
+ return Storage::SearchValidationResult::kAllData;
+ }
+ return Storage::SearchValidationResult::kNoData;
+ case SqlValue::kBytes:
+ return Storage::SearchValidationResult::kNoData;
+ }
+
+ // TODO(b/307482437): There is currently no support for comparison with double
+ // and it is prevented on QueryExecutor level.
+ if (type_ != ColumnType::kDouble) {
+ PERFETTO_CHECK(val.type != SqlValue::kDouble);
+ }
+
+ // Bounds of the value.
+ enum ExtremeVal { kTooBig, kTooSmall, kOk };
+ ExtremeVal extreme_validator = kOk;
+
+ switch (type_) {
+ case ColumnType::kDouble:
+ // Any value would make a sensible comparison with a double.
+ case ColumnType::kInt64:
+ // TODO(b/307482437): As long as the type is not double there is nothing
+ // to verify here, as all values are going to be in the int64_t limits.
+ break;
+ case ColumnType::kInt32:
+ if (val.AsLong() > std::numeric_limits<int32_t>::max()) {
+ extreme_validator = kTooBig;
+ break;
+ }
+ if (val.AsLong() < std::numeric_limits<int32_t>::min()) {
+ extreme_validator = kTooSmall;
+ break;
+ }
+ break;
+ case ColumnType::kUint32:
+ if (val.AsLong() > std::numeric_limits<uint32_t>::max()) {
+ extreme_validator = kTooBig;
+ break;
+ }
+ if (val.AsLong() < std::numeric_limits<uint32_t>::min()) {
+ extreme_validator = kTooSmall;
+ break;
+ }
+ break;
+ case ColumnType::kString:
+ case ColumnType::kDummy:
+ case ColumnType::kId:
+ break;
+ }
+
+ switch (extreme_validator) {
+ case kOk:
+ return Storage::SearchValidationResult::kOk;
+ case kTooBig:
+ if (op == FilterOp::kLt || op == FilterOp::kLe || op == FilterOp::kNe) {
+ return SearchValidationResult::kAllData;
+ }
+ return SearchValidationResult::kNoData;
+ case kTooSmall:
+ if (op == FilterOp::kGt || op == FilterOp::kGe || op == FilterOp::kNe) {
+ return SearchValidationResult::kAllData;
+ }
+ return SearchValidationResult::kNoData;
+ }
+
+ PERFETTO_FATAL("For GCC");
+}
+
RangeOrBitVector NumericStorageBase::Search(FilterOp op,
- SqlValue value,
- RowMap::Range range) const {
+ SqlValue sql_val,
+ RowMap::Range search_range) const {
PERFETTO_TP_TRACE(metatrace::Category::DB, "NumericStorage::Search",
- [&range, op](metatrace::Record* r) {
- r->AddArg("Start", std::to_string(range.start));
- r->AddArg("End", std::to_string(range.end));
+ [&search_range, op](metatrace::Record* r) {
+ r->AddArg("Start", std::to_string(search_range.start));
+ r->AddArg("End", std::to_string(search_range.end));
r->AddArg("Op",
std::to_string(static_cast<uint32_t>(op)));
});
+ // After this switch we assume the search is valid.
+ switch (ValidateSearchConstraints(sql_val, op)) {
+ case SearchValidationResult::kOk:
+ break;
+ case SearchValidationResult::kAllData:
+ return RangeOrBitVector(Range(0, search_range.end));
+ case SearchValidationResult::kNoData:
+ return RangeOrBitVector(Range());
+ }
+
+ NumericValue val = GetNumericTypeVariant(type_, sql_val);
+
if (is_sorted_) {
if (op != FilterOp::kNe) {
- return RangeOrBitVector(BinarySearchIntrinsic(op, value, range));
+ return RangeOrBitVector(BinarySearchIntrinsic(op, val, search_range));
}
// Not equal is a special operation on binary search, as it doesn't define a
// range, and rather just `not` range returned with `equal` operation.
- RowMap::Range r = BinarySearchIntrinsic(FilterOp::kEq, value, range);
+ RowMap::Range r = BinarySearchIntrinsic(FilterOp::kEq, val, search_range);
BitVector bv(r.start, true);
- bv.Resize(r.end);
- bv.Resize(range.end, true);
+ bv.Resize(r.end, false);
+ bv.Resize(search_range.end, true);
return RangeOrBitVector(std::move(bv));
}
- return RangeOrBitVector(LinearSearchInternal(op, value, range));
+ return RangeOrBitVector(LinearSearchInternal(op, val, search_range));
}
RangeOrBitVector NumericStorageBase::IndexSearch(FilterOp op,
- SqlValue value,
+ SqlValue sql_val,
uint32_t* indices,
- uint32_t indices_count,
+ uint32_t indices_size,
bool sorted) const {
PERFETTO_TP_TRACE(metatrace::Category::DB, "NumericStorage::IndexSearch",
- [indices_count, op](metatrace::Record* r) {
- r->AddArg("Count", std::to_string(indices_count));
+ [indices_size, op](metatrace::Record* r) {
+ r->AddArg("Count", std::to_string(indices_size));
r->AddArg("Op",
std::to_string(static_cast<uint32_t>(op)));
});
+
+ // After this switch we assume the search is valid.
+ switch (ValidateSearchConstraints(sql_val, op)) {
+ case SearchValidationResult::kOk:
+ break;
+ case SearchValidationResult::kAllData:
+ return RangeOrBitVector(Range(0, indices_size));
+ case SearchValidationResult::kNoData:
+ return RangeOrBitVector(Range());
+ }
+ NumericValue val = GetNumericTypeVariant(type_, sql_val);
if (sorted) {
return RangeOrBitVector(
- BinarySearchExtrinsic(op, value, indices, indices_count));
+ BinarySearchExtrinsic(op, val, indices, indices_size));
}
- return RangeOrBitVector(
- IndexSearchInternal(op, value, indices, indices_count));
+ return RangeOrBitVector(IndexSearchInternal(op, val, indices, indices_size));
}
BitVector NumericStorageBase::LinearSearchInternal(FilterOp op,
- SqlValue sql_val,
+ NumericValue val,
RowMap::Range range) const {
- std::optional<NumericValue> val = GetNumericTypeVariant(type_, sql_val);
- if (op == FilterOp::kIsNotNull)
- return BitVector(size(), true);
-
- if (!val.has_value() || op == FilterOp::kIsNull || op == FilterOp::kGlob)
- return BitVector(size(), false);
-
BitVector::Builder builder(range.end, range.start);
- if (const auto* u32 = std::get_if<uint32_t>(&*val)) {
+ if (const auto* u32 = std::get_if<uint32_t>(&val)) {
auto* start = static_cast<const uint32_t*>(data_) + range.start;
TypedLinearSearch(*u32, start, op, builder);
- } else if (const auto* i64 = std::get_if<int64_t>(&*val)) {
+ } else if (const auto* i64 = std::get_if<int64_t>(&val)) {
auto* start = static_cast<const int64_t*>(data_) + range.start;
TypedLinearSearch(*i64, start, op, builder);
- } else if (const auto* i32 = std::get_if<int32_t>(&*val)) {
+ } else if (const auto* i32 = std::get_if<int32_t>(&val)) {
auto* start = static_cast<const int32_t*>(data_) + range.start;
TypedLinearSearch(*i32, start, op, builder);
- } else if (const auto* db = std::get_if<double>(&*val)) {
+ } else if (const auto* db = std::get_if<double>(&val)) {
auto* start = static_cast<const double*>(data_) + range.start;
TypedLinearSearch(*db, start, op, builder);
} else {
@@ -278,16 +397,9 @@
BitVector NumericStorageBase::IndexSearchInternal(
FilterOp op,
- SqlValue sql_val,
+ NumericValue val,
uint32_t* indices,
uint32_t indices_count) const {
- std::optional<NumericValue> val = GetNumericTypeVariant(type_, sql_val);
- if (op == FilterOp::kIsNotNull)
- return BitVector(indices_count, true);
-
- if (!val.has_value() || op == FilterOp::kIsNull || op == FilterOp::kGlob)
- return BitVector(indices_count, false);
-
BitVector::Builder builder(indices_count);
std::visit(
[this, indices, op, &builder](auto val) {
@@ -300,37 +412,30 @@
},
GetFilterOpVariant<T>(op));
},
- *val);
+ val);
return std::move(builder).Build();
}
RowMap::Range NumericStorageBase::BinarySearchIntrinsic(
FilterOp op,
- SqlValue sql_val,
+ NumericValue val,
RowMap::Range search_range) const {
- std::optional<NumericValue> val = GetNumericTypeVariant(type_, sql_val);
- if (op == FilterOp::kIsNotNull)
- return search_range;
-
- if (!val.has_value() || op == FilterOp::kIsNull || op == FilterOp::kGlob)
- return RowMap::Range();
-
switch (op) {
case FilterOp::kEq:
- return RowMap::Range(LowerBoundIntrinsic(data_, *val, search_range),
- UpperBoundIntrinsic(data_, *val, search_range));
+ return RowMap::Range(LowerBoundIntrinsic(data_, val, search_range),
+ UpperBoundIntrinsic(data_, val, search_range));
case FilterOp::kLe: {
return RowMap::Range(search_range.start,
- UpperBoundIntrinsic(data_, *val, search_range));
+ UpperBoundIntrinsic(data_, val, search_range));
}
case FilterOp::kLt:
return RowMap::Range(search_range.start,
- LowerBoundIntrinsic(data_, *val, search_range));
+ LowerBoundIntrinsic(data_, val, search_range));
case FilterOp::kGe:
- return RowMap::Range(LowerBoundIntrinsic(data_, *val, search_range),
+ return RowMap::Range(LowerBoundIntrinsic(data_, val, search_range),
search_range.end);
case FilterOp::kGt:
- return RowMap::Range(UpperBoundIntrinsic(data_, *val, search_range),
+ return RowMap::Range(UpperBoundIntrinsic(data_, val, search_range),
search_range.end);
case FilterOp::kNe:
case FilterOp::kIsNull:
@@ -344,34 +449,26 @@
RowMap::Range NumericStorageBase::BinarySearchExtrinsic(
FilterOp op,
- SqlValue sql_val,
+ NumericValue val,
uint32_t* indices,
uint32_t indices_count) const {
- std::optional<NumericValue> val = GetNumericTypeVariant(type_, sql_val);
-
- if (op == FilterOp::kIsNotNull)
- return RowMap::Range(0, size());
-
- if (!val.has_value() || op == FilterOp::kIsNull || op == FilterOp::kGlob)
- return RowMap::Range();
-
switch (op) {
case FilterOp::kEq:
return RowMap::Range(
- LowerBoundExtrinsic(data_, *val, indices, indices_count),
- UpperBoundExtrinsic(data_, *val, indices, indices_count));
+ LowerBoundExtrinsic(data_, val, indices, indices_count),
+ UpperBoundExtrinsic(data_, val, indices, indices_count));
case FilterOp::kLe:
return RowMap::Range(
- 0, UpperBoundExtrinsic(data_, *val, indices, indices_count));
+ 0, UpperBoundExtrinsic(data_, val, indices, indices_count));
case FilterOp::kLt:
return RowMap::Range(
- 0, LowerBoundExtrinsic(data_, *val, indices, indices_count));
+ 0, LowerBoundExtrinsic(data_, val, indices, indices_count));
case FilterOp::kGe:
return RowMap::Range(
- LowerBoundExtrinsic(data_, *val, indices, indices_count), size_);
+ LowerBoundExtrinsic(data_, val, indices, indices_count), size_);
case FilterOp::kGt:
return RowMap::Range(
- UpperBoundExtrinsic(data_, *val, indices, indices_count), size_);
+ UpperBoundExtrinsic(data_, val, indices, indices_count), size_);
case FilterOp::kNe:
case FilterOp::kIsNull:
case FilterOp::kIsNotNull:
@@ -383,7 +480,6 @@
}
void NumericStorageBase::StableSort(uint32_t* rows, uint32_t rows_size) const {
- NumericValue val = *GetNumericTypeVariant(type_, SqlValue::Long(0));
std::visit(
[this, &rows, rows_size](auto val_data) {
using T = decltype(val_data);
@@ -395,10 +491,13 @@
return first_val < second_val;
});
},
- val);
+ GetNumericTypeVariant(type_, SqlValue::Long(0)));
}
-void NumericStorageBase::Sort(uint32_t*, uint32_t) const {}
+void NumericStorageBase::Sort(uint32_t*, uint32_t) const {
+ // TODO(b/307482437): Implement.
+ PERFETTO_ELOG("Not implemented");
+}
void NumericStorageBase::Serialize(StorageProto* msg) const {
auto* numeric_storage_msg = msg->set_numeric_storage();
@@ -425,7 +524,7 @@
PERFETTO_FATAL("Invalid column type for NumericStorage");
}
numeric_storage_msg->set_values(static_cast<const uint8_t*>(data_),
- static_cast<size_t>(type_size * size_));
+ static_cast<size_t>(type_size) * size_);
}
} // namespace storage
diff --git a/src/trace_processor/db/storage/numeric_storage.h b/src/trace_processor/db/storage/numeric_storage.h
index a91e289..741a8e0 100644
--- a/src/trace_processor/db/storage/numeric_storage.h
+++ b/src/trace_processor/db/storage/numeric_storage.h
@@ -18,6 +18,7 @@
#include <variant>
+#include "perfetto/trace_processor/basic_types.h"
#include "src/trace_processor/db/storage/storage.h"
#include "src/trace_processor/db/storage/types.h"
@@ -33,6 +34,9 @@
// Storage for all numeric type data (i.e. doubles, int32, int64, uint32).
class NumericStorageBase : public Storage {
public:
+ SearchValidationResult ValidateSearchConstraints(SqlValue,
+ FilterOp) const override;
+
RangeOrBitVector Search(FilterOp op,
SqlValue value,
RowMap::Range range) const override;
@@ -59,21 +63,24 @@
: size_(size), data_(data), type_(type), is_sorted_(is_sorted) {}
private:
+ // All viable numeric values for ColumnTypes.
+ using NumericValue = std::variant<uint32_t, int32_t, int64_t, double>;
+
BitVector LinearSearchInternal(FilterOp op,
- SqlValue val,
+ NumericValue val,
RowMap::Range) const;
BitVector IndexSearchInternal(FilterOp op,
- SqlValue value,
+ NumericValue value,
uint32_t* indices,
uint32_t indices_count) const;
RowMap::Range BinarySearchIntrinsic(FilterOp op,
- SqlValue val,
+ NumericValue val,
RowMap::Range search_range) const;
RowMap::Range BinarySearchExtrinsic(FilterOp op,
- SqlValue val,
+ NumericValue val,
uint32_t* indices,
uint32_t indices_count) const;
diff --git a/src/trace_processor/db/storage/numeric_storage_unittest.cc b/src/trace_processor/db/storage/numeric_storage_unittest.cc
index b6ffb59..e82883f 100644
--- a/src/trace_processor/db/storage/numeric_storage_unittest.cc
+++ b/src/trace_processor/db/storage/numeric_storage_unittest.cc
@@ -20,11 +20,160 @@
namespace perfetto {
namespace trace_processor {
+
+inline bool operator==(const RowMap::Range& a, const RowMap::Range& b) {
+ return std::tie(a.start, a.end) == std::tie(b.start, b.end);
+}
+
namespace storage {
namespace {
using Range = RowMap::Range;
+TEST(IdStorageUnittest, InvalidSearchConstraintsGeneralChecks) {
+ std::vector<uint32_t> data_vec(128);
+ std::iota(data_vec.begin(), data_vec.end(), 0);
+ NumericStorage<uint32_t> storage(&data_vec, ColumnType::kUint32);
+
+ Range test_range(20, 100);
+ Range full_range(0, 100);
+ Range empty_range;
+
+ // NULL checks
+ SqlValue val;
+ val.type = SqlValue::kNull;
+ Range search_result =
+ storage.Search(FilterOp::kIsNull, val, test_range).TakeIfRange();
+ ASSERT_EQ(search_result, empty_range);
+ search_result =
+ storage.Search(FilterOp::kIsNotNull, val, test_range).TakeIfRange();
+ ASSERT_EQ(search_result, full_range);
+
+ // FilterOp checks
+ search_result =
+ storage.Search(FilterOp::kGlob, SqlValue::Long(15), test_range)
+ .TakeIfRange();
+ ASSERT_EQ(search_result, empty_range);
+ search_result =
+ storage.Search(FilterOp::kRegex, SqlValue::Long(15), test_range)
+ .TakeIfRange();
+ ASSERT_EQ(search_result, empty_range);
+
+ // Type checks
+ search_result =
+ storage.Search(FilterOp::kGe, SqlValue::String("cheese"), test_range)
+ .TakeIfRange();
+ ASSERT_EQ(search_result, empty_range);
+}
+
+TEST(IdStorageUnittest, InvalidValueBoundsUint32) {
+ std::vector<uint32_t> data_vec(128);
+ std::iota(data_vec.begin(), data_vec.end(), 0);
+ NumericStorage<uint32_t> storage(&data_vec, ColumnType::kUint32);
+
+ Range test_range(20, 100);
+ Range full_range(0, 100);
+ Range empty_range;
+
+ SqlValue max_val = SqlValue::Long(
+ static_cast<int64_t>(std::numeric_limits<uint32_t>::max()) + 10);
+ Range search_result =
+ storage.Search(FilterOp::kGe, max_val, test_range).TakeIfRange();
+ ASSERT_EQ(search_result, empty_range);
+ search_result =
+ storage.Search(FilterOp::kGt, max_val, test_range).TakeIfRange();
+ ASSERT_EQ(search_result, empty_range);
+ search_result =
+ storage.Search(FilterOp::kEq, max_val, test_range).TakeIfRange();
+ ASSERT_EQ(search_result, empty_range);
+
+ search_result =
+ storage.Search(FilterOp::kLe, max_val, test_range).TakeIfRange();
+ ASSERT_EQ(search_result, full_range);
+ search_result =
+ storage.Search(FilterOp::kLt, max_val, test_range).TakeIfRange();
+ ASSERT_EQ(search_result, full_range);
+ search_result =
+ storage.Search(FilterOp::kNe, max_val, test_range).TakeIfRange();
+ ASSERT_EQ(search_result, full_range);
+
+ SqlValue min_val = SqlValue::Long(
+ static_cast<int64_t>(std::numeric_limits<uint32_t>::min()) - 1);
+ search_result =
+ storage.Search(FilterOp::kGe, min_val, test_range).TakeIfRange();
+ ASSERT_EQ(search_result, full_range);
+ search_result =
+ storage.Search(FilterOp::kGt, min_val, test_range).TakeIfRange();
+ ASSERT_EQ(search_result, full_range);
+ search_result =
+ storage.Search(FilterOp::kNe, min_val, test_range).TakeIfRange();
+ ASSERT_EQ(search_result, full_range);
+
+ search_result =
+ storage.Search(FilterOp::kLe, min_val, test_range).TakeIfRange();
+ ASSERT_EQ(search_result, empty_range);
+ search_result =
+ storage.Search(FilterOp::kLt, min_val, test_range).TakeIfRange();
+ ASSERT_EQ(search_result, empty_range);
+ search_result =
+ storage.Search(FilterOp::kEq, min_val, test_range).TakeIfRange();
+ ASSERT_EQ(search_result, empty_range);
+}
+
+TEST(IdStorageUnittest, InvalidValueBoundsInt32) {
+ std::vector<int32_t> data_vec(128);
+ std::iota(data_vec.begin(), data_vec.end(), 0);
+ NumericStorage<int32_t> storage(&data_vec, ColumnType::kInt32);
+
+ Range test_range(20, 100);
+ Range full_range(0, 100);
+ Range empty_range;
+
+ SqlValue max_val = SqlValue::Long(
+ static_cast<int64_t>(std::numeric_limits<int32_t>::max()) + 10);
+ Range search_result =
+ storage.Search(FilterOp::kGe, max_val, test_range).TakeIfRange();
+ ASSERT_EQ(search_result, empty_range);
+ search_result =
+ storage.Search(FilterOp::kGt, max_val, test_range).TakeIfRange();
+ ASSERT_EQ(search_result, empty_range);
+ search_result =
+ storage.Search(FilterOp::kEq, max_val, test_range).TakeIfRange();
+ ASSERT_EQ(search_result, empty_range);
+
+ search_result =
+ storage.Search(FilterOp::kLe, max_val, test_range).TakeIfRange();
+ ASSERT_EQ(search_result, full_range);
+ search_result =
+ storage.Search(FilterOp::kLt, max_val, test_range).TakeIfRange();
+ ASSERT_EQ(search_result, full_range);
+ search_result =
+ storage.Search(FilterOp::kNe, max_val, test_range).TakeIfRange();
+ ASSERT_EQ(search_result, full_range);
+
+ SqlValue min_val = SqlValue::Long(
+ static_cast<int64_t>(std::numeric_limits<int32_t>::min()) - 1);
+ search_result =
+ storage.Search(FilterOp::kGe, min_val, test_range).TakeIfRange();
+ ASSERT_EQ(search_result, full_range);
+ search_result =
+ storage.Search(FilterOp::kGt, min_val, test_range).TakeIfRange();
+ ASSERT_EQ(search_result, full_range);
+ search_result =
+ storage.Search(FilterOp::kNe, min_val, test_range).TakeIfRange();
+ ASSERT_EQ(search_result, full_range);
+
+ search_result =
+ storage.Search(FilterOp::kLe, min_val, test_range).TakeIfRange();
+ ASSERT_EQ(search_result, empty_range);
+ search_result =
+ storage.Search(FilterOp::kLt, min_val, test_range).TakeIfRange();
+ ASSERT_EQ(search_result, empty_range);
+ search_result =
+ storage.Search(FilterOp::kEq, min_val, test_range).TakeIfRange();
+ ASSERT_EQ(search_result, empty_range);
+}
+
TEST(NumericStorageUnittest, StableSortTrivial) {
std::vector<uint32_t> data_vec{0, 1, 2, 0, 1, 2, 0, 1, 2};
std::vector<uint32_t> out = {0, 1, 2, 3, 4, 5, 6, 7, 8};
diff --git a/src/trace_processor/db/storage/selector_storage.cc b/src/trace_processor/db/storage/selector_storage.cc
new file mode 100644
index 0000000..934b900
--- /dev/null
+++ b/src/trace_processor/db/storage/selector_storage.cc
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "src/trace_processor/db/storage/selector_storage.h"
+
+#include "protos/perfetto/trace_processor/serialization.pbzero.h"
+#include "src/trace_processor/containers/bit_vector.h"
+#include "src/trace_processor/db/storage/types.h"
+#include "src/trace_processor/tp_metatrace.h"
+
+namespace perfetto {
+namespace trace_processor {
+namespace storage {
+
+using Range = RowMap::Range;
+
+SelectorStorage::SelectorStorage(std::unique_ptr<Storage> inner,
+ const BitVector* selector)
+ : inner_(std::move(inner)), selector_(selector) {}
+
+Storage::SearchValidationResult SelectorStorage::ValidateSearchConstraints(
+ SqlValue sql_val,
+ FilterOp op) const {
+ return inner_->ValidateSearchConstraints(sql_val, op);
+}
+
+RangeOrBitVector SelectorStorage::Search(FilterOp op,
+ SqlValue sql_val,
+ RowMap::Range in) const {
+ PERFETTO_TP_TRACE(metatrace::Category::DB, "SelectorStorage::Search");
+
+ // Figure out the bounds of the indices in the underlying storage and search
+ // it.
+ uint32_t start_idx = selector_->IndexOfNthSet(in.start);
+ uint32_t end_idx = selector_->IndexOfNthSet(in.end - 1) + 1;
+
+ auto storage_result = inner_->Search(op, sql_val, Range(start_idx, end_idx));
+ if (storage_result.IsRange()) {
+ Range storage_range = std::move(storage_result).TakeIfRange();
+ uint32_t out_start = selector_->CountSetBits(storage_range.start);
+ uint32_t out_end = selector_->CountSetBits(storage_range.end);
+ return RangeOrBitVector(Range(out_start, out_end));
+ }
+
+ BitVector storage_bitvector = std::move(storage_result).TakeIfBitVector();
+ PERFETTO_DCHECK(storage_bitvector.size() <= selector_->size());
+
+ // TODO(b/283763282): implement ParallelExtractBits to optimize this
+ // operation.
+ BitVector::Builder res(in.end);
+ for (auto it = selector_->IterateSetBits();
+ it && it.index() < storage_bitvector.size(); it.Next()) {
+ res.Append(storage_bitvector.IsSet(it.index()));
+ }
+ return RangeOrBitVector(std::move(res).Build());
+}
+
+RangeOrBitVector SelectorStorage::IndexSearch(FilterOp op,
+ SqlValue sql_val,
+ uint32_t* indices,
+ uint32_t indices_size,
+ bool sorted) const {
+ PERFETTO_DCHECK(indices_size == 0 ||
+ *std::max_element(indices, indices + indices_size) <=
+ selector_->size());
+
+ PERFETTO_TP_TRACE(metatrace::Category::DB, "SelectorStorage::IndexSearch");
+
+ // To go from TableIndexVector to StorageIndexVector we need to find index in
+ // |selector_| by looking only into set bits.
+ std::vector<uint32_t> storage_iv;
+ storage_iv.reserve(indices_size);
+ for (const uint32_t* it = indices; it != indices + indices_size; ++it) {
+ storage_iv.push_back(selector_->IndexOfNthSet(*it));
+ }
+ return inner_->IndexSearch(op, sql_val, storage_iv.data(),
+ static_cast<uint32_t>(storage_iv.size()), sorted);
+}
+
+void SelectorStorage::StableSort(uint32_t*, uint32_t) const {
+ // TODO(b/307482437): Implement.
+ PERFETTO_FATAL("Not implemented");
+}
+
+void SelectorStorage::Sort(uint32_t*, uint32_t) const {
+ // TODO(b/307482437): Implement.
+ PERFETTO_FATAL("Not implemented");
+}
+
+void SelectorStorage::Serialize(StorageProto* storage) const {
+ auto* selector_storage = storage->set_selector_storage();
+ inner_->Serialize(selector_storage->set_storage());
+ selector_->Serialize(selector_storage->set_bit_vector());
+}
+
+} // namespace storage
+} // namespace trace_processor
+} // namespace perfetto
diff --git a/src/trace_processor/db/storage/selector_storage.h b/src/trace_processor/db/storage/selector_storage.h
new file mode 100644
index 0000000..9d368e2
--- /dev/null
+++ b/src/trace_processor/db/storage/selector_storage.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SRC_TRACE_PROCESSOR_DB_STORAGE_SELECTOR_STORAGE_H_
+#define SRC_TRACE_PROCESSOR_DB_STORAGE_SELECTOR_STORAGE_H_
+
+#include "src/trace_processor/db/storage/storage.h"
+#include "src/trace_processor/db/storage/types.h"
+
+namespace perfetto {
+namespace trace_processor {
+namespace storage {
+
+// Storage which "selects" specific rows from an underlying storage using a
+// BitVector. See ArrangementStorage for a more generic class which allows
+// duplication and rearragement but is less performant.
+class SelectorStorage : public Storage {
+ public:
+ SelectorStorage(std::unique_ptr<Storage> storage, const BitVector* non_null);
+
+ Storage::SearchValidationResult ValidateSearchConstraints(SqlValue, FilterOp)
+ const override;
+
+ RangeOrBitVector Search(FilterOp op,
+ SqlValue value,
+ RowMap::Range range) const override;
+
+ RangeOrBitVector IndexSearch(FilterOp op,
+ SqlValue value,
+ uint32_t* indices,
+ uint32_t indices_count,
+ bool sorted) const override;
+
+ void StableSort(uint32_t* rows, uint32_t rows_size) const override;
+
+ void Sort(uint32_t* rows, uint32_t rows_size) const override;
+
+ void Serialize(StorageProto*) const override;
+
+ uint32_t size() const override { return selector_->size(); }
+
+ private:
+ std::unique_ptr<Storage> inner_ = nullptr;
+ const BitVector* selector_ = nullptr;
+};
+
+} // namespace storage
+} // namespace trace_processor
+} // namespace perfetto
+
+#endif // SRC_TRACE_PROCESSOR_DB_STORAGE_SELECTOR_STORAGE_H_
diff --git a/src/trace_processor/db/storage/selector_storage_unittest.cc b/src/trace_processor/db/storage/selector_storage_unittest.cc
new file mode 100644
index 0000000..04c3de2
--- /dev/null
+++ b/src/trace_processor/db/storage/selector_storage_unittest.cc
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "src/trace_processor/db/storage/selector_storage.h"
+
+#include "src/trace_processor/db/storage/fake_storage.h"
+#include "test/gtest_and_gmock.h"
+
+namespace perfetto {
+namespace trace_processor {
+namespace storage {
+namespace {
+
+using testing::ElementsAre;
+using testing::IsEmpty;
+
+using Range = RowMap::Range;
+
+std::vector<uint32_t> ToIndexVector(RangeOrBitVector& r_or_bv) {
+ RowMap rm;
+ if (r_or_bv.IsBitVector()) {
+ rm = RowMap(std::move(r_or_bv).TakeIfBitVector());
+ } else {
+ Range range = std::move(r_or_bv).TakeIfRange();
+ rm = RowMap(range.start, range.end);
+ }
+ return rm.GetAllIndices();
+}
+
+TEST(SelectorStorage, SearchAll) {
+ BitVector selector{0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1};
+ SelectorStorage storage(FakeStorage::SearchAll(10), &selector);
+
+ auto res =
+ storage.Search(FilterOp::kGe, SqlValue::Long(0u), RowMap::Range(1, 4));
+ ASSERT_THAT(ToIndexVector(res), ElementsAre(1u, 2u, 3u));
+}
+
+TEST(SelectorStorage, SearchNone) {
+ BitVector selector{0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1};
+ SelectorStorage storage(FakeStorage::SearchNone(10), &selector);
+
+ auto res =
+ storage.Search(FilterOp::kGe, SqlValue::Long(0u), RowMap::Range(1, 4));
+ ASSERT_THAT(ToIndexVector(res), IsEmpty());
+}
+
+TEST(SelectorStorage, SearchLimited) {
+ BitVector selector{0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1};
+ SelectorStorage storage(FakeStorage::SearchSubset(10, Range(4, 5)),
+ &selector);
+
+ auto res =
+ storage.Search(FilterOp::kGe, SqlValue::Long(0u), RowMap::Range(1, 5));
+ ASSERT_THAT(ToIndexVector(res), ElementsAre(2u));
+}
+
+TEST(SelectorStorage, SearchBitVector) {
+ BitVector selector{0, 1, 1, 0, 0, 1, 1, 0};
+ SelectorStorage storage(
+ FakeStorage::SearchSubset(8, BitVector({0, 1, 0, 1, 0, 1, 0, 0})),
+ &selector);
+
+ auto res = storage.Search(FilterOp::kGe, SqlValue::Long(0u), Range(0, 4));
+ ASSERT_THAT(ToIndexVector(res), ElementsAre(0, 2));
+}
+
+TEST(SelectorStorage, IndexSearch) {
+ BitVector selector{0, 1, 1, 0, 0, 1, 1, 0};
+ SelectorStorage storage(
+ FakeStorage::SearchSubset(8, BitVector({0, 1, 0, 1, 0, 1, 0, 0})),
+ &selector);
+
+ std::vector<uint32_t> table_idx{1u, 0u, 3u};
+ RangeOrBitVector res =
+ storage.IndexSearch(FilterOp::kGe, SqlValue::Long(0u), table_idx.data(),
+ static_cast<uint32_t>(table_idx.size()), false);
+ ASSERT_THAT(ToIndexVector(res), ElementsAre(1u));
+}
+
+} // namespace
+} // namespace storage
+} // namespace trace_processor
+} // namespace perfetto
diff --git a/src/trace_processor/db/storage/set_id_storage.cc b/src/trace_processor/db/storage/set_id_storage.cc
index 76c7982..570afb7 100644
--- a/src/trace_processor/db/storage/set_id_storage.cc
+++ b/src/trace_processor/db/storage/set_id_storage.cc
@@ -58,73 +58,139 @@
} // namespace
+SetIdStorage::SearchValidationResult SetIdStorage::ValidateSearchConstraints(
+ SqlValue val,
+ FilterOp op) const {
+ // NULL checks.
+ if (PERFETTO_UNLIKELY(val.is_null())) {
+ if (op == FilterOp::kIsNotNull) {
+ return SearchValidationResult::kAllData;
+ }
+ if (op == FilterOp::kIsNull) {
+ return SearchValidationResult::kNoData;
+ }
+ PERFETTO_FATAL(
+ "Invalid filter operation. NULL should only be compared with 'IS NULL' "
+ "and 'IS NOT NULL'");
+ }
+
+ // FilterOp checks. Switch so that we get a warning if new FilterOp is not
+ // handled.
+ switch (op) {
+ case FilterOp::kEq:
+ case FilterOp::kNe:
+ case FilterOp::kLt:
+ case FilterOp::kLe:
+ case FilterOp::kGt:
+ case FilterOp::kGe:
+ break;
+ case FilterOp::kIsNull:
+ case FilterOp::kIsNotNull:
+ PERFETTO_FATAL("Invalid constraints.");
+ case FilterOp::kGlob:
+ case FilterOp::kRegex:
+ return SearchValidationResult::kNoData;
+ }
+
+ // Type checks.
+ switch (val.type) {
+ case SqlValue::kNull:
+ case SqlValue::kLong:
+ case SqlValue::kDouble:
+ break;
+ case SqlValue::kString:
+ // Any string is always more than any numeric.
+ if (op == FilterOp::kLt || op == FilterOp::kLe) {
+ return Storage::SearchValidationResult::kAllData;
+ }
+ return Storage::SearchValidationResult::kNoData;
+ case SqlValue::kBytes:
+ return Storage::SearchValidationResult::kNoData;
+ }
+
+ // TODO(b/307482437): Remove after adding support for double
+ PERFETTO_CHECK(val.type != SqlValue::kDouble);
+
+ // Bounds of the value.
+ if (PERFETTO_UNLIKELY(val.AsLong() > std::numeric_limits<uint32_t>::max())) {
+ if (op == FilterOp::kLe || op == FilterOp::kLt || op == FilterOp::kNe) {
+ return SearchValidationResult::kAllData;
+ }
+ return SearchValidationResult::kNoData;
+ }
+ if (PERFETTO_UNLIKELY(val.AsLong() < std::numeric_limits<uint32_t>::min())) {
+ if (op == FilterOp::kGe || op == FilterOp::kGt || op == FilterOp::kNe) {
+ return SearchValidationResult::kAllData;
+ }
+ return SearchValidationResult::kNoData;
+ }
+
+ return SearchValidationResult::kOk;
+}
+
RangeOrBitVector SetIdStorage::Search(FilterOp op,
SqlValue sql_val,
- RowMap::Range range) const {
+ RowMap::Range search_range) const {
PERFETTO_TP_TRACE(metatrace::Category::DB, "SetIdStorage::Search",
- [&range, op](metatrace::Record* r) {
- r->AddArg("Start", std::to_string(range.start));
- r->AddArg("End", std::to_string(range.end));
+ [&search_range, op](metatrace::Record* r) {
+ r->AddArg("Start", std::to_string(search_range.start));
+ r->AddArg("End", std::to_string(search_range.end));
r->AddArg("Op",
std::to_string(static_cast<uint32_t>(op)));
});
- PERFETTO_DCHECK(range.end <= size());
+ // After this switch we assume the search is valid.
+ switch (ValidateSearchConstraints(sql_val, op)) {
+ case SearchValidationResult::kOk:
+ break;
+ case SearchValidationResult::kAllData:
+ return RangeOrBitVector(Range(0, search_range.end));
+ case SearchValidationResult::kNoData:
+ return RangeOrBitVector(Range());
+ }
+
+ PERFETTO_DCHECK(search_range.end <= size());
+ uint32_t val = static_cast<uint32_t>(sql_val.AsLong());
if (op == FilterOp::kNe) {
- if (sql_val.is_null()) {
- return RangeOrBitVector(Range());
- }
// Not equal is a special operation on binary search, as it doesn't define a
// range, and rather just `not` range returned with `equal` operation.
RowMap::Range eq_range =
- BinarySearchIntrinsic(FilterOp::kEq, sql_val, range);
- BitVector bv(eq_range.start, true);
- bv.Resize(eq_range.end);
- bv.Resize(std::min(range.end - 1, eq_range.end), true);
+ BinarySearchIntrinsic(FilterOp::kEq, val, search_range);
+ BitVector bv(search_range.start, false);
+ bv.Resize(eq_range.start, true);
+ bv.Resize(eq_range.end, false);
+ bv.Resize(search_range.end, true);
return RangeOrBitVector(std::move(bv));
}
- return RangeOrBitVector(BinarySearchIntrinsic(op, sql_val, range));
+ return RangeOrBitVector(BinarySearchIntrinsic(op, val, search_range));
}
RangeOrBitVector SetIdStorage::IndexSearch(FilterOp op,
SqlValue sql_val,
uint32_t* indices,
- uint32_t indices_count,
+ uint32_t indices_size,
bool) const {
PERFETTO_TP_TRACE(metatrace::Category::DB, "SetIdStorage::IndexSearch",
- [indices_count, op](metatrace::Record* r) {
- r->AddArg("Count", std::to_string(indices_count));
+ [indices_size, op](metatrace::Record* r) {
+ r->AddArg("Count", std::to_string(indices_size));
r->AddArg("Op",
std::to_string(static_cast<uint32_t>(op)));
});
- // Validate sql_val
- if (PERFETTO_UNLIKELY(sql_val.is_null())) {
- if (op == FilterOp::kIsNotNull) {
- return RangeOrBitVector(Range(indices_count, true));
- }
- return RangeOrBitVector(Range());
+ // After this switch we assume the search is valid.
+ switch (ValidateSearchConstraints(sql_val, op)) {
+ case SearchValidationResult::kOk:
+ break;
+ case SearchValidationResult::kAllData:
+ return RangeOrBitVector(Range(0, indices_size));
+ case SearchValidationResult::kNoData:
+ return RangeOrBitVector(Range());
}
- if (PERFETTO_UNLIKELY(sql_val.AsLong() >
- std::numeric_limits<uint32_t>::max())) {
- if (op == FilterOp::kLe || op == FilterOp::kLt) {
- return RangeOrBitVector(Range(indices_count, true));
- }
- return RangeOrBitVector(Range());
- }
-
- if (PERFETTO_UNLIKELY(sql_val.AsLong() <
- std::numeric_limits<uint32_t>::min())) {
- if (op == FilterOp::kGe || op == FilterOp::kGt) {
- return RangeOrBitVector(Range(indices_count, true));
- }
- return RangeOrBitVector(Range());
- }
uint32_t val = static_cast<uint32_t>(sql_val.AsLong());
- BitVector::Builder builder(indices_count);
+ BitVector::Builder builder(indices_size);
// TODO(mayzner): Instead of utils::IndexSearchWithComparator, use the
// property of SetId data - that for each index i, data[i] <= i.
@@ -154,7 +220,7 @@
std::greater_equal<uint32_t>(), builder);
break;
case FilterOp::kIsNotNull:
- return RangeOrBitVector(Range(0, indices_count));
+ return RangeOrBitVector(Range(0, indices_size));
case FilterOp::kIsNull:
return RangeOrBitVector(Range());
case FilterOp::kGlob:
@@ -165,34 +231,8 @@
}
Range SetIdStorage::BinarySearchIntrinsic(FilterOp op,
- SqlValue sql_val,
+ SetId val,
Range range) const {
- // Validate sql_value
- if (PERFETTO_UNLIKELY(sql_val.is_null())) {
- if (op == FilterOp::kIsNotNull) {
- return range;
- }
- return Range();
- }
-
- if (PERFETTO_UNLIKELY(sql_val.AsLong() >
- std::numeric_limits<uint32_t>::max())) {
- if (op == FilterOp::kLe || op == FilterOp::kLt) {
- return range;
- }
- return Range();
- }
-
- if (PERFETTO_UNLIKELY(sql_val.AsLong() <
- std::numeric_limits<uint32_t>::min())) {
- if (op == FilterOp::kGe || op == FilterOp::kGt) {
- return range;
- }
- return Range();
- }
-
- uint32_t val = static_cast<uint32_t>(sql_val.AsLong());
-
switch (op) {
case FilterOp::kEq:
return Range(LowerBoundIntrinsic(values_->data(), val, range),
diff --git a/src/trace_processor/db/storage/set_id_storage.h b/src/trace_processor/db/storage/set_id_storage.h
index ad9fd1a..6886bef 100644
--- a/src/trace_processor/db/storage/set_id_storage.h
+++ b/src/trace_processor/db/storage/set_id_storage.h
@@ -36,6 +36,9 @@
explicit SetIdStorage(const std::vector<uint32_t>* data) : values_(data) {}
+ SearchValidationResult ValidateSearchConstraints(SqlValue,
+ FilterOp) const override;
+
RangeOrBitVector Search(FilterOp op,
SqlValue value,
RowMap::Range range) const override;
@@ -57,9 +60,9 @@
}
private:
- BitVector IndexSearch(FilterOp, SqlValue, uint32_t*, uint32_t) const;
- RowMap::Range BinarySearchIntrinsic(FilterOp op,
- SqlValue val,
+ BitVector IndexSearch(FilterOp, SetId, uint32_t*, uint32_t) const;
+ RowMap::Range BinarySearchIntrinsic(FilterOp,
+ SetId,
RowMap::Range search_range) const;
// TODO(b/307482437): After the migration vectors should be owned by storage,
diff --git a/src/trace_processor/db/storage/set_id_storage_unittest.cc b/src/trace_processor/db/storage/set_id_storage_unittest.cc
index f487dfa..658b731 100644
--- a/src/trace_processor/db/storage/set_id_storage_unittest.cc
+++ b/src/trace_processor/db/storage/set_id_storage_unittest.cc
@@ -19,11 +19,96 @@
namespace perfetto {
namespace trace_processor {
+
+inline bool operator==(const RowMap::Range& a, const RowMap::Range& b) {
+ return std::tie(a.start, a.end) == std::tie(b.start, b.end);
+}
+
namespace storage {
namespace {
using Range = RowMap::Range;
+TEST(IdStorageUnittest, InvalidSearchConstraints) {
+ std::vector<uint32_t> storage_data{0, 0, 0, 3, 3, 3, 6, 6, 6, 9, 9, 9};
+ SetIdStorage storage(&storage_data);
+
+ Range test_range(3, 9);
+ Range full_range(0, 9);
+ Range empty_range;
+
+ // NULL checks
+ SqlValue val;
+ val.type = SqlValue::kNull;
+ Range search_result =
+ storage.Search(FilterOp::kIsNull, val, test_range).TakeIfRange();
+ ASSERT_EQ(search_result, empty_range);
+ search_result =
+ storage.Search(FilterOp::kIsNotNull, val, test_range).TakeIfRange();
+ ASSERT_EQ(search_result, full_range);
+
+ // FilterOp checks
+ search_result =
+ storage.Search(FilterOp::kGlob, SqlValue::Long(15), test_range)
+ .TakeIfRange();
+ ASSERT_EQ(search_result, empty_range);
+ search_result =
+ storage.Search(FilterOp::kRegex, SqlValue::Long(15), test_range)
+ .TakeIfRange();
+ ASSERT_EQ(search_result, empty_range);
+
+ // Type checks
+ search_result =
+ storage.Search(FilterOp::kGe, SqlValue::String("cheese"), test_range)
+ .TakeIfRange();
+ ASSERT_EQ(search_result, empty_range);
+
+ // Value bounds
+ SqlValue max_val = SqlValue::Long(
+ static_cast<int64_t>(std::numeric_limits<uint32_t>::max()) + 10);
+ search_result =
+ storage.Search(FilterOp::kGe, max_val, test_range).TakeIfRange();
+ ASSERT_EQ(search_result, empty_range);
+ search_result =
+ storage.Search(FilterOp::kGt, max_val, test_range).TakeIfRange();
+ ASSERT_EQ(search_result, empty_range);
+ search_result =
+ storage.Search(FilterOp::kEq, max_val, test_range).TakeIfRange();
+ ASSERT_EQ(search_result, empty_range);
+
+ search_result =
+ storage.Search(FilterOp::kLe, max_val, test_range).TakeIfRange();
+ ASSERT_EQ(search_result, full_range);
+ search_result =
+ storage.Search(FilterOp::kLt, max_val, test_range).TakeIfRange();
+ ASSERT_EQ(search_result, full_range);
+ search_result =
+ storage.Search(FilterOp::kNe, max_val, test_range).TakeIfRange();
+ ASSERT_EQ(search_result, full_range);
+
+ SqlValue min_val = SqlValue::Long(
+ static_cast<int64_t>(std::numeric_limits<uint32_t>::min()) - 1);
+ search_result =
+ storage.Search(FilterOp::kGe, min_val, test_range).TakeIfRange();
+ ASSERT_EQ(search_result, full_range);
+ search_result =
+ storage.Search(FilterOp::kGt, min_val, test_range).TakeIfRange();
+ ASSERT_EQ(search_result, full_range);
+ search_result =
+ storage.Search(FilterOp::kNe, min_val, test_range).TakeIfRange();
+ ASSERT_EQ(search_result, full_range);
+
+ search_result =
+ storage.Search(FilterOp::kLe, min_val, test_range).TakeIfRange();
+ ASSERT_EQ(search_result, empty_range);
+ search_result =
+ storage.Search(FilterOp::kLt, min_val, test_range).TakeIfRange();
+ ASSERT_EQ(search_result, empty_range);
+ search_result =
+ storage.Search(FilterOp::kEq, min_val, test_range).TakeIfRange();
+ ASSERT_EQ(search_result, empty_range);
+}
+
TEST(SetIdStorageUnittest, SearchEqSimple) {
std::vector<uint32_t> storage_data{0, 0, 0, 3, 3, 3, 6, 6, 6, 9, 9, 9};
diff --git a/src/trace_processor/db/storage/storage.h b/src/trace_processor/db/storage/storage.h
index 025e077..2a9c9fb 100644
--- a/src/trace_processor/db/storage/storage.h
+++ b/src/trace_processor/db/storage/storage.h
@@ -16,13 +16,11 @@
#ifndef SRC_TRACE_PROCESSOR_DB_STORAGE_STORAGE_H_
#define SRC_TRACE_PROCESSOR_DB_STORAGE_STORAGE_H_
-#include "perfetto/trace_processor/basic_types.h"
#include "src/trace_processor/containers/bit_vector.h"
#include "src/trace_processor/containers/row_map.h"
#include "src/trace_processor/db/storage/types.h"
namespace perfetto {
-
namespace protos::pbzero {
class SerializedColumn_Storage;
}
@@ -35,23 +33,60 @@
public:
using StorageProto = protos::pbzero::SerializedColumn_Storage;
+ enum class SearchValidationResult { kOk = 0, kAllData = 1, kNoData = 2 };
+
virtual ~Storage();
+ // Verifies whether any further filtering is needed and if not, whether the
+ // search would return all values or none of them. This allows for skipping
+ // the |Search| and |IndexSearch| in special cases.
+ //
+ // Notes for callers:
+ // * This function is being called by Search and IndexSearch and there is no
+ // need to call it before searches.
+ // * The SqlValue and FilterOp have to be valid in Sqlite: it will crash if
+ // either: value is NULL and operation is different than "IS NULL" and "IS
+ // NOT NULL" or the operation is "IS NULL" and "IS NOT NULL" and value is
+ // different than NULL.
+ virtual SearchValidationResult ValidateSearchConstraints(SqlValue,
+ FilterOp) const = 0;
+
// Searches for elements which match |op| and |value| between |range.start|
// and |range.end|.
- virtual RangeOrBitVector Search(FilterOp op,
- SqlValue value,
- RowMap::Range range) const = 0;
+ //
+ // Returns either a range or BitVector which indicate the positions in |range|
+ // which match the constraint. If a BitVector is returned, it will be
+ // *precisely* as large as |range.end|.
+ //
+ // Notes for implementors:
+ // * Implementations should ensure that the return value *only* includes
+ // positions in |range| as callers will expect this to be true and can
+ // optimize based on this.
+ // * Implementations should ensure that, if they return a BitVector, it is
+ // precisely of size |range.end|.
+ virtual RangeOrBitVector Search(FilterOp, SqlValue, RowMap::Range) const = 0;
// Searches for elements which match |op| and |value| at the positions given
- // by |indices| array.
- // If the order defined by |indices| makes storage sorted, |sorted| flag
- // should be set to true.
- virtual RangeOrBitVector IndexSearch(FilterOp op,
- SqlValue value,
+ // by |indices| array. The |sorted| flag allows the caller to specify if the
+ // order defined by |indices| makes storage sorted; implementations can use
+ // this to optimize how they search the storage.
+ //
+ // Returns either a range of BitVector which indicate the positions in
+ // |indices| which match the constraint. If a BitVector is returned, it will
+ // be *precisely* as large as |indices_count|.
+ //
+ // Notes for callers:
+ // * Callers should note that the return value of this function corresponds
+ // to positions in |indices| *not* positions in the storage.
+ //
+ // Notes for implementors:
+ // * Implementations should ensure that, if they return a BitVector, it is
+ // precisely of size |indices_count|.
+ virtual RangeOrBitVector IndexSearch(FilterOp,
+ SqlValue,
uint32_t* indices,
uint32_t indices_count,
- bool sorted = false) const = 0;
+ bool sorted) const = 0;
// Sorts |rows| in ascending order with the comparator:
// data[rows[a]] < data[rows[b]].
diff --git a/src/trace_processor/db/storage/string_storage.cc b/src/trace_processor/db/storage/string_storage.cc
index 0ba5f00..d9c9b98 100644
--- a/src/trace_processor/db/storage/string_storage.cc
+++ b/src/trace_processor/db/storage/string_storage.cc
@@ -19,7 +19,6 @@
#include "perfetto/ext/base/scoped_file.h"
#include "perfetto/ext/base/status_or.h"
#include "perfetto/ext/base/string_utils.h"
-#include "perfetto/trace_processor/basic_types.h"
#include "protos/perfetto/trace_processor/serialization.pbzero.h"
#include "perfetto/base/logging.h"
@@ -27,6 +26,7 @@
#include "src/trace_processor/containers/null_term_string_view.h"
#include "src/trace_processor/containers/row_map.h"
#include "src/trace_processor/containers/string_pool.h"
+#include "src/trace_processor/db/storage/storage.h"
#include "src/trace_processor/db/storage/types.h"
#include "src/trace_processor/db/storage/utils.h"
@@ -163,63 +163,105 @@
} // namespace
+StringStorage::SearchValidationResult StringStorage::ValidateSearchConstraints(
+ SqlValue val,
+ FilterOp op) const {
+ // Type checks.
+ switch (val.type) {
+ case SqlValue::kNull:
+ case SqlValue::kString:
+ break;
+ case SqlValue::kLong:
+ case SqlValue::kDouble:
+ // Any string is always more than any numeric.
+ if (op == FilterOp::kGt || op == FilterOp::kGe) {
+ return Storage::SearchValidationResult::kAllData;
+ }
+ return Storage::SearchValidationResult::kNoData;
+ case SqlValue::kBytes:
+ return Storage::SearchValidationResult::kNoData;
+ }
+
+ return SearchValidationResult::kOk;
+}
+
RangeOrBitVector StringStorage::Search(FilterOp op,
- SqlValue value,
- RowMap::Range range) const {
- PERFETTO_TP_TRACE(metatrace::Category::DB, "StringStorage::LinearSearch",
- [&range, op](metatrace::Record* r) {
- r->AddArg("Start", std::to_string(range.start));
- r->AddArg("End", std::to_string(range.end));
+ SqlValue sql_val,
+ Range search_range) const {
+ PERFETTO_TP_TRACE(metatrace::Category::DB, "StringStorage::Search",
+ [&search_range, op](metatrace::Record* r) {
+ r->AddArg("Start", std::to_string(search_range.start));
+ r->AddArg("End", std::to_string(search_range.end));
r->AddArg("Op",
std::to_string(static_cast<uint32_t>(op)));
});
+ // After this switch we assume the search is valid.
+ switch (ValidateSearchConstraints(sql_val, op)) {
+ case SearchValidationResult::kOk:
+ break;
+ case SearchValidationResult::kAllData:
+ return RangeOrBitVector(Range(0, search_range.end));
+ case SearchValidationResult::kNoData:
+ return RangeOrBitVector(Range());
+ }
+
if (is_sorted_) {
if (op != FilterOp::kNe) {
- return RangeOrBitVector(BinarySearchIntrinsic(op, value, range));
+ return RangeOrBitVector(BinarySearchIntrinsic(op, sql_val, search_range));
}
// Not equal is a special operation on binary search, as it doesn't define
// a range, and rather just `not` range returned with `equal` operation.
- RowMap::Range r = BinarySearchIntrinsic(FilterOp::kEq, value, range);
+ Range r = BinarySearchIntrinsic(FilterOp::kEq, sql_val, search_range);
BitVector bv(r.start, true);
bv.Resize(r.end);
- bv.Resize(range.end, true);
+ bv.Resize(search_range.end, true);
return RangeOrBitVector(std::move(bv));
}
- return RangeOrBitVector(LinearSearchInternal(op, value, range));
+ return RangeOrBitVector(LinearSearch(op, sql_val, search_range));
}
RangeOrBitVector StringStorage::IndexSearch(FilterOp op,
- SqlValue value,
+ SqlValue sql_val,
uint32_t* indices,
- uint32_t indices_count,
- bool sorted) const {
+ uint32_t indices_size,
+ bool indices_sorted) const {
PERFETTO_TP_TRACE(metatrace::Category::DB, "StringStorage::IndexSearch",
- [indices_count, op](metatrace::Record* r) {
- r->AddArg("Count", std::to_string(indices_count));
+ [indices_size, op](metatrace::Record* r) {
+ r->AddArg("Count", std::to_string(indices_size));
r->AddArg("Op",
std::to_string(static_cast<uint32_t>(op)));
});
- if (sorted) {
+ // After this switch we assume the search is valid.
+ switch (ValidateSearchConstraints(sql_val, op)) {
+ case SearchValidationResult::kOk:
+ break;
+ case SearchValidationResult::kAllData:
+ return RangeOrBitVector(Range(0, indices_size));
+ case SearchValidationResult::kNoData:
+ return RangeOrBitVector(Range());
+ }
+
+ if (indices_sorted) {
return RangeOrBitVector(
- BinarySearchExtrinsic(op, value, indices, indices_count));
+ BinarySearchExtrinsic(op, sql_val, indices, indices_size));
}
return RangeOrBitVector(
- IndexSearchInternal(op, value, indices, indices_count, sorted));
+ IndexSearchInternal(op, sql_val, indices, indices_size));
}
-BitVector StringStorage::LinearSearchInternal(FilterOp op,
- SqlValue sql_val,
- RowMap::Range range) const {
+BitVector StringStorage::LinearSearch(FilterOp op,
+ SqlValue sql_val,
+ RowMap::Range range) const {
if (sql_val.is_null() &&
(op != FilterOp::kIsNotNull && op != FilterOp::kIsNull)) {
- return BitVector();
+ return BitVector(range.end, false);
}
if (sql_val.type != SqlValue::kString &&
(op == FilterOp::kGlob || op == FilterOp::kRegex)) {
- return BitVector();
+ return BitVector(range.end, false);
}
StringPool::Id val =
@@ -227,16 +269,6 @@
? StringPool::Id::Null()
: string_pool_->InternString(base::StringView(sql_val.AsString()));
const StringPool::Id* start = values_->data() + range.start;
- PERFETTO_TP_TRACE(
- metatrace::Category::DB, "StringStorage::Search",
- [range, op, &sql_val](metatrace::Record* r) {
- r->AddArg("Start", std::to_string(range.start));
- r->AddArg("End", std::to_string(range.end));
- r->AddArg("Op", std::to_string(static_cast<uint32_t>(op)));
- r->AddArg("String", sql_val.type == SqlValue::Type::kString
- ? sql_val.AsString()
- : "NULL");
- });
BitVector::Builder builder(range.end, range.start);
switch (op) {
@@ -318,11 +350,11 @@
return std::move(builder).Build();
}
-RangeOrBitVector StringStorage::IndexSearchInternal(FilterOp op,
- SqlValue sql_val,
- uint32_t* indices,
- uint32_t indices_size,
- bool) const {
+RangeOrBitVector StringStorage::IndexSearchInternal(
+ FilterOp op,
+ SqlValue sql_val,
+ uint32_t* indices,
+ uint32_t indices_size) const {
if (sql_val.is_null() &&
(op != FilterOp::kIsNotNull && op != FilterOp::kIsNull)) {
return RangeOrBitVector(Range());
diff --git a/src/trace_processor/db/storage/string_storage.h b/src/trace_processor/db/storage/string_storage.h
index 9f14917..1e89f24 100644
--- a/src/trace_processor/db/storage/string_storage.h
+++ b/src/trace_processor/db/storage/string_storage.h
@@ -16,6 +16,7 @@
#ifndef SRC_TRACE_PROCESSOR_DB_STORAGE_STRING_STORAGE_H_
#define SRC_TRACE_PROCESSOR_DB_STORAGE_STRING_STORAGE_H_
+#include "perfetto/trace_processor/basic_types.h"
#include "src/trace_processor/containers/row_map.h"
#include "src/trace_processor/containers/string_pool.h"
#include "src/trace_processor/db/storage/storage.h"
@@ -38,6 +39,9 @@
bool is_sorted = false)
: values_(data), string_pool_(string_pool), is_sorted_(is_sorted) {}
+ SearchValidationResult ValidateSearchConstraints(SqlValue,
+ FilterOp) const override;
+
RangeOrBitVector Search(FilterOp op,
SqlValue value,
RowMap::Range range) const override;
@@ -58,13 +62,12 @@
}
private:
- BitVector LinearSearchInternal(FilterOp, SqlValue, RowMap::Range) const;
+ BitVector LinearSearch(FilterOp, SqlValue, RowMap::Range) const;
RangeOrBitVector IndexSearchInternal(FilterOp op,
SqlValue sql_val,
uint32_t* indices,
- uint32_t indices_size,
- bool) const;
+ uint32_t indices_size) const;
RowMap::Range BinarySearchExtrinsic(FilterOp,
SqlValue,
diff --git a/src/trace_processor/db/storage/types.h b/src/trace_processor/db/storage/types.h
index ff3fc57..6884988 100644
--- a/src/trace_processor/db/storage/types.h
+++ b/src/trace_processor/db/storage/types.h
@@ -26,7 +26,8 @@
// Used for result of filtering, which is sometimes (for more optimised
// operations) a Range and BitVector otherwise. Stores a variant of Range and
// BitVector.
-struct RangeOrBitVector {
+class RangeOrBitVector {
+ public:
using Range = RowMap::Range;
explicit RangeOrBitVector(Range range) : val(range) {}
explicit RangeOrBitVector(BitVector bv) : val(std::move(bv)) {}
@@ -43,6 +44,7 @@
return std::move(*std::get_if<Range>(&val));
}
+ private:
std::variant<RowMap::Range, BitVector> val = Range();
};
diff --git a/src/trace_processor/importers/ftrace/ftrace_descriptors.cc b/src/trace_processor/importers/ftrace/ftrace_descriptors.cc
index 557512c..225f951 100644
--- a/src/trace_processor/importers/ftrace/ftrace_descriptors.cc
+++ b/src/trace_processor/importers/ftrace/ftrace_descriptors.cc
@@ -24,7 +24,7 @@
namespace trace_processor {
namespace {
-std::array<FtraceMessageDescriptor, 487> descriptors{{
+std::array<FtraceMessageDescriptor, 488> descriptors{{
{nullptr, 0, {}},
{nullptr, 0, {}},
{nullptr, 0, {}},
@@ -5351,6 +5351,30 @@
{"cmd", ProtoSchemaType::kUint32},
},
},
+ {
+ "sched_switch_with_ctrs",
+ 17,
+ {
+ {},
+ {"old_pid", ProtoSchemaType::kInt32},
+ {"new_pid", ProtoSchemaType::kInt32},
+ {"cctr", ProtoSchemaType::kUint32},
+ {"ctr0", ProtoSchemaType::kUint32},
+ {"ctr1", ProtoSchemaType::kUint32},
+ {"ctr2", ProtoSchemaType::kUint32},
+ {"ctr3", ProtoSchemaType::kUint32},
+ {"lctr0", ProtoSchemaType::kUint32},
+ {"lctr1", ProtoSchemaType::kUint32},
+ {"ctr4", ProtoSchemaType::kUint32},
+ {"ctr5", ProtoSchemaType::kUint32},
+ {"prev_comm", ProtoSchemaType::kString},
+ {"prev_pid", ProtoSchemaType::kInt32},
+ {"cyc", ProtoSchemaType::kUint32},
+ {"inst", ProtoSchemaType::kUint32},
+ {"stallbm", ProtoSchemaType::kUint32},
+ {"l3dm", ProtoSchemaType::kUint32},
+ },
+ },
}};
} // namespace
diff --git a/src/trace_processor/importers/json/json_trace_parser.cc b/src/trace_processor/importers/json/json_trace_parser.cc
index 4b4330b..70b8e81 100644
--- a/src/trace_processor/importers/json/json_trace_parser.cc
+++ b/src/trace_processor/importers/json/json_trace_parser.cc
@@ -109,8 +109,7 @@
base::StringView name = value.isMember("name")
? base::StringView(value["name"].asCString())
: base::StringView();
- StringId name_id = name.empty() ? storage->InternString("[No name]")
- : storage->InternString(name);
+ StringId name_id = name.empty() ? kNullStringId : storage->InternString(name);
auto args_inserter = [this, &value](ArgsTracker::BoundInserter* inserter) {
if (value.isMember("args")) {
@@ -128,7 +127,8 @@
row.ts = timestamp;
row.track_id = track_id;
row.category = cat_id;
- row.name = name_id;
+ row.name =
+ name_id == kNullStringId ? storage->InternString("[No name]") : name_id;
row.thread_ts = json::CoerceToTs(value["tts"]);
// tdur will only exist on 'X' events.
row.thread_dur = json::CoerceToTs(value["tdur"]);
@@ -166,15 +166,31 @@
case 'b':
case 'e':
case 'n': {
- if (!opt_pid || id.empty()) {
+ Json::Value id2 = value.isMember("id2") ? value["id2"] : Json::Value();
+ std::string local = id2.isMember("local") ? id2["local"].asString() : "";
+ std::string global =
+ id2.isMember("global") ? id2["global"].asString() : "";
+ if (!opt_pid || (id.empty() && global.empty() && local.empty())) {
context_->storage->IncrementStats(stats::json_parser_failure);
break;
}
UniquePid upid = context_->process_tracker->GetOrCreateProcess(pid);
- int64_t cookie = static_cast<int64_t>(base::Hasher::Combine(id.c_str()));
- StringId scope = kNullStringId;
- TrackId track_id = context_->track_tracker->InternLegacyChromeAsyncTrack(
- name_id, upid, cookie, true /* source_id_is_process_scoped */, scope);
+ TrackId track_id;
+ if (!id.empty() || !global.empty()) {
+ const std::string& real_id = id.empty() ? global : id;
+ int64_t cookie = static_cast<int64_t>(
+ base::Hasher::Combine(cat_id.raw_id(), real_id));
+ track_id = context_->track_tracker->InternLegacyChromeAsyncTrack(
+ name_id, upid, cookie, false /* source_id_is_process_scoped */,
+ kNullStringId /* source_scope */);
+ } else {
+ PERFETTO_DCHECK(!local.empty());
+ int64_t cookie =
+ static_cast<int64_t>(base::Hasher::Combine(cat_id.raw_id(), local));
+ track_id = context_->track_tracker->InternLegacyChromeAsyncTrack(
+ name_id, upid, cookie, true /* source_id_is_process_scoped */,
+ kNullStringId /* source_scope */);
+ }
if (phase == 'b') {
slice_tracker->BeginTyped(storage->mutable_slice_table(),
diff --git a/src/trace_processor/importers/proto/atoms.descriptor b/src/trace_processor/importers/proto/atoms.descriptor
index 2d4c191..923f583 100644
--- a/src/trace_processor/importers/proto/atoms.descriptor
+++ b/src/trace_processor/importers/proto/atoms.descriptor
Binary files differ
diff --git a/src/trace_processor/importers/proto/frame_timeline_event_parser.cc b/src/trace_processor/importers/proto/frame_timeline_event_parser.cc
index 04e10bd..c631a3d 100644
--- a/src/trace_processor/importers/proto/frame_timeline_event_parser.cc
+++ b/src/trace_processor/importers/proto/frame_timeline_event_parser.cc
@@ -163,6 +163,10 @@
"Expired Prediction") /* PREDICTION_EXPIRED */,
context->storage->InternString(
"Unknown Prediction") /* PREDICTION_UNKNOWN */}},
+ jank_severity_type_ids_{{context->storage->InternString("Unknown"),
+ context->storage->InternString("None"),
+ context->storage->InternString("Partial"),
+ context->storage->InternString("Full")}},
expected_timeline_track_name_(
context->storage->InternString("Expected Timeline")),
actual_timeline_track_name_(
@@ -175,6 +179,8 @@
on_time_finish_id_(context->storage->InternString("On time finish")),
gpu_composition_id_(context->storage->InternString("GPU composition")),
jank_type_id_(context->storage->InternString("Jank type")),
+ jank_severity_type_id_(
+ context->storage->InternString("Jank severity type")),
layer_name_id_(context->storage->InternString("Layer name")),
prediction_type_id_(context->storage->InternString("Prediction type")),
is_buffer_id_(context->storage->InternString("Is Buffer?")),
@@ -277,16 +283,36 @@
actual_row.name = name_id;
actual_row.display_frame_token = token;
actual_row.upid = upid;
+ actual_row.on_time_finish = event.on_time_finish();
+ actual_row.gpu_composition = event.gpu_composition();
+
+ // parse present type
StringId present_type = present_type_ids_[0];
if (event.has_present_type() &&
ValidatePresentType(context_, event.present_type())) {
present_type = present_type_ids_[static_cast<size_t>(event.present_type())];
}
actual_row.present_type = present_type;
- actual_row.on_time_finish = event.on_time_finish();
- actual_row.gpu_composition = event.gpu_composition();
+
+ // parse jank type
StringId jank_type = JankTypeBitmaskToStringId(context_, event.jank_type());
actual_row.jank_type = jank_type;
+
+ // parse jank severity type
+ if (event.has_jank_severity_type()) {
+ actual_row.jank_severity_type = jank_severity_type_ids_[static_cast<size_t>(
+ event.jank_severity_type())];
+ } else {
+ // NOTE: Older traces don't have this field. If JANK_NONE use
+ // |severity_type| "None", and is not present, use "Unknown".
+ actual_row.jank_severity_type =
+ (event.jank_type() == FrameTimelineEvent::JANK_NONE)
+ ? jank_severity_type_ids_[1] /* None */
+ : jank_severity_type_ids_[0]; /* Unknown */
+ }
+ StringId jank_severity_type = actual_row.jank_severity_type;
+
+ // parse prediction type
StringId prediction_type = prediction_type_ids_[0];
if (event.has_prediction_type() &&
ValidatePredictionType(context_, event.prediction_type())) {
@@ -294,6 +320,7 @@
prediction_type_ids_[static_cast<size_t>(event.prediction_type())];
}
actual_row.prediction_type = prediction_type;
+
if (DisplayFrameJanky(event.jank_type())) {
actual_row.jank_tag = jank_tag_self_id_;
} else if (event.jank_type() == FrameTimelineEvent::JANK_SF_STUFFING) {
@@ -307,8 +334,8 @@
std::optional<SliceId> opt_slice_id = context_->slice_tracker->BeginTyped(
context_->storage->mutable_actual_frame_timeline_slice_table(),
actual_row,
- [this, token, jank_type, present_type, prediction_type,
- &event](ArgsTracker::BoundInserter* inserter) {
+ [this, token, jank_type, jank_severity_type, present_type,
+ prediction_type, &event](ArgsTracker::BoundInserter* inserter) {
inserter->AddArg(display_frame_token_id_, Variadic::Integer(token));
inserter->AddArg(present_type_id_, Variadic::String(present_type));
inserter->AddArg(on_time_finish_id_,
@@ -316,6 +343,8 @@
inserter->AddArg(gpu_composition_id_,
Variadic::Integer(event.gpu_composition()));
inserter->AddArg(jank_type_id_, Variadic::String(jank_type));
+ inserter->AddArg(jank_severity_type_id_,
+ Variadic::String(jank_severity_type));
inserter->AddArg(prediction_type_id_,
Variadic::String(prediction_type));
});
@@ -471,6 +500,10 @@
actual_row.display_frame_token = display_frame_token;
actual_row.upid = upid;
actual_row.layer_name = layer_name_id;
+ actual_row.on_time_finish = event.on_time_finish();
+ actual_row.gpu_composition = event.gpu_composition();
+
+ // parse present type
StringId present_type = present_type_ids_[0];
bool present_type_validated = false;
if (event.has_present_type() &&
@@ -479,10 +512,26 @@
present_type = present_type_ids_[static_cast<size_t>(event.present_type())];
}
actual_row.present_type = present_type;
- actual_row.on_time_finish = event.on_time_finish();
- actual_row.gpu_composition = event.gpu_composition();
+
+ // parse jank type
StringId jank_type = JankTypeBitmaskToStringId(context_, event.jank_type());
actual_row.jank_type = jank_type;
+
+ // parse jank severity type
+ if (event.has_jank_severity_type()) {
+ actual_row.jank_severity_type = jank_severity_type_ids_[static_cast<size_t>(
+ event.jank_severity_type())];
+ } else {
+ // NOTE: Older traces don't have this field. If JANK_NONE use
+ // |severity_type| "None", and is not present, use "Unknown".
+ actual_row.jank_severity_type =
+ (event.jank_type() == FrameTimelineEvent::JANK_NONE)
+ ? jank_severity_type_ids_[1] /* None */
+ : jank_severity_type_ids_[0]; /* Unknown */
+ }
+ StringId jank_severity_type = actual_row.jank_severity_type;
+
+ // parse prediction type
StringId prediction_type = prediction_type_ids_[0];
if (event.has_prediction_type() &&
ValidatePredictionType(context_, event.prediction_type())) {
@@ -490,6 +539,7 @@
prediction_type_ids_[static_cast<size_t>(event.prediction_type())];
}
actual_row.prediction_type = prediction_type;
+
if (SurfaceFrameJanky(event.jank_type())) {
actual_row.jank_tag = jank_tag_self_id_;
} else if (DisplayFrameJanky(event.jank_type())) {
@@ -513,8 +563,8 @@
std::optional<SliceId> opt_slice_id = context_->slice_tracker->BeginTyped(
context_->storage->mutable_actual_frame_timeline_slice_table(),
actual_row,
- [this, jank_type, present_type, token, layer_name_id, display_frame_token,
- prediction_type, is_buffer,
+ [this, jank_type, jank_severity_type, present_type, token, layer_name_id,
+ display_frame_token, prediction_type, is_buffer,
&event](ArgsTracker::BoundInserter* inserter) {
inserter->AddArg(surface_frame_token_id_, Variadic::Integer(token));
inserter->AddArg(display_frame_token_id_,
@@ -526,6 +576,8 @@
inserter->AddArg(gpu_composition_id_,
Variadic::Integer(event.gpu_composition()));
inserter->AddArg(jank_type_id_, Variadic::String(jank_type));
+ inserter->AddArg(jank_severity_type_id_,
+ Variadic::String(jank_severity_type));
inserter->AddArg(prediction_type_id_,
Variadic::String(prediction_type));
inserter->AddArg(is_buffer_id_, Variadic::String(is_buffer));
diff --git a/src/trace_processor/importers/proto/frame_timeline_event_parser.h b/src/trace_processor/importers/proto/frame_timeline_event_parser.h
index 9c4e75e..596f415 100644
--- a/src/trace_processor/importers/proto/frame_timeline_event_parser.h
+++ b/src/trace_processor/importers/proto/frame_timeline_event_parser.h
@@ -66,6 +66,7 @@
std::map<int64_t, TrackSetId> cookie_track_set_id_map_;
std::array<StringId, 6> present_type_ids_;
std::array<StringId, 4> prediction_type_ids_;
+ std::array<StringId, 4> jank_severity_type_ids_;
StringId expected_timeline_track_name_;
StringId actual_timeline_track_name_;
@@ -75,6 +76,7 @@
StringId on_time_finish_id_;
StringId gpu_composition_id_;
StringId jank_type_id_;
+ StringId jank_severity_type_id_;
StringId layer_name_id_;
StringId prediction_type_id_;
StringId is_buffer_id_;
diff --git a/src/trace_processor/importers/proto/proto_trace_reader.cc b/src/trace_processor/importers/proto/proto_trace_reader.cc
index 8add6f0..6d68464 100644
--- a/src/trace_processor/importers/proto/proto_trace_reader.cc
+++ b/src/trace_processor/importers/proto/proto_trace_reader.cc
@@ -403,7 +403,8 @@
tables::ClockSnapshotTable::Row row;
row.ts = *opt_trace_ts;
row.clock_id = static_cast<int64_t>(clock_timestamp.clock.id);
- row.clock_value = clock_timestamp.timestamp;
+ row.clock_value =
+ clock_timestamp.timestamp * clock_timestamp.clock.unit_multiplier_ns;
row.clock_name = GetBuiltinClockNameOrNull(clock_timestamp.clock.id);
row.snapshot_id = *snapshot_id;
diff --git a/src/trace_processor/importers/proto/statsd_module.cc b/src/trace_processor/importers/proto/statsd_module.cc
index e536e11..49a7300 100644
--- a/src/trace_processor/importers/proto/statsd_module.cc
+++ b/src/trace_processor/importers/proto/statsd_module.cc
@@ -141,6 +141,54 @@
TraceStorage& storage_;
};
+// If we don't know about the atom format put whatever details we
+// can. This has the following restrictions:
+// - We can't tell the difference between double, fixed64, sfixed64
+// so those all show up as double
+// - We can't tell the difference between float, fixed32, sfixed32
+// so those all show up as float
+// - We can't tell the difference between int32, int64 and sint32
+// and sint64. We assume int32/int64.
+// - We only show the length of strings, nested messages, packed ints
+// and any other length delimited fields.
+base::Status ParseGenericEvent(const protozero::ConstBytes& cb,
+ util::ProtoToArgsParser::Delegate& delegate) {
+ protozero::ProtoDecoder decoder(cb);
+ for (auto f = decoder.ReadField(); f.valid(); f = decoder.ReadField()) {
+ switch (f.type()) {
+ case protozero::proto_utils::ProtoWireType::kLengthDelimited: {
+ base::StackString<64> name("field_%u", f.id());
+ std::string name_str = name.ToStdString();
+ util::ProtoToArgsParser::Key key{name_str, name_str};
+ delegate.AddBytes(key, f.as_bytes());
+ break;
+ }
+ case protozero::proto_utils::ProtoWireType::kVarInt: {
+ base::StackString<64> name("field_%u", f.id());
+ std::string name_str = name.ToStdString();
+ util::ProtoToArgsParser::Key key{name_str, name_str};
+ delegate.AddInteger(key, f.as_int64());
+ break;
+ }
+ case protozero::proto_utils::ProtoWireType::kFixed32: {
+ base::StackString<64> name("field_%u_assuming_float", f.id());
+ std::string name_str = name.ToStdString();
+ util::ProtoToArgsParser::Key key{name_str, name_str};
+ delegate.AddDouble(key, static_cast<double>(f.as_float()));
+ break;
+ }
+ case protozero::proto_utils::ProtoWireType::kFixed64: {
+ base::StackString<64> name("field_%u_assuming_double", f.id());
+ std::string name_str = name.ToStdString();
+ util::ProtoToArgsParser::Key key{name_str, name_str};
+ delegate.AddDouble(key, f.as_double());
+ break;
+ }
+ }
+ }
+ return base::OkStatus();
+}
+
} // namespace
using perfetto::protos::pbzero::StatsdAtom;
@@ -247,10 +295,26 @@
SliceId slice = opt_slice.value();
auto inserter = context_->args_tracker->AddArgsTo(slice);
InserterDelegate delegate(inserter, *context_->storage.get());
- base::Status result = args_parser_.ParseMessage(
- nested_bytes, kAtomProtoName, nullptr /* parse all fields */, delegate);
- if (!result.ok()) {
- PERFETTO_ELOG("%s", result.c_message());
+
+ const auto& fields = pool_.descriptor()->fields();
+ const auto& field_it = fields.find(nested_field_id);
+ base::Status status;
+
+ if (field_it == fields.end()) {
+ /// Field ids 100000 and over are OEM atoms - we can't have the
+ // descriptor for them so don't report errors. See:
+ // https://cs.android.com/android/platform/superproject/main/+/main:frameworks/proto_logging/stats/atoms.proto;l=1290;drc=a34b11bfebe897259a0340a59f1793ae2dffd762
+ if (nested_field_id < 100000) {
+ context_->storage->IncrementStats(stats::atom_unknown);
+ }
+
+ status = ParseGenericEvent(field.as_bytes(), delegate);
+ } else {
+ status = args_parser_.ParseMessage(
+ nested_bytes, kAtomProtoName, nullptr /* parse all fields */, delegate);
+ }
+
+ if (!status.ok()) {
context_->storage->IncrementStats(stats::atom_unknown);
}
}
@@ -263,18 +327,18 @@
return context_->storage->InternString("Could not load atom descriptor");
}
+ StringId name_id;
const auto& fields = pool_.descriptor()->fields();
const auto& field_it = fields.find(atom_field_id);
if (field_it == fields.end()) {
- context_->storage->IncrementStats(stats::atom_unknown);
- return context_->storage->InternString("Unknown atom");
+ base::StackString<255> name("atom_%u", atom_field_id);
+ name_id = context_->storage->InternString(name.string_view());
+ } else {
+ const FieldDescriptor& field = field_it->second;
+ name_id = context_->storage->InternString(base::StringView(field.name()));
}
-
- const FieldDescriptor& field = field_it->second;
- StringId name =
- context_->storage->InternString(base::StringView(field.name()));
- atom_names_[atom_field_id] = name;
- return name;
+ atom_names_[atom_field_id] = name_id;
+ return name_id;
}
return *cached_name;
}
diff --git a/src/trace_processor/sqlite/sqlite_engine.cc b/src/trace_processor/sqlite/sqlite_engine.cc
index b1d1be4..9f845b1 100644
--- a/src/trace_processor/sqlite/sqlite_engine.cc
+++ b/src/trace_processor/sqlite/sqlite_engine.cc
@@ -18,6 +18,7 @@
#include <memory>
#include <optional>
+#include <unordered_set>
#include <utility>
#include <vector>
@@ -105,11 +106,17 @@
// them) because |OnSqliteTableDestroyed| will be called as each DROP is
// executed.
std::vector<std::string> drop_stmts;
- for (auto it = sqlite_tables_.GetIterator(); it; ++it) {
- if (it.value() != SqliteTable::TableType::kExplicitCreate) {
+ std::unordered_set<std::string> dropped_tables;
+ for (auto it = all_created_sqlite_tables_.rbegin();
+ it != all_created_sqlite_tables_.rend(); it++) {
+ if (auto* type = sqlite_tables_.Find(*it);
+ !type || *type != SqliteTable::TableType::kExplicitCreate) {
continue;
}
- base::StackString<1024> drop("DROP TABLE %s", it.key().c_str());
+ if (auto it_and_ins = dropped_tables.insert(*it); !it_and_ins.second) {
+ continue;
+ }
+ base::StackString<1024> drop("DROP TABLE %s", it->c_str());
drop_stmts.emplace_back(drop.ToStdString());
}
for (const auto& drop : drop_stmts) {
@@ -248,6 +255,7 @@
SqliteTable::TableType type) {
auto it_and_inserted = sqlite_tables_.Insert(name, type);
PERFETTO_CHECK(it_and_inserted.second);
+ all_created_sqlite_tables_.push_back(name);
}
void SqliteEngine::OnSqliteTableDestroyed(const std::string& name) {
diff --git a/src/trace_processor/sqlite/sqlite_engine.h b/src/trace_processor/sqlite/sqlite_engine.h
index 42ef5ae..9af23fe 100644
--- a/src/trace_processor/sqlite/sqlite_engine.h
+++ b/src/trace_processor/sqlite/sqlite_engine.h
@@ -24,6 +24,7 @@
#include <optional>
#include <string>
#include <type_traits>
+#include <vector>
#include "perfetto/base/status.h"
#include "perfetto/ext/base/flat_hash_map.h"
@@ -137,6 +138,7 @@
SqliteEngine& operator=(SqliteEngine&&) = delete;
base::FlatHashMap<std::string, SqliteTable::TableType> sqlite_tables_;
+ std::vector<std::string> all_created_sqlite_tables_;
base::FlatHashMap<std::string, std::unique_ptr<SqliteTable>> saved_tables_;
base::FlatHashMap<std::pair<std::string, int>, void*, FnHasher> fn_ctx_;
diff --git a/src/trace_processor/sqlite/sqlite_table.h b/src/trace_processor/sqlite/sqlite_table.h
index 3f7c3bd..d6d40b3 100644
--- a/src/trace_processor/sqlite/sqlite_table.h
+++ b/src/trace_processor/sqlite/sqlite_table.h
@@ -324,7 +324,7 @@
module.xDisconnect = &xDestroy;
break;
case TableType::kExplicitCreate:
- // xConnect and xDestroy will be called when the table is CREATE-ed and
+ // xCreate and xDestroy will be called when the table is CREATE-ed and
// DROP-ed respectively.
module.xCreate = &xCreate;
module.xDestroy = &xDestroy;
diff --git a/src/trace_processor/tables/slice_tables.py b/src/trace_processor/tables/slice_tables.py
index 7548637..241fa10 100644
--- a/src/trace_processor/tables/slice_tables.py
+++ b/src/trace_processor/tables/slice_tables.py
@@ -190,13 +190,24 @@
],
parent=SLICE_TABLE,
tabledoc=TableDoc(
- doc='''''',
+ doc='''
+ This table contains information on the expected timeline of either
+ a display frame or a surface frame.
+ ''',
group='Slice',
columns={
- 'display_frame_token': '''''',
- 'surface_frame_token': '''''',
- 'upid': '''''',
- 'layer_name': ''''''
+ 'display_frame_token':
+ 'Display frame token (vsync id).',
+ 'surface_frame_token':
+ '''
+ Surface frame token (vsync id), null if this is a display frame.
+ ''',
+ 'upid':
+ '''
+ Unique process id of the app that generates the surface frame.
+ ''',
+ 'layer_name':
+ 'Layer name if this is a surface frame.',
}))
ACTUAL_FRAME_TIMELINE_SLICE_TABLE = Table(
@@ -212,24 +223,48 @@
C('on_time_finish', CppInt32()),
C('gpu_composition', CppInt32()),
C('jank_type', CppString()),
+ C('jank_severity_type', CppString()),
C('prediction_type', CppString()),
C('jank_tag', CppString()),
],
parent=SLICE_TABLE,
tabledoc=TableDoc(
- doc='''''',
+ doc='''
+ This table contains information on the actual timeline and additional
+ analysis related to the performance of either a display frame or a
+ surface frame.
+ ''',
group='Slice',
columns={
- 'display_frame_token': '''''',
- 'surface_frame_token': '''''',
- 'upid': '''''',
- 'layer_name': '''''',
- 'present_type': '''''',
- 'on_time_finish': '''''',
- 'gpu_composition': '''''',
- 'jank_type': '''''',
- 'prediction_type': '''''',
- 'jank_tag': ''''''
+ 'display_frame_token':
+ 'Display frame token (vsync id).',
+ 'surface_frame_token':
+ '''
+ Surface frame token (vsync id), null if this is a display frame.
+ ''',
+ 'upid':
+ '''
+ Unique process id of the app that generates the surface frame.
+ ''',
+ 'layer_name':
+ 'Layer name if this is a surface frame.',
+ 'present_type':
+ 'Frame\'s present type (eg. on time / early / late).',
+ 'on_time_finish':
+ 'Whether the frame finishes on time.',
+ 'gpu_composition':
+ 'Whether the frame used gpu composition.',
+ 'jank_type':
+ '''
+ Specify the jank types for this frame if there's jank, or
+ none if no jank occured.
+ ''',
+ 'jank_severity_type':
+ 'Severity of the jank: none if no jank.',
+ 'prediction_type':
+ 'Frame\'s prediction type (eg. valid / expired).',
+ 'jank_tag':
+ 'Jank tag based on jank type, used for slice visualization.'
}))
EXPERIMENTAL_FLAT_SLICE_TABLE = Table(
diff --git a/src/trace_processor/trace_processor_impl.cc b/src/trace_processor/trace_processor_impl.cc
index db65dae..766df13 100644
--- a/src/trace_processor/trace_processor_impl.cc
+++ b/src/trace_processor/trace_processor_impl.cc
@@ -479,12 +479,13 @@
PERFETTO_CHECK(tables_views_in_sqlite_count_ >=
engine_->RuntimeTablesAndViewsCount());
- // Tables and views in sqlite with all objects from Perfeto Sql Engine without
- // tables and views.
+ // Add the number of tables/views registered with SQLite to the number of
+ // "objects" (tables, views, functions etc) that we've registered and take
+ // away the number of "runtime" tables/views which are registered (which will
+ // be double counted).
uint64_t registered_count_before = tables_views_in_sqlite_count_ +
engine_->AllRegisteredObjectsCount() -
engine_->RuntimeTablesAndViewsCount();
-
InitPerfettoSqlEngine();
return static_cast<size_t>(registered_count_before -
engine_->AllRegisteredObjectsCount());
diff --git a/src/traceconv/pprof_builder.cc b/src/traceconv/pprof_builder.cc
index 1ca8654..d8de2dc 100644
--- a/src/traceconv/pprof_builder.cc
+++ b/src/traceconv/pprof_builder.cc
@@ -559,7 +559,7 @@
bool WriteMappings(trace_processor::TraceProcessor* tp,
const std::set<int64_t>& seen_mappings) {
Iterator mapping_it = tp->ExecuteQuery(
- "SELECT id, exact_offset, start, end, name "
+ "SELECT id, exact_offset, start, end, name, build_id "
"FROM stack_profile_mapping;");
size_t mappings_no = 0;
while (mapping_it.Next()) {
@@ -569,10 +569,10 @@
++mappings_no;
auto interned_filename = ToStringTableId(
interner_->InternString(mapping_it.Get(4).AsString()));
+ auto interned_build_id = ToStringTableId(
+ interner_->InternString(mapping_it.Get(5).AsString()));
auto* gmapping = result_->add_mapping();
gmapping->set_id(ToPprofId(id));
- // Do not set the build_id here to avoid downstream services
- // trying to symbolize (e.g. b/141735056)
gmapping->set_file_offset(
static_cast<uint64_t>(mapping_it.Get(1).AsLong()));
gmapping->set_memory_start(
@@ -580,6 +580,7 @@
gmapping->set_memory_limit(
static_cast<uint64_t>(mapping_it.Get(3).AsLong()));
gmapping->set_filename(interned_filename);
+ gmapping->set_build_id(interned_build_id);
}
if (!mapping_it.Status().ok()) {
PERFETTO_DFATAL_OR_ELOG("Invalid mapping iterator: %s",
diff --git a/src/traced/probes/ftrace/event_info.cc b/src/traced/probes/ftrace/event_info.cc
index 7ad51cf..62bd4b9 100644
--- a/src/traced/probes/ftrace/event_info.cc
+++ b/src/traced/probes/ftrace/event_info.cc
@@ -7361,6 +7361,64 @@
kUnsetFtraceId,
430,
kUnsetSize},
+ {"sched_switch_with_ctrs",
+ "perf_trace_counters",
+ {
+ {kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
+ "old_pid", 1, ProtoSchemaType::kInt32,
+ TranslationStrategy::kInvalidTranslationStrategy},
+ {kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
+ "new_pid", 2, ProtoSchemaType::kInt32,
+ TranslationStrategy::kInvalidTranslationStrategy},
+ {kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
+ "cctr", 3, ProtoSchemaType::kUint32,
+ TranslationStrategy::kInvalidTranslationStrategy},
+ {kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
+ "ctr0", 4, ProtoSchemaType::kUint32,
+ TranslationStrategy::kInvalidTranslationStrategy},
+ {kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
+ "ctr1", 5, ProtoSchemaType::kUint32,
+ TranslationStrategy::kInvalidTranslationStrategy},
+ {kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
+ "ctr2", 6, ProtoSchemaType::kUint32,
+ TranslationStrategy::kInvalidTranslationStrategy},
+ {kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
+ "ctr3", 7, ProtoSchemaType::kUint32,
+ TranslationStrategy::kInvalidTranslationStrategy},
+ {kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
+ "lctr0", 8, ProtoSchemaType::kUint32,
+ TranslationStrategy::kInvalidTranslationStrategy},
+ {kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
+ "lctr1", 9, ProtoSchemaType::kUint32,
+ TranslationStrategy::kInvalidTranslationStrategy},
+ {kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
+ "ctr4", 10, ProtoSchemaType::kUint32,
+ TranslationStrategy::kInvalidTranslationStrategy},
+ {kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
+ "ctr5", 11, ProtoSchemaType::kUint32,
+ TranslationStrategy::kInvalidTranslationStrategy},
+ {kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
+ "prev_comm", 12, ProtoSchemaType::kString,
+ TranslationStrategy::kInvalidTranslationStrategy},
+ {kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
+ "prev_pid", 13, ProtoSchemaType::kInt32,
+ TranslationStrategy::kInvalidTranslationStrategy},
+ {kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
+ "cyc", 14, ProtoSchemaType::kUint32,
+ TranslationStrategy::kInvalidTranslationStrategy},
+ {kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
+ "inst", 15, ProtoSchemaType::kUint32,
+ TranslationStrategy::kInvalidTranslationStrategy},
+ {kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
+ "stallbm", 16, ProtoSchemaType::kUint32,
+ TranslationStrategy::kInvalidTranslationStrategy},
+ {kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
+ "l3dm", 17, ProtoSchemaType::kUint32,
+ TranslationStrategy::kInvalidTranslationStrategy},
+ },
+ kUnsetFtraceId,
+ 487,
+ kUnsetSize},
{"cpu_frequency",
"power",
{
diff --git a/src/traced/probes/ftrace/test/data/synthetic/events/perf_trace_counters/sched_switch_with_ctrs/format b/src/traced/probes/ftrace/test/data/synthetic/events/perf_trace_counters/sched_switch_with_ctrs/format
new file mode 100644
index 0000000..e357f11
--- /dev/null
+++ b/src/traced/probes/ftrace/test/data/synthetic/events/perf_trace_counters/sched_switch_with_ctrs/format
@@ -0,0 +1,16 @@
+name: sched_switch_with_ctrs
+ID: 1237
+format:
+ field:unsigned short common_type; offset:0; size:2; signed:0;
+ field:unsigned char common_flags; offset:2; size:1; signed:0;
+ field:unsigned char common_preempt_count; offset:3; size:1; signed:0;
+ field:int common_pid; offset:4; size:4; signed:1;
+
+ field:char prev_comm[16]; offset:8; size:16; signed:0;
+ field:pid_t prev_pid; offset:24; size:4; signed:1;
+ field:u32 cyc; offset:28; size:4; signed:0;
+ field:u32 inst; offset:32; size:4; signed:0;
+ field:u32 stallbm; offset:36; size:4; signed:0;
+ field:u32 l3dm; offset:40; size:4; signed:0;
+
+print fmt: "prev_comm=%s, prev_pid=%d, CYC=%u, INST=%u, STALLBM=%u, L3DM=%u", REC->prev_comm, REC->prev_pid, REC->cyc, REC->inst, REC->stallbm, REC->l3dm
diff --git a/src/traced_relay/relay_service.cc b/src/traced_relay/relay_service.cc
index 1ef5855..1a67439 100644
--- a/src/traced_relay/relay_service.cc
+++ b/src/traced_relay/relay_service.cc
@@ -15,22 +15,37 @@
*/
#include "src/traced_relay/relay_service.h"
+
#include <memory>
+#include "perfetto/base/build_config.h"
#include "perfetto/base/logging.h"
#include "perfetto/base/task_runner.h"
+#include "perfetto/ext/base/file_utils.h"
+#include "perfetto/ext/base/hash.h"
+#include "perfetto/ext/base/string_utils.h"
#include "perfetto/ext/base/unix_socket.h"
#include "perfetto/ext/base/utils.h"
#include "protos/perfetto/ipc/wire_protocol.gen.h"
#include "src/ipc/buffered_frame_deserializer.h"
#include "src/traced_relay/socket_relay_handler.h"
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/utsname.h>
+#include <unistd.h>
+#endif
+
using ::perfetto::protos::gen::IPCFrame;
namespace perfetto {
RelayService::RelayService(base::TaskRunner* task_runner)
- : task_runner_(task_runner) {}
+ : task_runner_(task_runner), machine_id_hint_(GetMachineIdHint()) {}
void RelayService::Start(const char* listening_socket_name,
const char* client_socket_name) {
@@ -77,6 +92,8 @@
set_peer_identity->set_uid(
static_cast<int32_t>(server_conn->peer_uid_posix()));
+ set_peer_identity->set_machine_id_hint(machine_id_hint_);
+
// Buffer the SetPeerIdentity request.
auto req = ipc::BufferedFrameDeserializer::Serialize(ipc_frame);
SocketWithBuffer server, client;
@@ -123,4 +140,61 @@
PERFETTO_DFATAL("Should be unreachable.");
}
+std::string RelayService::GetMachineIdHint(
+ bool use_pseudo_boot_id_for_testing) {
+ // Gets kernel boot ID if possible.
+ std::string boot_id;
+ if (!use_pseudo_boot_id_for_testing &&
+ base::ReadFile("/proc/sys/kernel/random/boot_id", &boot_id)) {
+ return base::StripSuffix(boot_id, "\n");
+ }
+
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
+ auto get_pseudo_boot_id = []() -> std::string {
+ base::Hasher hasher;
+ const char* dev_path = "/dev";
+ // Generate a pseudo-unique identifier for the current machine.
+ // Source 1: system boot timestamp from the creation time of /dev inode.
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
+ // Mac or iOS, just use stat(2).
+ struct stat stat_buf {};
+ int rc = PERFETTO_EINTR(stat(dev_path, &stat_buf));
+ if (rc == -1)
+ return std::string();
+ hasher.Update(reinterpret_cast<const char*>(&stat_buf.st_birthtimespec),
+ sizeof(stat_buf.st_birthtimespec));
+#else
+ // Android or Linux, use statx(2)
+ struct statx stat_buf {};
+ auto rc = PERFETTO_EINTR(syscall(__NR_statx, /*dirfd=*/-1, dev_path,
+ /*flags=*/0, STATX_BTIME, &stat_buf));
+ if (rc == -1)
+ return std::string();
+ hasher.Update(reinterpret_cast<const char*>(&stat_buf.stx_btime),
+ sizeof(stat_buf.stx_btime));
+#endif
+
+ // Source 2: uname(2).
+ utsname kernel_info{};
+ if (uname(&kernel_info) == -1)
+ return std::string();
+
+ // Create a non-cryptographic digest of bootup timestamp and everything in
+ // utsname.
+ hasher.Update(reinterpret_cast<const char*>(&kernel_info),
+ sizeof(kernel_info));
+ return base::Uint64ToHexStringNoPrefix(hasher.digest());
+ };
+
+ auto pseudo_boot_id = get_pseudo_boot_id();
+ if (!pseudo_boot_id.empty())
+ return pseudo_boot_id;
+#endif
+
+ // If all above failed, return nothing.
+ return std::string();
+}
+
} // namespace perfetto
diff --git a/src/traced_relay/relay_service.h b/src/traced_relay/relay_service.h
index 8e5bf6d..1760df3 100644
--- a/src/traced_relay/relay_service.h
+++ b/src/traced_relay/relay_service.h
@@ -40,6 +40,13 @@
// |server_socket_name| and |client_socket_name| ports.
void Start(const char* server_socket_name, const char* client_socket_name);
+ static std::string GetMachineIdHint(
+ bool use_pseudo_boot_id_for_testing = false);
+
+ void SetMachineIdHintForTesting(std::string machine_id_hint) {
+ machine_id_hint_ = machine_id_hint;
+ }
+
private:
struct PendingConnection {
// This keeps a connected UnixSocketRaw server socket in its first element.
@@ -60,6 +67,9 @@
base::TaskRunner* const task_runner_ = nullptr;
+ // A hint to the host traced for inferring the identifier of this machine.
+ std::string machine_id_hint_;
+
std::unique_ptr<base::UnixSocket> listening_socket_;
std::string client_socket_name_;
diff --git a/src/traced_relay/relay_service_integrationtest.cc b/src/traced_relay/relay_service_integrationtest.cc
index 7e29041..bb83ecf 100644
--- a/src/traced_relay/relay_service_integrationtest.cc
+++ b/src/traced_relay/relay_service_integrationtest.cc
@@ -15,6 +15,9 @@
*/
#include <memory>
+#include <string>
+#include <vector>
+#include "perfetto/ext/base/unix_socket.h"
#include "src/traced_relay/relay_service.h"
#include "src/base/test/test_task_runner.h"
@@ -28,6 +31,17 @@
namespace perfetto {
namespace {
+struct TestParams {
+ std::string id;
+ std::string tcp_sock_name;
+ std::string unix_sock_name;
+ std::string producer_name;
+
+ std::unique_ptr<RelayService> relay_service;
+ std::unique_ptr<base::UnixSocket> server_socket;
+ std::unique_ptr<FakeProducerThread> producer_thread;
+};
+
TEST(TracedRelayIntegrationTest, BasicCase) {
base::TestTaskRunner task_runner;
@@ -102,6 +116,125 @@
ASSERT_EQ(packet.trusted_pid(), pid);
ASSERT_EQ(packet.trusted_uid(), uid);
ASSERT_EQ(packet.for_testing().seq_value(), rnd_engine());
+ // The tracing service should emit non-default machine ID in trace packets.
+ ASSERT_NE(packet.machine_id(), 0u);
+ }
+}
+
+TEST(TracedRelayIntegrationTest, MachineID_MultiRelayService) {
+ base::TestTaskRunner task_runner;
+ std::vector<TestParams> test_params(2);
+
+ base::UnixSocket::EventListener event_listener;
+ for (size_t i = 0; i < test_params.size(); i++) {
+ auto& param = test_params[i];
+ param.id = std::to_string(i + 1);
+ param.server_socket = base::UnixSocket::Listen(
+ "127.0.0.1:0", &event_listener, &task_runner, base::SockFamily::kInet,
+ base::SockType::kStream);
+ ASSERT_TRUE(param.server_socket->is_listening());
+ param.tcp_sock_name = param.server_socket->GetSockAddr();
+ param.relay_service = std::make_unique<RelayService>(&task_runner);
+ param.relay_service->SetMachineIdHintForTesting("test-machine-id-" +
+ param.id);
+ param.unix_sock_name = std::string("@traced_relay_") + param.id;
+ param.producer_name = std::string("perfetto.FakeProducer.") + param.id;
+ }
+ for (auto& param : test_params) {
+ // Shut down listening sockets to free the port. It's unlikely that the port
+ // will be taken by another process so quickly before we reach the code
+ // below.
+ param.server_socket = nullptr;
+ }
+ auto relay_sock_name =
+ test_params[0].tcp_sock_name + "," + test_params[1].tcp_sock_name;
+
+ for (auto& param : test_params) {
+ param.relay_service->Start(param.unix_sock_name.c_str(),
+ param.tcp_sock_name.c_str());
+ }
+
+ TestHelper helper(&task_runner, TestHelper::Mode::kStartDaemons,
+ relay_sock_name.c_str());
+ ASSERT_EQ(helper.num_producers(), 2u);
+ helper.StartServiceIfRequired();
+
+ for (auto& param : test_params) {
+ auto checkpoint_name = "perfetto.FakeProducer.connected." + param.id;
+ auto producer_connected = task_runner.CreateCheckpoint(checkpoint_name);
+ auto noop = []() {};
+ auto connected = std::bind(
+ [&](std::function<void()> checkpoint) {
+ task_runner.PostTask(checkpoint);
+ },
+ producer_connected);
+ // We won't use the built-in fake producer and will start our own.
+ param.producer_thread = std::make_unique<FakeProducerThread>(
+ param.unix_sock_name, connected, noop, noop, param.producer_name);
+ param.producer_thread->Connect();
+ task_runner.RunUntilCheckpoint(checkpoint_name);
+ }
+
+ helper.ConnectConsumer();
+ helper.WaitForConsumerConnect();
+
+ TraceConfig trace_config;
+ trace_config.add_buffers()->set_size_kb(1024);
+ trace_config.set_duration_ms(200);
+
+ static constexpr uint32_t kMsgSize = 1024;
+ static constexpr uint32_t kRandomSeed = 42;
+
+ // Enable the 1st producer.
+ auto* ds_config = trace_config.add_data_sources()->mutable_config();
+ ds_config->set_name("perfetto.FakeProducer.1");
+ ds_config->set_target_buffer(0);
+ ds_config->mutable_for_testing()->set_message_count(12);
+ ds_config->mutable_for_testing()->set_message_size(kMsgSize);
+ ds_config->mutable_for_testing()->set_send_batch_on_register(true);
+ // Enable the 2nd producer.
+ ds_config = trace_config.add_data_sources()->mutable_config();
+ ds_config->set_name("perfetto.FakeProducer.2");
+ ds_config->set_target_buffer(0);
+ ds_config->mutable_for_testing()->set_message_count(24);
+ ds_config->mutable_for_testing()->set_message_size(kMsgSize);
+ ds_config->mutable_for_testing()->set_send_batch_on_register(true);
+
+ helper.StartTracing(trace_config);
+ helper.WaitForTracingDisabled();
+
+ helper.ReadData();
+ helper.WaitForReadData();
+
+ const auto& packets = helper.trace();
+ ASSERT_EQ(packets.size(), 36u);
+
+ // The producer is connected from this process. The relay service will inject
+ // the SetPeerIdentity message using the pid and euid of the current process.
+ auto pid = static_cast<int32_t>(getpid());
+ auto uid = static_cast<int32_t>(geteuid());
+
+ std::minstd_rand0 rnd_engine(kRandomSeed);
+ std::map<uint32_t, size_t> packets_counts; // machine ID => count.
+
+ for (const auto& packet : packets) {
+ ASSERT_TRUE(packet.has_for_testing());
+ ASSERT_EQ(packet.trusted_pid(), pid);
+ ASSERT_EQ(packet.trusted_uid(), uid);
+ packets_counts[packet.machine_id()]++;
+ }
+
+ // Fake producer (1, 2) either gets machine ID (1, 2), or (2, 1), depending on
+ // which on is seen by the tracing service first.
+ ASSERT_EQ(packets_counts.size(), 2u);
+ auto count_1 = packets_counts.begin()->second;
+ auto count_2 = packets_counts.rbegin()->second;
+ ASSERT_TRUE(count_1 == 12u || count_1 == 24u);
+ ASSERT_EQ(count_1 + count_2, 36u);
+
+ for (auto& param : test_params) {
+ param.producer_thread = nullptr;
+ param.relay_service = nullptr;
}
}
diff --git a/src/traced_relay/relay_service_unittest.cc b/src/traced_relay/relay_service_unittest.cc
index 649f552..0508328 100644
--- a/src/traced_relay/relay_service_unittest.cc
+++ b/src/traced_relay/relay_service_unittest.cc
@@ -116,6 +116,7 @@
const auto& set_peer_identity = frame->set_peer_identity();
EXPECT_EQ(set_peer_identity.pid(), getpid());
EXPECT_EQ(set_peer_identity.uid(), static_cast<int32_t>(geteuid()));
+ EXPECT_TRUE(set_peer_identity.has_machine_id_hint());
frame = deserializer.PopNextFrame();
EXPECT_EQ(1u, frame->data_for_testing().size());
@@ -126,5 +127,34 @@
task_runner.RunUntilCheckpoint("peer_identity_recv");
}
+TEST(RelayServiceTest, MachineIDHint) {
+ base::TestTaskRunner task_runner;
+ auto relay_service = std::make_unique<RelayService>(&task_runner);
+
+ auto hint1 = relay_service->GetMachineIdHint();
+ auto hint2 =
+ relay_service->GetMachineIdHint(/*use_pseudo_boot_id_for_testing=*/true);
+ EXPECT_NE(hint1, hint2);
+
+ // Add a short sleep to verify that pseudo boot ID isn't affected.
+ std::this_thread::sleep_for(std::chrono::milliseconds(1));
+
+ relay_service = std::make_unique<RelayService>(&task_runner);
+ auto hint3 = relay_service->GetMachineIdHint();
+ auto hint4 =
+ relay_service->GetMachineIdHint(/*use_pseudo_boot_id_for_testing=*/true);
+ EXPECT_NE(hint3, hint4);
+
+ EXPECT_FALSE(hint1.empty());
+#if !PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
+ // This test can run on Android kernel 3.x, but pseudo boot ID uses statx(2)
+ // that requires kernel 4.11.
+ EXPECT_FALSE(hint2.empty());
+#endif
+
+ EXPECT_EQ(hint1, hint3);
+ EXPECT_EQ(hint2, hint4);
+}
+
} // namespace
} // namespace perfetto
diff --git a/src/traced_relay/socket_relay_handler_unittest.cc b/src/traced_relay/socket_relay_handler_unittest.cc
index a96308a..380c594 100644
--- a/src/traced_relay/socket_relay_handler_unittest.cc
+++ b/src/traced_relay/socket_relay_handler_unittest.cc
@@ -110,8 +110,17 @@
// Test the SocketRelayHander with randomized request and response data.
TEST_P(SocketRelayHandlerTest, RandomizedRequestResponse) {
+#if defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER) || \
+ defined(MEMORY_SANITIZER) || defined(LEAK_SANITIZER)
+ // Reduce the test strength for sanitizer builds.
+ constexpr size_t kMaxMsgSizeRng = 1 << 16;
+ constexpr size_t kMaxNumRequests = 10;
+#else
// The max message size in the number of RNG calls.
- constexpr size_t kMaxMsgSizeRng = 1 << 20;
+ constexpr size_t kMaxMsgSizeRng = 1 << 18;
+ // The max number of requests.
+ constexpr size_t kMaxNumRequests = 25;
+#endif
// Create the threads for sending and receiving data through the
// SocketRelayHandler.
@@ -122,7 +131,7 @@
auto& rng = client.data_prng;
// The max number of requests.
- const size_t num_requests = rng() % 50;
+ const size_t num_requests = rng() % kMaxNumRequests;
for (size_t j = 0; j < num_requests; j++) {
auto& send_endpoint = client.endpoint_sockets.first;
@@ -196,9 +205,12 @@
}
}
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
+INSTANTIATE_TEST_SUITE_P(ByConnections, SocketRelayHandlerTest, Values(1, 5));
+#else
INSTANTIATE_TEST_SUITE_P(ByConnections,
SocketRelayHandlerTest,
- Values(1, 5, 50));
-
+ Values(1, 5, 25));
+#endif
} // namespace
} // namespace perfetto
diff --git a/src/tracing/core/packet_stream_validator.cc b/src/tracing/core/packet_stream_validator.cc
index d84eed3..9bed9b7 100644
--- a/src/tracing/core/packet_stream_validator.cc
+++ b/src/tracing/core/packet_stream_validator.cc
@@ -40,6 +40,7 @@
protos::pbzero::TracePacket::kCompressedPacketsFieldNumber,
protos::pbzero::TracePacket::kSynchronizationMarkerFieldNumber,
protos::pbzero::TracePacket::kTrustedPidFieldNumber,
+ protos::pbzero::TracePacket::kMachineIdFieldNumber,
};
// This translation unit is quite subtle and perf-sensitive. Remember to check
diff --git a/src/tracing/core/packet_stream_validator_unittest.cc b/src/tracing/core/packet_stream_validator_unittest.cc
index 74de04c..62de98a 100644
--- a/src/tracing/core/packet_stream_validator_unittest.cc
+++ b/src/tracing/core/packet_stream_validator_unittest.cc
@@ -181,6 +181,26 @@
EXPECT_FALSE(PacketStreamValidator::Validate(seq));
}
+TEST(PacketStreamValidatorTest, SimplePacketWithMachineID) {
+ protos::gen::TracePacket proto;
+ proto.set_machine_id(123);
+ std::string ser_buf = proto.SerializeAsString();
+
+ Slices seq;
+ seq.emplace_back(&ser_buf[0], ser_buf.size());
+ EXPECT_FALSE(PacketStreamValidator::Validate(seq));
+}
+
+TEST(PacketStreamValidatorTest, SimplePacketWithZeroMachineID) {
+ protos::gen::TracePacket proto;
+ proto.set_machine_id(0);
+ std::string ser_buf = proto.SerializeAsString();
+
+ Slices seq;
+ seq.emplace_back(&ser_buf[0], ser_buf.size());
+ EXPECT_FALSE(PacketStreamValidator::Validate(seq));
+}
+
TEST(PacketStreamValidatorTest, ComplexPacketWithPid) {
protos::gen::TracePacket proto;
proto.mutable_for_testing()->set_str("string field");
diff --git a/src/tracing/core/tracing_service_impl.cc b/src/tracing/core/tracing_service_impl.cc
index 1e4783a..1d469ac 100644
--- a/src/tracing/core/tracing_service_impl.cc
+++ b/src/tracing/core/tracing_service_impl.cc
@@ -2329,8 +2329,8 @@
PERFETTO_DCHECK(sequence_properties.producer_id_trusted != 0);
PERFETTO_DCHECK(sequence_properties.writer_id != 0);
PERFETTO_DCHECK(sequence_properties.client_identity_trusted.has_uid());
- // Not checking sequence_properties.producer_pid_trusted: it is
- // base::kInvalidPid if the platform doesn't support it.
+ // Not checking sequence_properties.client_identity_trusted.has_pid():
+ // it is false if the platform doesn't support it.
PERFETTO_DCHECK(packet.size() > 0);
if (!PacketStreamValidator::Validate(packet.slices())) {
@@ -2356,6 +2356,7 @@
static_cast<int32_t>(client_identity_trusted.uid()));
trusted_packet->set_trusted_packet_sequence_id(
tracing_session->GetPacketSequenceID(
+ client_identity_trusted.machine_id(),
sequence_properties.producer_id_trusted,
sequence_properties.writer_id));
if (client_identity_trusted.has_pid()) {
@@ -2363,6 +2364,9 @@
trusted_packet->set_trusted_pid(
static_cast<int32_t>(client_identity_trusted.pid()));
}
+ if (client_identity_trusted.has_non_default_machine_id()) {
+ trusted_packet->set_machine_id(client_identity_trusted.machine_id());
+ }
if (previous_packet_dropped)
trusted_packet->set_previous_packet_dropped(previous_packet_dropped);
slice.size = trusted_packet.Finalize();
@@ -3430,7 +3434,8 @@
}
}
auto* wri_stats = trace_stats.add_writer_stats();
- wri_stats->set_sequence_id(tracing_session->GetPacketSequenceID(p, w));
+ wri_stats->set_sequence_id(
+ tracing_session->GetPacketSequenceID(kDefaultMachineID, p, w));
for (size_t i = 0; i < hist.num_buckets(); ++i) {
wri_stats->add_chunk_payload_histogram_counts(hist.GetBucketCount(i));
wri_stats->add_chunk_payload_histogram_sum(hist.GetBucketSum(i));
diff --git a/src/tracing/core/tracing_service_impl.h b/src/tracing/core/tracing_service_impl.h
index 2639875..0f99493 100644
--- a/src/tracing/core/tracing_service_impl.h
+++ b/src/tracing/core/tracing_service_impl.h
@@ -465,9 +465,10 @@
return timeout_ms ? timeout_ms : kDataSourceStopTimeoutMs;
}
- PacketSequenceID GetPacketSequenceID(ProducerID producer_id,
+ PacketSequenceID GetPacketSequenceID(MachineID machine_id,
+ ProducerID producer_id,
WriterID writer_id) {
- auto key = std::make_pair(producer_id, writer_id);
+ auto key = std::make_tuple(machine_id, producer_id, writer_id);
auto it = packet_sequence_ids.find(key);
if (it != packet_sequence_ids.end())
return it->second;
@@ -551,7 +552,7 @@
// many entries as |config.buffers_size()|.
std::vector<BufferID> buffers_index;
- std::map<std::pair<ProducerID, WriterID>, PacketSequenceID>
+ std::map<std::tuple<MachineID, ProducerID, WriterID>, PacketSequenceID>
packet_sequence_ids;
PacketSequenceID last_packet_sequence_id = kServicePacketSequenceID;
diff --git a/src/tracing/ipc/service/producer_ipc_service.cc b/src/tracing/ipc/service/producer_ipc_service.cc
index b24c632..1e9e316 100644
--- a/src/tracing/ipc/service/producer_ipc_service.cc
+++ b/src/tracing/ipc/service/producer_ipc_service.cc
@@ -117,7 +117,8 @@
}
// Copy the data fields to be emitted to trace packets into ClientIdentity.
- ClientIdentity client_identity(client_info.uid(), client_info.pid());
+ ClientIdentity client_identity(client_info.uid(), client_info.pid(),
+ client_info.machine_id());
// ConnectProducer will call OnConnect() on the next task.
producer->service_endpoint = core_service_->ConnectProducer(
producer.get(), client_identity, req.producer_name(),
diff --git a/src/tracing/tracing.cc b/src/tracing/tracing.cc
index e2d931c..a0ab7b2 100644
--- a/src/tracing/tracing.cc
+++ b/src/tracing/tracing.cc
@@ -20,7 +20,7 @@
#include <condition_variable>
#include <mutex>
-#include "include/perfetto/base/time.h"
+#include "perfetto/base/time.h"
#include "perfetto/ext/base/no_destructor.h"
#include "perfetto/ext/base/waitable_event.h"
#include "perfetto/tracing/internal/track_event_internal.h"
diff --git a/test/data/statsd_atoms_oem.pb.sha256 b/test/data/statsd_atoms_oem.pb.sha256
new file mode 100644
index 0000000..9ab0459
--- /dev/null
+++ b/test/data/statsd_atoms_oem.pb.sha256
@@ -0,0 +1 @@
+5c38eaf8133ca06b1e9ab800c54430ac4807c98aa4684be3da48c56175bca679
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-android_trace_30s_expand_camera.png.sha256 b/test/data/ui-screenshots/ui-android_trace_30s_expand_camera.png.sha256
index e5e8fa3..a022411 100644
--- a/test/data/ui-screenshots/ui-android_trace_30s_expand_camera.png.sha256
+++ b/test/data/ui-screenshots/ui-android_trace_30s_expand_camera.png.sha256
@@ -1 +1 @@
-041ebd18b8b3f62f76b1613f548c8cf8ea5660f818b4ecfab787c4b08fd55b50
\ No newline at end of file
+35d52b18e2dd2805641fbfa121a66f62a0c602418a46926f5f61ddce91d450f8
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-android_trace_30s_load.png.sha256 b/test/data/ui-screenshots/ui-android_trace_30s_load.png.sha256
index 6cee1b2..9ed3863 100644
--- a/test/data/ui-screenshots/ui-android_trace_30s_load.png.sha256
+++ b/test/data/ui-screenshots/ui-android_trace_30s_load.png.sha256
@@ -1 +1 @@
-ec0a00856b147b2e13d0fe18666a307eb085ac437d67f78787131d4ea4190581
\ No newline at end of file
+2d29987562fb3b106e0f1794d2cb341c72a4a51fb5d94bf347048bbe198b7302
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-chrome_missing_track_names_load.png.sha256 b/test/data/ui-screenshots/ui-chrome_missing_track_names_load.png.sha256
index 6e1e7b7..d8f53e7 100644
--- a/test/data/ui-screenshots/ui-chrome_missing_track_names_load.png.sha256
+++ b/test/data/ui-screenshots/ui-chrome_missing_track_names_load.png.sha256
@@ -1 +1 @@
-875e17941e1dd5c362eef4bc679af41db5a9b2e37bbde5e5b2d1e90fd54b9e28
\ No newline at end of file
+a4b1867255b838c3ab73f6d00c84aa5bd7fc31bb53da5b83f52ceb84d99e96b2
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-chrome_rendering_desktop_expand_browser_proc.png.sha256 b/test/data/ui-screenshots/ui-chrome_rendering_desktop_expand_browser_proc.png.sha256
index 9203ad1..6cbb409 100644
--- a/test/data/ui-screenshots/ui-chrome_rendering_desktop_expand_browser_proc.png.sha256
+++ b/test/data/ui-screenshots/ui-chrome_rendering_desktop_expand_browser_proc.png.sha256
@@ -1 +1 @@
-1d185424a99b85372cecac21728fbf782fe33abf6a0664791ad08a3902bcdc3e
\ No newline at end of file
+ec9873453c3834735d55eb21138bf510069cf863342509a799076d821a8f01dd
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-chrome_rendering_desktop_load.png.sha256 b/test/data/ui-screenshots/ui-chrome_rendering_desktop_load.png.sha256
index 64e5c99..6667e5f 100644
--- a/test/data/ui-screenshots/ui-chrome_rendering_desktop_load.png.sha256
+++ b/test/data/ui-screenshots/ui-chrome_rendering_desktop_load.png.sha256
@@ -1 +1 @@
-1ae776d7033331f560685bfd61aa83a8a3f9639a400150bfe7be19642be3855a
\ No newline at end of file
+351edcf1ade9e6b1b7ced9d4f204e9a939370b7a56066f66793e56c9d93ec972
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-chrome_rendering_desktop_select_slice_with_flows.png.sha256 b/test/data/ui-screenshots/ui-chrome_rendering_desktop_select_slice_with_flows.png.sha256
index 7481c80..ea7e6de 100644
--- a/test/data/ui-screenshots/ui-chrome_rendering_desktop_select_slice_with_flows.png.sha256
+++ b/test/data/ui-screenshots/ui-chrome_rendering_desktop_select_slice_with_flows.png.sha256
@@ -1 +1 @@
-1fa69f1c7b6098b1e7ab944f4900a3b52984522e18ce94a6c68f8c46c6c06154
\ No newline at end of file
+d9f429e9adad0ce321ab12dbdd062a9a8661c6dc3b6357646bcad5910a215407
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-modal_dialog_dismiss_1.png.sha256 b/test/data/ui-screenshots/ui-modal_dialog_dismiss_1.png.sha256
index 9b5f546..108417f 100644
--- a/test/data/ui-screenshots/ui-modal_dialog_dismiss_1.png.sha256
+++ b/test/data/ui-screenshots/ui-modal_dialog_dismiss_1.png.sha256
@@ -1 +1 @@
-846bdc1f6e20082da46d483049322300d91cb38ef72f922c934d46cc5df3507d
\ No newline at end of file
+9605f5ae3dbcb6555520046a73ea276c27601dd74235454af797544097015b19
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-modal_dialog_dismiss_2.png.sha256 b/test/data/ui-screenshots/ui-modal_dialog_dismiss_2.png.sha256
index 6710525..0f29bad 100644
--- a/test/data/ui-screenshots/ui-modal_dialog_dismiss_2.png.sha256
+++ b/test/data/ui-screenshots/ui-modal_dialog_dismiss_2.png.sha256
@@ -1 +1 @@
-5f6f302958f0b26df40b90740bd8786480d7e8aa89232baa4fe2d881c070ba3c
\ No newline at end of file
+c7bb5ef50e96b3bdd96d684cbc65025e60ff9dd3281b220e4b99e07c2a896afe
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-modal_dialog_show_dialog_1.png.sha256 b/test/data/ui-screenshots/ui-modal_dialog_show_dialog_1.png.sha256
index e138b33..1672234 100644
--- a/test/data/ui-screenshots/ui-modal_dialog_show_dialog_1.png.sha256
+++ b/test/data/ui-screenshots/ui-modal_dialog_show_dialog_1.png.sha256
@@ -1 +1 @@
-1dd5883861cff0c03811e5e97c479097771b8ab6ee97b5320593eb5f850c9a25
\ No newline at end of file
+df3d897c8b07ef8707df034e264fea6d32d391ea0d42abdf9349614fa5e57b44
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-modal_dialog_show_dialog_2.png.sha256 b/test/data/ui-screenshots/ui-modal_dialog_show_dialog_2.png.sha256
index 5aee346..89f4d6f 100644
--- a/test/data/ui-screenshots/ui-modal_dialog_show_dialog_2.png.sha256
+++ b/test/data/ui-screenshots/ui-modal_dialog_show_dialog_2.png.sha256
@@ -1 +1 @@
-f93e24fcd03c2f69570c4a01bc8df04b05260b35983d479ab24f7b912ebccd4d
\ No newline at end of file
+8b1beeabcb5321575c4513eb8b572838e61513935098ddde3be368a9325b60f5
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-modal_dialog_switch_page_no_dialog.png.sha256 b/test/data/ui-screenshots/ui-modal_dialog_switch_page_no_dialog.png.sha256
index 38f1e1d..58840ee 100644
--- a/test/data/ui-screenshots/ui-modal_dialog_switch_page_no_dialog.png.sha256
+++ b/test/data/ui-screenshots/ui-modal_dialog_switch_page_no_dialog.png.sha256
@@ -1 +1 @@
-cf12d662d4137c081875afbb1c508827c9430e2837013bd917acd6eaadfac37c
\ No newline at end of file
+b9146d41d92c3e164adb9ada4ed0b384f225220ef458a70c152a14c6bd29aef3
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_navigate_navigate_back_and_forward.png.sha256 b/test/data/ui-screenshots/ui-routing_navigate_navigate_back_and_forward.png.sha256
index 895dc82..be09ae5 100644
--- a/test/data/ui-screenshots/ui-routing_navigate_navigate_back_and_forward.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_navigate_navigate_back_and_forward.png.sha256
@@ -1 +1 @@
-177e27d4d86bee1a17fce48d651b160f1541434aeb0f9e8fc1bac2b8fb07ac6d
\ No newline at end of file
+b9f04ac7c1d9bc25023a22bd2e6d79c48cf44ac62da30db9454f3e367dc9a824
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_navigate_open_trace_from_url.png.sha256 b/test/data/ui-screenshots/ui-routing_navigate_open_trace_from_url.png.sha256
index 5294534..92f9c01 100644
--- a/test/data/ui-screenshots/ui-routing_navigate_open_trace_from_url.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_navigate_open_trace_from_url.png.sha256
@@ -1 +1 @@
-c099f4ab43ee73de87c83ca2bb8cd2c087abdb12512ca3855e5cb6e5203e378b
\ No newline at end of file
+1bcbdbf6d1c2c1c2e77faa90be1c060b350f21472f67aed9477e6ba5e5219e81
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_open_invalid_trace_from_blank_page.png.sha256 b/test/data/ui-screenshots/ui-routing_open_invalid_trace_from_blank_page.png.sha256
index 766073d..88676c9 100644
--- a/test/data/ui-screenshots/ui-routing_open_invalid_trace_from_blank_page.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_open_invalid_trace_from_blank_page.png.sha256
@@ -1 +1 @@
-133e44411f05ea57299a67258d307ec06d381c2852143bf012059365fd2a7716
\ No newline at end of file
+5192001c1342677f7aebade9574bd9de5622c004d88d1a2a4a9453e35a376b16
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_open_trace_and_go_back_to_landing_page.png.sha256 b/test/data/ui-screenshots/ui-routing_open_trace_and_go_back_to_landing_page.png.sha256
index b0f92e9..657b6fe 100644
--- a/test/data/ui-screenshots/ui-routing_open_trace_and_go_back_to_landing_page.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_open_trace_and_go_back_to_landing_page.png.sha256
@@ -1 +1 @@
-3c80ba72b9bd0454af4aac3352c4e8f855f48feeba53d2a5ac7566333b4cf763
\ No newline at end of file
+1f40c5a9cfbd5e7eb6f8536fb7e51a95b2863443e0774d394716c97de2fa4b05
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_access_subpage_then_go_back.png.sha256 b/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_access_subpage_then_go_back.png.sha256
index 33f95ef..ff33850 100644
--- a/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_access_subpage_then_go_back.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_access_subpage_then_go_back.png.sha256
@@ -1 +1 @@
-7506ad1268c6d92743d19f52d37a1e8b7cf00fc7907bf9e3e06966dbbb1b40c1
\ No newline at end of file
+7d8429af94229b4cb96f3e7691e987b4eb0ade9683acce9a2c14c41777415d73
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_open_first_trace_from_url.png.sha256 b/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_open_first_trace_from_url.png.sha256
index 5294534..92f9c01 100644
--- a/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_open_first_trace_from_url.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_open_first_trace_from_url.png.sha256
@@ -1 +1 @@
-c099f4ab43ee73de87c83ca2bb8cd2c087abdb12512ca3855e5cb6e5203e378b
\ No newline at end of file
+1bcbdbf6d1c2c1c2e77faa90be1c060b350f21472f67aed9477e6ba5e5219e81
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_open_second_trace_from_url.png.sha256 b/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_open_second_trace_from_url.png.sha256
index 33f95ef..ff33850 100644
--- a/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_open_second_trace_from_url.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_open_second_trace_from_url.png.sha256
@@ -1 +1 @@
-7506ad1268c6d92743d19f52d37a1e8b7cf00fc7907bf9e3e06966dbbb1b40c1
\ No newline at end of file
+7d8429af94229b4cb96f3e7691e987b4eb0ade9683acce9a2c14c41777415d73
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_start_from_no_trace_go_back_to_first_trace.png.sha256 b/test/data/ui-screenshots/ui-routing_start_from_no_trace_go_back_to_first_trace.png.sha256
index 33f95ef..ff33850 100644
--- a/test/data/ui-screenshots/ui-routing_start_from_no_trace_go_back_to_first_trace.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_start_from_no_trace_go_back_to_first_trace.png.sha256
@@ -1 +1 @@
-7506ad1268c6d92743d19f52d37a1e8b7cf00fc7907bf9e3e06966dbbb1b40c1
\ No newline at end of file
+7d8429af94229b4cb96f3e7691e987b4eb0ade9683acce9a2c14c41777415d73
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_start_from_no_trace_go_to_page_with_no_trace.png.sha256 b/test/data/ui-screenshots/ui-routing_start_from_no_trace_go_to_page_with_no_trace.png.sha256
index 22444d8..0aacaa4 100644
--- a/test/data/ui-screenshots/ui-routing_start_from_no_trace_go_to_page_with_no_trace.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_start_from_no_trace_go_to_page_with_no_trace.png.sha256
@@ -1 +1 @@
-52be49df180c482cad1a48979ce0bb2d20a7cdd27ad10cb972b5bad61b9865ca
\ No newline at end of file
+539226bd5412f6f573473f91ae2fc6edda026744c143bdc4b027a069094de96f
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_start_from_no_trace_open_invalid_trace.png.sha256 b/test/data/ui-screenshots/ui-routing_start_from_no_trace_open_invalid_trace.png.sha256
index 5949d49..f8f7010 100644
--- a/test/data/ui-screenshots/ui-routing_start_from_no_trace_open_invalid_trace.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_start_from_no_trace_open_invalid_trace.png.sha256
@@ -1 +1 @@
-f650a9a968e978dfa37f900cc5509bdc9118e8f3c74197164982285acde6149f
\ No newline at end of file
+428b6a704a5c68df10bc6543112ed9e1c367abf07219c50ceaa8989421f3b373
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_start_from_no_trace_open_second_trace.png.sha256 b/test/data/ui-screenshots/ui-routing_start_from_no_trace_open_second_trace.png.sha256
index 5294534..92f9c01 100644
--- a/test/data/ui-screenshots/ui-routing_start_from_no_trace_open_second_trace.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_start_from_no_trace_open_second_trace.png.sha256
@@ -1 +1 @@
-c099f4ab43ee73de87c83ca2bb8cd2c087abdb12512ca3855e5cb6e5203e378b
\ No newline at end of file
+1bcbdbf6d1c2c1c2e77faa90be1c060b350f21472f67aed9477e6ba5e5219e81
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_start_from_no_trace_open_trace_.png.sha256 b/test/data/ui-screenshots/ui-routing_start_from_no_trace_open_trace_.png.sha256
index 33f95ef..ff33850 100644
--- a/test/data/ui-screenshots/ui-routing_start_from_no_trace_open_trace_.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_start_from_no_trace_open_trace_.png.sha256
@@ -1 +1 @@
-7506ad1268c6d92743d19f52d37a1e8b7cf00fc7907bf9e3e06966dbbb1b40c1
\ No newline at end of file
+7d8429af94229b4cb96f3e7691e987b4eb0ade9683acce9a2c14c41777415d73
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_start_from_no_trace_refresh.png.sha256 b/test/data/ui-screenshots/ui-routing_start_from_no_trace_refresh.png.sha256
index 33f95ef..ff33850 100644
--- a/test/data/ui-screenshots/ui-routing_start_from_no_trace_refresh.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_start_from_no_trace_refresh.png.sha256
@@ -1 +1 @@
-7506ad1268c6d92743d19f52d37a1e8b7cf00fc7907bf9e3e06966dbbb1b40c1
\ No newline at end of file
+7d8429af94229b4cb96f3e7691e987b4eb0ade9683acce9a2c14c41777415d73
\ No newline at end of file
diff --git a/test/synth_common.py b/test/synth_common.py
index a239fa9..d9970c9 100644
--- a/test/synth_common.py
+++ b/test/synth_common.py
@@ -763,11 +763,19 @@
event.pid = pid
event.layer_name = layer_name
- def add_actual_surface_frame_start_event(self, ts, cookie, token,
- display_frame_token, pid, layer_name,
- present_type, on_time_finish,
- gpu_composition, jank_type,
- prediction_type):
+ def add_actual_surface_frame_start_event(self,
+ ts,
+ cookie,
+ token,
+ display_frame_token,
+ pid,
+ layer_name,
+ present_type,
+ on_time_finish,
+ gpu_composition,
+ jank_type,
+ prediction_type,
+ jank_severity_type=None):
packet = self.add_packet()
packet.timestamp = ts
event = packet.frame_timeline_event.actual_surface_frame_start
@@ -781,6 +789,12 @@
event.on_time_finish = on_time_finish
event.gpu_composition = gpu_composition
event.jank_type = jank_type
+ # jank severity type is not available on every trace.
+ # When not set, default to none if no jank; otherwise default to unknown
+ if jank_severity_type is None:
+ event.jank_severity_type = 1 if event.jank_type == 1 else 0
+ else:
+ event.jank_severity_type = jank_severity_type
event.prediction_type = prediction_type
def add_frame_end_event(self, ts, cookie):
diff --git a/test/trace_processor/diff_tests/parser/graphics/actual_frame_timeline_events_test.sql b/test/trace_processor/diff_tests/parser/graphics/actual_frame_timeline_events_test.sql
index a46f6aa..269523c 100644
--- a/test/trace_processor/diff_tests/parser/graphics/actual_frame_timeline_events_test.sql
+++ b/test/trace_processor/diff_tests/parser/graphics/actual_frame_timeline_events_test.sql
@@ -13,8 +13,8 @@
-- See the License for the specific language governing permissions and
-- limitations under the License.
-SELECT ts, dur, process.pid AS pid, display_frame_token, surface_frame_token, layer_name,
- present_type, on_time_finish, gpu_composition, jank_type, prediction_type, jank_tag
+SELECT ts, dur, process.pid, display_frame_token, surface_frame_token, layer_name,
+ present_type, on_time_finish, gpu_composition, jank_type, prediction_type, jank_tag, jank_severity_type
FROM
(SELECT t.*, process_track.name AS track_name FROM
process_track LEFT JOIN actual_frame_timeline_slice t
diff --git a/test/trace_processor/diff_tests/parser/graphics/frame_timeline_events.py b/test/trace_processor/diff_tests/parser/graphics/frame_timeline_events.py
index 91590fb..90bae3a 100644
--- a/test/trace_processor/diff_tests/parser/graphics/frame_timeline_events.py
+++ b/test/trace_processor/diff_tests/parser/graphics/frame_timeline_events.py
@@ -33,6 +33,13 @@
JANK_DROPPED = 1024
+class JankSeverityType:
+ UNKNOWN = 0
+ NONE = 1
+ PARTIAL = 2
+ FULL = 3
+
+
class PresentType:
PRESENT_UNSPECIFIED = 0
PRESENT_ON_TIME = 1
@@ -135,6 +142,7 @@
on_time_finish=0,
gpu_composition=0,
jank_type=JankType.JANK_APP_DEADLINE_MISSED,
+ jank_severity_type=JankSeverityType.FULL,
prediction_type=PredictionType.PREDICTION_VALID)
trace.add_frame_end_event(ts=74, cookie=10)
@@ -276,6 +284,7 @@
on_time_finish=0,
gpu_composition=0,
jank_type=JankType.JANK_UNKNOWN,
+ jank_severity_type=JankSeverityType.PARTIAL,
prediction_type=PredictionType.PREDICTION_EXPIRED)
trace.add_frame_end_event(ts=190, cookie=25)
diff --git a/test/trace_processor/diff_tests/parser/graphics/tests.py b/test/trace_processor/diff_tests/parser/graphics/tests.py
index 3a2bf84..7fe4af1 100644
--- a/test/trace_processor/diff_tests/parser/graphics/tests.py
+++ b/test/trace_processor/diff_tests/parser/graphics/tests.py
@@ -110,22 +110,22 @@
trace=Path('frame_timeline_events.py'),
query=Path('actual_frame_timeline_events_test.sql'),
out=Csv("""
- "ts","dur","pid","display_frame_token","surface_frame_token","layer_name","present_type","on_time_finish","gpu_composition","jank_type","prediction_type","jank_tag"
- 20,6,666,2,0,"[NULL]","On-time Present",1,0,"None","Valid Prediction","No Jank"
- 21,16,1000,4,1,"Layer1","On-time Present",1,0,"None","Valid Prediction","No Jank"
- 41,33,1000,6,5,"Layer1","Late Present",0,0,"App Deadline Missed","Valid Prediction","Self Jank"
- 42,5,666,4,0,"[NULL]","On-time Present",1,0,"None","Valid Prediction","No Jank"
- 80,110,1000,17,16,"Layer1","Unknown Present",0,0,"Unknown Jank","Expired Prediction","Self Jank"
- 81,7,666,6,0,"[NULL]","On-time Present",1,0,"None","Valid Prediction","No Jank"
- 90,16,1000,8,7,"Layer1","Early Present",1,0,"SurfaceFlinger Scheduling","Valid Prediction","Other Jank"
- 108,4,666,8,0,"[NULL]","Early Present",1,0,"SurfaceFlinger Scheduling","Valid Prediction","Self Jank"
- 148,8,666,12,0,"[NULL]","Late Present",0,0,"SurfaceFlinger Scheduling, SurfaceFlinger CPU Deadline Missed","Valid Prediction","Self Jank"
- 150,17,1000,15,14,"Layer1","On-time Present",1,0,"None","Valid Prediction","No Jank"
- 150,17,1000,15,14,"Layer2","On-time Present",1,0,"None","Valid Prediction","No Jank"
- 170,6,666,15,0,"[NULL]","On-time Present",1,0,"None","Valid Prediction","No Jank"
- 200,6,666,17,0,"[NULL]","On-time Present",1,0,"None","Valid Prediction","No Jank"
- 245,-1,666,18,0,"[NULL]","Late Present",0,0,"SurfaceFlinger Stuffing","Valid Prediction","SurfaceFlinger Stuffing"
- 245,15,666,18,0,"[NULL]","Dropped Frame",0,0,"Dropped Frame","Unspecified Prediction","Dropped Frame"
+ "ts","dur","pid","display_frame_token","surface_frame_token","layer_name","present_type","on_time_finish","gpu_composition","jank_type","prediction_type","jank_tag","jank_severity_type"
+ 20,6,666,2,0,"[NULL]","On-time Present",1,0,"None","Valid Prediction","No Jank","None"
+ 21,16,1000,4,1,"Layer1","On-time Present",1,0,"None","Valid Prediction","No Jank","None"
+ 41,33,1000,6,5,"Layer1","Late Present",0,0,"App Deadline Missed","Valid Prediction","Self Jank","Full"
+ 42,5,666,4,0,"[NULL]","On-time Present",1,0,"None","Valid Prediction","No Jank","None"
+ 80,110,1000,17,16,"Layer1","Unknown Present",0,0,"Unknown Jank","Expired Prediction","Self Jank","Partial"
+ 81,7,666,6,0,"[NULL]","On-time Present",1,0,"None","Valid Prediction","No Jank","None"
+ 90,16,1000,8,7,"Layer1","Early Present",1,0,"SurfaceFlinger Scheduling","Valid Prediction","Other Jank","Unknown"
+ 108,4,666,8,0,"[NULL]","Early Present",1,0,"SurfaceFlinger Scheduling","Valid Prediction","Self Jank","Unknown"
+ 148,8,666,12,0,"[NULL]","Late Present",0,0,"SurfaceFlinger Scheduling, SurfaceFlinger CPU Deadline Missed","Valid Prediction","Self Jank","Unknown"
+ 150,17,1000,15,14,"Layer1","On-time Present",1,0,"None","Valid Prediction","No Jank","None"
+ 150,17,1000,15,14,"Layer2","On-time Present",1,0,"None","Valid Prediction","No Jank","None"
+ 170,6,666,15,0,"[NULL]","On-time Present",1,0,"None","Valid Prediction","No Jank","None"
+ 200,6,666,17,0,"[NULL]","On-time Present",1,0,"None","Valid Prediction","No Jank","None"
+ 245,-1,666,18,0,"[NULL]","Late Present",0,0,"SurfaceFlinger Stuffing","Valid Prediction","SurfaceFlinger Stuffing","Unknown"
+ 245,15,666,18,0,"[NULL]","Dropped Frame",0,0,"Dropped Frame","Unspecified Prediction","Dropped Frame","Unknown"
"""))
# Video 4 Linux 2 related tests
diff --git a/test/trace_processor/diff_tests/parser/parsing/tests.py b/test/trace_processor/diff_tests/parser/parsing/tests.py
index 5261b09..90067a7 100644
--- a/test/trace_processor/diff_tests/parser/parsing/tests.py
+++ b/test/trace_processor/diff_tests/parser/parsing/tests.py
@@ -1110,6 +1110,16 @@
query=Path('all_atoms_test.sql'),
out=Path('statsd_atoms_all_atoms.out'))
+ # Statsd Atoms
+ def test_statsd_atoms_unknown_atoms(self):
+ return DiffTestBlueprint(
+ trace=DataPath('statsd_atoms_oem.pb'),
+ query=Path('all_atoms_test.sql'),
+ out=Csv("""
+ "name","key","display_value"
+ "atom_202001","field_1","1"
+ """))
+
# Kernel function tracing.
def test_funcgraph_trace_funcgraph(self):
return DiffTestBlueprint(
diff --git a/test/trace_processor/diff_tests/stdlib/chrome/tests_scroll_jank.py b/test/trace_processor/diff_tests/stdlib/chrome/tests_scroll_jank.py
index b9d19fd..80b679c 100755
--- a/test/trace_processor/diff_tests/stdlib/chrome/tests_scroll_jank.py
+++ b/test/trace_processor/diff_tests/stdlib/chrome/tests_scroll_jank.py
@@ -105,6 +105,99 @@
1991,4687329240739,-28.999969,-175.999969
"""))
+ def test_chrome_janky_event_latencies_v3(self):
+ return DiffTestBlueprint(
+ trace=DataPath('chrome_input_with_frame_view.pftrace'),
+ query="""
+ INCLUDE PERFETTO MODULE chrome.scroll_jank.scroll_jank_intervals;
+
+ SELECT
+ id,
+ ts,
+ dur,
+ track_id,
+ name,
+ cause_of_jank,
+ sub_cause_of_jank,
+ delayed_frame_count,
+ frame_jank_ts,
+ frame_jank_dur
+ FROM chrome_janky_event_latencies_v3
+ ORDER by id;
+ """,
+ out=Csv("""
+ "id","ts","dur","track_id","name","cause_of_jank","sub_cause_of_jank","delayed_frame_count","frame_jank_ts","frame_jank_dur"
+ 29926,174795897267797,48088000,1431,"EventLatency","RendererCompositorQueueingDelay","[NULL]",1,174795928261797,17094000
+ 38463,174796315541797,131289000,2163,"EventLatency","RendererCompositorFinishedToBeginImplFrame","[NULL]",5,174796362924797,83906000
+ 88876,174799556245797,49856000,4329,"EventLatency","RendererCompositorQueueingDelay","[NULL]",1,174799589065797,17036000
+ """))
+
+ def test_chrome_janky_frame_presentation_intervals(self):
+ return DiffTestBlueprint(
+ trace=DataPath('chrome_input_with_frame_view.pftrace'),
+ query="""
+ INCLUDE PERFETTO MODULE chrome.scroll_jank.scroll_jank_intervals;
+
+ SELECT
+ id,
+ ts,
+ dur,
+ cause_of_jank,
+ sub_cause_of_jank,
+ delayed_frame_count,
+ event_latency_id
+ FROM chrome_janky_frame_presentation_intervals
+ ORDER by id;
+ """,
+ out=Csv("""
+ "id","ts","dur","cause_of_jank","sub_cause_of_jank","delayed_frame_count","event_latency_id"
+ 1,174795928261797,17094000,"RendererCompositorQueueingDelay","[NULL]",1,29926
+ 2,174796362924797,83906000,"RendererCompositorFinishedToBeginImplFrame","[NULL]",5,38463
+ 3,174799589065797,17036000,"RendererCompositorQueueingDelay","[NULL]",1,88876
+ """))
+
+ def test_chrome_scroll_stats(self):
+ return DiffTestBlueprint(
+ trace=DataPath('chrome_input_with_frame_view.pftrace'),
+ query="""
+ INCLUDE PERFETTO MODULE chrome.scroll_jank.scroll_jank_intervals;
+
+ SELECT
+ scroll_id,
+ missed_vsyncs,
+ frame_count,
+ presented_frame_count,
+ janky_frame_count,
+ janky_frame_percent
+ FROM chrome_scroll_stats
+ ORDER by scroll_id;
+ """,
+ out=Csv("""
+ "scroll_id","missed_vsyncs","frame_count","presented_frame_count","janky_frame_count","janky_frame_percent"
+ 1186,6,110,105,2,1.900000
+ 1889,"[NULL]",101,102,0,0.000000
+ 2506,1,84,84,1,1.190000
+ """))
+
+ def test_chrome_scroll_jank_intervals_v3(self):
+ return DiffTestBlueprint(
+ trace=DataPath('chrome_input_with_frame_view.pftrace'),
+ query="""
+ INCLUDE PERFETTO MODULE chrome.scroll_jank.scroll_jank_intervals;
+
+ SELECT
+ id,
+ ts,
+ dur
+ FROM chrome_scroll_jank_intervals_v3
+ ORDER by id;
+ """,
+ out=Csv("""
+ "id","ts","dur"
+ 1,174795928261797,17094000
+ 2,174796362924797,83906000
+ 3,174799589065797,17036000
+ """))
def test_chrome_presented_scroll_offsets(self):
return DiffTestBlueprint(
trace=DataPath('scroll_offsets.pftrace'),
diff --git a/test/trace_processor/diff_tests/tables/tests.py b/test/trace_processor/diff_tests/tables/tests.py
index 03c7eb0..5a8f393 100644
--- a/test/trace_processor/diff_tests/tables/tests.py
+++ b/test/trace_processor/diff_tests/tables/tests.py
@@ -356,3 +356,26 @@
0,"flow",0,1,57,0
1,"flow",1,2,57,0
"""))
+
+ def test_clock_snapshot_table_multiplier(self):
+ return DiffTestBlueprint(
+ trace=TextProto("""
+ packet {
+ clock_snapshot {
+ clocks {
+ clock_id: 1
+ timestamp: 42
+ unit_multiplier_ns: 10
+ }
+ clocks {
+ clock_id: 6
+ timestamp: 0
+ }
+ }
+ }
+ """),
+ query="SELECT TO_REALTIME(0);",
+ out=Csv("""
+ "TO_REALTIME(0)"
+ 420
+ """))
diff --git a/tools/cpu_profile b/tools/cpu_profile
index 166daff..9654a2a 100755
--- a/tools/cpu_profile
+++ b/tools/cpu_profile
@@ -37,18 +37,18 @@
# ----- Amalgamator: begin of python/perfetto/prebuilts/manifests/traceconv.py
-# This file has been generated by: tools/roll-prebuilts 6ba75cc5d93c39d4f86e2777709a460b30ce06fc
+# This file has been generated by: tools/roll-prebuilts v40.0
TRACECONV_MANIFEST = [{
'arch':
'mac-amd64',
'file_name':
'traceconv',
'file_size':
- 9020880,
+ 9184800,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/mac-amd64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/mac-amd64/traceconv',
'sha256':
- 'ae7903f9bb8a98b32fdf96c0124797cf9b4b58a9bcb45a05574d74d33b11ada9',
+ 'b651d0a5b5606c1c3e24723e94d8ecb233a01f0dfccc95a2c6a4e773cb8f52d7',
'platform':
'darwin',
'machine': ['x86_64']
@@ -58,11 +58,11 @@
'file_name':
'traceconv',
'file_size':
- 7580200,
+ 7761896,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/mac-arm64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/mac-arm64/traceconv',
'sha256':
- '619f31cd84a70fcb75e2a1cbe911f77feca0273ea0b1e706ae4be5ac020cdf7d',
+ '3b019f5ddd5293d3181f7c30f91dc7b08f3a2e83ebb3b52b8f3905dc5161747d',
'platform':
'darwin',
'machine': ['arm64']
@@ -72,11 +72,11 @@
'file_name':
'traceconv',
'file_size':
- 8773576,
+ 8928296,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/linux-amd64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/linux-amd64/traceconv',
'sha256':
- 'abc0b4191abe5106e1d4382bc0d238e53c39a83e1ba91237fbed5f789ef1c82b',
+ '830d20ffec266218d49f6b6c8efed4538bc59b51d8d2f735cbbb6a1435131b50',
'platform':
'linux',
'machine': ['x86_64']
@@ -86,11 +86,11 @@
'file_name':
'traceconv',
'file_size':
- 6620748,
+ 6770204,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/linux-arm/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/linux-arm/traceconv',
'sha256':
- 'f2dd9f1bfabea567ff20aedd0798e90093eff2bfdc15aacbfafe0abe52aa1fd1',
+ '93a9e5ccb94559b871af8f6da45f858aee01801b31776703892dcf3d7ea769b7',
'platform':
'linux',
'machine': ['armv6l', 'armv7l', 'armv8l']
@@ -100,11 +100,11 @@
'file_name':
'traceconv',
'file_size':
- 8240792,
+ 8393944,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/linux-arm64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/linux-arm64/traceconv',
'sha256':
- '76428eca01ced4b769241915fb5233b43b9b59e9062917e45d523db10f33e546',
+ '88a92ccbcd8e851673e018b7f599514daf05dde9b7e4de9641fa5629124abf12',
'platform':
'linux',
'machine': ['aarch64']
@@ -114,55 +114,55 @@
'file_name':
'traceconv',
'file_size':
- 6247672,
+ 6378744,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/android-arm/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/android-arm/traceconv',
'sha256':
- '3eb80bbd78c6210b73ef20654b9d80994747e552b3d342a8d2ec4aa58dabcc33'
+ '6cb7d30d656aa4f172e6724f105a56e249e7043ecf637c65e1e3868885535cff'
}, {
'arch':
'android-arm64',
'file_name':
'traceconv',
'file_size':
- 7545032,
+ 7692488,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/android-arm64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/android-arm64/traceconv',
'sha256':
- '30037aba74f7718f71273a83141373e623ddfe561294d01b41433dc9b572fee5'
+ '1668808efbdf8d5b116d4716d61d2bd002f71ce465206d3b83af4fcc7a4c19cd'
}, {
'arch':
'android-x86',
'file_name':
'traceconv',
'file_size':
- 8410300,
+ 8557756,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/android-x86/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/android-x86/traceconv',
'sha256':
- '9ad420368453699da12ce6359db514283e92b2caa2d415d9db61977cc79649a9'
+ '653733582cae0021eae0e1b5d8db387c1bae772d77b307f1e2111b78ec4ea67c'
}, {
'arch':
'android-x64',
'file_name':
'traceconv',
'file_size':
- 8544512,
+ 8708352,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/android-x64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/android-x64/traceconv',
'sha256':
- '60a62f8712186c5f984ff2fbc4ff8c47b6226b62a83b31f878e0597c8bb90cd8'
+ '7fc564ac581b81d79573f57dae027c47bd7a857ff0f89df984380c3c657d5876'
}, {
'arch':
'windows-amd64',
'file_name':
'traceconv.exe',
'file_size':
- 8049664,
+ 8204288,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/windows-amd64/traceconv.exe',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/windows-amd64/traceconv.exe',
'sha256':
- '9e89ccd0cdb466ea5fe960b71538b0ff8a2858b9e7ecdbcafa9ffe60839c9afc',
+ 'e33bad8061f08f9c3cfe6e91ef6f1696b6ac90d0799edcb57052f24888b436e2',
'platform':
'win32',
'machine': ['amd64']
diff --git a/tools/heap_profile b/tools/heap_profile
index 17155d8..77885fc 100755
--- a/tools/heap_profile
+++ b/tools/heap_profile
@@ -34,18 +34,18 @@
# ----- Amalgamator: begin of python/perfetto/prebuilts/manifests/traceconv.py
-# This file has been generated by: tools/roll-prebuilts 6ba75cc5d93c39d4f86e2777709a460b30ce06fc
+# This file has been generated by: tools/roll-prebuilts v40.0
TRACECONV_MANIFEST = [{
'arch':
'mac-amd64',
'file_name':
'traceconv',
'file_size':
- 9020880,
+ 9184800,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/mac-amd64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/mac-amd64/traceconv',
'sha256':
- 'ae7903f9bb8a98b32fdf96c0124797cf9b4b58a9bcb45a05574d74d33b11ada9',
+ 'b651d0a5b5606c1c3e24723e94d8ecb233a01f0dfccc95a2c6a4e773cb8f52d7',
'platform':
'darwin',
'machine': ['x86_64']
@@ -55,11 +55,11 @@
'file_name':
'traceconv',
'file_size':
- 7580200,
+ 7761896,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/mac-arm64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/mac-arm64/traceconv',
'sha256':
- '619f31cd84a70fcb75e2a1cbe911f77feca0273ea0b1e706ae4be5ac020cdf7d',
+ '3b019f5ddd5293d3181f7c30f91dc7b08f3a2e83ebb3b52b8f3905dc5161747d',
'platform':
'darwin',
'machine': ['arm64']
@@ -69,11 +69,11 @@
'file_name':
'traceconv',
'file_size':
- 8773576,
+ 8928296,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/linux-amd64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/linux-amd64/traceconv',
'sha256':
- 'abc0b4191abe5106e1d4382bc0d238e53c39a83e1ba91237fbed5f789ef1c82b',
+ '830d20ffec266218d49f6b6c8efed4538bc59b51d8d2f735cbbb6a1435131b50',
'platform':
'linux',
'machine': ['x86_64']
@@ -83,11 +83,11 @@
'file_name':
'traceconv',
'file_size':
- 6620748,
+ 6770204,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/linux-arm/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/linux-arm/traceconv',
'sha256':
- 'f2dd9f1bfabea567ff20aedd0798e90093eff2bfdc15aacbfafe0abe52aa1fd1',
+ '93a9e5ccb94559b871af8f6da45f858aee01801b31776703892dcf3d7ea769b7',
'platform':
'linux',
'machine': ['armv6l', 'armv7l', 'armv8l']
@@ -97,11 +97,11 @@
'file_name':
'traceconv',
'file_size':
- 8240792,
+ 8393944,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/linux-arm64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/linux-arm64/traceconv',
'sha256':
- '76428eca01ced4b769241915fb5233b43b9b59e9062917e45d523db10f33e546',
+ '88a92ccbcd8e851673e018b7f599514daf05dde9b7e4de9641fa5629124abf12',
'platform':
'linux',
'machine': ['aarch64']
@@ -111,55 +111,55 @@
'file_name':
'traceconv',
'file_size':
- 6247672,
+ 6378744,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/android-arm/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/android-arm/traceconv',
'sha256':
- '3eb80bbd78c6210b73ef20654b9d80994747e552b3d342a8d2ec4aa58dabcc33'
+ '6cb7d30d656aa4f172e6724f105a56e249e7043ecf637c65e1e3868885535cff'
}, {
'arch':
'android-arm64',
'file_name':
'traceconv',
'file_size':
- 7545032,
+ 7692488,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/android-arm64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/android-arm64/traceconv',
'sha256':
- '30037aba74f7718f71273a83141373e623ddfe561294d01b41433dc9b572fee5'
+ '1668808efbdf8d5b116d4716d61d2bd002f71ce465206d3b83af4fcc7a4c19cd'
}, {
'arch':
'android-x86',
'file_name':
'traceconv',
'file_size':
- 8410300,
+ 8557756,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/android-x86/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/android-x86/traceconv',
'sha256':
- '9ad420368453699da12ce6359db514283e92b2caa2d415d9db61977cc79649a9'
+ '653733582cae0021eae0e1b5d8db387c1bae772d77b307f1e2111b78ec4ea67c'
}, {
'arch':
'android-x64',
'file_name':
'traceconv',
'file_size':
- 8544512,
+ 8708352,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/android-x64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/android-x64/traceconv',
'sha256':
- '60a62f8712186c5f984ff2fbc4ff8c47b6226b62a83b31f878e0597c8bb90cd8'
+ '7fc564ac581b81d79573f57dae027c47bd7a857ff0f89df984380c3c657d5876'
}, {
'arch':
'windows-amd64',
'file_name':
'traceconv.exe',
'file_size':
- 8049664,
+ 8204288,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/windows-amd64/traceconv.exe',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/windows-amd64/traceconv.exe',
'sha256':
- '9e89ccd0cdb466ea5fe960b71538b0ff8a2858b9e7ecdbcafa9ffe60839c9afc',
+ 'e33bad8061f08f9c3cfe6e91ef6f1696b6ac90d0799edcb57052f24888b436e2',
'platform':
'win32',
'machine': ['amd64']
diff --git a/tools/open_trace_in_ui b/tools/open_trace_in_ui
index 30e4b01..0bf8ea7 100755
--- a/tools/open_trace_in_ui
+++ b/tools/open_trace_in_ui
@@ -63,7 +63,7 @@
fname = os.path.basename(path)
socketserver.TCPServer.allow_reuse_address = True
with socketserver.TCPServer(('127.0.0.1', PORT), HttpHandler) as httpd:
- address = f'{origin}/#!/?url=http://127.0.0.1:{PORT}/{fname}'
+ address = f'{origin}/#!/?url=http://127.0.0.1:{PORT}/{fname}&referrer=open_trace_in_ui'
if open_browser:
webbrowser.open_new_tab(address)
else:
diff --git a/tools/record_android_trace b/tools/record_android_trace
index d463dd9..d4a740a 100755
--- a/tools/record_android_trace
+++ b/tools/record_android_trace
@@ -33,18 +33,18 @@
# ----- Amalgamator: begin of python/perfetto/prebuilts/manifests/tracebox.py
-# This file has been generated by: tools/roll-prebuilts 6ba75cc5d93c39d4f86e2777709a460b30ce06fc
+# This file has been generated by: tools/roll-prebuilts v40.0
TRACEBOX_MANIFEST = [{
'arch':
'mac-amd64',
'file_name':
'tracebox',
'file_size':
- 1498680,
+ 1498816,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/mac-amd64/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/mac-amd64/tracebox',
'sha256':
- '57252aaf73b6a82cfb3bbc6cd68a9ec953f61296cf2c2d651125bb437dc50144',
+ '185014447d35357edbd20e7ce9924842a0d5c6576bd2257abae2ed48b65fd3b8',
'platform':
'darwin',
'machine': ['x86_64']
@@ -54,11 +54,11 @@
'file_name':
'tracebox',
'file_size':
- 1376136,
+ 1392776,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/mac-arm64/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/mac-arm64/tracebox',
'sha256':
- '5f37217af7d47b39624c62625847ec6b98db2ebd1a512e85921eb16bcb402b35',
+ '082bb50e64df5e232673eebb1cd8b0dd752a394105f600cb0262730833f6b7f3',
'platform':
'darwin',
'machine': ['arm64']
@@ -68,11 +68,11 @@
'file_name':
'tracebox',
'file_size':
- 2218840,
+ 2229096,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/linux-amd64/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/linux-amd64/tracebox',
'sha256':
- '89b1412e66b0a227cd8d16e6bf3d7416609c153d4b5c64d6e1a7c600870cd27b',
+ 'c99120caedb845e1c3fad4428263a683b44c357c76d65848dd8e437250066e38',
'platform':
'linux',
'machine': ['x86_64']
@@ -82,11 +82,11 @@
'file_name':
'tracebox',
'file_size':
- 1332292,
+ 1339796,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/linux-arm/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/linux-arm/tracebox',
'sha256':
- 'b5a3a8e0869b35bc9ceb06f3e4ca5bb6c1e1b1c5e6ea23cfed541e40a45ad96a',
+ '6732165916b74f0b820991d1aaed2086a6b56e91f6c604291efe6636f0bdda71',
'platform':
'linux',
'machine': ['armv6l', 'armv7l', 'armv8l']
@@ -96,11 +96,11 @@
'file_name':
'tracebox',
'file_size':
- 2147464,
+ 2157312,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/linux-arm64/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/linux-arm64/tracebox',
'sha256':
- '00fdbdfc5877352b9323b6ea1a119132b66e696941f380da117d0d47ae1baaf9',
+ '7d09865a6d7118e67d2acd0c56b2a94ce8bd5f614869d29a72fe633515ab1fbd',
'platform':
'linux',
'machine': ['aarch64']
@@ -110,11 +110,11 @@
'file_name':
'tracebox',
'file_size':
- 1230804,
+ 1247188,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/android-arm/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/android-arm/tracebox',
'sha256':
- '02ee157f995708e78f57d6e5e110054d2e2b407dbf2db120cc967c7c553081e7'
+ '4ecc192172ac2bca49557cbdbb1f7d660718d4fb4a7314fd19b2b2e52be8bc0c'
}, {
'arch':
'android-arm64',
@@ -123,9 +123,9 @@
'file_size':
1854120,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/android-arm64/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/android-arm64/tracebox',
'sha256':
- 'e0031963f623da25c387b78e20747e07829043732f5afe16cfdea9bad3c0f27c'
+ '1ca89113279d5c6a9ae273bde03b4d84373efe6923dc637cb840908f13b9639e'
}, {
'arch':
'android-x86',
@@ -134,9 +134,9 @@
'file_size':
1853356,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/android-x86/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/android-x86/tracebox',
'sha256':
- '6e9e4b7b0d3773ab5011e476eca883eeb0ab7538fc7d2cd4642b6abc01711ba9'
+ 'cf689a191c1252734ebbfda3106600da324610f761515cfbffbeac2ebdfee715'
}, {
'arch':
'android-x64',
@@ -145,9 +145,9 @@
'file_size':
2149032,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/android-x64/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/android-x64/tracebox',
'sha256':
- '4b494907a43e898047ce98271796464deb3010b6755cee8d9c8a6c341502979b'
+ '99e9ebdb5b5308d95551a4ad060d615d7defb6877c4061d21c783c45a71d372f'
}]
# ----- Amalgamator: end of python/perfetto/prebuilts/manifests/tracebox.py
@@ -718,7 +718,7 @@
fname = os.path.basename(path)
socketserver.TCPServer.allow_reuse_address = True
with socketserver.TCPServer(('127.0.0.1', PORT), HttpHandler) as httpd:
- address = f'{origin}/#!/?url=http://127.0.0.1:{PORT}/{fname}'
+ address = f'{origin}/#!/?url=http://127.0.0.1:{PORT}/{fname}&referrer=record_android_trace'
if open_browser:
webbrowser.open_new_tab(address)
else:
diff --git a/tools/trace_processor b/tools/trace_processor
index 6328084..60de377 100755
--- a/tools/trace_processor
+++ b/tools/trace_processor
@@ -30,18 +30,18 @@
# ----- Amalgamator: begin of python/perfetto/prebuilts/manifests/trace_processor_shell.py
-# This file has been generated by: tools/roll-prebuilts 6ba75cc5d93c39d4f86e2777709a460b30ce06fc
+# This file has been generated by: tools/roll-prebuilts v40.0
TRACE_PROCESSOR_SHELL_MANIFEST = [{
'arch':
'mac-amd64',
'file_name':
'trace_processor_shell',
'file_size':
- 9830664,
+ 9978200,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/mac-amd64/trace_processor_shell',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/mac-amd64/trace_processor_shell',
'sha256':
- 'd617f9237f77477a6e80065cbcfc84d6ce80505ee34851a0b435f0815aba2645',
+ 'f3e21eb29fb51cb2ea9b81b69132c5ae93ce3276c57ccd27fcf7c675306b4e41',
'platform':
'darwin',
'machine': ['x86_64']
@@ -51,11 +51,11 @@
'file_name':
'trace_processor_shell',
'file_size':
- 8328808,
+ 8493976,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/mac-arm64/trace_processor_shell',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/mac-arm64/trace_processor_shell',
'sha256':
- 'cc5b81618ddfa0a6eb63e0d418c0a52e302ca2617906fae6743d71f82c454611',
+ '84f35765141374b8d883813ac533e0c004cf72d1c6f05aef0c973364ff541eb9',
'platform':
'darwin',
'machine': ['arm64']
@@ -65,11 +65,11 @@
'file_name':
'trace_processor_shell',
'file_size':
- 9682088,
+ 9830856,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/linux-amd64/trace_processor_shell',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/linux-amd64/trace_processor_shell',
'sha256':
- '0beb26c1d744cb982630b23ce031a767d6ed7113b81dca0710f792111592ee9e',
+ 'b3dc0a9c641b84a57fa5d59637921ae2237e4f05b1778341a691df220faf0cd7',
'platform':
'linux',
'machine': ['x86_64']
@@ -79,11 +79,11 @@
'file_name':
'trace_processor_shell',
'file_size':
- 7087544,
+ 7231096,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/linux-arm/trace_processor_shell',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/linux-arm/trace_processor_shell',
'sha256':
- '4df289643b09261bd5718d6894e301023b4101e94e2dd81ead63037fb454054d',
+ 'a21252830fb1bbb7b3fd9665ce6e70920cffa6b1e72c16589c90896c002c3348',
'platform':
'linux',
'machine': ['armv6l', 'armv7l', 'armv8l']
@@ -93,11 +93,11 @@
'file_name':
'trace_processor_shell',
'file_size':
- 9090808,
+ 9238056,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/linux-arm64/trace_processor_shell',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/linux-arm64/trace_processor_shell',
'sha256':
- '9cb0ce22fba1929bef599d89a197a2ea718061840006c4122032cf0fc5fc0c90',
+ 'f77519ec19743ec2c22ed78fe3a20106a482a28d77c4154378af108c5f7bdd4a',
'platform':
'linux',
'machine': ['aarch64']
@@ -107,55 +107,55 @@
'file_name':
'trace_processor_shell',
'file_size':
- 6723512,
+ 6870968,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/android-arm/trace_processor_shell',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/android-arm/trace_processor_shell',
'sha256':
- 'c5949a736b1b5edb285f56c22e9af83e1d0ec6d331adaac77330a277d8bee07c'
+ '2c7055fb44085ec60ad8bb970d495c9c88070fce08902f11fcd44e0ae3369876'
}, {
'arch':
'android-arm64',
'file_name':
'trace_processor_shell',
'file_size':
- 8267112,
+ 8414568,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/android-arm64/trace_processor_shell',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/android-arm64/trace_processor_shell',
'sha256':
- '32475b5fe7e1af557eab0d898accb37c657bc4b2dd221135b55114e61bd8be39'
+ 'd8ca0dc2bab7ea604a6721f0ac0e2b433b43261f247c6c98c510dc17aafe5a72'
}, {
'arch':
'android-x86',
'file_name':
'trace_processor_shell',
'file_size':
- 9164668,
+ 9328508,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/android-x86/trace_processor_shell',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/android-x86/trace_processor_shell',
'sha256':
- '02aeff08c0c3e553c95c851401ade9aac6784ad2f19e312dabbb24801d02c0e5'
+ 'de6a6ea45769888e59a1678d37b6e355b27b834d34a0b9e4980a942d333b88cc'
}, {
'arch':
'android-x64',
'file_name':
'trace_processor_shell',
'file_size':
- 9430440,
+ 9577896,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/android-x64/trace_processor_shell',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/android-x64/trace_processor_shell',
'sha256':
- 'de75622f96f2551a7bbc28a0f063e0dfcc39241cd4fe09c39d0b2541d860a30a'
+ 'cd4b16c5f78a060934204737ba8b312e824ff7cc28f3732daf7d64e733a727f9'
}, {
'arch':
'windows-amd64',
'file_name':
'trace_processor_shell.exe',
'file_size':
- 9100288,
+ 9248256,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/windows-amd64/trace_processor_shell.exe',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/windows-amd64/trace_processor_shell.exe',
'sha256':
- 'f0065f1dfa3f8001959bf18f5cd30138aa58409e39a13ccdd52a1860384e34fb',
+ '26584b4bbab40f8b0ad991a869e7483f92d7223e1473b879a6ceafa49b76390a',
'platform':
'win32',
'machine': ['amd64']
diff --git a/tools/tracebox b/tools/tracebox
index df4911a..a4c278b 100755
--- a/tools/tracebox
+++ b/tools/tracebox
@@ -30,18 +30,18 @@
# ----- Amalgamator: begin of python/perfetto/prebuilts/manifests/tracebox.py
-# This file has been generated by: tools/roll-prebuilts 6ba75cc5d93c39d4f86e2777709a460b30ce06fc
+# This file has been generated by: tools/roll-prebuilts v40.0
TRACEBOX_MANIFEST = [{
'arch':
'mac-amd64',
'file_name':
'tracebox',
'file_size':
- 1498680,
+ 1498816,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/mac-amd64/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/mac-amd64/tracebox',
'sha256':
- '57252aaf73b6a82cfb3bbc6cd68a9ec953f61296cf2c2d651125bb437dc50144',
+ '185014447d35357edbd20e7ce9924842a0d5c6576bd2257abae2ed48b65fd3b8',
'platform':
'darwin',
'machine': ['x86_64']
@@ -51,11 +51,11 @@
'file_name':
'tracebox',
'file_size':
- 1376136,
+ 1392776,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/mac-arm64/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/mac-arm64/tracebox',
'sha256':
- '5f37217af7d47b39624c62625847ec6b98db2ebd1a512e85921eb16bcb402b35',
+ '082bb50e64df5e232673eebb1cd8b0dd752a394105f600cb0262730833f6b7f3',
'platform':
'darwin',
'machine': ['arm64']
@@ -65,11 +65,11 @@
'file_name':
'tracebox',
'file_size':
- 2218840,
+ 2229096,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/linux-amd64/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/linux-amd64/tracebox',
'sha256':
- '89b1412e66b0a227cd8d16e6bf3d7416609c153d4b5c64d6e1a7c600870cd27b',
+ 'c99120caedb845e1c3fad4428263a683b44c357c76d65848dd8e437250066e38',
'platform':
'linux',
'machine': ['x86_64']
@@ -79,11 +79,11 @@
'file_name':
'tracebox',
'file_size':
- 1332292,
+ 1339796,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/linux-arm/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/linux-arm/tracebox',
'sha256':
- 'b5a3a8e0869b35bc9ceb06f3e4ca5bb6c1e1b1c5e6ea23cfed541e40a45ad96a',
+ '6732165916b74f0b820991d1aaed2086a6b56e91f6c604291efe6636f0bdda71',
'platform':
'linux',
'machine': ['armv6l', 'armv7l', 'armv8l']
@@ -93,11 +93,11 @@
'file_name':
'tracebox',
'file_size':
- 2147464,
+ 2157312,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/linux-arm64/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/linux-arm64/tracebox',
'sha256':
- '00fdbdfc5877352b9323b6ea1a119132b66e696941f380da117d0d47ae1baaf9',
+ '7d09865a6d7118e67d2acd0c56b2a94ce8bd5f614869d29a72fe633515ab1fbd',
'platform':
'linux',
'machine': ['aarch64']
@@ -107,11 +107,11 @@
'file_name':
'tracebox',
'file_size':
- 1230804,
+ 1247188,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/android-arm/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/android-arm/tracebox',
'sha256':
- '02ee157f995708e78f57d6e5e110054d2e2b407dbf2db120cc967c7c553081e7'
+ '4ecc192172ac2bca49557cbdbb1f7d660718d4fb4a7314fd19b2b2e52be8bc0c'
}, {
'arch':
'android-arm64',
@@ -120,9 +120,9 @@
'file_size':
1854120,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/android-arm64/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/android-arm64/tracebox',
'sha256':
- 'e0031963f623da25c387b78e20747e07829043732f5afe16cfdea9bad3c0f27c'
+ '1ca89113279d5c6a9ae273bde03b4d84373efe6923dc637cb840908f13b9639e'
}, {
'arch':
'android-x86',
@@ -131,9 +131,9 @@
'file_size':
1853356,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/android-x86/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/android-x86/tracebox',
'sha256':
- '6e9e4b7b0d3773ab5011e476eca883eeb0ab7538fc7d2cd4642b6abc01711ba9'
+ 'cf689a191c1252734ebbfda3106600da324610f761515cfbffbeac2ebdfee715'
}, {
'arch':
'android-x64',
@@ -142,9 +142,9 @@
'file_size':
2149032,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/android-x64/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/android-x64/tracebox',
'sha256':
- '4b494907a43e898047ce98271796464deb3010b6755cee8d9c8a6c341502979b'
+ '99e9ebdb5b5308d95551a4ad060d615d7defb6877c4061d21c783c45a71d372f'
}]
# ----- Amalgamator: end of python/perfetto/prebuilts/manifests/tracebox.py
diff --git a/tools/traceconv b/tools/traceconv
index 5127ab5..0136e37 100755
--- a/tools/traceconv
+++ b/tools/traceconv
@@ -30,18 +30,18 @@
# ----- Amalgamator: begin of python/perfetto/prebuilts/manifests/traceconv.py
-# This file has been generated by: tools/roll-prebuilts 6ba75cc5d93c39d4f86e2777709a460b30ce06fc
+# This file has been generated by: tools/roll-prebuilts v40.0
TRACECONV_MANIFEST = [{
'arch':
'mac-amd64',
'file_name':
'traceconv',
'file_size':
- 9020880,
+ 9184800,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/mac-amd64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/mac-amd64/traceconv',
'sha256':
- 'ae7903f9bb8a98b32fdf96c0124797cf9b4b58a9bcb45a05574d74d33b11ada9',
+ 'b651d0a5b5606c1c3e24723e94d8ecb233a01f0dfccc95a2c6a4e773cb8f52d7',
'platform':
'darwin',
'machine': ['x86_64']
@@ -51,11 +51,11 @@
'file_name':
'traceconv',
'file_size':
- 7580200,
+ 7761896,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/mac-arm64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/mac-arm64/traceconv',
'sha256':
- '619f31cd84a70fcb75e2a1cbe911f77feca0273ea0b1e706ae4be5ac020cdf7d',
+ '3b019f5ddd5293d3181f7c30f91dc7b08f3a2e83ebb3b52b8f3905dc5161747d',
'platform':
'darwin',
'machine': ['arm64']
@@ -65,11 +65,11 @@
'file_name':
'traceconv',
'file_size':
- 8773576,
+ 8928296,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/linux-amd64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/linux-amd64/traceconv',
'sha256':
- 'abc0b4191abe5106e1d4382bc0d238e53c39a83e1ba91237fbed5f789ef1c82b',
+ '830d20ffec266218d49f6b6c8efed4538bc59b51d8d2f735cbbb6a1435131b50',
'platform':
'linux',
'machine': ['x86_64']
@@ -79,11 +79,11 @@
'file_name':
'traceconv',
'file_size':
- 6620748,
+ 6770204,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/linux-arm/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/linux-arm/traceconv',
'sha256':
- 'f2dd9f1bfabea567ff20aedd0798e90093eff2bfdc15aacbfafe0abe52aa1fd1',
+ '93a9e5ccb94559b871af8f6da45f858aee01801b31776703892dcf3d7ea769b7',
'platform':
'linux',
'machine': ['armv6l', 'armv7l', 'armv8l']
@@ -93,11 +93,11 @@
'file_name':
'traceconv',
'file_size':
- 8240792,
+ 8393944,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/linux-arm64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/linux-arm64/traceconv',
'sha256':
- '76428eca01ced4b769241915fb5233b43b9b59e9062917e45d523db10f33e546',
+ '88a92ccbcd8e851673e018b7f599514daf05dde9b7e4de9641fa5629124abf12',
'platform':
'linux',
'machine': ['aarch64']
@@ -107,55 +107,55 @@
'file_name':
'traceconv',
'file_size':
- 6247672,
+ 6378744,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/android-arm/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/android-arm/traceconv',
'sha256':
- '3eb80bbd78c6210b73ef20654b9d80994747e552b3d342a8d2ec4aa58dabcc33'
+ '6cb7d30d656aa4f172e6724f105a56e249e7043ecf637c65e1e3868885535cff'
}, {
'arch':
'android-arm64',
'file_name':
'traceconv',
'file_size':
- 7545032,
+ 7692488,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/android-arm64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/android-arm64/traceconv',
'sha256':
- '30037aba74f7718f71273a83141373e623ddfe561294d01b41433dc9b572fee5'
+ '1668808efbdf8d5b116d4716d61d2bd002f71ce465206d3b83af4fcc7a4c19cd'
}, {
'arch':
'android-x86',
'file_name':
'traceconv',
'file_size':
- 8410300,
+ 8557756,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/android-x86/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/android-x86/traceconv',
'sha256':
- '9ad420368453699da12ce6359db514283e92b2caa2d415d9db61977cc79649a9'
+ '653733582cae0021eae0e1b5d8db387c1bae772d77b307f1e2111b78ec4ea67c'
}, {
'arch':
'android-x64',
'file_name':
'traceconv',
'file_size':
- 8544512,
+ 8708352,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/android-x64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/android-x64/traceconv',
'sha256':
- '60a62f8712186c5f984ff2fbc4ff8c47b6226b62a83b31f878e0597c8bb90cd8'
+ '7fc564ac581b81d79573f57dae027c47bd7a857ff0f89df984380c3c657d5876'
}, {
'arch':
'windows-amd64',
'file_name':
'traceconv.exe',
'file_size':
- 8049664,
+ 8204288,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/6ba75cc5d93c39d4f86e2777709a460b30ce06fc/windows-amd64/traceconv.exe',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v40.0/windows-amd64/traceconv.exe',
'sha256':
- '9e89ccd0cdb466ea5fe960b71538b0ff8a2858b9e7ecdbcafa9ffe60839c9afc',
+ 'e33bad8061f08f9c3cfe6e91ef6f1696b6ac90d0799edcb57052f24888b436e2',
'platform':
'win32',
'machine': ['amd64']
diff --git a/tools/update-statsd-descriptor b/tools/update-statsd-descriptor
index fe9ff0e..eca6c02 100755
--- a/tools/update-statsd-descriptor
+++ b/tools/update-statsd-descriptor
@@ -21,6 +21,7 @@
import tempfile
import contextlib
import argparse
+import itertools
ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
TOOLS_DIR = os.path.join(ROOT_DIR, "tools")
@@ -34,8 +35,10 @@
PROTO_LOGGING_URL = "https://android.googlesource.com/platform/frameworks/proto_logging.git"
ATOM_RE = r" message_type {\n. name: \"Atom\"(\n .+)+(\n })"
FIELD_RE = r" field {\n name: \"([^\"]+)\"\n number: ([0-9]+)"
+EXTENSIONS_RE = r" extension {\n name: \"([^\"]+)\"\n extendee: \".android.os.statsd.Atom\"\n number: ([0-9]+)(\n .+)+(\n })"
ATOM_IDS_PATH = os.path.join(ROOT_DIR, "protos", "perfetto", "config", "statsd",
"atom_ids.proto")
+
ATOM_IDS_TEMPLATE = """/*
* Copyright (C) 2022 The Android Open Source Project
*
@@ -75,6 +78,31 @@
exit(1)
+# Extract core atoms. To do this we regex the pbtext
+# of the descriptor. This is hopefully:
+# - more stable than regexing atom.proto directly
+# - less complicated than parsing finding, importing, and using the
+# Python protobuf library.
+def atoms_from_descriptor():
+ with contextlib.ExitStack() as stack:
+ descriptor_in = stack.enter_context(open(DESCRIPTOR_PATH))
+ pbtext = call(
+ PROTOC_PATH,
+ f"--proto_path={PROTOBUF_BUILTINS_DIR}",
+ f"{PROTOBUF_BUILTINS_DIR}/google/protobuf/descriptor.proto",
+ "--decode=google.protobuf.FileDescriptorSet",
+ stdin=descriptor_in).decode("utf8")
+
+ # Core atoms:
+ atom_pbtext = re.search(ATOM_RE, pbtext, re.MULTILINE)[0]
+ for m in re.finditer(FIELD_RE, atom_pbtext):
+ yield m[1], m[2]
+
+ # Extensions
+ for m in re.finditer(EXTENSIONS_RE, pbtext):
+ yield m[1], m[2]
+
+
def main():
parser = argparse.ArgumentParser()
parser.add_argument("--atoms-checkout")
@@ -97,31 +125,29 @@
pathlib.Path(proto_logging_dir).mkdir(parents=True, exist_ok=True)
call("git", "clone", PROTO_LOGGING_URL, proto_logging_dir)
- atoms_path = os.path.join(proto_logging_dir, "stats", "atoms.proto")
- call(PROTOC_PATH, f"--proto_path={PROTOBUF_BUILTINS_DIR}",
- f"--proto_path={atoms_root}",
- f"--descriptor_set_out={DESCRIPTOR_PATH}", "--include_imports",
- atoms_path)
- # Extract and update atom_ids.proto. To do this we regex the pbtext
- # of the descriptor. This is hopefully:
- # - more stable than regexing atom.proto directly
- # - less complicated than parsing finding, importing, and using the
- # Python protobuf library.
- descriptor_in = stack.enter_context(open(DESCRIPTOR_PATH))
- pbtext = call(
- PROTOC_PATH,
- f"--proto_path={PROTOBUF_BUILTINS_DIR}",
- f"{PROTOBUF_BUILTINS_DIR}/google/protobuf/descriptor.proto",
- "--decode=google.protobuf.FileDescriptorSet",
- stdin=descriptor_in)
+ extensions_path = os.path.join(proto_logging_dir, "stats", "atoms")
+ extensions = []
+ if os.path.isdir(extensions_path):
+ for dirpath, dirnames, filenames in os.walk(extensions_path):
+ for name in filenames:
+ if name.endswith(".proto"):
+ path = os.path.join(dirpath, name)
+ extensions.append(path)
- atom_pbtext = re.search(ATOM_RE, pbtext.decode("utf8"), re.MULTILINE)[0]
+ cmd = [
+ f"--proto_path={PROTOBUF_BUILTINS_DIR}",
+ f"--proto_path={atoms_root}",
+ f"--descriptor_set_out={DESCRIPTOR_PATH}",
+ "--include_imports",
+ ] + extensions + [
+ os.path.join(proto_logging_dir, "stats", "atoms.proto")
+ ]
+ call(PROTOC_PATH, *cmd)
lines = []
- for m in re.finditer(FIELD_RE, atom_pbtext):
- name = "ATOM_" + m[1].upper()
- field = m[2]
+ for name, field in atoms_from_descriptor():
+ name = "ATOM_" + name.upper()
lines.append(f" {name} = {field};".format(name=name, field=field))
atom_ids_out = stack.enter_context(open(ATOM_IDS_PATH, "w"))
atom_ids_out.write(ATOM_IDS_TEMPLATE.format(atoms="\n".join(lines)))
diff --git a/ui/build.js b/ui/build.js
index ba02879..4afe0cd 100644
--- a/ui/build.js
+++ b/ui/build.js
@@ -352,6 +352,9 @@
function copyAssets(src, dst) {
addTask(cp, [src, pjoin(cfg.outDistDir, 'assets', dst)]);
+ if (cfg.bigtrace) {
+ addTask(cp, [src, pjoin(cfg.outBigtraceDistDir, 'assets', dst)]);
+ }
}
function copyUiTestArtifactsAssets(src, dst) {
diff --git a/ui/release/channels.json b/ui/release/channels.json
index 8ee9b76..9ade987 100644
--- a/ui/release/channels.json
+++ b/ui/release/channels.json
@@ -2,7 +2,7 @@
"channels": [
{
"name": "stable",
- "rev": "c69b33b9abcc20fad9ad5f39de883216e4b43130"
+ "rev": "fa6ee75b6f4a9374ade506697c65a8a73edc54be"
},
{
"name": "canary",
diff --git a/ui/src/common/canvas_utils.ts b/ui/src/common/canvas_utils.ts
index 2d09617..ad78f96 100644
--- a/ui/src/common/canvas_utils.ts
+++ b/ui/src/common/canvas_utils.ts
@@ -75,7 +75,11 @@
x: number,
y: number,
width: number,
- height: number) {
+ height: number,
+ showGradient: boolean = true) {
+ if (width <= 0 || height <= 0) {
+ return;
+ }
ctx.beginPath();
const triangleSize = height / 4;
ctx.moveTo(x, y);
@@ -92,10 +96,12 @@
const fillStyle = ctx.fillStyle;
if (isString(fillStyle)) {
- const gradient = ctx.createLinearGradient(x, y, x + width, y + height);
- gradient.addColorStop(0.66, fillStyle);
- gradient.addColorStop(1, '#FFFFFF');
- ctx.fillStyle = gradient;
+ if (showGradient) {
+ const gradient = ctx.createLinearGradient(x, y, x + width, y + height);
+ gradient.addColorStop(0.66, fillStyle);
+ gradient.addColorStop(1, '#FFFFFF');
+ ctx.fillStyle = gradient;
+ }
} else {
throw new Error(
`drawIncompleteSlice() expects fillStyle to be a simple color not ${
diff --git a/ui/src/common/track_adapter.ts b/ui/src/common/track_adapter.ts
index 7514c5f..acc142d 100644
--- a/ui/src/common/track_adapter.ts
+++ b/ui/src/common/track_adapter.ts
@@ -22,7 +22,7 @@
import {SliceRect} from '../public';
import {EngineProxy} from '../trace_processor/engine';
-import {BasicAsyncTrack} from './basic_async_track';
+import {TrackHelperLEGACY} from './track_helper';
export {Store} from '../frontend/store';
export {EngineProxy} from '../trace_processor/engine';
@@ -38,7 +38,7 @@
// This is an adapter to convert old style controller based tracks to new style
// tracks.
export class TrackWithControllerAdapter<Config, Data> extends
- BasicAsyncTrack<Data> {
+ TrackHelperLEGACY<Data> {
private track: TrackAdapter<Config, Data>;
private controller: TrackControllerAdapter<Config, Data>;
private isSetup = false;
diff --git a/ui/src/common/basic_async_track.ts b/ui/src/common/track_helper.ts
similarity index 81%
rename from ui/src/common/basic_async_track.ts
rename to ui/src/common/track_helper.ts
index d5e0dda..114e2c9 100644
--- a/ui/src/common/basic_async_track.ts
+++ b/ui/src/common/track_helper.ts
@@ -33,12 +33,22 @@
STR_NULL,
} from '../trace_processor/query_result';
-// This shim track provides the base for async style tracks implementing the new
-// plugin track interface.
-// This provides the logic to perform data reloads at appropriate times as the
-// window is panned and zoomed about.
-// The extending class need only define renderCanvas() and onBoundsChange().
-export abstract class BasicAsyncTrack<Data> implements Track {
+// A helper class which provides a base track implementation for tracks which
+// load their content asynchronously from the trace.
+//
+// Tracks extending this base class need only define |renderCanvas()| and
+// |onBoundsChange()|. This helper provides sensible default implementations for
+// all the |Track| interface methods which subclasses may also choose to
+// override if necessary.
+//
+// This helper provides the logic to call |onBoundsChange()| only when more data
+// is needed as the visible window is panned and zoomed about, and includes an
+// FSM to ensure onBoundsChange is not re-entered, and that the track doesn't
+// render stale data.
+//
+// Note: This class is deprecated and should not be used for new tracks. Use
+// |BaseSliceTrack| instead.
+export abstract class TrackHelperLEGACY<Data> implements Track {
private requestingData = false;
private queuedRequest = false;
private currentState?: TrackData;
diff --git a/ui/src/controller/aggregation/frame_aggregation_controller.ts b/ui/src/controller/aggregation/frame_aggregation_controller.ts
index e51bde9..c45a40c 100644
--- a/ui/src/controller/aggregation/frame_aggregation_controller.ts
+++ b/ui/src/controller/aggregation/frame_aggregation_controller.ts
@@ -17,7 +17,7 @@
import {Area, Sorting} from '../../common/state';
import {globals} from '../../frontend/globals';
import {Engine} from '../../trace_processor/engine';
-import {ACTUAL_FRAMES_SLICE_TRACK_KIND} from '../../tracks/actual_frames';
+import {ACTUAL_FRAMES_SLICE_TRACK_KIND} from '../../tracks/frames';
import {AggregationController} from './aggregation_controller';
diff --git a/ui/src/controller/flow_events_controller.ts b/ui/src/controller/flow_events_controller.ts
index 89d870e..a7ad34c 100644
--- a/ui/src/controller/flow_events_controller.ts
+++ b/ui/src/controller/flow_events_controller.ts
@@ -21,8 +21,8 @@
import {asSliceSqlId} from '../frontend/sql_types';
import {Engine} from '../trace_processor/engine';
import {LONG, NUM, STR_NULL} from '../trace_processor/query_result';
-import {ACTUAL_FRAMES_SLICE_TRACK_KIND} from '../tracks/actual_frames';
import {SLICE_TRACK_KIND} from '../tracks/chrome_slices';
+import {ACTUAL_FRAMES_SLICE_TRACK_KIND} from '../tracks/frames';
import {Controller} from './controller';
diff --git a/ui/src/controller/track_decider.ts b/ui/src/controller/track_decider.ts
index 8c6433b..1df6bee 100644
--- a/ui/src/controller/track_decider.ts
+++ b/ui/src/controller/track_decider.ts
@@ -38,7 +38,6 @@
STR,
STR_NULL,
} from '../trace_processor/query_result';
-import {ACTUAL_FRAMES_SLICE_TRACK_KIND} from '../tracks/actual_frames';
import {ASYNC_SLICE_TRACK_KIND} from '../tracks/async_slices/async_slice_track';
import {
ENABLE_SCROLL_JANK_PLUGIN_V2,
@@ -49,7 +48,10 @@
} from '../tracks/chrome_scroll_jank/chrome_tasks_scroll_jank_track';
import {SLICE_TRACK_KIND} from '../tracks/chrome_slices';
import {COUNTER_TRACK_KIND} from '../tracks/counter';
-import {EXPECTED_FRAMES_SLICE_TRACK_KIND} from '../tracks/expected_frames';
+import {
+ ACTUAL_FRAMES_SLICE_TRACK_KIND,
+ EXPECTED_FRAMES_SLICE_TRACK_KIND,
+} from '../tracks/frames';
import {NULL_TRACK_URI} from '../tracks/null_track';
import {
decideTracks as screenshotDecideTracks,
@@ -60,7 +62,7 @@
id: 'tracksV2.1',
name: 'Tracks V2',
description: 'Show tracks built on top of the Track V2 API.',
- defaultValue: false,
+ defaultValue: true,
});
const TRACKS_V2_COMPARE_FLAG = featureFlags.register({
@@ -860,12 +862,13 @@
}
const priority = InThreadTrackSortKey.THREAD_SCHEDULING_STATE_TRACK;
+ const name =
+ getTrackName({utid, tid, threadName, kind: THREAD_STATE_TRACK_KIND});
if (showV1()) {
- const kind = THREAD_STATE_TRACK_KIND;
this.tracksToAdd.push({
uri: `perfetto.ThreadState#${upid}.${utid}`,
- name: getTrackName({utid, tid, threadName, kind}),
+ name,
trackGroup: uuid,
trackSortKey: {
utid,
@@ -877,8 +880,7 @@
if (showV2()) {
this.tracksToAdd.push({
uri: `perfetto.ThreadState#${utid}.v2`,
- name:
- getTrackName({utid, tid, threadName, kind: 'ThreadStateTrackV2'}),
+ name,
trackGroup: uuid,
trackSortKey: {
utid,
diff --git a/ui/src/frontend/analytics.ts b/ui/src/frontend/analytics.ts
index 8b01523..74c42fc 100644
--- a/ui/src/frontend/analytics.ts
+++ b/ui/src/frontend/analytics.ts
@@ -16,11 +16,25 @@
import {VERSION} from '../gen/perfetto_version';
import {globals} from './globals';
+import {Router} from './router';
type TraceCategories = 'Trace Actions'|'Record Trace'|'User Actions';
const ANALYTICS_ID = 'G-BD89KT2P3C';
const PAGE_TITLE = 'no-page-title';
+// Get the referrer from either:
+// - If present: the referrer argument if present
+// - document.referrer
+function getReferrer(): string {
+ const route = Router.parseUrl(window.location.href);
+ const referrer = route.args.referrer;
+ if (referrer) {
+ return referrer;
+ } else {
+ return document.referrer.split('?')[0];
+ }
+}
+
export function initAnalytics() {
// Only initialize logging on the official site and on localhost (to catch
// analytics bugs when testing locally).
@@ -95,14 +109,14 @@
console.log(
`GA initialized. route=${route}`,
`isInternalUser=${globals.isInternalUser}`);
- // GA's reccomendation for SPAs is to disable automatic page views and
+ // GA's recommendation for SPAs is to disable automatic page views and
// manually send page_view events. See:
// https://developers.google.com/analytics/devguides/collection/gtagjs/pages#manual_pageviews
gtagGlobals.gtag('config', ANALYTICS_ID, {
allow_google_signals: false,
anonymize_ip: true,
page_location: route,
- referrer: document.referrer.split('?')[0],
+ page_referrer: getReferrer(),
send_page_view: false,
page_title: PAGE_TITLE,
perfetto_is_internal_user: globals.isInternalUser ? '1' : '0',
diff --git a/ui/src/frontend/base_slice_track.ts b/ui/src/frontend/base_slice_track.ts
index c0c637e..2dbe0f2 100644
--- a/ui/src/frontend/base_slice_track.ts
+++ b/ui/src/frontend/base_slice_track.ts
@@ -41,6 +41,7 @@
import {PxSpan, TimeScale} from './time_scale';
import {NewTrackArgs, TrackBase} from './track';
import {BUCKETS_PER_PIXEL, CacheKey, TrackCache} from './track_cache';
+import {featureFlags} from '../core/feature_flags';
// The common class that underpins all tracks drawing slices.
@@ -52,6 +53,14 @@
const SLICE_MIN_WIDTH_PX = 1 / BUCKETS_PER_PIXEL;
const CHEVRON_WIDTH_PX = 10;
const DEFAULT_SLICE_COLOR = UNEXPECTED_PINK;
+const INCOMPLETE_SLICE_WIDTH_PX = 20;
+
+export const CROP_INCOMPLETE_SLICE_FLAG = featureFlags.register({
+ id: 'cropIncompleteSlice',
+ name: 'Crop incomplete Slice',
+ description: 'Display incomplete slice in short form',
+ defaultValue: false,
+});
// Exposed and standalone to allow for testing without making this
// visible to subclasses.
@@ -391,8 +400,16 @@
slice.x -= CHEVRON_WIDTH_PX / 2;
slice.w = CHEVRON_WIDTH_PX;
} else if (slice.flags & SLICE_FLAGS_INCOMPLETE) {
- slice.x = Math.max(slice.x, 0);
- slice.w = pxEnd - slice.x;
+ let widthPx;
+ if (CROP_INCOMPLETE_SLICE_FLAG.get()) {
+ widthPx = slice.x > 0 ? Math.min(pxEnd, INCOMPLETE_SLICE_WIDTH_PX) :
+ Math.max(0, INCOMPLETE_SLICE_WIDTH_PX + slice.x);
+ slice.x = Math.max(slice.x, 0);
+ } else {
+ slice.x = Math.max(slice.x, 0);
+ widthPx = pxEnd - slice.x;
+ }
+ slice.w = widthPx;
} else {
// If the slice is an actual slice, intersect the slice geometry with
// the visible viewport (this affects only the first and last slice).
@@ -429,8 +446,10 @@
if (slice.flags & SLICE_FLAGS_INSTANT) {
this.drawChevron(ctx, slice.x, y, sliceHeight);
} else if (slice.flags & SLICE_FLAGS_INCOMPLETE) {
- const w = Math.max(slice.w - 2, 2);
- drawIncompleteSlice(ctx, slice.x, y, w, sliceHeight);
+ const w = CROP_INCOMPLETE_SLICE_FLAG.get() ? slice.w :
+ Math.max(slice.w - 2, 2);
+ drawIncompleteSlice(
+ ctx, slice.x, y, w, sliceHeight, !CROP_INCOMPLETE_SLICE_FLAG.get());
} else {
const w = Math.max(slice.w, SLICE_MIN_WIDTH_PX);
ctx.fillRect(slice.x, y, w, sliceHeight);
@@ -798,7 +817,15 @@
}
for (const slice of this.incomplete) {
- if (slice.depth === depth && slice.x <= x) {
+ const visibleTimeScale = globals.frontendLocalState.visibleTimeScale;
+ const startPx = CROP_INCOMPLETE_SLICE_FLAG.get() ?
+ visibleTimeScale.timeToPx(slice.startNsQ) :
+ slice.x;
+ const cropUnfinishedSlicesCondition = CROP_INCOMPLETE_SLICE_FLAG.get() ?
+ startPx + INCOMPLETE_SLICE_WIDTH_PX >= x : true;
+
+ if (slice.depth === depth && startPx <= x &&
+ cropUnfinishedSlicesCondition) {
return slice;
}
}
diff --git a/ui/src/frontend/chrome_slice_details_tab.ts b/ui/src/frontend/chrome_slice_details_tab.ts
index 7f83b36..5311cb2 100644
--- a/ui/src/frontend/chrome_slice_details_tab.ts
+++ b/ui/src/frontend/chrome_slice_details_tab.ts
@@ -35,7 +35,7 @@
NewBottomTabArgs,
} from './bottom_tab';
import {FlowPoint, globals} from './globals';
-import {renderArguments} from './slice_args';
+import {hasArgs, renderArguments} from './slice_args';
import {renderDetails} from './slice_details';
import {getSlice, SliceDetails, SliceRef} from './sql/slice';
import {
@@ -288,7 +288,10 @@
private renderRhs(engine: EngineProxy, slice: SliceDetails): m.Children {
const precFlows = this.renderPrecedingFlows(slice);
const followingFlows = this.renderFollowingFlows(slice);
- const args = renderArguments(engine, slice);
+ const args = hasArgs(slice) &&
+ m(Section,
+ {title: 'Arguments'},
+ m(Tree, renderArguments(engine, slice)));
if (precFlows ?? followingFlows ?? args) {
return m(
GridLayoutColumn,
diff --git a/ui/src/frontend/router.ts b/ui/src/frontend/router.ts
index 27ab289..5c7a8ff 100644
--- a/ui/src/frontend/router.ts
+++ b/ui/src/frontend/router.ts
@@ -63,9 +63,14 @@
// DEPRECATED: for #!/record?p=cpu subpages (b/191255021).
p: optStr,
- // For fetching traces from Cloud Storage.
+ // For fetching traces from Cloud Storage or local servers
+ // as with record_android_trace.
url: optStr,
+ // Override the referrer. Useful for scripts such as
+ // record_android_trace to record where the trace is coming from.
+ referrer: optStr,
+
// For the 'mode' of the UI. For example when the mode is 'embedded'
// some features are disabled.
mode: oneOf<Mode>(modes, undefined),
diff --git a/ui/src/frontend/slice_args.ts b/ui/src/frontend/slice_args.ts
index 70beacb..9e1798f 100644
--- a/ui/src/frontend/slice_args.ts
+++ b/ui/src/frontend/slice_args.ts
@@ -30,8 +30,7 @@
} from '../tracks/visualised_args';
import {Anchor} from '../widgets/anchor';
import {MenuItem, PopupMenu2} from '../widgets/menu';
-import {Section} from '../widgets/section';
-import {Tree, TreeNode} from '../widgets/tree';
+import {TreeNode} from '../widgets/tree';
import {addTab} from './bottom_tab';
import {globals} from './globals';
@@ -40,20 +39,21 @@
import {SqlTableTab} from './sql_table/tab';
import {SqlTables} from './sql_table/well_known_tables';
-// Renders slice arguments (key/value pairs) into a Tree widget.
+// Renders slice arguments (key/value pairs) as a subtree.
export function renderArguments(
engine: EngineProxy, slice: SliceDetails): m.Children {
if (slice.args && slice.args.length > 0) {
const tree = convertArgsToTree(slice.args);
- return m(
- Section,
- {title: 'Arguments'},
- m(Tree, renderArgTreeNodes(engine, tree)));
+ return renderArgTreeNodes(engine, tree);
} else {
return undefined;
}
}
+export function hasArgs(slice: SliceDetails): boolean {
+ return exists(slice.args) && slice.args.length > 0;
+}
+
function renderArgTreeNodes(
engine: EngineProxy, args: ArgNode<Arg>[]): m.Children {
return args.map((arg) => {
diff --git a/ui/src/frontend/slice_track_base.ts b/ui/src/frontend/slice_track.ts
similarity index 90%
rename from ui/src/frontend/slice_track_base.ts
rename to ui/src/frontend/slice_track.ts
index bf66782..dd8756d 100644
--- a/ui/src/frontend/slice_track_base.ts
+++ b/ui/src/frontend/slice_track.ts
@@ -14,13 +14,14 @@
import {duration, Span, Time, time} from '../base/time';
import {Actions} from '../common/actions';
-import {BasicAsyncTrack} from '../common/basic_async_track';
import {cropText, drawIncompleteSlice} from '../common/canvas_utils';
import {getColorForSlice} from '../common/colorizer';
import {HighPrecisionTime} from '../common/high_precision_time';
import {TrackData} from '../common/track_data';
+import {TrackHelperLEGACY} from '../common/track_helper';
import {SliceRect} from '../public';
+import {CROP_INCOMPLETE_SLICE_FLAG} from './base_slice_track';
import {checkerboardExcept} from './checkerboard';
import {globals} from './globals';
import {PxSpan, TimeScale} from './time_scale';
@@ -30,6 +31,7 @@
const TRACK_PADDING = 2;
const CHEVRON_WIDTH_PX = 10;
const HALF_CHEVRON_WIDTH_PX = CHEVRON_WIDTH_PX / 2;
+const INCOMPLETE_SLICE_WIDTH_PX = 20;
export interface SliceData extends TrackData {
// Slices are stored in a columnar fashion.
@@ -51,7 +53,9 @@
// tracks before they are ported to v2.
// Slice tracks should extend this class and implement the abstract methods,
// notably onBoundsChange().
-export abstract class SliceTrackBase extends BasicAsyncTrack<SliceData> {
+// Note: This class is deprecated and should not be used for new tracks. Use
+// |BaseSliceTrack| instead.
+export abstract class SliceTrackLEGACY extends TrackHelperLEGACY<SliceData> {
constructor(
private maxDepth: number, protected trackKey: string,
private tableName: string, private namespace?: string) {
@@ -115,7 +119,7 @@
if (isIncomplete) { // incomplete slice
// TODO(stevegolton): This isn't exactly equivalent, ideally we should
// choose tEnd once we've converted to screen space coords.
- tEnd = visibleWindowTime.end.toTime('ceil');
+ tEnd = this.getEndTimeIfInComplete(tStart);
}
if (!visibleTimeSpan.intersects(tStart, tEnd)) {
@@ -187,7 +191,13 @@
}
if (isIncomplete && rect.width > SLICE_HEIGHT / 4) {
- drawIncompleteSlice(ctx, rect.left, rect.top, rect.width, SLICE_HEIGHT);
+ drawIncompleteSlice(
+ ctx,
+ rect.left,
+ rect.top,
+ rect.width,
+ SLICE_HEIGHT,
+ !CROP_INCOMPLETE_SLICE_FLAG.get());
} else if (
data.cpuTimeRatio !== undefined && data.cpuTimeRatio[i] < 1 - 1e-9) {
// We draw two rectangles, representing the ratio between wall time and
@@ -248,7 +258,6 @@
if (data === undefined) return;
const {
visibleTimeScale: timeScale,
- visibleWindowTime: visibleHPTimeSpan,
} = globals.frontendLocalState;
if (y < TRACK_PADDING) return;
const instantWidthTime = timeScale.pxDeltaToDuration(HALF_CHEVRON_WIDTH_PX);
@@ -269,7 +278,8 @@
const end = Time.fromRaw(data.ends[i]);
let tEnd = HighPrecisionTime.fromTime(end);
if (data.isIncomplete[i]) {
- tEnd = visibleHPTimeSpan.end;
+ const endTime = this.getEndTimeIfInComplete(start);
+ tEnd = HighPrecisionTime.fromTime(endTime);
}
if (tStart.lte(t) && t.lte(tEnd)) {
return i;
@@ -278,6 +288,20 @@
}
}
+ getEndTimeIfInComplete(start: time): time {
+ const {visibleTimeScale, visibleWindowTime} = globals.frontendLocalState;
+
+ let end = visibleWindowTime.end.toTime('ceil');
+ if (CROP_INCOMPLETE_SLICE_FLAG.get()) {
+ const widthTime =
+ visibleTimeScale.pxDeltaToDuration(INCOMPLETE_SLICE_WIDTH_PX)
+ .toTime();
+ end = Time.add(start, widthTime);
+ }
+
+ return end;
+ }
+
onMouseMove({x, y}: {x: number, y: number}) {
this.hoveredTitleId = -1;
globals.dispatch(Actions.setHighlightedSliceId({sliceId: -1}));
diff --git a/ui/src/frontend/sql_table/argument_selector.ts b/ui/src/frontend/sql_table/argument_selector.ts
index 2c86138..f7cd374 100644
--- a/ui/src/frontend/sql_table/argument_selector.ts
+++ b/ui/src/frontend/sql_table/argument_selector.ts
@@ -69,7 +69,7 @@
this.argList = [];
const it = queryResult.iter({key: STR});
for (; it.valid(); it.next()) {
- const arg = argColumn(attrs.argSetId, it.key);
+ const arg = argColumn(attrs.tableName, attrs.argSetId, it.key);
if (attrs.alreadySelectedColumns.has(arg.alias)) continue;
this.argList.push(it.key);
}
diff --git a/ui/src/frontend/sql_table/column.ts b/ui/src/frontend/sql_table/column.ts
index f4a6543..133c5fb 100644
--- a/ui/src/frontend/sql_table/column.ts
+++ b/ui/src/frontend/sql_table/column.ts
@@ -46,10 +46,11 @@
};
}
-export function argColumn(c: ArgSetIdColumn, argName: string): Column {
+export function argColumn(
+ tableName: string, c: ArgSetIdColumn, argName: string): Column {
const escape = (name: string) => name.replace(/[^A-Za-z0-9]/g, '_');
return {
- expression: `extract_arg(${c.name}, ${sqliteString(argName)})`,
+ expression: `extract_arg(${tableName}.${c.name}, ${sqliteString(argName)})`,
alias: `_arg_${c.name}_${escape(argName)}`,
title: `${c.title ?? c.name} ${argName}`,
};
diff --git a/ui/src/frontend/sql_table/column_unittest.ts b/ui/src/frontend/sql_table/column_unittest.ts
index 8fd944e..849eb03 100644
--- a/ui/src/frontend/sql_table/column_unittest.ts
+++ b/ui/src/frontend/sql_table/column_unittest.ts
@@ -72,11 +72,12 @@
},
});
- expect(argColumn(table.columns[3] as ArgSetIdColumn, 'foo.bar')).toEqual({
- expression: 'extract_arg(arg_set_id, \'foo.bar\')',
- alias: '_arg_arg_set_id_foo_bar',
- title: 'Arg foo.bar',
- });
+ expect(argColumn('slice', table.columns[3] as ArgSetIdColumn, 'foo.bar'))
+ .toEqual({
+ expression: 'extract_arg(slice.arg_set_id, \'foo.bar\')',
+ alias: '_arg_arg_set_id_foo_bar',
+ title: 'Arg foo.bar',
+ });
});
function formatSqlProjectionsForColumn(c: Column): string {
diff --git a/ui/src/frontend/sql_table/table.ts b/ui/src/frontend/sql_table/table.ts
index de1c9cb..d6de8e3 100644
--- a/ui/src/frontend/sql_table/table.ts
+++ b/ui/src/frontend/sql_table/table.ts
@@ -89,7 +89,7 @@
constraints: this.state.getQueryConstraints(),
alreadySelectedColumns: existingColumns,
onArgumentSelected: (argument: string) => {
- addColumn(argColumn(column, argument));
+ addColumn(argColumn(this.table.name, column, argument));
},
})));
continue;
diff --git a/ui/src/frontend/thread_state.ts b/ui/src/frontend/thread_state.ts
index 81b1346..977b608 100644
--- a/ui/src/frontend/thread_state.ts
+++ b/ui/src/frontend/thread_state.ts
@@ -181,7 +181,6 @@
let trackKey: string|number|undefined;
for (const track of Object.values(globals.state.tracks)) {
const trackDesc = pluginManager.resolveTrackInfo(track.uri);
- // TODO(stevegolton): Handle v2.
if (trackDesc && trackDesc.kind === THREAD_STATE_TRACK_KIND &&
trackDesc.utid === vnode.attrs.utid) {
trackKey = track.key;
diff --git a/ui/src/tracks/actual_frames/index.ts b/ui/src/tracks/actual_frames/index.ts
deleted file mode 100644
index 8fcd597..0000000
--- a/ui/src/tracks/actual_frames/index.ts
+++ /dev/null
@@ -1,125 +0,0 @@
-// 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.
-
-import {
- Plugin,
- PluginContext,
- PluginContextTrace,
- PluginDescriptor,
-} from '../../public';
-import {getTrackName} from '../../public/utils';
-import {
- NUM,
- NUM_NULL,
- STR,
- STR_NULL,
-} from '../../trace_processor/query_result';
-
-import {ActualFramesTrack} from './actual_frames_track';
-import {
- ActualFramesTrack as ActualFramesTrackV2,
-} from './actual_frames_track_v2';
-
-export const ACTUAL_FRAMES_SLICE_TRACK_KIND = 'ActualFramesSliceTrack';
-
-class ActualFrames implements Plugin {
- onActivate(_ctx: PluginContext): void {}
-
- async onTraceLoad(ctx: PluginContextTrace): Promise<void> {
- const {engine} = ctx;
- const result = await engine.query(`
- with process_async_tracks as materialized (
- select
- process_track.upid as upid,
- process_track.name as trackName,
- process.name as processName,
- process.pid as pid,
- group_concat(process_track.id) as trackIds,
- count(1) as trackCount
- from process_track
- left join process using(upid)
- where process_track.name = "Actual Timeline"
- group by
- process_track.upid,
- process_track.name
- )
- select
- t.*,
- max_layout_depth(t.trackCount, t.trackIds) as maxDepth
- from process_async_tracks t;
- `);
-
- const it = result.iter({
- upid: NUM,
- trackName: STR_NULL,
- trackIds: STR,
- processName: STR_NULL,
- pid: NUM_NULL,
- maxDepth: NUM_NULL,
- });
- for (; it.valid(); it.next()) {
- const upid = it.upid;
- const trackName = it.trackName;
- const rawTrackIds = it.trackIds;
- const trackIds = rawTrackIds.split(',').map((v) => Number(v));
- const processName = it.processName;
- const pid = it.pid;
- const maxDepth = it.maxDepth;
-
- if (maxDepth === null) {
- // If there are no slices in this track, skip it.
- continue;
- }
-
- const kind = 'ActualFrames';
- const displayName =
- getTrackName({name: trackName, upid, pid, processName, kind});
-
- ctx.registerStaticTrack({
- uri: `perfetto.ActualFrames#${upid}`,
- displayName,
- trackIds,
- kind: ACTUAL_FRAMES_SLICE_TRACK_KIND,
- track: ({trackKey}) => {
- return new ActualFramesTrack(
- engine,
- maxDepth,
- trackKey,
- trackIds,
- );
- },
- });
-
- ctx.registerStaticTrack({
- uri: `perfetto.ActualFrames#${upid}.v2`,
- displayName,
- trackIds,
- kind: ACTUAL_FRAMES_SLICE_TRACK_KIND,
- track: ({trackKey}) => {
- return new ActualFramesTrackV2(
- engine,
- maxDepth,
- trackKey,
- trackIds,
- );
- },
- });
- }
- }
-}
-
-export const plugin: PluginDescriptor = {
- pluginId: 'perfetto.ActualFrames',
- plugin: ActualFrames,
-};
diff --git a/ui/src/tracks/async_slices/async_slice_track.ts b/ui/src/tracks/async_slices/async_slice_track.ts
index 5d6e25a..d3d8f92 100644
--- a/ui/src/tracks/async_slices/async_slice_track.ts
+++ b/ui/src/tracks/async_slices/async_slice_track.ts
@@ -14,7 +14,7 @@
import {BigintMath as BIMath} from '../../base/bigint_math';
import {duration, time} from '../../base/time';
-import {SliceData, SliceTrackBase} from '../../frontend/slice_track_base';
+import {SliceData, SliceTrackLEGACY} from '../../frontend/slice_track';
import {EngineProxy} from '../../public';
import {
LONG,
@@ -25,7 +25,7 @@
export const ASYNC_SLICE_TRACK_KIND = 'AsyncSliceTrack';
-export class AsyncSliceTrack extends SliceTrackBase {
+export class AsyncSliceTrack extends SliceTrackLEGACY {
private maxDurNs: duration = 0n;
constructor(
diff --git a/ui/src/tracks/chrome_critical_user_interactions/index.ts b/ui/src/tracks/chrome_critical_user_interactions/index.ts
index 73e7428..2e0a381 100644
--- a/ui/src/tracks/chrome_critical_user_interactions/index.ts
+++ b/ui/src/tracks/chrome_critical_user_interactions/index.ts
@@ -23,7 +23,6 @@
NAMED_ROW,
NamedSliceTrackTypes,
} from '../../frontend/named_slice_track';
-import {NewTrackArgs, TrackBase} from '../../frontend/track';
import {
Plugin,
PluginContext,
@@ -80,10 +79,6 @@
CustomSqlTableSliceTrack<CriticalUserInteractionSliceTrackTypes> {
static readonly kind = CRITICAL_USER_INTERACTIONS_KIND;
- static create(args: NewTrackArgs): TrackBase {
- return new CriticalUserInteractionTrack(args);
- }
-
getSqlDataSource(): CustomSqlTableDefConfig {
return {
columns: ['scoped_id AS id', 'name', 'ts', 'dur', 'type'],
diff --git a/ui/src/tracks/chrome_scroll_jank/chrome_tasks_scroll_jank_track.ts b/ui/src/tracks/chrome_scroll_jank/chrome_tasks_scroll_jank_track.ts
index 95d1924..5b87694 100644
--- a/ui/src/tracks/chrome_scroll_jank/chrome_tasks_scroll_jank_track.ts
+++ b/ui/src/tracks/chrome_scroll_jank/chrome_tasks_scroll_jank_track.ts
@@ -17,7 +17,7 @@
NamedSliceTrack,
NamedSliceTrackTypes,
} from '../../frontend/named_slice_track';
-import {NewTrackArgs, TrackBase} from '../../frontend/track';
+import {NewTrackArgs} from '../../frontend/track';
import {Engine} from '../../trace_processor/engine';
import {NUM} from '../../trace_processor/query_result';
@@ -35,9 +35,6 @@
export class ChromeTasksScrollJankTrack extends
NamedSliceTrack<ChromeTasksScrollJankTrackTypes> {
static readonly kind = 'org.chromium.ScrollJank.BrowserUIThreadLongTasks';
- static create(args: NewTrackArgs): TrackBase {
- return new ChromeTasksScrollJankTrack(args);
- }
constructor(args: NewTrackArgs) {
super(args);
diff --git a/ui/src/tracks/chrome_scroll_jank/event_latency_details_panel.ts b/ui/src/tracks/chrome_scroll_jank/event_latency_details_panel.ts
index 5014d14..83a884c 100644
--- a/ui/src/tracks/chrome_scroll_jank/event_latency_details_panel.ts
+++ b/ui/src/tracks/chrome_scroll_jank/event_latency_details_panel.ts
@@ -171,7 +171,9 @@
m(GridLayout,
m(GridLayoutColumn,
renderDetails(slice),
- renderArguments(this.engine, slice)),
+ m(Section,
+ {title: 'Arguments'},
+ m(Tree, renderArguments(this.engine, slice)))),
m(GridLayoutColumn,
m(Section,
{title: 'Description'},
diff --git a/ui/src/tracks/chrome_scroll_jank/scroll_jank_v3_track.ts b/ui/src/tracks/chrome_scroll_jank/scroll_jank_v3_track.ts
index a5bf0aa..14d296a 100644
--- a/ui/src/tracks/chrome_scroll_jank/scroll_jank_v3_track.ts
+++ b/ui/src/tracks/chrome_scroll_jank/scroll_jank_v3_track.ts
@@ -14,7 +14,7 @@
import {globals} from '../../frontend/globals';
import {NamedRow, NamedSliceTrackTypes} from '../../frontend/named_slice_track';
-import {NewTrackArgs, TrackBase} from '../../frontend/track';
+import {NewTrackArgs} from '../../frontend/track';
import {PrimaryTrackSortKey, Slice} from '../../public';
import {
CustomSqlDetailsPanelConfig,
@@ -38,10 +38,6 @@
CustomSqlTableSliceTrack<NamedSliceTrackTypes> {
static readonly kind = 'org.chromium.ScrollJank.scroll_jank_v3_track';
- static create(args: NewTrackArgs): TrackBase {
- return new ScrollJankV3Track(args);
- }
-
constructor(args: NewTrackArgs) {
super(args);
ScrollJankPluginState.getInstance().registerTrack({
diff --git a/ui/src/tracks/chrome_scroll_jank/scroll_track.ts b/ui/src/tracks/chrome_scroll_jank/scroll_track.ts
index 7eaba65..a888844 100644
--- a/ui/src/tracks/chrome_scroll_jank/scroll_track.ts
+++ b/ui/src/tracks/chrome_scroll_jank/scroll_track.ts
@@ -13,13 +13,14 @@
// limitations under the License.
import {NamedSliceTrackTypes} from '../../frontend/named_slice_track';
-import {NewTrackArgs, TrackBase} from '../../frontend/track';
+import {NewTrackArgs} from '../../frontend/track';
import {PrimaryTrackSortKey} from '../../public';
import {
CustomSqlDetailsPanelConfig,
CustomSqlTableDefConfig,
CustomSqlTableSliceTrack,
} from '../custom_sql_table_slices';
+
import {
SCROLL_JANK_GROUP_ID,
ScrollJankPluginState,
@@ -33,9 +34,6 @@
export class TopLevelScrollTrack extends
CustomSqlTableSliceTrack<NamedSliceTrackTypes> {
public static kind = CHROME_TOPLEVEL_SCROLLS_KIND;
- static create(args: NewTrackArgs): TrackBase {
- return new TopLevelScrollTrack(args);
- }
getSqlDataSource(): CustomSqlTableDefConfig {
return {
diff --git a/ui/src/tracks/chrome_slices/index.ts b/ui/src/tracks/chrome_slices/index.ts
index ccf318b..8d36341 100644
--- a/ui/src/tracks/chrome_slices/index.ts
+++ b/ui/src/tracks/chrome_slices/index.ts
@@ -22,8 +22,8 @@
} from '../../frontend/named_slice_track';
import {
SliceData,
- SliceTrackBase,
-} from '../../frontend/slice_track_base';
+ SliceTrackLEGACY,
+} from '../../frontend/slice_track';
import {NewTrackArgs} from '../../frontend/track';
import {
EngineProxy,
@@ -44,7 +44,7 @@
export const SLICE_TRACK_KIND = 'ChromeSliceTrack';
-export class ChromeSliceTrack extends SliceTrackBase {
+export class ChromeSliceTrack extends SliceTrackLEGACY {
private maxDurNs: duration = 0n;
constructor(
diff --git a/ui/src/tracks/counter/index.ts b/ui/src/tracks/counter/index.ts
index 21ef5e6..4f2b7f4 100644
--- a/ui/src/tracks/counter/index.ts
+++ b/ui/src/tracks/counter/index.ts
@@ -20,13 +20,13 @@
import {isString} from '../../base/object_utils';
import {duration, time, Time} from '../../base/time';
import {Actions} from '../../common/actions';
-import {
- BasicAsyncTrack,
- NUM_NULL,
- STR_NULL,
-} from '../../common/basic_async_track';
import {drawTrackHoverTooltip} from '../../common/canvas_utils';
import {TrackData} from '../../common/track_data';
+import {
+ NUM_NULL,
+ STR_NULL,
+ TrackHelperLEGACY,
+} from '../../common/track_helper';
import {checkerboardExcept} from '../../frontend/checkerboard';
import {globals} from '../../frontend/globals';
import {
@@ -126,7 +126,7 @@
}
}
-export class CounterTrack extends BasicAsyncTrack<Data> {
+export class CounterTrack extends TrackHelperLEGACY<Data> {
private maximumValueSeen = 0;
private minimumValueSeen = 0;
private maximumDeltaSeen = 0;
diff --git a/ui/src/tracks/cpu_freq/index.ts b/ui/src/tracks/cpu_freq/index.ts
index c42b480..f07f263 100644
--- a/ui/src/tracks/cpu_freq/index.ts
+++ b/ui/src/tracks/cpu_freq/index.ts
@@ -274,10 +274,6 @@
const RECT_HEIGHT = 20;
class CpuFreqTrack extends TrackAdapter<Config, Data> {
- static create(args: NewTrackArgs): CpuFreqTrack {
- return new CpuFreqTrack(args);
- }
-
private mousePos = {x: 0, y: 0};
private hoveredValue: number|undefined = undefined;
private hoveredTs: time|undefined = undefined;
diff --git a/ui/src/tracks/cpu_profile/index.ts b/ui/src/tracks/cpu_profile/index.ts
index 143e057..59ad373 100644
--- a/ui/src/tracks/cpu_profile/index.ts
+++ b/ui/src/tracks/cpu_profile/index.ts
@@ -90,10 +90,6 @@
}
class CpuProfileTrack extends TrackAdapter<Config, Data> {
- static create(args: NewTrackArgs): CpuProfileTrack {
- return new CpuProfileTrack(args);
- }
-
private centerY = this.getHeight() / 2 + BAR_HEIGHT;
private markerWidth = (this.getHeight() - MARGIN_TOP - BAR_HEIGHT) / 2;
private hoveredTs: time|undefined = undefined;
diff --git a/ui/src/tracks/cpu_slices/index.ts b/ui/src/tracks/cpu_slices/index.ts
index 28497a2..0e9c470 100644
--- a/ui/src/tracks/cpu_slices/index.ts
+++ b/ui/src/tracks/cpu_slices/index.ts
@@ -206,10 +206,6 @@
const TRACK_HEIGHT = MARGIN_TOP * 2 + RECT_HEIGHT;
class CpuSliceTrack extends TrackAdapter<Config, Data> {
- static create(args: NewTrackArgs): CpuSliceTrack {
- return new CpuSliceTrack(args);
- }
-
private mousePos?: {x: number, y: number};
private utidHoveredInThisTrack = -1;
diff --git a/ui/src/tracks/debug/details_tab.ts b/ui/src/tracks/debug/details_tab.ts
index 3523f4f..5616a6b 100644
--- a/ui/src/tracks/debug/details_tab.ts
+++ b/ui/src/tracks/debug/details_tab.ts
@@ -24,6 +24,7 @@
import {
GenericSliceDetailsTabConfig,
} from '../../frontend/generic_slice_details_tab';
+import {hasArgs, renderArguments} from '../../frontend/slice_args';
import {
getSlice,
SliceDetails,
@@ -162,11 +163,24 @@
left: sliceRef(this.slice, 'Slice'),
right: '',
},
- renderTreeContents({
- 'Name': this.slice.name,
- 'Thread': getThreadName(this.slice.thread),
- 'Process': getProcessName(this.slice.process),
- }));
+ m(TreeNode, {
+ left: 'Name',
+ right: this.slice.name,
+ }),
+ m(TreeNode, {
+ left: 'Thread',
+ right: getThreadName(this.slice.thread),
+ }),
+ m(TreeNode, {
+ left: 'Process',
+ right: getProcessName(this.slice.process),
+ }),
+ hasArgs(this.slice) &&
+ m(TreeNode,
+ {
+ left: 'Args',
+ },
+ renderArguments(this.engine, this.slice)));
}
diff --git a/ui/src/tracks/expected_frames/index.ts b/ui/src/tracks/expected_frames/index.ts
deleted file mode 100644
index 10b3f44..0000000
--- a/ui/src/tracks/expected_frames/index.ts
+++ /dev/null
@@ -1,126 +0,0 @@
-// 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.
-
-// import { NamedSliceTrack } from 'src/frontend/named_slice_track';
-import {
- Plugin,
- PluginContext,
- PluginContextTrace,
- PluginDescriptor,
-} from '../../public';
-import {getTrackName} from '../../public/utils';
-import {
- NUM,
- NUM_NULL,
- STR,
- STR_NULL,
-} from '../../trace_processor/query_result';
-
-import {ExpectedFramesTrack} from './expected_frames_track';
-import {
- ExpectedFramesTrack as ExpectedFramesTrackV2,
-} from './expected_frames_track_v2';
-
-export const EXPECTED_FRAMES_SLICE_TRACK_KIND = 'ExpectedFramesSliceTrack';
-
-class ExpectedFramesPlugin implements Plugin {
- onActivate(_ctx: PluginContext): void {}
-
- async onTraceLoad(ctx: PluginContextTrace): Promise<void> {
- const {engine} = ctx;
- const result = await engine.query(`
- with process_async_tracks as materialized (
- select
- process_track.upid as upid,
- process_track.name as trackName,
- process.name as processName,
- process.pid as pid,
- group_concat(process_track.id) as trackIds,
- count(1) as trackCount
- from process_track
- left join process using(upid)
- where process_track.name = "Expected Timeline"
- group by
- process_track.upid,
- process_track.name
- )
- select
- t.*,
- max_layout_depth(t.trackCount, t.trackIds) as maxDepth
- from process_async_tracks t;
- `);
-
- const it = result.iter({
- upid: NUM,
- trackName: STR_NULL,
- trackIds: STR,
- processName: STR_NULL,
- pid: NUM_NULL,
- maxDepth: NUM_NULL,
- });
-
- for (; it.valid(); it.next()) {
- const upid = it.upid;
- const trackName = it.trackName;
- const rawTrackIds = it.trackIds;
- const trackIds = rawTrackIds.split(',').map((v) => Number(v));
- const processName = it.processName;
- const pid = it.pid;
- const maxDepth = it.maxDepth;
-
- if (maxDepth === null) {
- // If there are no slices in this track, skip it.
- continue;
- }
-
- const displayName = getTrackName(
- {name: trackName, upid, pid, processName, kind: 'ExpectedFrames'});
-
- ctx.registerStaticTrack({
- uri: `perfetto.ExpectedFrames#${upid}`,
- displayName,
- trackIds,
- kind: EXPECTED_FRAMES_SLICE_TRACK_KIND,
- track: ({trackKey}) => {
- return new ExpectedFramesTrack(
- engine,
- maxDepth,
- trackKey,
- trackIds,
- );
- },
- });
-
- ctx.registerStaticTrack({
- uri: `perfetto.ExpectedFrames#${upid}.v2`,
- displayName,
- trackIds,
- kind: EXPECTED_FRAMES_SLICE_TRACK_KIND,
- track: ({trackKey}) => {
- return new ExpectedFramesTrackV2(
- engine,
- maxDepth,
- trackKey,
- trackIds,
- );
- },
- });
- }
- }
-}
-
-export const plugin: PluginDescriptor = {
- pluginId: 'perfetto.ExpectedFrames',
- plugin: ExpectedFramesPlugin,
-};
diff --git a/ui/src/tracks/actual_frames/actual_frames_track.ts b/ui/src/tracks/frames/actual_frames_track.ts
similarity index 96%
rename from ui/src/tracks/actual_frames/actual_frames_track.ts
rename to ui/src/tracks/frames/actual_frames_track.ts
index 4b6c198b..4c46619 100644
--- a/ui/src/tracks/actual_frames/actual_frames_track.ts
+++ b/ui/src/tracks/frames/actual_frames_track.ts
@@ -14,7 +14,7 @@
import {BigintMath as BIMath} from '../../base/bigint_math';
import {duration, time} from '../../base/time';
-import {SliceData, SliceTrackBase} from '../../frontend/slice_track_base';
+import {SliceData, SliceTrackLEGACY} from '../../frontend/slice_track';
import {
EngineProxy,
} from '../../public';
@@ -34,7 +34,7 @@
const LIGHT_GREEN_COLOR = '#C0D588'; // Light Green 500
const PINK_COLOR = '#F515E0'; // Pink 500
-export class ActualFramesTrack extends SliceTrackBase {
+export class ActualFramesTrack extends SliceTrackLEGACY {
private maxDur = 0n;
constructor(
diff --git a/ui/src/tracks/actual_frames/actual_frames_track_v2.ts b/ui/src/tracks/frames/actual_frames_track_v2.ts
similarity index 100%
rename from ui/src/tracks/actual_frames/actual_frames_track_v2.ts
rename to ui/src/tracks/frames/actual_frames_track_v2.ts
diff --git a/ui/src/tracks/expected_frames/expected_frames_track.ts b/ui/src/tracks/frames/expected_frames_track.ts
similarity index 96%
rename from ui/src/tracks/expected_frames/expected_frames_track.ts
rename to ui/src/tracks/frames/expected_frames_track.ts
index 665cfc5..05af78a 100644
--- a/ui/src/tracks/expected_frames/expected_frames_track.ts
+++ b/ui/src/tracks/frames/expected_frames_track.ts
@@ -14,7 +14,7 @@
import {BigintMath as BIMath} from '../../base/bigint_math';
import {Duration, duration, time} from '../../base/time';
-import {SliceData, SliceTrackBase} from '../../frontend/slice_track_base';
+import {SliceData, SliceTrackLEGACY} from '../../frontend/slice_track';
import {EngineProxy} from '../../public';
import {
LONG,
@@ -23,7 +23,7 @@
STR,
} from '../../trace_processor/query_result';
-export class ExpectedFramesTrack extends SliceTrackBase {
+export class ExpectedFramesTrack extends SliceTrackLEGACY {
private maxDur = Duration.ZERO;
constructor(
diff --git a/ui/src/tracks/expected_frames/expected_frames_track_v2.ts b/ui/src/tracks/frames/expected_frames_track_v2.ts
similarity index 100%
rename from ui/src/tracks/expected_frames/expected_frames_track_v2.ts
rename to ui/src/tracks/frames/expected_frames_track_v2.ts
diff --git a/ui/src/tracks/frames/index.ts b/ui/src/tracks/frames/index.ts
new file mode 100644
index 0000000..e1cfc85
--- /dev/null
+++ b/ui/src/tracks/frames/index.ts
@@ -0,0 +1,217 @@
+// 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.
+
+import {
+ Plugin,
+ PluginContext,
+ PluginContextTrace,
+ PluginDescriptor,
+} from '../../public';
+import {getTrackName} from '../../public/utils';
+import {
+ NUM,
+ NUM_NULL,
+ STR,
+ STR_NULL,
+} from '../../trace_processor/query_result';
+
+import {ActualFramesTrack} from './actual_frames_track';
+import {
+ ActualFramesTrack as ActualFramesTrackV2,
+} from './actual_frames_track_v2';
+import {ExpectedFramesTrack} from './expected_frames_track';
+import {
+ ExpectedFramesTrack as ExpectedFramesTrackV2,
+} from './expected_frames_track_v2';
+
+export const EXPECTED_FRAMES_SLICE_TRACK_KIND = 'ExpectedFramesSliceTrack';
+export const ACTUAL_FRAMES_SLICE_TRACK_KIND = 'ActualFramesSliceTrack';
+
+class FramesPlugin implements Plugin {
+ onActivate(_ctx: PluginContext): void {}
+
+ async onTraceLoad(ctx: PluginContextTrace): Promise<void> {
+ this.addExpectedFrames(ctx);
+ this.addActualFrames(ctx);
+ }
+
+ async addExpectedFrames(ctx: PluginContextTrace): Promise<void> {
+ const {engine} = ctx;
+ const result = await engine.query(`
+ with process_async_tracks as materialized (
+ select
+ process_track.upid as upid,
+ process_track.name as trackName,
+ process.name as processName,
+ process.pid as pid,
+ group_concat(process_track.id) as trackIds,
+ count(1) as trackCount
+ from process_track
+ left join process using(upid)
+ where process_track.name = "Expected Timeline"
+ group by
+ process_track.upid,
+ process_track.name
+ )
+ select
+ t.*,
+ max_layout_depth(t.trackCount, t.trackIds) as maxDepth
+ from process_async_tracks t;
+ `);
+
+ const it = result.iter({
+ upid: NUM,
+ trackName: STR_NULL,
+ trackIds: STR,
+ processName: STR_NULL,
+ pid: NUM_NULL,
+ maxDepth: NUM_NULL,
+ });
+
+ for (; it.valid(); it.next()) {
+ const upid = it.upid;
+ const trackName = it.trackName;
+ const rawTrackIds = it.trackIds;
+ const trackIds = rawTrackIds.split(',').map((v) => Number(v));
+ const processName = it.processName;
+ const pid = it.pid;
+ const maxDepth = it.maxDepth;
+
+ if (maxDepth === null) {
+ // If there are no slices in this track, skip it.
+ continue;
+ }
+
+ const displayName = getTrackName(
+ {name: trackName, upid, pid, processName, kind: 'ExpectedFrames'});
+
+ ctx.registerStaticTrack({
+ uri: `perfetto.ExpectedFrames#${upid}`,
+ displayName,
+ trackIds,
+ kind: EXPECTED_FRAMES_SLICE_TRACK_KIND,
+ track: ({trackKey}) => {
+ return new ExpectedFramesTrack(
+ engine,
+ maxDepth,
+ trackKey,
+ trackIds,
+ );
+ },
+ });
+
+ ctx.registerStaticTrack({
+ uri: `perfetto.ExpectedFrames#${upid}.v2`,
+ displayName,
+ trackIds,
+ kind: EXPECTED_FRAMES_SLICE_TRACK_KIND,
+ track: ({trackKey}) => {
+ return new ExpectedFramesTrackV2(
+ engine,
+ maxDepth,
+ trackKey,
+ trackIds,
+ );
+ },
+ });
+ }
+ }
+
+ async addActualFrames(ctx: PluginContextTrace): Promise<void> {
+ const {engine} = ctx;
+ const result = await engine.query(`
+ with process_async_tracks as materialized (
+ select
+ process_track.upid as upid,
+ process_track.name as trackName,
+ process.name as processName,
+ process.pid as pid,
+ group_concat(process_track.id) as trackIds,
+ count(1) as trackCount
+ from process_track
+ left join process using(upid)
+ where process_track.name = "Actual Timeline"
+ group by
+ process_track.upid,
+ process_track.name
+ )
+ select
+ t.*,
+ max_layout_depth(t.trackCount, t.trackIds) as maxDepth
+ from process_async_tracks t;
+ `);
+
+ const it = result.iter({
+ upid: NUM,
+ trackName: STR_NULL,
+ trackIds: STR,
+ processName: STR_NULL,
+ pid: NUM_NULL,
+ maxDepth: NUM_NULL,
+ });
+ for (; it.valid(); it.next()) {
+ const upid = it.upid;
+ const trackName = it.trackName;
+ const rawTrackIds = it.trackIds;
+ const trackIds = rawTrackIds.split(',').map((v) => Number(v));
+ const processName = it.processName;
+ const pid = it.pid;
+ const maxDepth = it.maxDepth;
+
+ if (maxDepth === null) {
+ // If there are no slices in this track, skip it.
+ continue;
+ }
+
+ const kind = 'ActualFrames';
+ const displayName =
+ getTrackName({name: trackName, upid, pid, processName, kind});
+
+ ctx.registerStaticTrack({
+ uri: `perfetto.ActualFrames#${upid}`,
+ displayName,
+ trackIds,
+ kind: ACTUAL_FRAMES_SLICE_TRACK_KIND,
+ track: ({trackKey}) => {
+ return new ActualFramesTrack(
+ engine,
+ maxDepth,
+ trackKey,
+ trackIds,
+ );
+ },
+ });
+
+ ctx.registerStaticTrack({
+ uri: `perfetto.ActualFrames#${upid}.v2`,
+ displayName,
+ trackIds,
+ kind: ACTUAL_FRAMES_SLICE_TRACK_KIND,
+ track: ({trackKey}) => {
+ return new ActualFramesTrackV2(
+ engine,
+ maxDepth,
+ trackKey,
+ trackIds,
+ );
+ },
+ });
+ }
+ }
+}
+
+export const plugin: PluginDescriptor = {
+ pluginId: 'perfetto.Frames',
+ plugin: FramesPlugin,
+};
diff --git a/ui/src/tracks/ftrace/index.ts b/ui/src/tracks/ftrace/index.ts
index 6a2a966..75c741e 100644
--- a/ui/src/tracks/ftrace/index.ts
+++ b/ui/src/tracks/ftrace/index.ts
@@ -13,9 +13,9 @@
// limitations under the License.
import {duration, Time, time} from '../../base/time';
-import {BasicAsyncTrack} from '../../common/basic_async_track';
import {colorForFtrace} from '../../common/colorizer';
import {LIMIT, TrackData} from '../../common/track_data';
+import {TrackHelperLEGACY} from '../../common/track_helper';
import {checkerboardExcept} from '../../frontend/checkerboard';
import {globals} from '../../frontend/globals';
import {
@@ -42,7 +42,7 @@
const RECT_HEIGHT = 18;
const TRACK_HEIGHT = (RECT_HEIGHT) + (2 * MARGIN);
-class FtraceRawTrack extends BasicAsyncTrack<Data> {
+class FtraceRawTrack extends TrackHelperLEGACY<Data> {
constructor(private engine: EngineProxy, private cpu: number) {
super();
}
diff --git a/ui/src/tracks/null_track/index.ts b/ui/src/tracks/null_track/index.ts
index 1b2bb24..7bc77b5 100644
--- a/ui/src/tracks/null_track/index.ts
+++ b/ui/src/tracks/null_track/index.ts
@@ -28,10 +28,6 @@
super(args);
}
- static create(args: NewTrackArgs): NullTrack {
- return new NullTrack(args);
- }
-
getHeight(): number {
return 30;
}
@@ -50,7 +46,7 @@
uri: NULL_TRACK_URI,
displayName: 'Null Track',
kind: NULL_TRACK_KIND,
- track: ({trackKey}) => NullTrack.create({
+ track: ({trackKey}) => new NullTrack({
engine: ctx.engine,
trackKey,
}),
diff --git a/ui/src/tracks/perf_samples_profile/index.ts b/ui/src/tracks/perf_samples_profile/index.ts
index 5da1f71..dd30045 100644
--- a/ui/src/tracks/perf_samples_profile/index.ts
+++ b/ui/src/tracks/perf_samples_profile/index.ts
@@ -87,10 +87,6 @@
const RECT_HEIGHT = 30.5;
class PerfSamplesProfileTrack extends TrackAdapter<Config, Data> {
- static create(args: NewTrackArgs): PerfSamplesProfileTrack {
- return new PerfSamplesProfileTrack(args);
- }
-
private centerY = this.getHeight() / 2;
private markerWidth = (this.getHeight() - MARGIN_TOP) / 2;
private hoveredTs: time|undefined = undefined;
diff --git a/ui/src/tracks/process_summary/process_scheduling_track.ts b/ui/src/tracks/process_summary/process_scheduling_track.ts
index f7ad4c1..a955278 100644
--- a/ui/src/tracks/process_summary/process_scheduling_track.ts
+++ b/ui/src/tracks/process_summary/process_scheduling_track.ts
@@ -189,10 +189,6 @@
}
export class ProcessSchedulingTrack extends TrackAdapter<Config, Data> {
- static create(args: NewTrackArgs): ProcessSchedulingTrack {
- return new ProcessSchedulingTrack(args);
- }
-
private mousePos?: {x: number, y: number};
private utidHoveredInThisTrack = -1;
diff --git a/ui/src/tracks/process_summary/process_summary_track.ts b/ui/src/tracks/process_summary/process_summary_track.ts
index a1b32c7..ee0bcc8 100644
--- a/ui/src/tracks/process_summary/process_summary_track.ts
+++ b/ui/src/tracks/process_summary/process_summary_track.ts
@@ -142,10 +142,6 @@
const SUMMARY_HEIGHT = TRACK_HEIGHT - MARGIN_TOP;
export class ProcessSummaryTrack extends TrackAdapter<Config, Data> {
- static create(args: NewTrackArgs): ProcessSummaryTrack {
- return new ProcessSummaryTrack(args);
- }
-
constructor(args: NewTrackArgs) {
super(args);
}
diff --git a/ui/src/tracks/screenshots/index.ts b/ui/src/tracks/screenshots/index.ts
index 32df756..4af3c94 100644
--- a/ui/src/tracks/screenshots/index.ts
+++ b/ui/src/tracks/screenshots/index.ts
@@ -16,7 +16,6 @@
import {
NamedSliceTrackTypes,
} from '../../frontend/named_slice_track';
-import {NewTrackArgs, TrackBase} from '../../frontend/track';
import {
Plugin,
PluginContext,
@@ -36,9 +35,6 @@
class ScreenshotsTrack extends CustomSqlTableSliceTrack<NamedSliceTrackTypes> {
static readonly kind = 'dev.perfetto.ScreenshotsTrack';
- static create(args: NewTrackArgs): TrackBase {
- return new ScreenshotsTrack(args);
- }
getSqlDataSource(): CustomSqlTableDefConfig {
return {
diff --git a/ui/src/tracks/thread_state/index.ts b/ui/src/tracks/thread_state/index.ts
index 457ef28..7544ddb 100644
--- a/ui/src/tracks/thread_state/index.ts
+++ b/ui/src/tracks/thread_state/index.ts
@@ -48,7 +48,6 @@
} from './thread_state_v2';
export const THREAD_STATE_TRACK_KIND = 'ThreadStateTrack';
-export const THREAD_STATE_TRACK_V2_KIND = 'ThreadStateTrackV2';
interface Data extends TrackData {
strings: string[];
@@ -180,10 +179,6 @@
const EXCESS_WIDTH = 10;
class ThreadStateTrack extends TrackAdapter<Config, Data> {
- static create(args: NewTrackArgs): ThreadStateTrack {
- return new ThreadStateTrack(args);
- }
-
constructor(args: NewTrackArgs) {
super(args);
}
@@ -345,7 +340,7 @@
ctx.registerStaticTrack({
uri: `perfetto.ThreadState#${utid}.v2`,
displayName,
- kind: THREAD_STATE_TRACK_V2_KIND,
+ kind: THREAD_STATE_TRACK_KIND,
utid,
track: ({trackKey}) => {
return new ThreadStateTrackV2(