Merge "[stdlib]: Add util methods to generate monitor contention graphs" into main
diff --git a/docs/contributing/ui-plugins.md b/docs/contributing/ui-plugins.md
new file mode 100644
index 0000000..7a674e8
--- /dev/null
+++ b/docs/contributing/ui-plugins.md
@@ -0,0 +1,81 @@
+# UI plugins
+The Perfetto UI can be extended with plugins. These plugins are shipped
+part of Perfetto.
+
+## Create a plugin
+The guide below explains how to create a plugin for the Perfetto UI.
+
+### Prepare for UI development
+First we need to prepare the UI development environment.
+You will need to use a MacOS or Linux machine.
+Follow the steps below or see the
+[Getting Started](./getting-started) guide for more detail.
+
+```sh
+git clone https://android.googlesource.com/platform/external/perfetto/
+cd perfetto
+./tool/install-build-deps --ui
+```
+
+### Copy the plugin skeleton
+```sh
+cp -r ui/plugins/com.example.Skeleton ui/plugins/<your-plugin-name>
+```
+Now edit `ui/plugins/<your-plugin-name>/index.ts`.
+Search for all instances of `SKELETON: <instruction>` in the file and
+follow the instructions.
+
+Notes on naming:
+- Don't name the directory `XyzPlugin` just `Xyz`.
+- The `pluginId` and directory name must match.
+- Plugins should be prefixed with the reversed components of a domain
+ name you control. For example if `example.com` is your domain your
+ plugin should be named `com.example.Foo`.
+- Core plugins maintained by the Perfetto team should use
+ `dev.perfetto.Foo`.
+
+### Start the dev server
+```sh
+./ui/run-dev-server
+```
+Now navigate to [](http://localhost:10000/settings)
+
+### Upload your plugin for review
+- Update `ui/plugins/<your-plugin-name>/OWNERS` to include your email.
+- Follow the [Contributing](./getting-started#contributing)
+ instructions to upload your CL to the codereview tool.
+- Once uploaded add `hjd@google.com` as a reviewer for your CL.
+
+## Plugin extension points
+Plugins can extend a handful of specific places in the UI. The sections
+below show these extension points and give examples of how they can be
+used.
+
+### Commands
+TBD
+
+### Tracks
+TBD
+
+### Detail tabs
+TBD
+
+### Metric Visualisations
+TBD
+
+## Guide to the plugin API
+TBD
+
+## Default plugins
+TBD
+
+## Misc notes
+- Plugins must be licensed under
+ [Apache-2.0](https://spdx.org/licenses/Apache-2.0.html)
+ the same as all other code in the repository.
+- Plugins are the responsibility of the OWNERS of that plugin to
+ maintain, not the responsibility of the Perfetto team. All
+ efforts will be made to keep the plugin API stable and existing
+ plugins working however plugins that remain unmaintained for long
+ periods of time will be disabled and ultimately deleted.
+
diff --git a/docs/faq.md b/docs/faq.md
index df41ff3..89491ec 100644
--- a/docs/faq.md
+++ b/docs/faq.md
@@ -20,7 +20,7 @@
tools/open_trace_in_ui -i /path/to/trace
```
-## Why does Perfetto not support <some obscure JSON format feature>?
+## Why does Perfetto not support \<some obscure JSON format feature\>?
The JSON trace format is considered a legacy trace format and is supported on a
best-effort basis. While we try our best to maintain compatibility with the
diff --git a/docs/toc.md b/docs/toc.md
index 6fe3ae9..b0d8fc1 100644
--- a/docs/toc.md
+++ b/docs/toc.md
@@ -75,11 +75,12 @@
* [Getting started](contributing/getting-started.md)
* [Build instructions](contributing/build-instructions.md)
* [Running tests](contributing/testing.md)
- * [Common tasks](contributing/common-tasks.md)
+ * [UI plugins](contributing/ui-plugins.md)
+ * [UI development hints](contributing/ui-development.md)
* [Embedding Perfetto](contributing/embedding.md)
* [Releasing the SDK](contributing/sdk-releasing.md)
* [Chrome branches](contributing/chrome-branches.md)
- * [UI development](contributing/ui-development.md)
+ * [Common tasks](contributing/common-tasks.md)
* [Press](contributing/perfetto-in-the-press.md)
* [Design documents](#)
diff --git a/examples/sdk/README.md b/examples/sdk/README.md
index 3519006..21b64e2 100644
--- a/examples/sdk/README.md
+++ b/examples/sdk/README.md
@@ -67,6 +67,10 @@
```bash
export NDK=/path/to/ndk
cmake -DCMAKE_TOOLCHAIN_FILE=$NDK/build/cmake/android.toolchain.cmake \
+ -DANDROID_ABI=arm64-v8a \
+ -DANDROID_PLATFORM=android-21 \
+ -DANDROID_LD=lld \
+ -DCMAKE_BUILD_TYPE=Release \
-B build_android
cmake --build build_android
```
diff --git a/examples/sdk/example_system_wide.cc b/examples/sdk/example_system_wide.cc
index 87fb7a5..177b38b 100644
--- a/examples/sdk/example_system_wide.cc
+++ b/examples/sdk/example_system_wide.cc
@@ -91,6 +91,7 @@
// are going to use the system-wide tracing service, so that we can see our
// app's events in context with system profiling information.
args.backends = perfetto::kSystemBackend;
+ args.enable_system_consumer = false;
perfetto::Tracing::Initialize(args);
perfetto::TrackEvent::Register();
diff --git a/examples/shared_lib/example_shlib_data_source.c b/examples/shared_lib/example_shlib_data_source.c
index f9e4040..d8aa1f7 100644
--- a/examples/shared_lib/example_shlib_data_source.c
+++ b/examples/shared_lib/example_shlib_data_source.c
@@ -29,7 +29,7 @@
PerfettoProducerInit(args);
PerfettoDsRegister(&custom, "com.example.custom_data_source",
- PerfettoDsNoCallbacks());
+ PerfettoDsParamsDefault());
for (;;) {
PERFETTO_DS_TRACE(custom, ctx) {
diff --git a/include/perfetto/public/abi/data_source_abi.h b/include/perfetto/public/abi/data_source_abi.h
index 9eae031..a3a60aa 100644
--- a/include/perfetto/public/abi/data_source_abi.h
+++ b/include/perfetto/public/abi/data_source_abi.h
@@ -172,6 +172,27 @@
PERFETTO_SDK_EXPORT void PerfettoDsSetCbUserArg(struct PerfettoDsImpl*,
void* user_arg);
+enum PerfettoDsBufferExhaustedPolicy {
+ // If the data source runs out of space when trying to acquire a new chunk,
+ // it will drop data.
+ PERFETTO_DS_BUFFER_EXHAUSTED_POLICY_DROP = 0,
+ // If the data source runs out of space when trying to acquire a new chunk,
+ // it will stall, retry and eventually abort if a free chunk is not acquired
+ // after a while.
+ PERFETTO_DS_BUFFER_EXHAUSTED_POLICY_STALL_AND_ABORT = 1,
+};
+
+// If the data source doesn't find an empty chunk when trying to emit tracing
+// data, it will behave according to `policy` (which is a `enum
+// PerfettoDsBufferExhaustedPolicy`).
+//
+// Should not be called after PerfettoDsImplRegister().
+//
+// Returns true if successful, false otherwise.
+PERFETTO_SDK_EXPORT bool PerfettoDsSetBufferExhaustedPolicy(
+ struct PerfettoDsImpl*,
+ uint32_t policy);
+
// Registers the `*ds_impl` data source type.
//
// `ds_impl` must be obtained via a call to `PerfettoDsImplCreate()`.
diff --git a/include/perfetto/public/abi/producer_abi.h b/include/perfetto/public/abi/producer_abi.h
index 94dc134..a939b73 100644
--- a/include/perfetto/public/abi/producer_abi.h
+++ b/include/perfetto/public/abi/producer_abi.h
@@ -31,6 +31,19 @@
// Initializes the global in-process perfetto producer.
PERFETTO_SDK_EXPORT void PerfettoProducerInProcessInit(void);
+// Informs the tracing services to activate any of these triggers if any tracing
+// session was waiting for them.
+//
+// `trigger_names` is an array of `const char*` (zero terminated strings). The
+// last pointer in the array must be NULL.
+//
+// Sends the trigger signal to all the initialized backends that are currently
+// connected and that connect in the next `ttl_ms` milliseconds (but
+// returns immediately anyway).
+PERFETTO_SDK_EXPORT void PerfettoProducerActivateTriggers(
+ const char* trigger_names[],
+ uint32_t ttl_ms);
+
#ifdef __cplusplus
}
#endif
diff --git a/include/perfetto/public/abi/tracing_session_abi.h b/include/perfetto/public/abi/tracing_session_abi.h
index 113ac9b..4446bb8 100644
--- a/include/perfetto/public/abi/tracing_session_abi.h
+++ b/include/perfetto/public/abi/tracing_session_abi.h
@@ -41,6 +41,15 @@
void* cfg_begin,
size_t cfg_len);
+typedef void (*PerfettoTracingSessionStopCb)(struct PerfettoTracingSessionImpl*,
+ void* user_arg);
+
+// Calls `*cb` with `user_arg` when the tracing session is stopped.
+PERFETTO_SDK_EXPORT void PerfettoTracingSessionSetStopCb(
+ struct PerfettoTracingSessionImpl*,
+ PerfettoTracingSessionStopCb cb,
+ void* user_arg);
+
PERFETTO_SDK_EXPORT void PerfettoTracingSessionStartAsync(
struct PerfettoTracingSessionImpl*);
diff --git a/include/perfetto/public/data_source.h b/include/perfetto/public/data_source.h
index b244df1..65f1256 100644
--- a/include/perfetto/public/data_source.h
+++ b/include/perfetto/public/data_source.h
@@ -22,9 +22,11 @@
#include "perfetto/public/abi/atomic.h"
#include "perfetto/public/abi/data_source_abi.h"
+#include "perfetto/public/abi/heap_buffer.h"
#include "perfetto/public/compiler.h"
#include "perfetto/public/pb_msg.h"
#include "perfetto/public/pb_utils.h"
+#include "perfetto/public/protos/common/data_source_descriptor.pzc.h"
#include "perfetto/public/protos/trace/trace_packet.pzc.h"
// A data source type.
@@ -40,7 +42,7 @@
{ &perfetto_atomic_false, PERFETTO_NULL }
// All the callbacks are optional and can be NULL if not needed.
-struct PerfettoDsCallbacks {
+struct PerfettoDsParams {
// Instance lifecycle callbacks:
PerfettoDsOnSetupCb on_setup_cb;
PerfettoDsOnStartCb on_start_cb;
@@ -60,75 +62,87 @@
// Passed to all the callbacks as the `user_arg` param.
void* user_arg;
+
+ // How to behave when running out of shared memory buffer space.
+ enum PerfettoDsBufferExhaustedPolicy buffer_exhausted_policy;
};
-static inline struct PerfettoDsCallbacks PerfettoDsNoCallbacks(void) {
- struct PerfettoDsCallbacks ret = {
- PERFETTO_NULL, PERFETTO_NULL, PERFETTO_NULL, PERFETTO_NULL, PERFETTO_NULL,
- PERFETTO_NULL, PERFETTO_NULL, PERFETTO_NULL, PERFETTO_NULL};
+static inline struct PerfettoDsParams PerfettoDsParamsDefault(void) {
+ struct PerfettoDsParams ret = {
+ PERFETTO_NULL, PERFETTO_NULL,
+ PERFETTO_NULL, PERFETTO_NULL,
+ PERFETTO_NULL, PERFETTO_NULL,
+ PERFETTO_NULL, PERFETTO_NULL,
+ PERFETTO_NULL, PERFETTO_DS_BUFFER_EXHAUSTED_POLICY_DROP};
return ret;
}
// Registers the data source type `ds`, named `data_source_name` with the global
// perfetto producer.
-//
-// `callbacks` are called when certain events happen on the data source type.
-// PerfettoDsNoCallbacks() can be used if callbacks are not needed.
-//
-// TODO(ddiproietto): Accept the full DataSourceDescriptor, not just the
-// data_source_name
static inline bool PerfettoDsRegister(struct PerfettoDs* ds,
const char* data_source_name,
- struct PerfettoDsCallbacks callbacks) {
+ struct PerfettoDsParams params) {
struct PerfettoDsImpl* ds_impl;
bool success;
- // Build the DataSourceDescriptor protobuf message.
- size_t data_source_name_len = strlen(data_source_name);
- uint8_t* data_source_desc = PERFETTO_STATIC_CAST(
- uint8_t*, malloc(data_source_name_len + PERFETTO_PB_VARINT_MAX_SIZE_32 +
- PERFETTO_PB_VARINT_MAX_SIZE_64));
- uint8_t* write_ptr = data_source_desc;
- const int32_t name_field_id = 1; // perfetto.protos.DataSourceDescriptor.name
- write_ptr = PerfettoPbWriteVarInt(
- PerfettoPbMakeTag(name_field_id, PERFETTO_PB_WIRE_TYPE_DELIMITED),
- write_ptr);
- write_ptr = PerfettoPbWriteVarInt(data_source_name_len, write_ptr);
- memcpy(write_ptr, data_source_name, data_source_name_len);
- write_ptr += data_source_name_len;
+ void* desc_buf;
+ size_t desc_size;
+
+ ds->enabled = &perfetto_atomic_false;
+ ds->impl = PERFETTO_NULL;
+
+ {
+ struct PerfettoPbMsgWriter writer;
+ struct PerfettoHeapBuffer* hb = PerfettoHeapBufferCreate(&writer.writer);
+ struct perfetto_protos_DataSourceDescriptor desc;
+ PerfettoPbMsgInit(&desc.msg, &writer);
+
+ perfetto_protos_DataSourceDescriptor_set_cstr_name(&desc, data_source_name);
+
+ desc_size = PerfettoStreamWriterGetWrittenSize(&writer.writer);
+ desc_buf = malloc(desc_size);
+ PerfettoHeapBufferCopyInto(hb, &writer.writer, desc_buf, desc_size);
+ PerfettoHeapBufferDestroy(hb, &writer.writer);
+ }
+
+ if (!desc_buf) {
+ return false;
+ }
ds_impl = PerfettoDsImplCreate();
- if (callbacks.on_setup_cb) {
- PerfettoDsSetOnSetupCallback(ds_impl, callbacks.on_setup_cb);
+ if (params.on_setup_cb) {
+ PerfettoDsSetOnSetupCallback(ds_impl, params.on_setup_cb);
}
- if (callbacks.on_start_cb) {
- PerfettoDsSetOnStartCallback(ds_impl, callbacks.on_start_cb);
+ if (params.on_start_cb) {
+ PerfettoDsSetOnStartCallback(ds_impl, params.on_start_cb);
}
- if (callbacks.on_stop_cb) {
- PerfettoDsSetOnStopCallback(ds_impl, callbacks.on_stop_cb);
+ if (params.on_stop_cb) {
+ PerfettoDsSetOnStopCallback(ds_impl, params.on_stop_cb);
}
- if (callbacks.on_flush_cb) {
- PerfettoDsSetOnFlushCallback(ds_impl, callbacks.on_flush_cb);
+ if (params.on_flush_cb) {
+ PerfettoDsSetOnFlushCallback(ds_impl, params.on_flush_cb);
}
- if (callbacks.on_create_tls_cb) {
- PerfettoDsSetOnCreateTls(ds_impl, callbacks.on_create_tls_cb);
+ if (params.on_create_tls_cb) {
+ PerfettoDsSetOnCreateTls(ds_impl, params.on_create_tls_cb);
}
- if (callbacks.on_delete_tls_cb) {
- PerfettoDsSetOnDeleteTls(ds_impl, callbacks.on_delete_tls_cb);
+ if (params.on_delete_tls_cb) {
+ PerfettoDsSetOnDeleteTls(ds_impl, params.on_delete_tls_cb);
}
- if (callbacks.on_create_incr_cb) {
- PerfettoDsSetOnCreateIncr(ds_impl, callbacks.on_create_incr_cb);
+ if (params.on_create_incr_cb) {
+ PerfettoDsSetOnCreateIncr(ds_impl, params.on_create_incr_cb);
}
- if (callbacks.on_delete_incr_cb) {
- PerfettoDsSetOnDeleteIncr(ds_impl, callbacks.on_delete_incr_cb);
+ if (params.on_delete_incr_cb) {
+ PerfettoDsSetOnDeleteIncr(ds_impl, params.on_delete_incr_cb);
}
- if (callbacks.user_arg) {
- PerfettoDsSetCbUserArg(ds_impl, callbacks.user_arg);
+ if (params.user_arg) {
+ PerfettoDsSetCbUserArg(ds_impl, params.user_arg);
+ }
+ if (params.buffer_exhausted_policy !=
+ PERFETTO_DS_BUFFER_EXHAUSTED_POLICY_DROP) {
+ PerfettoDsSetBufferExhaustedPolicy(ds_impl, params.buffer_exhausted_policy);
}
- success = PerfettoDsImplRegister(
- ds_impl, &ds->enabled, data_source_desc,
- PERFETTO_STATIC_CAST(size_t, write_ptr - data_source_desc));
- free(data_source_desc);
+ success = PerfettoDsImplRegister(ds_impl, &ds->enabled, desc_buf, desc_size);
+ free(desc_buf);
if (!success) {
return false;
}
diff --git a/include/perfetto/public/producer.h b/include/perfetto/public/producer.h
index 4545baa..56692c6 100644
--- a/include/perfetto/public/producer.h
+++ b/include/perfetto/public/producer.h
@@ -17,8 +17,11 @@
#ifndef INCLUDE_PERFETTO_PUBLIC_PRODUCER_H_
#define INCLUDE_PERFETTO_PUBLIC_PRODUCER_H_
+#include <stdint.h>
+
#include "perfetto/public/abi/backend_type.h"
#include "perfetto/public/abi/producer_abi.h"
+#include "perfetto/public/compiler.h"
// Arguments for PerfettoProducerInit. This struct is not ABI-stable, fields can
// be added and rearranged.
@@ -37,4 +40,18 @@
}
}
+// Informs the tracing services to activate the single trigger `trigger_name` if
+// any tracing session was waiting for it.
+//
+// Sends the trigger signal to all the initialized backends that are currently
+// connected and that connect in the next `ttl_ms` milliseconds (but
+// returns immediately anyway).
+static inline void PerfettoProducerActivateTrigger(const char* trigger_name,
+ uint32_t ttl_ms) {
+ const char* trigger_names[2];
+ trigger_names[0] = trigger_name;
+ trigger_names[1] = PERFETTO_NULL;
+ PerfettoProducerActivateTriggers(trigger_names, ttl_ms);
+}
+
#endif // INCLUDE_PERFETTO_PUBLIC_PRODUCER_H_
diff --git a/include/perfetto/public/protos/BUILD.gn b/include/perfetto/public/protos/BUILD.gn
index 5901a27..64d324f 100644
--- a/include/perfetto/public/protos/BUILD.gn
+++ b/include/perfetto/public/protos/BUILD.gn
@@ -25,5 +25,6 @@
"trace/track_event/debug_annotation.pzc.h",
"trace/track_event/track_descriptor.pzc.h",
"trace/track_event/track_event.pzc.h",
+ "trace/trigger.pzc.h",
]
}
diff --git a/include/perfetto/public/protos/common/data_source_descriptor.pzc.h b/include/perfetto/public/protos/common/data_source_descriptor.pzc.h
new file mode 100644
index 0000000..21e62fb
--- /dev/null
+++ b/include/perfetto/public/protos/common/data_source_descriptor.pzc.h
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ */
+
+// Autogenerated by the ProtoZero C compiler plugin.
+// Invoked by tools/gen_c_protos
+// DO NOT EDIT.
+#ifndef INCLUDE_PERFETTO_PUBLIC_PROTOS_COMMON_DATA_SOURCE_DESCRIPTOR_PZC_H_
+#define INCLUDE_PERFETTO_PUBLIC_PROTOS_COMMON_DATA_SOURCE_DESCRIPTOR_PZC_H_
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "perfetto/public/pb_macros.h"
+
+PERFETTO_PB_MSG_DECL(perfetto_protos_FtraceDescriptor);
+PERFETTO_PB_MSG_DECL(perfetto_protos_GpuCounterDescriptor);
+PERFETTO_PB_MSG_DECL(perfetto_protos_TrackEventDescriptor);
+
+PERFETTO_PB_MSG(perfetto_protos_DataSourceDescriptor);
+PERFETTO_PB_FIELD(perfetto_protos_DataSourceDescriptor,
+ STRING,
+ const char*,
+ name,
+ 1);
+PERFETTO_PB_FIELD(perfetto_protos_DataSourceDescriptor,
+ VARINT,
+ uint64_t,
+ id,
+ 7);
+PERFETTO_PB_FIELD(perfetto_protos_DataSourceDescriptor,
+ VARINT,
+ bool,
+ will_notify_on_stop,
+ 2);
+PERFETTO_PB_FIELD(perfetto_protos_DataSourceDescriptor,
+ VARINT,
+ bool,
+ will_notify_on_start,
+ 3);
+PERFETTO_PB_FIELD(perfetto_protos_DataSourceDescriptor,
+ VARINT,
+ bool,
+ handles_incremental_state_clear,
+ 4);
+PERFETTO_PB_FIELD(perfetto_protos_DataSourceDescriptor,
+ MSG,
+ perfetto_protos_GpuCounterDescriptor,
+ gpu_counter_descriptor,
+ 5);
+PERFETTO_PB_FIELD(perfetto_protos_DataSourceDescriptor,
+ MSG,
+ perfetto_protos_TrackEventDescriptor,
+ track_event_descriptor,
+ 6);
+PERFETTO_PB_FIELD(perfetto_protos_DataSourceDescriptor,
+ MSG,
+ perfetto_protos_FtraceDescriptor,
+ ftrace_descriptor,
+ 8);
+
+#endif // INCLUDE_PERFETTO_PUBLIC_PROTOS_COMMON_DATA_SOURCE_DESCRIPTOR_PZC_H_
diff --git a/include/perfetto/public/protos/trace/trigger.pzc.h b/include/perfetto/public/protos/trace/trigger.pzc.h
new file mode 100644
index 0000000..1ad6749
--- /dev/null
+++ b/include/perfetto/public/protos/trace/trigger.pzc.h
@@ -0,0 +1,42 @@
+/*
+ * 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 INCLUDE_PERFETTO_PUBLIC_PROTOS_TRACE_TRIGGER_PZC_H_
+#define INCLUDE_PERFETTO_PUBLIC_PROTOS_TRACE_TRIGGER_PZC_H_
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "perfetto/public/pb_macros.h"
+
+PERFETTO_PB_MSG(perfetto_protos_Trigger);
+PERFETTO_PB_FIELD(perfetto_protos_Trigger,
+ STRING,
+ const char*,
+ trigger_name,
+ 1);
+PERFETTO_PB_FIELD(perfetto_protos_Trigger,
+ STRING,
+ const char*,
+ producer_name,
+ 2);
+PERFETTO_PB_FIELD(perfetto_protos_Trigger,
+ VARINT,
+ int32_t,
+ trusted_producer_uid,
+ 3);
+
+#endif // INCLUDE_PERFETTO_PUBLIC_PROTOS_TRACE_TRIGGER_PZC_H_
diff --git a/protos/third_party/chromium/chrome_track_event.proto b/protos/third_party/chromium/chrome_track_event.proto
index 474cb98..f0801da 100644
--- a/protos/third_party/chromium/chrome_track_event.proto
+++ b/protos/third_party/chromium/chrome_track_event.proto
@@ -750,6 +750,7 @@
TASK_TYPE_LOW_PRIORITY_SCRIPT_EXECUTION = 81;
TASK_TYPE_STORAGE = 82;
TASK_TYPE_NETWORKING_UNFREEZABLE_IMAGE_LOADING = 83;
+ TASK_TYPE_MAIN_THREAD_TASK_QUEUE_V8_LOW_PRIORITY = 84;
}
enum FrameType {
@@ -806,6 +807,9 @@
// This is same as LatencyInfo's trace_id, using the name event_latency_id to
// move away from the generic trace_id name used at other places as well.
optional int64 event_latency_id = 4;
+ // This is set only for scroll updates and is based on the
+ // Event.ScrollJank.DelayedFramesPercentage.FixedWindow metric.
+ optional bool is_janky_scrolled_frame = 5;
}
message ProcessSingleton {
@@ -950,6 +954,8 @@
UI_BEFORE_UNLOAD_BROWSER_RESPONSE_TQ = 54;
IO_BEFORE_UNLOAD_BROWSER_RESPONSE_TQ = 55;
+
+ V8_LOW_PRIORITY_TQ = 56;
}
optional Priority priority = 1;
diff --git a/python/tools/check_imports.py b/python/tools/check_imports.py
index 9845d73..8313702 100755
--- a/python/tools/check_imports.py
+++ b/python/tools/check_imports.py
@@ -149,6 +149,16 @@
r'/core/.*',
'core should depend on base not the other way round',
),
+ NoDep(
+ r'/base/.*',
+ r'/common/.*',
+ 'common should depend on base not the other way round',
+ ),
+ NoDep(
+ r'/common/.*',
+ r'/chrome_extension/.*',
+ 'chrome_extension must be a leaf',
+ ),
# Fails at the moment as we have several circular dependencies. One
# example:
diff --git a/src/shared_lib/data_source.cc b/src/shared_lib/data_source.cc
index 1482f56..1e46c32 100644
--- a/src/shared_lib/data_source.cc
+++ b/src/shared_lib/data_source.cc
@@ -18,6 +18,7 @@
#include <bitset>
+#include "perfetto/tracing/buffer_exhausted_policy.h"
#include "perfetto/tracing/data_source.h"
#include "perfetto/tracing/internal/basic_types.h"
#include "protos/perfetto/common/data_source_descriptor.gen.h"
@@ -60,6 +61,9 @@
// Passed to all the callbacks as the `user_arg` param.
void* cb_user_arg;
+ perfetto::BufferExhaustedPolicy buffer_exhausted_policy =
+ perfetto::BufferExhaustedPolicy::kDrop;
+
DataSourceType cpp_type;
std::atomic<bool> enabled{false};
std::mutex mu;
@@ -262,6 +266,24 @@
ds_impl->cb_user_arg = user_arg;
}
+bool PerfettoDsSetBufferExhaustedPolicy(struct PerfettoDsImpl* ds_impl,
+ uint32_t policy) {
+ if (ds_impl->IsRegistered()) {
+ return false;
+ }
+
+ switch (policy) {
+ case PERFETTO_DS_BUFFER_EXHAUSTED_POLICY_DROP:
+ ds_impl->buffer_exhausted_policy = perfetto::BufferExhaustedPolicy::kDrop;
+ return true;
+ case PERFETTO_DS_BUFFER_EXHAUSTED_POLICY_STALL_AND_ABORT:
+ ds_impl->buffer_exhausted_policy =
+ perfetto::BufferExhaustedPolicy::kStall;
+ return true;
+ }
+ return false;
+}
+
bool PerfettoDsImplRegister(struct PerfettoDsImpl* ds_impl,
PERFETTO_ATOMIC(bool) * *enabled_ptr,
const void* descriptor,
@@ -295,7 +317,7 @@
params.supports_multiple_instances = true;
params.requires_callbacks_under_lock = false;
bool success = data_source_type->cpp_type.Register(
- dsd, factory, params, perfetto::BufferExhaustedPolicy::kDrop,
+ dsd, factory, params, data_source_type->buffer_exhausted_policy,
create_custom_tls_fn, create_incremental_state_fn, cb_ctx);
if (!success) {
return false;
diff --git a/src/shared_lib/producer.cc b/src/shared_lib/producer.cc
index e4991b8..ebd28b2 100644
--- a/src/shared_lib/producer.cc
+++ b/src/shared_lib/producer.cc
@@ -46,3 +46,12 @@
args.backends = perfetto::kSystemBackend;
perfetto::Tracing::Initialize(args);
}
+
+void PerfettoProducerActivateTriggers(const char* trigger_names[],
+ uint32_t ttl_ms) {
+ std::vector<std::string> triggers;
+ for (size_t i = 0; trigger_names[i] != nullptr; i++) {
+ triggers.push_back(trigger_names[i]);
+ }
+ perfetto::Tracing::ActivateTriggers(triggers, ttl_ms);
+}
diff --git a/src/shared_lib/test/api_integrationtest.cc b/src/shared_lib/test/api_integrationtest.cc
index 96ce34c..3ef111e 100644
--- a/src/shared_lib/test/api_integrationtest.cc
+++ b/src/shared_lib/test/api_integrationtest.cc
@@ -14,18 +14,21 @@
* limitations under the License.
*/
-#include <condition_variable>
-#include <mutex>
#include <thread>
#include "perfetto/public/abi/data_source_abi.h"
+#include "perfetto/public/abi/heap_buffer.h"
#include "perfetto/public/abi/pb_decoder_abi.h"
+#include "perfetto/public/abi/tracing_session_abi.h"
#include "perfetto/public/data_source.h"
#include "perfetto/public/pb_decoder.h"
#include "perfetto/public/producer.h"
+#include "perfetto/public/protos/config/data_source_config.pzc.h"
+#include "perfetto/public/protos/config/trace_config.pzc.h"
#include "perfetto/public/protos/trace/test_event.pzc.h"
#include "perfetto/public/protos/trace/trace.pzc.h"
#include "perfetto/public/protos/trace/trace_packet.pzc.h"
+#include "perfetto/public/protos/trace/trigger.pzc.h"
#include "test/gtest_and_gmock.h"
@@ -188,7 +191,7 @@
args.backends = PERFETTO_BACKEND_IN_PROCESS;
PerfettoProducerInit(args);
PerfettoDsRegister(&data_source_1, kDataSourceName1,
- PerfettoDsNoCallbacks());
+ PerfettoDsParamsDefault());
RegisterDataSource2();
}
@@ -208,36 +211,36 @@
};
void RegisterDataSource2() {
- static struct PerfettoDsCallbacks callbacks = {};
- callbacks.on_setup_cb = [](struct PerfettoDsImpl* ds_impl,
- PerfettoDsInstanceIndex inst_id, void* ds_config,
- size_t ds_config_size, void* user_arg) -> void* {
+ struct PerfettoDsParams params = PerfettoDsParamsDefault();
+ params.on_setup_cb = [](struct PerfettoDsImpl* ds_impl,
+ PerfettoDsInstanceIndex inst_id, void* ds_config,
+ size_t ds_config_size, void* user_arg) -> void* {
auto* thiz = static_cast<SharedLibDataSourceTest*>(user_arg);
return thiz->ds2_callbacks_.OnSetup(ds_impl, inst_id, ds_config,
ds_config_size, thiz->ds2_user_arg_);
};
- callbacks.on_start_cb = [](struct PerfettoDsImpl* ds_impl,
- PerfettoDsInstanceIndex inst_id, void* user_arg,
- void* inst_ctx) -> void {
+ params.on_start_cb = [](struct PerfettoDsImpl* ds_impl,
+ PerfettoDsInstanceIndex inst_id, void* user_arg,
+ void* inst_ctx) -> void {
auto* thiz = static_cast<SharedLibDataSourceTest*>(user_arg);
return thiz->ds2_callbacks_.OnStart(ds_impl, inst_id, thiz->ds2_user_arg_,
inst_ctx);
};
- callbacks.on_stop_cb =
+ params.on_stop_cb =
[](struct PerfettoDsImpl* ds_impl, PerfettoDsInstanceIndex inst_id,
void* user_arg, void* inst_ctx, struct PerfettoDsOnStopArgs* args) {
auto* thiz = static_cast<SharedLibDataSourceTest*>(user_arg);
return thiz->ds2_callbacks_.OnStop(
ds_impl, inst_id, thiz->ds2_user_arg_, inst_ctx, args);
};
- callbacks.on_flush_cb =
+ params.on_flush_cb =
[](struct PerfettoDsImpl* ds_impl, PerfettoDsInstanceIndex inst_id,
void* user_arg, void* inst_ctx, struct PerfettoDsOnFlushArgs* args) {
auto* thiz = static_cast<SharedLibDataSourceTest*>(user_arg);
return thiz->ds2_callbacks_.OnFlush(
ds_impl, inst_id, thiz->ds2_user_arg_, inst_ctx, args);
};
- callbacks.on_create_tls_cb =
+ params.on_create_tls_cb =
[](struct PerfettoDsImpl* ds_impl, PerfettoDsInstanceIndex inst_id,
struct PerfettoDsTracerImpl* tracer, void* user_arg) -> void* {
auto* thiz = static_cast<SharedLibDataSourceTest*>(user_arg);
@@ -247,12 +250,12 @@
thiz->ds2_user_arg_);
return state;
};
- callbacks.on_delete_tls_cb = [](void* ptr) {
+ params.on_delete_tls_cb = [](void* ptr) {
auto* state = static_cast<Ds2CustomState*>(ptr);
state->thiz->ds2_callbacks_.OnDeleteTls(state->actual);
delete state;
};
- callbacks.on_create_incr_cb =
+ params.on_create_incr_cb =
[](struct PerfettoDsImpl* ds_impl, PerfettoDsInstanceIndex inst_id,
struct PerfettoDsTracerImpl* tracer, void* user_arg) -> void* {
auto* thiz = static_cast<SharedLibDataSourceTest*>(user_arg);
@@ -262,13 +265,13 @@
ds_impl, inst_id, tracer, thiz->ds2_user_arg_);
return state;
};
- callbacks.on_delete_incr_cb = [](void* ptr) {
+ params.on_delete_incr_cb = [](void* ptr) {
auto* state = static_cast<Ds2CustomState*>(ptr);
state->thiz->ds2_callbacks_.OnDeleteIncr(state->actual);
delete state;
};
- callbacks.user_arg = this;
- PerfettoDsRegister(&data_source_2, kDataSourceName2, callbacks);
+ params.user_arg = this;
+ PerfettoDsRegister(&data_source_2, kDataSourceName2, params);
}
void* Ds2ActualCustomState(void* ptr) {
@@ -558,4 +561,77 @@
PERFETTO_DS_TRACE(data_source_1, ctx) {}
}
+class SharedLibProducerTest : public testing::Test {
+ protected:
+ void SetUp() override {
+ struct PerfettoProducerInitArgs args = {0};
+ args.backends = PERFETTO_BACKEND_IN_PROCESS;
+ PerfettoProducerInit(args);
+ }
+
+ void TearDown() override { perfetto::shlib::ResetForTesting(); }
+};
+
+TEST_F(SharedLibDataSourceTest, ActivateTriggers) {
+ struct PerfettoPbMsgWriter writer;
+ struct PerfettoHeapBuffer* hb = PerfettoHeapBufferCreate(&writer.writer);
+
+ struct perfetto_protos_TraceConfig cfg;
+ PerfettoPbMsgInit(&cfg.msg, &writer);
+ {
+ struct perfetto_protos_TraceConfig_BufferConfig buffers;
+ perfetto_protos_TraceConfig_begin_buffers(&cfg, &buffers);
+ perfetto_protos_TraceConfig_BufferConfig_set_size_kb(&buffers, 1024);
+ perfetto_protos_TraceConfig_end_buffers(&cfg, &buffers);
+ }
+ {
+ struct perfetto_protos_TraceConfig_TriggerConfig trigger_config;
+ perfetto_protos_TraceConfig_begin_trigger_config(&cfg, &trigger_config);
+ perfetto_protos_TraceConfig_TriggerConfig_set_trigger_mode(
+ &trigger_config,
+ perfetto_protos_TraceConfig_TriggerConfig_STOP_TRACING);
+ perfetto_protos_TraceConfig_TriggerConfig_set_trigger_timeout_ms(
+ &trigger_config, 5000);
+ {
+ struct perfetto_protos_TraceConfig_TriggerConfig_Trigger trigger;
+ perfetto_protos_TraceConfig_TriggerConfig_begin_triggers(&trigger_config,
+ &trigger);
+ perfetto_protos_TraceConfig_TriggerConfig_Trigger_set_cstr_name(
+ &trigger, "trigger1");
+ perfetto_protos_TraceConfig_TriggerConfig_end_triggers(&trigger_config,
+ &trigger);
+ }
+ perfetto_protos_TraceConfig_end_trigger_config(&cfg, &trigger_config);
+ }
+ size_t cfg_size = PerfettoStreamWriterGetWrittenSize(&writer.writer);
+ std::unique_ptr<uint8_t[]> ser(new uint8_t[cfg_size]);
+ PerfettoHeapBufferCopyInto(hb, &writer.writer, ser.get(), cfg_size);
+ PerfettoHeapBufferDestroy(hb, &writer.writer);
+
+ struct PerfettoTracingSessionImpl* ts =
+ PerfettoTracingSessionCreate(PERFETTO_BACKEND_IN_PROCESS);
+
+ PerfettoTracingSessionSetup(ts, ser.get(), cfg_size);
+
+ PerfettoTracingSessionStartBlocking(ts);
+ TracingSession tracing_session = TracingSession::Adopt(ts);
+
+ const char* triggers[3];
+ triggers[0] = "trigger0";
+ triggers[1] = "trigger1";
+ triggers[2] = nullptr;
+ PerfettoProducerActivateTriggers(triggers, 10000);
+
+ tracing_session.WaitForStopped();
+ std::vector<uint8_t> data = tracing_session.ReadBlocking();
+ EXPECT_THAT(FieldView(data),
+ Contains(PbField(
+ perfetto_protos_Trace_packet_field_number,
+ MsgField(Contains(PbField(
+ perfetto_protos_TracePacket_trigger_field_number,
+ MsgField(Contains(PbField(
+ perfetto_protos_Trigger_trigger_name_field_number,
+ StringField("trigger1"))))))))));
+}
+
} // namespace
diff --git a/src/shared_lib/test/benchmark.cc b/src/shared_lib/test/benchmark.cc
index b30e86f..4861a31 100644
--- a/src/shared_lib/test/benchmark.cc
+++ b/src/shared_lib/test/benchmark.cc
@@ -45,7 +45,7 @@
struct PerfettoProducerInitArgs args = {0};
args.backends = PERFETTO_BACKEND_IN_PROCESS;
PerfettoProducerInit(args);
- PerfettoDsRegister(&custom, kDataSourceName, PerfettoDsNoCallbacks());
+ PerfettoDsRegister(&custom, kDataSourceName, PerfettoDsParamsDefault());
return true;
}
diff --git a/src/shared_lib/test/utils.cc b/src/shared_lib/test/utils.cc
index a479078..69013bd 100644
--- a/src/shared_lib/test/utils.cc
+++ b/src/shared_lib/test/utils.cc
@@ -85,22 +85,37 @@
PerfettoTracingSessionStartBlocking(ts);
+ return TracingSession::Adopt(ts);
+}
+
+TracingSession TracingSession::Adopt(
+ struct PerfettoTracingSessionImpl* session) {
TracingSession ret;
- ret.session_ = ts;
+ ret.session_ = session;
+ ret.stopped_ = std::make_unique<WaitableEvent>();
+ PerfettoTracingSessionSetStopCb(
+ ret.session_,
+ [](struct PerfettoTracingSessionImpl*, void* arg) {
+ static_cast<WaitableEvent*>(arg)->Notify();
+ },
+ ret.stopped_.get());
return ret;
}
TracingSession::TracingSession(TracingSession&& other) noexcept {
session_ = other.session_;
other.session_ = nullptr;
+ stopped_ = std::move(other.stopped_);
+ other.stopped_ = nullptr;
}
TracingSession::~TracingSession() {
if (!session_) {
return;
}
- if (!stopped_) {
+ if (!stopped_->IsNotified()) {
PerfettoTracingSessionStopBlocking(session_);
+ stopped_->WaitForNotification();
}
PerfettoTracingSessionDestroy(session_);
}
@@ -124,8 +139,11 @@
return result;
}
+void TracingSession::WaitForStopped() {
+ stopped_->WaitForNotification();
+}
+
void TracingSession::StopBlocking() {
- stopped_ = true;
PerfettoTracingSessionStopBlocking(session_);
}
diff --git a/src/shared_lib/test/utils.h b/src/shared_lib/test/utils.h
index 5197b19..875162f 100644
--- a/src/shared_lib/test/utils.h
+++ b/src/shared_lib/test/utils.h
@@ -22,6 +22,7 @@
#include <cstdint>
#include <functional>
#include <iterator>
+#include <memory>
#include <mutex>
#include <ostream>
#include <string>
@@ -78,6 +79,9 @@
private:
std::string data_source_name_;
};
+
+ static TracingSession Adopt(struct PerfettoTracingSessionImpl*);
+
TracingSession(TracingSession&&) noexcept;
~TracingSession();
@@ -85,13 +89,14 @@
struct PerfettoTracingSessionImpl* session() const { return session_; }
bool FlushBlocking(uint32_t timeout_ms);
+ void WaitForStopped();
void StopBlocking();
std::vector<uint8_t> ReadBlocking();
private:
TracingSession() = default;
struct PerfettoTracingSessionImpl* session_;
- bool stopped_ = false;
+ std::unique_ptr<WaitableEvent> stopped_;
};
template <typename FieldSkipper>
diff --git a/src/shared_lib/tracing_session.cc b/src/shared_lib/tracing_session.cc
index 8a8ee82..28872e6 100644
--- a/src/shared_lib/tracing_session.cc
+++ b/src/shared_lib/tracing_session.cc
@@ -45,6 +45,13 @@
ts->Setup(cfg);
}
+void PerfettoTracingSessionSetStopCb(struct PerfettoTracingSessionImpl* session,
+ PerfettoTracingSessionStopCb cb,
+ void* user_arg) {
+ auto* ts = reinterpret_cast<perfetto::TracingSession*>(session);
+ ts->SetOnStopCallback([session, cb, user_arg]() { cb(session, user_arg); });
+}
+
void PerfettoTracingSessionStartAsync(
struct PerfettoTracingSessionImpl* session) {
auto* ts = reinterpret_cast<perfetto::TracingSession*>(session);
diff --git a/src/trace_processor/perfetto_sql/engine/perfetto_sql_parser.cc b/src/trace_processor/perfetto_sql/engine/perfetto_sql_parser.cc
index d820da6..459c6e0 100644
--- a/src/trace_processor/perfetto_sql/engine/perfetto_sql_parser.cc
+++ b/src/trace_processor/perfetto_sql/engine/perfetto_sql_parser.cc
@@ -17,6 +17,7 @@
#include "src/trace_processor/perfetto_sql/engine/perfetto_sql_parser.h"
#include <algorithm>
+#include <optional>
#include "perfetto/base/logging.h"
#include "perfetto/base/status.h"
@@ -62,13 +63,13 @@
} // namespace
PerfettoSqlParser::PerfettoSqlParser(SqlSource sql)
- : sql_(std::move(sql)), tokenizer_(sql_.sql().c_str()) {}
+ : tokenizer_(std::move(sql)) {}
bool PerfettoSqlParser::Next() {
PERFETTO_DCHECK(status_.ok());
State state = State::kStmtStart;
- const char* non_space_ptr = nullptr;
+ std::optional<Token> first_non_space_token;
for (Token token = tokenizer_.Next();; token = tokenizer_.Next()) {
// Space should always be completely ignored by any logic below as it will
// never change the current state in the state machine.
@@ -79,13 +80,9 @@
if (token.IsTerminal()) {
// If we have a non-space character we've seen, just return all the stuff
// after that point.
- if (non_space_ptr) {
- uint32_t offset_of_non_space =
- static_cast<uint32_t>(non_space_ptr - sql_.sql().c_str());
- uint32_t chars_since_non_space =
- static_cast<uint32_t>(tokenizer_.ptr() - non_space_ptr);
+ if (first_non_space_token) {
statement_ =
- SqliteSql{sql_.Substr(offset_of_non_space, chars_since_non_space)};
+ SqliteSql{tokenizer_.Substr(*first_non_space_token, token)};
return true;
}
// This means we've seen a semi-colon without any non-space content. Just
@@ -99,8 +96,8 @@
}
// If we've not seen a space character, keep track of the current position.
- if (!non_space_ptr) {
- non_space_ptr = token.str.data();
+ if (!first_non_space_token) {
+ first_non_space_token = token;
}
switch (state) {
@@ -172,15 +169,9 @@
return ErrorAtToken(token, err.c_str());
}
- Token tok = tokenizer_.NextNonWhitespace();
- Token first = tok;
-
- tok = tokenizer_.NextTerminal();
-
- uint32_t offset = static_cast<uint32_t>(first.str.data() - sql_.sql().data());
- uint32_t len = static_cast<uint32_t>(tok.str.end() - sql_.sql().data());
-
- statement_ = CreateTable{std::move(name), sql_.Substr(offset, len)};
+ Token first = tokenizer_.NextNonWhitespace();
+ statement_ = CreateTable{std::move(name),
+ tokenizer_.Substr(first, tokenizer_.NextTerminal())};
return true;
}
@@ -243,15 +234,9 @@
}
Token first = tokenizer_.NextNonWhitespace();
- Token token = first;
- token = tokenizer_.NextTerminal();
-
- uint32_t offset = static_cast<uint32_t>(first.str.data() - sql_.sql().data());
- uint32_t len = static_cast<uint32_t>((token.str.data() + token.str.size()) -
- first.str.data());
-
- statement_ = CreateFunction{replace, std::move(prototype), std::move(ret),
- sql_.Substr(offset, len), table_return};
+ statement_ = CreateFunction{
+ replace, std::move(prototype), std::move(ret),
+ tokenizer_.Substr(first, tokenizer_.NextTerminal()), table_return};
return true;
}
@@ -282,8 +267,7 @@
bool PerfettoSqlParser::ErrorAtToken(const SqliteTokenizer::Token& token,
const char* error) {
- uint32_t offset = static_cast<uint32_t>(token.str.data() - sql_.sql().data());
- std::string traceback = sql_.AsTraceback(offset);
+ std::string traceback = tokenizer_.AsTraceback(token);
status_ = base::ErrStatus("%s%s", traceback.c_str(), error);
return false;
}
diff --git a/src/trace_processor/perfetto_sql/engine/perfetto_sql_parser.h b/src/trace_processor/perfetto_sql/engine/perfetto_sql_parser.h
index 6631d38..52bf68f 100644
--- a/src/trace_processor/perfetto_sql/engine/perfetto_sql_parser.h
+++ b/src/trace_processor/perfetto_sql/engine/perfetto_sql_parser.h
@@ -97,7 +97,6 @@
bool ErrorAtToken(const SqliteTokenizer::Token&, const char* error);
- SqlSource sql_;
SqliteTokenizer tokenizer_;
base::Status status_;
std::optional<Statement> statement_;
diff --git a/src/trace_processor/perfetto_sql/engine/perfetto_sql_parser_unittest.cc b/src/trace_processor/perfetto_sql/engine/perfetto_sql_parser_unittest.cc
index 555f25a..e5eb2f6 100644
--- a/src/trace_processor/perfetto_sql/engine/perfetto_sql_parser_unittest.cc
+++ b/src/trace_processor/perfetto_sql/engine/perfetto_sql_parser_unittest.cc
@@ -81,19 +81,24 @@
TEST_F(PerfettoSqlParserTest, SemiColonTerminatedStatement) {
auto res = SqlSource::FromExecuteQuery("SELECT * FROM slice;");
- ASSERT_THAT(*Parse(res), testing::ElementsAre(SqliteSql{res}));
+ ASSERT_THAT(
+ *Parse(res),
+ testing::ElementsAre(SqliteSql{FindSubstr(res, "SELECT * FROM slice")}));
}
TEST_F(PerfettoSqlParserTest, MultipleStmts) {
auto res =
SqlSource::FromExecuteQuery("SELECT * FROM slice; SELECT * FROM s");
- ASSERT_THAT(*Parse(res), testing::ElementsAre(SqliteSql{res.Substr(0, 20)},
- SqliteSql{res.Substr(21, 15)}));
+ ASSERT_THAT(
+ *Parse(res),
+ testing::ElementsAre(SqliteSql{FindSubstr(res, "SELECT * FROM slice")},
+ SqliteSql{FindSubstr(res, "SELECT * FROM s")}));
}
TEST_F(PerfettoSqlParserTest, IgnoreOnlySpace) {
auto res = SqlSource::FromExecuteQuery(" ; SELECT * FROM s; ; ;");
- ASSERT_THAT(*Parse(res), testing::ElementsAre(SqliteSql{res.Substr(3, 16)}));
+ ASSERT_THAT(*Parse(res), testing::ElementsAre(
+ SqliteSql{FindSubstr(res, "SELECT * FROM s")}));
}
TEST_F(PerfettoSqlParserTest, CreatePerfettoFunctionScalar) {
@@ -135,10 +140,10 @@
TEST_F(PerfettoSqlParserTest, CreatePerfettoFunctionAndOther) {
auto res = SqlSource::FromExecuteQuery(
"create perfetto function foo() returns INT as select 1; select foo()");
- ASSERT_THAT(*Parse(res), testing::ElementsAre(
- CreateFn{false, "foo()", "INT",
- FindSubstr(res, "select 1;"), false},
- SqliteSql{FindSubstr(res, "select foo()")}));
+ ASSERT_THAT(*Parse(res),
+ testing::ElementsAre(CreateFn{false, "foo()", "INT",
+ FindSubstr(res, "select 1"), false},
+ SqliteSql{FindSubstr(res, "select foo()")}));
}
} // namespace
diff --git a/src/trace_processor/sqlite/sqlite_tokenizer.cc b/src/trace_processor/sqlite/sqlite_tokenizer.cc
index c582637..6d07c53 100644
--- a/src/trace_processor/sqlite/sqlite_tokenizer.cc
+++ b/src/trace_processor/sqlite/sqlite_tokenizer.cc
@@ -426,13 +426,14 @@
} // namespace
-SqliteTokenizer::SqliteTokenizer(const char* sql) : ptr_(sql) {}
+SqliteTokenizer::SqliteTokenizer(SqlSource sql) : source_(std::move(sql)) {}
SqliteTokenizer::Token SqliteTokenizer::Next() {
Token token;
- const char* start = ptr_;
- int n = GetSqliteToken(unsigned_ptr(), &token.token_type);
- ptr_ += n;
+ const char* start = source_.sql().data() + offset_;
+ int n = GetSqliteToken(reinterpret_cast<const unsigned char*>(start),
+ &token.token_type);
+ offset_ += static_cast<uint32_t>(n);
token.str = std::string_view(start, static_cast<uint32_t>(n));
return token;
}
@@ -452,5 +453,18 @@
return tok;
}
+SqlSource SqliteTokenizer::Substr(Token start, Token end) const {
+ uint32_t offset =
+ static_cast<uint32_t>(start.str.data() - source_.sql().c_str());
+ uint32_t len = static_cast<uint32_t>(end.str.data() - start.str.data());
+ return source_.Substr(offset, len);
+}
+
+std::string SqliteTokenizer::AsTraceback(Token token) const {
+ uint32_t offset =
+ static_cast<uint32_t>(token.str.data() - source_.sql().c_str());
+ return source_.AsTraceback(offset);
+}
+
} // namespace trace_processor
} // namespace perfetto
diff --git a/src/trace_processor/sqlite/sqlite_tokenizer.h b/src/trace_processor/sqlite/sqlite_tokenizer.h
index 507d46e..c2b4ccc 100644
--- a/src/trace_processor/sqlite/sqlite_tokenizer.h
+++ b/src/trace_processor/sqlite/sqlite_tokenizer.h
@@ -19,6 +19,7 @@
#include <optional>
#include <string_view>
+#include "src/trace_processor/sqlite/sql_source.h"
namespace perfetto {
namespace trace_processor {
@@ -67,7 +68,7 @@
// https://www2.sqlite.org/hlr40000.html
//
// Usage of this class:
-// SqliteTokenizer tzr(my_sql_string.c_str());
+// SqliteTokenizer tzr(std::move(my_sql_source));
// for (auto t = tzr.Next(); t.token_type != TK_SEMI; t = tzr.Next()) {
// // Handle t here
// }
@@ -91,7 +92,7 @@
}
};
- explicit SqliteTokenizer(const char* sql);
+ explicit SqliteTokenizer(SqlSource sql);
// Returns the next SQL token.
Token Next();
@@ -102,15 +103,32 @@
// Returns the next SQL token which is terminal.
Token NextTerminal();
- // Returns the pointer to the start of the next token which will be returned.
- const char* ptr() const { return ptr_; }
+ // Returns an SqlSource containing all the tokens between |start| and |end|.
+ //
+ // Note: |start| and |end| must both have been previously returned by this
+ // tokenizer.
+ SqlSource Substr(Token start, Token end) const;
- private:
- const unsigned char* unsigned_ptr() const {
- return reinterpret_cast<const unsigned char*>(ptr_);
+ // Returns a traceback error message for the SqlSource backing this tokenizer
+ // pointing to |token|. See SqlSource::AsTraceback for more information about
+ // this method.
+ //
+ // Note: |token| must have been previously returned by this tokenizer.
+ std::string AsTraceback(Token) const;
+
+ // Resets this tokenizer to tokenize |source|. Any previous returned tokens
+ // are invalidated.
+ void Reset(SqlSource source) {
+ source_ = std::move(source);
+ offset_ = 0;
}
- const char* ptr_ = nullptr;
+ private:
+ SqliteTokenizer(SqliteTokenizer&&) = delete;
+ SqliteTokenizer& operator=(SqliteTokenizer&&) = delete;
+
+ SqlSource source_;
+ uint32_t offset_ = 0;
};
} // namespace trace_processor
diff --git a/src/trace_processor/sqlite/sqlite_tokenizer_unittest.cc b/src/trace_processor/sqlite/sqlite_tokenizer_unittest.cc
index 44946b7..e2301fa 100644
--- a/src/trace_processor/sqlite/sqlite_tokenizer_unittest.cc
+++ b/src/trace_processor/sqlite/sqlite_tokenizer_unittest.cc
@@ -18,6 +18,7 @@
#include <vector>
#include "perfetto/base/logging.h"
+#include "src/trace_processor/sqlite/sql_source.h"
#include "test/gtest_and_gmock.h"
namespace perfetto {
@@ -30,13 +31,16 @@
class SqliteTokenizerTest : public ::testing::Test {
protected:
std::vector<SqliteTokenizer::Token> Tokenize(const char* ptr) {
- SqliteTokenizer tokenizer(ptr);
+ tokenizer_.Reset(SqlSource::FromTraceProcessorImplementation(ptr));
std::vector<SqliteTokenizer::Token> tokens;
- for (auto t = tokenizer.Next(); !t.str.empty(); t = tokenizer.Next()) {
+ for (auto t = tokenizer_.Next(); !t.str.empty(); t = tokenizer_.Next()) {
tokens.push_back(t);
}
return tokens;
}
+
+ private:
+ SqliteTokenizer tokenizer_{SqlSource::FromTraceProcessorImplementation("")};
};
TEST_F(SqliteTokenizerTest, EmptyString) {
diff --git a/src/trace_processor/trace_database_integrationtest.cc b/src/trace_processor/trace_database_integrationtest.cc
index 3be0a12..2fd2cdd 100644
--- a/src/trace_processor/trace_database_integrationtest.cc
+++ b/src/trace_processor/trace_database_integrationtest.cc
@@ -512,7 +512,7 @@
ASSERT_EQ(it.Status().message(),
R"(Traceback (most recent call last):
File "stdin" line 1 col 1
- select RUN_METRIC('foo/bar.sql');
+ select RUN_METRIC('foo/bar.sql')
^
Metric file "foo/bar.sql" line 1 col 8
select t from slice
@@ -534,7 +534,7 @@
ASSERT_EQ(it.Status().message(),
R"(Traceback (most recent call last):
File "stdin" line 1 col 1
- select IMPORT('foo.bar');
+ select IMPORT('foo.bar')
^
Module import "foo.bar" line 1 col 8
select t from slice
diff --git a/src/trace_processor/trace_processor_shell.cc b/src/trace_processor/trace_processor_shell.cc
index ba49625..7c0380f 100644
--- a/src/trace_processor/trace_processor_shell.cc
+++ b/src/trace_processor/trace_processor_shell.cc
@@ -401,56 +401,38 @@
};
base::Status RunMetrics(const std::vector<MetricNameAndPath>& metrics,
- OutputFormat format,
- const google::protobuf::DescriptorPool& pool) {
+ OutputFormat format) {
std::vector<std::string> metric_names(metrics.size());
for (size_t i = 0; i < metrics.size(); ++i) {
metric_names[i] = metrics[i].name;
}
- if (format == OutputFormat::kTextProto) {
- std::string out;
- base::Status status =
- g_tp->ComputeMetricText(metric_names, TraceProcessor::kProtoText, &out);
- if (!status.ok()) {
- return status;
- }
- out += '\n';
- fwrite(out.c_str(), sizeof(char), out.size(), stdout);
- return base::OkStatus();
- }
-
- std::vector<uint8_t> metric_result;
- RETURN_IF_ERROR(g_tp->ComputeMetric(metric_names, &metric_result));
switch (format) {
- case OutputFormat::kJson: {
- // TODO(b/182165266): Handle this using ComputeMetricText.
- google::protobuf::DynamicMessageFactory factory(&pool);
- auto* descriptor =
- pool.FindMessageTypeByName("perfetto.protos.TraceMetrics");
- std::unique_ptr<google::protobuf::Message> metric_msg(
- factory.GetPrototype(descriptor)->New());
- metric_msg->ParseFromArray(metric_result.data(),
- static_cast<int>(metric_result.size()));
-
- // We need to instantiate field options from dynamic message factory
- // because otherwise it cannot parse our custom extensions.
- const google::protobuf::Message* field_options_prototype =
- factory.GetPrototype(
- pool.FindMessageTypeByName("google.protobuf.FieldOptions"));
- auto out = proto_to_json::MessageToJsonWithAnnotations(
- *metric_msg, field_options_prototype, 0);
- fwrite(out.c_str(), sizeof(char), out.size(), stdout);
- break;
- }
- case OutputFormat::kBinaryProto:
+ case OutputFormat::kBinaryProto: {
+ std::vector<uint8_t> metric_result;
+ RETURN_IF_ERROR(g_tp->ComputeMetric(metric_names, &metric_result));
fwrite(metric_result.data(), sizeof(uint8_t), metric_result.size(),
stdout);
break;
+ }
+ case OutputFormat::kJson: {
+ std::string out;
+ RETURN_IF_ERROR(g_tp->ComputeMetricText(
+ metric_names, TraceProcessor::MetricResultFormat::kJson, &out));
+ out += '\n';
+ fwrite(out.c_str(), sizeof(char), out.size(), stdout);
+ break;
+ }
+ case OutputFormat::kTextProto: {
+ std::string out;
+ RETURN_IF_ERROR(g_tp->ComputeMetricText(
+ metric_names, TraceProcessor::MetricResultFormat::kProtoText, &out));
+ out += '\n';
+ fwrite(out.c_str(), sizeof(char), out.size(), stdout);
+ break;
+ }
case OutputFormat::kNone:
break;
- case OutputFormat::kTextProto:
- PERFETTO_FATAL("This case was already handled.");
}
return base::OkStatus();
@@ -1495,7 +1477,7 @@
}
base::Status status =
- RunMetrics(options.metrics, options.metric_format, *options.pool);
+ RunMetrics(options.metrics, options.metric_format);
if (!status.ok()) {
fprintf(stderr, "%s\n", status.c_message());
}
@@ -1660,7 +1642,7 @@
OutputFormat metric_format = ParseOutputFormat(options);
if (!metrics.empty()) {
- RETURN_IF_ERROR(RunMetrics(metrics, metric_format, pool));
+ RETURN_IF_ERROR(RunMetrics(metrics, metric_format));
}
if (!options.query_file_path.empty()) {
diff --git a/ui/src/chrome_extension/chrome_tracing_controller.ts b/ui/src/chrome_extension/chrome_tracing_controller.ts
index 42f2a48..9ed3930 100644
--- a/ui/src/chrome_extension/chrome_tracing_controller.ts
+++ b/ui/src/chrome_extension/chrome_tracing_controller.ts
@@ -18,17 +18,17 @@
import {base64Encode} from '../base/string_utils';
import {
- browserSupportsPerfettoConfig,
- extractTraceConfig,
- hasSystemDataSourceConfig,
-} from '../base/trace_config_utils';
-import {TraceConfig} from '../common/protos';
-import {
ConsumerPortResponse,
GetTraceStatsResponse,
ReadBuffersResponse,
} from '../controller/consumer_port_types';
import {RpcConsumerPort} from '../controller/record_controller_interfaces';
+import {TraceConfig} from '../core/protos';
+import {
+ browserSupportsPerfettoConfig,
+ extractTraceConfig,
+ hasSystemDataSourceConfig,
+} from '../core/trace_config_utils';
import {perfetto} from '../gen/protos';
import {DevToolsSocket} from './devtools_socket';
diff --git a/ui/src/common/engine.ts b/ui/src/common/engine.ts
index 7bbde09..5546ea2 100644
--- a/ui/src/common/engine.ts
+++ b/ui/src/common/engine.ts
@@ -15,16 +15,16 @@
import {defer, Deferred} from '../base/deferred';
import {assertExists, assertTrue} from '../base/logging';
import {Span, Time} from '../common/time';
-import {perfetto} from '../gen/protos';
-
-import {ProtoRingBuffer} from './proto_ring_buffer';
import {
ComputeMetricArgs,
ComputeMetricResult,
DisableAndReadMetatraceResult,
QueryArgs,
ResetTraceProcessorArgs,
-} from './protos';
+} from '../core/protos';
+import {perfetto} from '../gen/protos';
+
+import {ProtoRingBuffer} from './proto_ring_buffer';
import {
createQueryResult,
LONG,
diff --git a/ui/src/common/http_rpc_engine.ts b/ui/src/common/http_rpc_engine.ts
index ddeec7c..f9db060 100644
--- a/ui/src/common/http_rpc_engine.ts
+++ b/ui/src/common/http_rpc_engine.ts
@@ -14,7 +14,7 @@
import {fetchWithTimeout} from '../base/http_utils';
import {assertExists} from '../base/logging';
-import {StatusResult} from '../common/protos';
+import {StatusResult} from '../core/protos';
import {Engine, LoadingTracker} from './engine';
diff --git a/ui/src/common/metatracing.ts b/ui/src/common/metatracing.ts
index 6099de5..99c5ea9 100644
--- a/ui/src/common/metatracing.ts
+++ b/ui/src/common/metatracing.ts
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-import {PerfettoMetatrace, Trace, TracePacket} from '../common/protos';
+import {PerfettoMetatrace, Trace, TracePacket} from '../core/protos';
import {perfetto} from '../gen/protos';
import {featureFlags} from './feature_flags';
diff --git a/ui/src/common/protos_unittest.ts b/ui/src/common/protos_unittest.ts
index 181917a..174e350 100644
--- a/ui/src/common/protos_unittest.ts
+++ b/ui/src/common/protos_unittest.ts
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-import {TraceConfig} from './protos';
+import {TraceConfig} from '../core/protos';
test('round trip config proto', () => {
const input = TraceConfig.create({
diff --git a/ui/src/common/recordingV2/chrome_traced_tracing_session.ts b/ui/src/common/recordingV2/chrome_traced_tracing_session.ts
index e36a5aa..a42528b 100644
--- a/ui/src/common/recordingV2/chrome_traced_tracing_session.ts
+++ b/ui/src/common/recordingV2/chrome_traced_tracing_session.ts
@@ -33,7 +33,8 @@
IBufferStats,
ISlice,
TraceConfig,
-} from '../protos';
+} from '../../core/protos';
+
import {RecordingError} from './recording_error_handling';
import {
TracingSession,
diff --git a/ui/src/common/recordingV2/recording_config_utils.ts b/ui/src/common/recordingV2/recording_config_utils.ts
index 139227e..9524670 100644
--- a/ui/src/common/recordingV2/recording_config_utils.ts
+++ b/ui/src/common/recordingV2/recording_config_utils.ts
@@ -15,7 +15,6 @@
import {base64Encode} from '../../base/string_utils';
import {RecordConfig} from '../../controller/record_config_types';
-import {perfetto} from '../../gen/protos';
import {
AndroidLogConfig,
AndroidLogId,
@@ -36,7 +35,8 @@
TraceConfig,
TrackEventConfig,
VmstatCounters,
-} from '../protos';
+} from '../../core/protos';
+import {perfetto} from '../../gen/protos';
import {TargetInfo} from './recording_interfaces_v2';
diff --git a/ui/src/common/recordingV2/recording_interfaces_v2.ts b/ui/src/common/recordingV2/recording_interfaces_v2.ts
index 974d277..ca187e2 100644
--- a/ui/src/common/recordingV2/recording_interfaces_v2.ts
+++ b/ui/src/common/recordingV2/recording_interfaces_v2.ts
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-import {TraceConfig} from '../protos';
+import {TraceConfig} from '../../core/protos';
// TargetFactory connects, disconnects and keeps track of targets.
// There is one factory for AndroidWebusb, AndroidWebsocket, Chrome etc.
diff --git a/ui/src/common/recordingV2/recording_page_controller.ts b/ui/src/common/recordingV2/recording_page_controller.ts
index 438843d..c42130c 100644
--- a/ui/src/common/recordingV2/recording_page_controller.ts
+++ b/ui/src/common/recordingV2/recording_page_controller.ts
@@ -13,6 +13,7 @@
// limitations under the License.
import {assertExists, assertTrue} from '../../base/logging';
+import {TraceConfig} from '../../core/protos';
import {raf} from '../../core/raf_scheduler';
import {globals} from '../../frontend/globals';
import {autosaveConfigStore} from '../../frontend/record_config';
@@ -25,7 +26,6 @@
} from '../../frontend/recording/reset_interface_modal';
import {Actions} from '../actions';
import {TRACE_SUFFIX} from '../constants';
-import {TraceConfig} from '../protos';
import {currentDateHourAndMinute} from '../time';
import {genTraceConfig} from './recording_config_utils';
diff --git a/ui/src/common/recordingV2/traced_tracing_session.ts b/ui/src/common/recordingV2/traced_tracing_session.ts
index 0b1f656..a49c780 100644
--- a/ui/src/common/recordingV2/traced_tracing_session.ts
+++ b/ui/src/common/recordingV2/traced_tracing_session.ts
@@ -34,7 +34,7 @@
ReadBuffersRequest,
ReadBuffersResponse,
TraceConfig,
-} from '../protos';
+} from '../../core/protos';
import {RecordingError} from './recording_error_handling';
import {
diff --git a/ui/src/controller/adb_base_controller.ts b/ui/src/controller/adb_base_controller.ts
index bbafbc3..144614e 100644
--- a/ui/src/controller/adb_base_controller.ts
+++ b/ui/src/controller/adb_base_controller.ts
@@ -12,9 +12,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-import {extractDurationFromTraceConfig} from '../base/trace_config_utils';
-import {extractTraceConfig} from '../base/trace_config_utils';
import {isAdbTarget} from '../common/state';
+import {
+ extractDurationFromTraceConfig,
+ extractTraceConfig,
+} from '../core/trace_config_utils';
import {globals} from '../frontend/globals';
import {Adb} from './adb_interfaces';
diff --git a/ui/src/controller/adb_shell_controller.ts b/ui/src/controller/adb_shell_controller.ts
index 4c7b6a2..d2fe620 100644
--- a/ui/src/controller/adb_shell_controller.ts
+++ b/ui/src/controller/adb_shell_controller.ts
@@ -15,7 +15,7 @@
import {_TextDecoder} from 'custom_utils';
import {base64Encode} from '../base/string_utils';
-import {extractTraceConfig} from '../base/trace_config_utils';
+import {extractTraceConfig} from '../core/trace_config_utils';
import {AdbBaseConsumerPort, AdbConnectionState} from './adb_base_controller';
import {Adb, AdbStream} from './adb_interfaces';
diff --git a/ui/src/controller/record_controller.ts b/ui/src/controller/record_controller.ts
index e8cb6dd..32d5e75 100644
--- a/ui/src/controller/record_controller.ts
+++ b/ui/src/controller/record_controller.ts
@@ -17,10 +17,6 @@
import {base64Encode} from '../base/string_utils';
import {Actions} from '../common/actions';
import {TRACE_SUFFIX} from '../common/constants';
-import {
- ConsumerPort,
- TraceConfig,
-} from '../common/protos';
import {genTraceConfig} from '../common/recordingV2/recording_config_utils';
import {TargetInfo} from '../common/recordingV2/recording_interfaces_v2';
import {
@@ -29,6 +25,10 @@
isChromeTarget,
RecordingTarget,
} from '../common/state';
+import {
+ ConsumerPort,
+ TraceConfig,
+} from '../core/protos';
import {globals} from '../frontend/globals';
import {publishBufferUsage, publishTrackData} from '../frontend/publish';
diff --git a/ui/src/controller/record_controller_jsdomtest.ts b/ui/src/controller/record_controller_jsdomtest.ts
index bc7c15b..55411ec 100644
--- a/ui/src/controller/record_controller_jsdomtest.ts
+++ b/ui/src/controller/record_controller_jsdomtest.ts
@@ -13,7 +13,7 @@
// limitations under the License.
import {assertExists} from '../base/logging';
-import {TraceConfig} from '../common/protos';
+import {TraceConfig} from '../core/protos';
import {createEmptyRecordConfig} from './record_config_types';
import {genConfigProto, toPbtxt} from './record_controller';
diff --git a/ui/src/common/protos.ts b/ui/src/core/protos.ts
similarity index 99%
rename from ui/src/common/protos.ts
rename to ui/src/core/protos.ts
index fa83fac..c3fdaca 100644
--- a/ui/src/common/protos.ts
+++ b/ui/src/core/protos.ts
@@ -86,12 +86,12 @@
BatteryCounters,
BufferConfig,
ChromeConfig,
- ConsumerPort,
ComputeMetricArgs,
ComputeMetricResult,
+ ConsumerPort,
DataSourceConfig,
- DisableAndReadMetatraceResult,
DataSourceDescriptor,
+ DisableAndReadMetatraceResult,
DisableTracingRequest,
DisableTracingResponse,
EnableTracingRequest,
@@ -116,21 +116,21 @@
MeminfoCounters,
NativeContinuousDumpConfig,
NetworkPacketTraceConfig,
- ProcessStatsConfig,
PerfettoMetatrace,
PerfEventConfig,
- ReadBuffersRequest,
- ReadBuffersResponse,
+ ProcessStatsConfig,
+ QueryArgs,
QueryServiceStateRequest,
QueryServiceStateResponse,
- QueryArgs,
+ ReadBuffersRequest,
+ ReadBuffersResponse,
ResetTraceProcessorArgs,
StatCounters,
StatusResult,
SysStatsConfig,
Trace,
TraceConfig,
- TrackEventConfig,
TracePacket,
+ TrackEventConfig,
VmstatCounters,
};
diff --git a/ui/src/base/trace_config_utils.ts b/ui/src/core/trace_config_utils.ts
similarity index 97%
rename from ui/src/base/trace_config_utils.ts
rename to ui/src/core/trace_config_utils.ts
index 3a08963..e7e6daf 100644
--- a/ui/src/base/trace_config_utils.ts
+++ b/ui/src/core/trace_config_utils.ts
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-import {TraceConfig} from '../common/protos';
+import {TraceConfig} from '../core/protos';
import {perfetto} from '../gen/protos';
// In this file are contained a few functions to simplify the proto parsing.
diff --git a/ui/src/frontend/recording/android_settings.ts b/ui/src/frontend/recording/android_settings.ts
index 4e41ac1..6568187 100644
--- a/ui/src/frontend/recording/android_settings.ts
+++ b/ui/src/frontend/recording/android_settings.ts
@@ -14,7 +14,7 @@
import m from 'mithril';
-import {DataSourceDescriptor} from '../../common/protos';
+import {DataSourceDescriptor} from '../../core/protos';
import {globals} from '../globals';
import {
Dropdown,
diff --git a/ui/src/frontend/recording/memory_settings.ts b/ui/src/frontend/recording/memory_settings.ts
index 002d6db..1db2b75 100644
--- a/ui/src/frontend/recording/memory_settings.ts
+++ b/ui/src/frontend/recording/memory_settings.ts
@@ -14,7 +14,7 @@
import m from 'mithril';
-import {MeminfoCounters, VmstatCounters} from '../../common/protos';
+import {MeminfoCounters, VmstatCounters} from '../../core/protos';
import {globals} from '../globals';
import {
Dropdown,
diff --git a/ui/src/frontend/rpc_http_dialog.ts b/ui/src/frontend/rpc_http_dialog.ts
index 7bd0a5f..024a113 100644
--- a/ui/src/frontend/rpc_http_dialog.ts
+++ b/ui/src/frontend/rpc_http_dialog.ts
@@ -17,7 +17,7 @@
import {assertExists} from '../base/logging';
import {Actions} from '../common/actions';
import {HttpRpcEngine, RPC_URL} from '../common/http_rpc_engine';
-import {StatusResult} from '../common/protos';
+import {StatusResult} from '../core/protos';
import {VERSION} from '../gen/perfetto_version';
import {perfetto} from '../gen/protos';
diff --git a/ui/src/plugins/com.example.Skeleton/OWNERS b/ui/src/plugins/com.example.Skeleton/OWNERS
new file mode 100644
index 0000000..1acc35b
--- /dev/null
+++ b/ui/src/plugins/com.example.Skeleton/OWNERS
@@ -0,0 +1 @@
+# SKELETON: Add your email to this file!
diff --git a/ui/src/plugins/com.example.Skeleton/index.ts b/ui/src/plugins/com.example.Skeleton/index.ts
new file mode 100644
index 0000000..c7735c0
--- /dev/null
+++ b/ui/src/plugins/com.example.Skeleton/index.ts
@@ -0,0 +1,41 @@
+// 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 {
+ EngineProxy,
+ PluginContext,
+ Store,
+ TracePlugin,
+} from '../../public';
+
+interface State {}
+
+// SKELETON: Rename this class to match your plugin.
+class Skeleton implements TracePlugin {
+ static migrate(_initialState: unknown): State {
+ return {};
+ }
+
+ constructor(_store: Store<State>, _engine: EngineProxy) {}
+
+ dispose(): void {}
+}
+
+export const plugin = {
+ // SKELETON: Update pluginId to match the directory of the plugin.
+ pluginId: 'com.example.Skeleton',
+ activate: (ctx: PluginContext) => {
+ ctx.registerTracePluginFactory(Skeleton);
+ },
+};