Shared library ABI for custom data sources
This commit implements an ABI and API for the shared library to support
registering custom data sources and creating tracing packets on them.
Most of the features of the C++ data sources are supported. Exceptions
are:
* Using custom thread local storage (not to be confused with custom
per-instance thread local state, which is supported). The feature in
C++ relies on heavily inlined template Traits. It is only used by the
TrackEvent data source implementation, which in the shared library is
going to has a separate ABI.
Bug: 237053857
Change-Id: I9fc49ea895facec8364f6ba2fd4b60e9fb287b4e
diff --git a/BUILD b/BUILD
index 7f10679..cb88289 100644
--- a/BUILD
+++ b/BUILD
@@ -574,6 +574,7 @@
perfetto_filegroup(
name = "include_perfetto_public_abi_base",
srcs = [
+ "include/perfetto/public/abi/atomic.h",
"include/perfetto/public/abi/export.h",
],
)
diff --git a/examples/shared_lib/example_shlib_data_source.c b/examples/shared_lib/example_shlib_data_source.c
index 49893d9..d743cd3 100644
--- a/examples/shared_lib/example_shlib_data_source.c
+++ b/examples/shared_lib/example_shlib_data_source.c
@@ -14,10 +14,24 @@
* limitations under the License.
*/
+#include <threads.h>
+#include <time.h>
+
+#include "perfetto/public/data_source.h"
#include "perfetto/public/producer.h"
+static struct PerfettoDs custom = PERFETTO_DS_INIT();
+
int main(void) {
struct PerfettoProducerInitArgs args = {0};
args.backends = PERFETTO_BACKEND_SYSTEM;
PerfettoProducerInit(args);
+
+ PerfettoDsRegister(&custom, "com.example.custom_data_source",
+ PerfettoDsNoCallbacks());
+
+ for (;;) {
+ PERFETTO_DS_TRACE(custom, ctx) {}
+ thrd_sleep(&(struct timespec){.tv_sec = 1}, NULL);
+ }
}
diff --git a/include/perfetto/public/BUILD.gn b/include/perfetto/public/BUILD.gn
index ae2c91d..3b5ab5f 100644
--- a/include/perfetto/public/BUILD.gn
+++ b/include/perfetto/public/BUILD.gn
@@ -18,6 +18,9 @@
}
source_set("protozero") {
- sources = [ "stream_writer.h" ]
+ sources = [
+ "pb_utils.h",
+ "stream_writer.h",
+ ]
public_deps = [ "./abi:protozero" ]
}
diff --git a/include/perfetto/public/abi/BUILD.gn b/include/perfetto/public/abi/BUILD.gn
index f17098b..6d5d565 100644
--- a/include/perfetto/public/abi/BUILD.gn
+++ b/include/perfetto/public/abi/BUILD.gn
@@ -13,7 +13,10 @@
# limitations under the License.
source_set("base") {
- sources = [ "export.h" ]
+ sources = [
+ "atomic.h",
+ "export.h",
+ ]
}
source_set("protozero") {
diff --git a/include/perfetto/public/abi/atomic.h b/include/perfetto/public/abi/atomic.h
new file mode 100644
index 0000000..5506f8b
--- /dev/null
+++ b/include/perfetto/public/abi/atomic.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef INCLUDE_PERFETTO_PUBLIC_ABI_ATOMIC_H_
+#define INCLUDE_PERFETTO_PUBLIC_ABI_ATOMIC_H_
+
+// Problem: C++11 and C11 use a different syntax for atomics and the C11 syntax
+// is not supported in C++11.
+//
+// This header bridges the gap.
+//
+// This assumes that C++11 atomics are binary compatible with C11 atomics. While
+// this is technically not required by the standards, reasonable compilers
+// appear to guarantee this.
+
+#ifdef __cplusplus
+#include <atomic>
+#else
+#include <stdatomic.h>
+#endif
+
+#ifdef __cplusplus
+#define PERFETTO_ATOMIC(TYPE) std::atomic<TYPE>
+#else
+#define PERFETTO_ATOMIC(TYPE) _Atomic(TYPE)
+#endif
+
+#ifdef __cplusplus
+#define PERFETTO_ATOMIC_LOAD std::atomic_load
+#define PERFETTO_ATOMIC_LOAD_EXPLICIT std::atomic_load_explicit
+#define PERFETTO_ATOMIC_STORE std::atomic_store
+#define PERFETTO_ATOMIC_STORE_EXPLICIT std::atomic_store_explicit
+
+#define PERFETTO_MEMORY_ORDER_ACQ_REL std::memory_order_acq_rel
+#define PERFETTO_MEMORY_ORDER_ACQUIRE std::memory_order_acquire
+#define PERFETTO_MEMORY_ORDER_CONSUME std::memory_order_consume
+#define PERFETTO_MEMORY_ORDER_RELAXED std::memory_order_relaxed
+#define PERFETTO_MEMORY_ORDER_RELEASE std::memory_order_release
+#define PERFETTO_MEMORY_ORDER_SEQ_CST std::memory_order_seq_cst
+#else
+#define PERFETTO_ATOMIC_LOAD atomic_load
+#define PERFETTO_ATOMIC_LOAD_EXPLICIT atomic_load_explicit
+#define PERFETTO_ATOMIC_STORE atomic_store
+#define PERFETTO_ATOMIC_STORE_EXPLICIT atomic_store_explicit
+
+#define PERFETTO_MEMORY_ORDER_ACQ_REL memory_order_acq_rel
+#define PERFETTO_MEMORY_ORDER_ACQUIRE memory_order_acquire
+#define PERFETTO_MEMORY_ORDER_CONSUME memory_order_consume
+#define PERFETTO_MEMORY_ORDER_RELAXED memory_order_relaxed
+#define PERFETTO_MEMORY_ORDER_RELEASE memory_order_release
+#define PERFETTO_MEMORY_ORDER_SEQ_CST memory_order_seq_cst
+#endif
+
+#endif // INCLUDE_PERFETTO_PUBLIC_ABI_ATOMIC_H_
diff --git a/include/perfetto/public/abi/data_source_abi.h b/include/perfetto/public/abi/data_source_abi.h
new file mode 100644
index 0000000..3a31650
--- /dev/null
+++ b/include/perfetto/public/abi/data_source_abi.h
@@ -0,0 +1,273 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef INCLUDE_PERFETTO_PUBLIC_ABI_DATA_SOURCE_ABI_H_
+#define INCLUDE_PERFETTO_PUBLIC_ABI_DATA_SOURCE_ABI_H_
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "perfetto/public/abi/atomic.h"
+#include "perfetto/public/abi/export.h"
+#include "perfetto/public/abi/stream_writer_abi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Internal representation of a data source type.
+struct PerfettoDsImpl;
+
+// Internal thread local state of a data source type.
+struct PerfettoDsTlsImpl;
+
+// Internal thread local state of a data source instance used for tracing.
+struct PerfettoDsTracerImpl;
+
+// A global atomic boolean that's always false.
+extern PERFETTO_SDK_EXPORT PERFETTO_ATOMIC(bool) perfetto_atomic_false;
+
+// There can be more than one data source instance for each data source type.
+// This index identifies one of them.
+typedef uint32_t PerfettoDsInstanceIndex;
+
+// Creates a data source type.
+//
+// The data source type needs to be registered later with
+// PerfettoDsImplRegister().
+PERFETTO_SDK_EXPORT struct PerfettoDsImpl* PerfettoDsImplCreate(void);
+
+// Called when a data source instance of a specific type is created. `ds_config`
+// points to a serialized perfetto.protos.DataSourceConfig message,
+// `ds_config_size` bytes long. `user_arg` is the value passed to
+// PerfettoDsSetCbUserArg().
+typedef void* (*PerfettoDsOnSetupCb)(PerfettoDsInstanceIndex inst_id,
+ void* ds_config,
+ size_t ds_config_size,
+ void* user_arg);
+
+// Called when tracing starts for a data source instance. `user_arg` is the
+// value passed to PerfettoDsSetCbUserArg(). `inst_ctx` is the return
+// value of PerfettoDsOnSetupCb.
+typedef void (*PerfettoDsOnStartCb)(PerfettoDsInstanceIndex inst_id,
+ void* user_arg,
+ void* inst_ctx);
+
+// Internal handle used to perform operations from the OnStop callback.
+struct PerfettoDsOnStopArgs;
+
+// Internal handle used to signal when the data source stop operation is
+// complete.
+struct PerfettoDsAsyncStopper;
+
+// Tells the tracing service to postpone the stopping of a data source instance.
+// The returned handle can be used to signal the tracing service when the data
+// source instance can be stopped.
+PERFETTO_SDK_EXPORT struct PerfettoDsAsyncStopper* PerfettoDsOnStopArgsPostpone(
+ struct PerfettoDsOnStopArgs*);
+
+// Tells the tracing service to stop a data source instance (whose stop
+// operation was previously postponed with PerfettoDsOnStopArgsPostpone).
+PERFETTO_SDK_EXPORT void PerfettoDsStopDone(struct PerfettoDsAsyncStopper*);
+
+// Called when tracing stops for a data source instance. `user_arg` is the value
+// passed to PerfettoDsSetCbUserArg(). `inst_ctx` is the return value of
+// PerfettoDsOnSetupCb. `args` can be used to postpone stopping this data source
+// instance.
+typedef void (*PerfettoDsOnStopCb)(PerfettoDsInstanceIndex inst_id,
+ void* user_arg,
+ void* inst_ctx,
+ struct PerfettoDsOnStopArgs* args);
+
+// Creates custom state (either thread local state or incremental state) for
+// instance `inst_id`. `user_arg` is the value passed to
+// PerfettoDsSetCbUserArg().
+typedef void* (*PerfettoDsOnCreateCustomState)(
+ PerfettoDsInstanceIndex inst_id,
+ struct PerfettoDsTracerImpl* tracer,
+ void* user_arg);
+
+// Deletes the previously created custom state `obj`.
+typedef void (*PerfettoDsOnDeleteCustomState)(void* obj);
+
+// Setters for callbacks: can not be called after PerfettoDsImplRegister().
+
+PERFETTO_SDK_EXPORT void PerfettoDsSetOnSetupCallback(struct PerfettoDsImpl*,
+ PerfettoDsOnSetupCb);
+
+PERFETTO_SDK_EXPORT void PerfettoDsSetOnStartCallback(struct PerfettoDsImpl*,
+ PerfettoDsOnStartCb);
+
+PERFETTO_SDK_EXPORT void PerfettoDsSetOnStopCallback(struct PerfettoDsImpl*,
+ PerfettoDsOnStopCb);
+
+// Callbacks for custom per instance thread local state.
+PERFETTO_SDK_EXPORT void PerfettoDsSetOnCreateTls(
+ struct PerfettoDsImpl*,
+ PerfettoDsOnCreateCustomState);
+
+PERFETTO_SDK_EXPORT void PerfettoDsSetOnDeleteTls(
+ struct PerfettoDsImpl*,
+ PerfettoDsOnDeleteCustomState);
+
+// Callbacks for custom per instance thread local incremental state.
+PERFETTO_SDK_EXPORT void PerfettoDsSetOnCreateIncr(
+ struct PerfettoDsImpl*,
+ PerfettoDsOnCreateCustomState);
+
+PERFETTO_SDK_EXPORT void PerfettoDsSetOnDeleteIncr(
+ struct PerfettoDsImpl*,
+ PerfettoDsOnDeleteCustomState);
+
+// Stores the `user_arg` that's going to be passed later to the callbacks for
+// this data source type.
+PERFETTO_SDK_EXPORT void PerfettoDsSetCbUserArg(struct PerfettoDsImpl*,
+ void* user_arg);
+
+// Registers the `*ds_impl` data source type.
+//
+// `ds_impl` must be obtained via a call to `PerfettoDsImplCreate()`.
+//
+// `**enabled_ptr` will be set to true when the data source type has been
+// enabled.
+//
+// `descriptor` should point to a serialized
+// perfetto.protos.DataSourceDescriptor message, `descriptor_size` bytes long.
+//
+// Returns `true` in case of success, `false` in case of failure (in which case
+// `ds_impl is invalid`).
+PERFETTO_SDK_EXPORT bool PerfettoDsImplRegister(struct PerfettoDsImpl* ds_impl,
+ PERFETTO_ATOMIC(bool) *
+ *enabled_ptr,
+ const void* descriptor,
+ size_t descriptor_size);
+
+// Updates the descriptor the `*ds_impl` data source type.
+//
+// `descriptor` should point to a serialized
+// perfetto.protos.DataSourceDescriptor message, `descriptor_size` bytes long.
+PERFETTO_SDK_EXPORT void PerfettoDsImplUpdateDescriptor(
+ struct PerfettoDsImpl* ds_impl,
+ const void* descriptor,
+ size_t descriptor_size);
+
+// Tries to get the `inst_ctx` returned by PerfettoDsOnSetupCb() for the
+// instance with index `inst_id`.
+//
+// If successful, returns a non-null pointer and acquires a lock, which must be
+// released with PerfettoDsImplReleaseInstanceLocked.
+//
+// If unsuccessful (because the instance was destroyed in the meantime) or if
+// PerfettoDsOnSetupCb() returned a null value, returns null and does not
+// acquire any lock.
+PERFETTO_SDK_EXPORT void* PerfettoDsImplGetInstanceLocked(
+ struct PerfettoDsImpl* ds_impl,
+ PerfettoDsInstanceIndex inst_id);
+
+// Releases a lock previouly acquired by a PerfettoDsImplGetInstanceLocked()
+// call, which must have returned a non null value.
+PERFETTO_SDK_EXPORT void PerfettoDsImplReleaseInstanceLocked(
+ struct PerfettoDsImpl* ds_impl,
+ PerfettoDsInstanceIndex inst_id);
+
+// Gets the data source thread local instance custom state created by
+// the callback passed to `PerfettoDsSetOnCreateTls`.
+PERFETTO_SDK_EXPORT void* PerfettoDsImplGetCustomTls(
+ struct PerfettoDsImpl* ds_impl,
+ struct PerfettoDsTracerImpl* tracer,
+ PerfettoDsInstanceIndex inst_id);
+
+// Gets the data source thread local instance incremental state created by
+// the callback passed to `PerfettoDsSetOnCreateIncr`.
+PERFETTO_SDK_EXPORT void* PerfettoDsImplGetIncrementalState(
+ struct PerfettoDsImpl* ds_impl,
+ struct PerfettoDsTracerImpl* tracer,
+ PerfettoDsInstanceIndex inst_id);
+
+// Iterator for all the active instances (on this thread) of a data source type.
+struct PerfettoDsImplTracerIterator {
+ // Instance id.
+ PerfettoDsInstanceIndex inst_id;
+ // Caches a pointer to the internal thread local state of the data source
+ // type.
+ struct PerfettoDsTlsImpl* tls;
+ // Pointer to the object used to output trace packets. When nullptr, the
+ // iteration is over.
+ struct PerfettoDsTracerImpl* tracer;
+};
+
+// Start iterating over all the active instances of the data source type
+// (`ds_impl`).
+//
+// If the returned tracer is not nullptr, the user must continue the iteration
+// with PerfettoDsImplTraceIterateNext(), until it is. The iteration can
+// only be interrupted early by calling PerfettoDsImplTraceIterateBreak().
+PERFETTO_SDK_EXPORT struct PerfettoDsImplTracerIterator
+PerfettoDsImplTraceIterateBegin(struct PerfettoDsImpl* ds_impl);
+
+// Advances the iterator to the next active instance of the data source type
+// (`ds_impl`).
+//
+// The user must call PerfettoDsImplTraceIterateNext(), until it returns a
+// nullptr tracer. The iteration can only be interrupted early by calling
+// PerfettoDsImplTraceIterateBreak().
+PERFETTO_SDK_EXPORT void PerfettoDsImplTraceIterateNext(
+ struct PerfettoDsImpl* ds_impl,
+ struct PerfettoDsImplTracerIterator* iterator);
+
+// Prematurely interrupts iteration over all the active instances of the data
+// source type (`ds_impl`).
+PERFETTO_SDK_EXPORT void PerfettoDsImplTraceIterateBreak(
+ struct PerfettoDsImpl* ds_impl,
+ struct PerfettoDsImplTracerIterator* iterator);
+
+// Creates a new trace packet on `tracer`. Returns a stream writer that can be
+// used to write data to the packet. The caller must use
+// PerfettoDsTracerImplPacketEnd() when done.
+PERFETTO_SDK_EXPORT struct PerfettoStreamWriter PerfettoDsTracerImplPacketBegin(
+ struct PerfettoDsTracerImpl* tracer);
+
+// Signals that the trace packets created previously on `tracer` with
+// PerfettoDsTracerImplBeginPacket(), has been fully written.
+//
+// `writer` should point to the writer returned by
+// PerfettoDsTracerImplBeginPacket() and cannot be used anymore after this call.
+PERFETTO_SDK_EXPORT void PerfettoDsTracerImplPacketEnd(
+ struct PerfettoDsTracerImpl* tracer,
+ struct PerfettoStreamWriter* writer);
+
+// Called when a flush request is complete.
+typedef void (*PerfettoDsTracerOnFlushCb)(void* user_arg);
+
+// Forces a commit of the thread-local tracing data written so far to the
+// service.
+//
+// If `cb` is not NULL, it is called on a dedicated internal thread (with
+// `user_arg`), when flushing is complete. It may never be called (e.g. if the
+// tracing service disconnects).
+//
+// This is almost never required (tracing data is periodically committed as
+// trace pages are filled up) and has a non-negligible performance hit.
+PERFETTO_SDK_EXPORT void PerfettoDsTracerImplFlush(
+ struct PerfettoDsTracerImpl* tracer,
+ PerfettoDsTracerOnFlushCb cb,
+ void* user_arg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // INCLUDE_PERFETTO_PUBLIC_ABI_DATA_SOURCE_ABI_H_
diff --git a/include/perfetto/public/compiler.h b/include/perfetto/public/compiler.h
index 4d8905b..1ff416d 100644
--- a/include/perfetto/public/compiler.h
+++ b/include/perfetto/public/compiler.h
@@ -17,6 +17,8 @@
#ifndef INCLUDE_PERFETTO_PUBLIC_COMPILER_H_
#define INCLUDE_PERFETTO_PUBLIC_COMPILER_H_
+#include <stddef.h>
+
#if defined(__GNUC__) || defined(__clang__)
#define PERFETTO_LIKELY(_x) __builtin_expect(!!(_x), 1)
#define PERFETTO_UNLIKELY(_x) __builtin_expect(!!(_x), 0)
@@ -33,4 +35,12 @@
#define PERFETTO_STATIC_CAST(TYPE, VAL) ((TYPE)(VAL))
#endif
+// PERFETTO_NULL: avoids the -Wzero-as-null-pointer-constant warning when
+// writing code that needs to be compiled as C and C++.
+#ifdef __cplusplus
+#define PERFETTO_NULL nullptr
+#else
+#define PERFETTO_NULL NULL
+#endif
+
#endif // INCLUDE_PERFETTO_PUBLIC_COMPILER_H_
diff --git a/include/perfetto/public/data_source.h b/include/perfetto/public/data_source.h
new file mode 100644
index 0000000..7bbb7d9
--- /dev/null
+++ b/include/perfetto/public/data_source.h
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef INCLUDE_PERFETTO_PUBLIC_DATA_SOURCE_H_
+#define INCLUDE_PERFETTO_PUBLIC_DATA_SOURCE_H_
+
+#include <malloc.h>
+#include <string.h>
+
+#include "perfetto/public/abi/atomic.h"
+#include "perfetto/public/abi/data_source_abi.h"
+#include "perfetto/public/compiler.h"
+#include "perfetto/public/pb_utils.h"
+
+// A data source type.
+struct PerfettoDs {
+ // Pointer to a (atomic) boolean, which is set to true if there is at
+ // least one enabled instance of this data source type.
+ PERFETTO_ATOMIC(bool) * enabled;
+ struct PerfettoDsImpl* impl;
+};
+
+// Initializes a PerfettoDs struct.
+#define PERFETTO_DS_INIT() \
+ { &perfetto_atomic_false, PERFETTO_NULL }
+
+// All the callbacks are optional and can be NULL if not needed.
+struct PerfettoDsCallbacks {
+ // Instance lifecycle callbacks:
+ PerfettoDsOnSetupCb on_setup_cb;
+ PerfettoDsOnStartCb on_start_cb;
+ PerfettoDsOnStopCb on_stop_cb;
+
+ // These are called to create/delete custom thread-local instance state, which
+ // can be accessed with PerfettoDsTracerImplGetCustomTls().
+ PerfettoDsOnCreateCustomState on_create_tls_cb;
+ PerfettoDsOnDeleteCustomState on_delete_tls_cb;
+
+ // These are called to create/delete custom thread-local instance incremental
+ // state. Incremental state may be cleared periodically by the tracing service
+ // and can be accessed with PerfettoDsTracerImplGetIncrementalState().
+ PerfettoDsOnCreateCustomState on_create_incr_cb;
+ PerfettoDsOnDeleteCustomState on_delete_incr_cb;
+
+ // Passed to all the callbacks as the `user_arg` param.
+ void* user_arg;
+};
+
+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};
+ 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 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;
+
+ ds_impl = PerfettoDsImplCreate();
+ if (callbacks.on_setup_cb) {
+ PerfettoDsSetOnSetupCallback(ds_impl, callbacks.on_setup_cb);
+ }
+ if (callbacks.on_start_cb) {
+ PerfettoDsSetOnStartCallback(ds_impl, callbacks.on_start_cb);
+ }
+ if (callbacks.on_stop_cb) {
+ PerfettoDsSetOnStopCallback(ds_impl, callbacks.on_stop_cb);
+ }
+ if (callbacks.on_create_tls_cb) {
+ PerfettoDsSetOnCreateTls(ds_impl, callbacks.on_create_tls_cb);
+ }
+ if (callbacks.on_delete_tls_cb) {
+ PerfettoDsSetOnDeleteTls(ds_impl, callbacks.on_delete_tls_cb);
+ }
+ if (callbacks.on_create_incr_cb) {
+ PerfettoDsSetOnCreateIncr(ds_impl, callbacks.on_create_incr_cb);
+ }
+ if (callbacks.on_delete_incr_cb) {
+ PerfettoDsSetOnDeleteIncr(ds_impl, callbacks.on_delete_incr_cb);
+ }
+ if (callbacks.user_arg) {
+ PerfettoDsSetCbUserArg(ds_impl, callbacks.user_arg);
+ }
+
+ success = PerfettoDsImplRegister(
+ ds_impl, &ds->enabled, data_source_desc,
+ PERFETTO_STATIC_CAST(size_t, write_ptr - data_source_desc));
+ free(data_source_desc);
+ if (!success) {
+ return false;
+ }
+ ds->impl = ds_impl;
+ return true;
+}
+
+// Iterator for all the active instances (on this thread) of a data source type.
+struct PerfettoDsTracerIterator {
+ struct PerfettoDsImplTracerIterator impl;
+};
+
+static inline struct PerfettoDsTracerIterator PerfettoDsTraceIterateBegin(
+ struct PerfettoDs* ds) {
+ struct PerfettoDsTracerIterator ret;
+ PERFETTO_ATOMIC(bool)* enabled = ds->enabled;
+ if (PERFETTO_LIKELY(!PERFETTO_ATOMIC_LOAD_EXPLICIT(
+ enabled, PERFETTO_MEMORY_ORDER_RELAXED))) {
+ // Tracing fast path: bail out immediately if the enabled flag is false.
+ ret.impl.tracer = PERFETTO_NULL;
+ } else {
+ // Else, make an ABI call to start iteration over the data source type
+ // active instances.
+ ret.impl = PerfettoDsImplTraceIterateBegin(ds->impl);
+ }
+ return ret;
+}
+
+static inline void PerfettoDsTraceIterateNext(
+ struct PerfettoDs* ds,
+ struct PerfettoDsTracerIterator* iterator) {
+ PerfettoDsImplTraceIterateNext(ds->impl, &iterator->impl);
+}
+
+static inline void PerfettoDsTraceIterateBreak(
+ struct PerfettoDs* ds,
+ struct PerfettoDsTracerIterator* iterator) {
+ if (iterator->impl.tracer) {
+ PerfettoDsImplTraceIterateBreak(ds->impl, &iterator->impl);
+ }
+}
+
+// For loop over the active instances of a data source type.
+//
+// `NAME` is the data source type (struct PerfettoDs).
+//
+// A local variable called `ITERATOR` will be instantiated. It can be used to
+// perform tracing on each instance.
+//
+// N.B. The iteration MUST NOT be interrupted early with `break`.
+// PERFETTO_DS_TRACE_BREAK should be used instead.
+#define PERFETTO_DS_TRACE(NAME, ITERATOR) \
+ for (struct PerfettoDsTracerIterator ITERATOR = \
+ PerfettoDsTraceIterateBegin(&(NAME)); \
+ (ITERATOR).impl.tracer != NULL; \
+ PerfettoDsTraceIterateNext(&(NAME), &(ITERATOR)))
+
+// Used to break the iteration in a PERFETTO_DS_TRACE loop.
+#define PERFETTO_DS_TRACE_BREAK(NAME, ITERATOR) \
+ PerfettoDsTraceIterateBreak(&(NAME), &(ITERATOR)); \
+ break
+
+static inline void* PerfettoDsGetCustomTls(
+ struct PerfettoDs* ds,
+ struct PerfettoDsTracerIterator* iterator) {
+ return PerfettoDsImplGetCustomTls(ds->impl, iterator->impl.tracer,
+ iterator->impl.inst_id);
+}
+
+static inline void* PerfettoDsGetIncrementalState(
+ struct PerfettoDs* ds,
+ struct PerfettoDsTracerIterator* iterator) {
+ return PerfettoDsImplGetIncrementalState(ds->impl, iterator->impl.tracer,
+ iterator->impl.inst_id);
+}
+
+static inline void PerfettoDsTracerFlush(
+ struct PerfettoDsTracerIterator* iterator,
+ PerfettoDsTracerOnFlushCb cb,
+ void* ctx) {
+ PerfettoDsTracerImplFlush(iterator->impl.tracer, cb, ctx);
+}
+
+#endif // INCLUDE_PERFETTO_PUBLIC_DATA_SOURCE_H_
diff --git a/include/perfetto/public/pb_utils.h b/include/perfetto/public/pb_utils.h
new file mode 100644
index 0000000..17cabc1
--- /dev/null
+++ b/include/perfetto/public/pb_utils.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef INCLUDE_PERFETTO_PUBLIC_PB_UTILS_H_
+#define INCLUDE_PERFETTO_PUBLIC_PB_UTILS_H_
+
+#include <stdint.h>
+
+#include "perfetto/public/compiler.h"
+
+// Type of fields that can be found in a protobuf serialized message.
+enum PerfettoPbWireType {
+ PERFETTO_PB_WIRE_TYPE_VARINT = 0,
+ PERFETTO_PB_WIRE_TYPE_DELIMITED = 2,
+};
+
+// Creates a field tag, which encodes the field type and the field id.
+static inline uint32_t PerfettoPbMakeTag(int32_t field_id,
+ enum PerfettoPbWireType wire_type) {
+ return ((PERFETTO_STATIC_CAST(uint32_t, field_id)) << 3) |
+ PERFETTO_STATIC_CAST(uint32_t, wire_type);
+}
+
+enum {
+ // Maximum bytes size of a 64-bit integer encoded as a VarInt.
+ PERFETTO_PB_VARINT_MAX_SIZE_64 = 10,
+ // Maximum bytes size of a 32-bit integer encoded as a VarInt.
+ PERFETTO_PB_VARINT_MAX_SIZE_32 = 5,
+};
+
+// Encodes `value` as a VarInt into `*dst`.
+//
+// `dst` must point into a buffer big enough to represent `value`:
+// PERFETTO_PB_VARINT_MAX_SIZE_* can help.
+static inline uint8_t* PerfettoPbWriteVarInt(uint64_t value, uint8_t* dst) {
+ uint8_t byte;
+ while (value >= 0x80) {
+ byte = (value & 0x7f) | 0x80;
+ *dst++ = byte;
+ value >>= 7;
+ }
+ byte = value & 0x7f;
+ *dst++ = byte;
+
+ return dst;
+}
+
+#endif // INCLUDE_PERFETTO_PUBLIC_PB_UTILS_H_
diff --git a/include/perfetto/tracing/internal/tracing_tls.h b/include/perfetto/tracing/internal/tracing_tls.h
index b2340a4..dc3a7b6 100644
--- a/include/perfetto/tracing/internal/tracing_tls.h
+++ b/include/perfetto/tracing/internal/tracing_tls.h
@@ -81,6 +81,10 @@
// handlers. See comment in TracingTLS::~TracingTLS().
bool is_in_trace_point = false;
+ // Used inside a trace point (only one trace point per thread can be active at
+ // any time) to cache the instances bitmap.
+ uint32_t cached_instances = 0;
+
// By default all data source instances have independent thread-local state
// (see above).
std::array<DataSourceThreadLocalState, kMaxDataSources> data_sources_tls{};
diff --git a/src/shared_lib/BUILD.gn b/src/shared_lib/BUILD.gn
index 4d8ef73..c653a81 100644
--- a/src/shared_lib/BUILD.gn
+++ b/src/shared_lib/BUILD.gn
@@ -22,6 +22,7 @@
"../tracing:platform_impl",
]
sources = [
+ "data_source.cc",
"producer.cc",
"stream_writer.cc",
"stream_writer.h",
diff --git a/src/shared_lib/data_source.cc b/src/shared_lib/data_source.cc
new file mode 100644
index 0000000..dfab70a
--- /dev/null
+++ b/src/shared_lib/data_source.cc
@@ -0,0 +1,439 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "perfetto/public/abi/data_source_abi.h"
+
+#include <bitset>
+
+#include "perfetto/tracing/data_source.h"
+#include "perfetto/tracing/internal/basic_types.h"
+#include "protos/perfetto/common/data_source_descriptor.gen.h"
+#include "protos/perfetto/config/data_source_config.gen.h"
+#include "src/shared_lib/stream_writer.h"
+
+namespace {
+
+using ::perfetto::internal::DataSourceInstanceThreadLocalState;
+using ::perfetto::internal::DataSourceThreadLocalState;
+using ::perfetto::internal::DataSourceType;
+
+thread_local DataSourceThreadLocalState*
+ g_tls_cache[perfetto::internal::kMaxDataSources];
+
+} // namespace
+
+// Implementation of a shared library data source type (there's one of these per
+// type, not per instance).
+//
+// Returned to the C side when invoking PerfettoDsCreateImpl(). The C side only
+// has an opaque pointer to this.
+struct PerfettoDsImpl {
+ // Instance lifecycle callbacks.
+ PerfettoDsOnSetupCb on_setup_cb = nullptr;
+ PerfettoDsOnStartCb on_start_cb = nullptr;
+ PerfettoDsOnStopCb on_stop_cb = nullptr;
+
+ // These are called to create/delete custom thread-local instance state.
+ PerfettoDsOnCreateCustomState on_create_tls_cb = nullptr;
+ PerfettoDsOnDeleteCustomState on_delete_tls_cb = nullptr;
+
+ // These are called to create/delete custom thread-local instance incremental
+ // state.
+ PerfettoDsOnCreateCustomState on_create_incr_cb = nullptr;
+ PerfettoDsOnDeleteCustomState on_delete_incr_cb = nullptr;
+
+ // Passed to all the callbacks as the `user_arg` param.
+ void* cb_user_arg;
+
+ DataSourceType cpp_type;
+ std::atomic<bool> enabled{false};
+ std::mutex mu;
+ // Guarded by mu
+ std::bitset<perfetto::internal::kMaxDataSourceInstances> enabled_instances;
+
+ bool IsRegistered() {
+ return cpp_type.static_state()->index !=
+ perfetto::internal::kMaxDataSources;
+ }
+};
+
+namespace {
+
+// Represents a global data source instance (there can be more than one of these
+// for a single data source type).
+class ShlibDataSource : public perfetto::DataSourceBase {
+ public:
+ explicit ShlibDataSource(PerfettoDsImpl* type) : type_(*type) {}
+
+ void OnSetup(const SetupArgs& args) override {
+ if (type_.on_setup_cb) {
+ std::vector<uint8_t> serialized_config = args.config->SerializeAsArray();
+ inst_ctx_ = type_.on_setup_cb(
+ args.internal_instance_index, serialized_config.data(),
+ serialized_config.size(), type_.cb_user_arg);
+ }
+ std::lock_guard<std::mutex> lock(type_.mu);
+ const bool was_enabled = type_.enabled_instances.any();
+ type_.enabled_instances.set(args.internal_instance_index);
+ if (!was_enabled && type_.enabled_instances.any()) {
+ type_.enabled.store(true, std::memory_order_release);
+ }
+ }
+
+ void OnStart(const StartArgs& args) override {
+ if (type_.on_start_cb) {
+ type_.on_start_cb(args.internal_instance_index, type_.cb_user_arg,
+ inst_ctx_);
+ }
+ }
+
+ void OnStop(const StopArgs& args) override {
+ if (type_.on_stop_cb) {
+ type_.on_stop_cb(
+ args.internal_instance_index, type_.cb_user_arg, inst_ctx_,
+ const_cast<PerfettoDsOnStopArgs*>(
+ reinterpret_cast<const PerfettoDsOnStopArgs*>(&args)));
+ }
+
+ std::lock_guard<std::mutex> lock(type_.mu);
+ type_.enabled_instances.reset(args.internal_instance_index);
+ if (type_.enabled_instances.none()) {
+ type_.enabled.store(false, std::memory_order_release);
+ }
+ }
+
+ const PerfettoDsImpl& type() const { return type_; }
+
+ void* inst_ctx() const { return inst_ctx_; }
+
+ private:
+ PerfettoDsImpl& type_;
+ void* inst_ctx_ = nullptr;
+};
+
+struct DataSourceTraits {
+ static DataSourceThreadLocalState* GetDataSourceTLS(
+ perfetto::internal::DataSourceStaticState* static_state,
+ perfetto::internal::TracingTLS* root_tls) {
+ auto* ds_tls = &root_tls->data_sources_tls[static_state->index];
+ // The per-type TLS is either zero-initialized or must have been
+ // initialized for this specific data source type.
+ PERFETTO_DCHECK(!ds_tls->static_state ||
+ ds_tls->static_state->index == static_state->index);
+ return ds_tls;
+ }
+};
+
+struct TracePointTraits {
+ using TracePointData = DataSourceType*;
+ static std::atomic<uint32_t>* GetActiveInstances(TracePointData s) {
+ return s->valid_instances();
+ }
+};
+
+DataSourceInstanceThreadLocalState::ObjectWithDeleter CreateShlibTls(
+ DataSourceInstanceThreadLocalState* tls_inst,
+ uint32_t inst_idx,
+ void* ctx) {
+ auto* ds_impl = reinterpret_cast<PerfettoDsImpl*>(ctx);
+
+ void* custom_state = ds_impl->on_create_tls_cb(
+ inst_idx, reinterpret_cast<PerfettoDsTracerImpl*>(tls_inst),
+ ds_impl->cb_user_arg);
+ return DataSourceInstanceThreadLocalState::ObjectWithDeleter(
+ custom_state, ds_impl->on_delete_tls_cb);
+}
+
+DataSourceInstanceThreadLocalState::ObjectWithDeleter
+CreateShlibIncrementalState(DataSourceInstanceThreadLocalState* tls_inst,
+ uint32_t inst_idx,
+ void* ctx) {
+ auto* ds_impl = reinterpret_cast<PerfettoDsImpl*>(ctx);
+
+ void* custom_state = ds_impl->on_create_incr_cb(
+ inst_idx, reinterpret_cast<PerfettoDsTracerImpl*>(tls_inst),
+ ds_impl->cb_user_arg);
+ return DataSourceInstanceThreadLocalState::ObjectWithDeleter(
+ custom_state, ds_impl->on_delete_incr_cb);
+}
+
+} // namespace
+
+// Exposed through data_source_abi.h
+std::atomic<bool> perfetto_atomic_false{false};
+
+struct PerfettoDsImpl* PerfettoDsImplCreate() {
+ return new PerfettoDsImpl();
+}
+
+void PerfettoDsSetOnSetupCallback(struct PerfettoDsImpl* ds_impl,
+ PerfettoDsOnSetupCb cb) {
+ PERFETTO_CHECK(!ds_impl->IsRegistered());
+ ds_impl->on_setup_cb = cb;
+}
+
+void PerfettoDsSetOnStartCallback(struct PerfettoDsImpl* ds_impl,
+ PerfettoDsOnStartCb cb) {
+ PERFETTO_CHECK(!ds_impl->IsRegistered());
+ ds_impl->on_start_cb = cb;
+}
+
+void PerfettoDsSetOnStopCallback(struct PerfettoDsImpl* ds_impl,
+ PerfettoDsOnStopCb cb) {
+ PERFETTO_CHECK(!ds_impl->IsRegistered());
+ ds_impl->on_stop_cb = cb;
+}
+
+void PerfettoDsSetOnCreateTls(struct PerfettoDsImpl* ds_impl,
+ PerfettoDsOnCreateCustomState cb) {
+ PERFETTO_CHECK(!ds_impl->IsRegistered());
+ ds_impl->on_create_tls_cb = cb;
+}
+
+void PerfettoDsSetOnDeleteTls(struct PerfettoDsImpl* ds_impl,
+ PerfettoDsOnDeleteCustomState cb) {
+ PERFETTO_CHECK(!ds_impl->IsRegistered());
+ ds_impl->on_delete_tls_cb = cb;
+}
+
+void PerfettoDsSetOnCreateIncr(struct PerfettoDsImpl* ds_impl,
+ PerfettoDsOnCreateCustomState cb) {
+ PERFETTO_CHECK(!ds_impl->IsRegistered());
+ ds_impl->on_create_incr_cb = cb;
+}
+
+void PerfettoDsSetOnDeleteIncr(struct PerfettoDsImpl* ds_impl,
+ PerfettoDsOnDeleteCustomState cb) {
+ PERFETTO_CHECK(!ds_impl->IsRegistered());
+ ds_impl->on_delete_incr_cb = cb;
+}
+
+void PerfettoDsSetCbUserArg(struct PerfettoDsImpl* ds_impl, void* user_arg) {
+ PERFETTO_CHECK(!ds_impl->IsRegistered());
+ ds_impl->cb_user_arg = user_arg;
+}
+
+bool PerfettoDsImplRegister(struct PerfettoDsImpl* ds_impl,
+ PERFETTO_ATOMIC(bool) * *enabled_ptr,
+ const void* descriptor,
+ size_t descriptor_size) {
+ perfetto::DataSourceDescriptor dsd;
+ dsd.ParseFromArray(descriptor, descriptor_size);
+
+ std::unique_ptr<PerfettoDsImpl> data_source_type(ds_impl);
+
+ auto factory = [ds_impl]() {
+ return std::unique_ptr<perfetto::DataSourceBase>(
+ new ShlibDataSource(ds_impl));
+ };
+
+ DataSourceType::CreateCustomTlsFn create_custom_tls_fn = nullptr;
+ DataSourceType::CreateIncrementalStateFn create_incremental_state_fn =
+ nullptr;
+ void* cb_ctx = nullptr;
+ if (data_source_type->on_create_incr_cb &&
+ data_source_type->on_delete_incr_cb) {
+ create_incremental_state_fn = CreateShlibIncrementalState;
+ cb_ctx = data_source_type.get();
+ }
+ if (data_source_type->on_create_tls_cb &&
+ data_source_type->on_delete_tls_cb) {
+ create_custom_tls_fn = CreateShlibTls;
+ cb_ctx = data_source_type.get();
+ }
+
+ perfetto::internal::DataSourceParams params;
+ 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,
+ create_custom_tls_fn, create_incremental_state_fn, cb_ctx);
+ if (!success) {
+ return false;
+ }
+ *enabled_ptr = &data_source_type->enabled;
+ perfetto::base::ignore_result(data_source_type.release());
+ return true;
+}
+
+void PerfettoDsImplUpdateDescriptor(struct PerfettoDsImpl* ds_impl,
+ const void* descriptor,
+ size_t descriptor_size) {
+ perfetto::DataSourceDescriptor dsd;
+ dsd.ParseFromArray(descriptor, descriptor_size);
+
+ ds_impl->cpp_type.UpdateDescriptor(dsd);
+}
+
+PerfettoDsAsyncStopper* PerfettoDsOnStopArgsPostpone(
+ PerfettoDsOnStopArgs* args) {
+ auto* cb = new std::function<void()>();
+ *cb = reinterpret_cast<const ShlibDataSource::StopArgs*>(args)
+ ->HandleStopAsynchronously();
+ return reinterpret_cast<PerfettoDsAsyncStopper*>(cb);
+}
+
+void PerfettoDsStopDone(PerfettoDsAsyncStopper* stopper) {
+ auto* cb = reinterpret_cast<std::function<void()>*>(stopper);
+ (*cb)();
+ delete cb;
+}
+
+void* PerfettoDsImplGetInstanceLocked(struct PerfettoDsImpl* ds_impl,
+ PerfettoDsInstanceIndex idx) {
+ auto* internal_state = ds_impl->cpp_type.static_state()->TryGet(idx);
+ if (!internal_state) {
+ return nullptr;
+ }
+ std::unique_lock<std::recursive_mutex> lock(internal_state->lock);
+ auto* data_source =
+ static_cast<ShlibDataSource*>(internal_state->data_source.get());
+ if (&data_source->type() != ds_impl) {
+ // The data source instance has been destroyed and recreated as a different
+ // type while we where tracing.
+ return nullptr;
+ }
+ void* inst_ctx = data_source->inst_ctx();
+ if (inst_ctx != nullptr) {
+ lock.release();
+ }
+ return inst_ctx;
+}
+
+void PerfettoDsImplReleaseInstanceLocked(struct PerfettoDsImpl* ds_impl,
+ PerfettoDsInstanceIndex idx) {
+ auto* internal_state = ds_impl->cpp_type.static_state()->TryGet(idx);
+ PERFETTO_CHECK(internal_state);
+ internal_state->lock.unlock();
+}
+
+void* PerfettoDsImplGetCustomTls(struct PerfettoDsImpl*,
+ struct PerfettoDsTracerImpl* tracer,
+ PerfettoDsInstanceIndex) {
+ auto* tls_inst =
+ reinterpret_cast<DataSourceInstanceThreadLocalState*>(tracer);
+
+ PERFETTO_DCHECK(tls_inst->data_source_custom_tls);
+ return tls_inst->data_source_custom_tls.get();
+}
+
+void* PerfettoDsImplGetIncrementalState(struct PerfettoDsImpl* ds_impl,
+ struct PerfettoDsTracerImpl* tracer,
+ PerfettoDsInstanceIndex idx) {
+ auto* tls_inst =
+ reinterpret_cast<DataSourceInstanceThreadLocalState*>(tracer);
+
+ return ds_impl->cpp_type.GetIncrementalState(tls_inst, idx);
+}
+
+struct PerfettoDsImplTracerIterator PerfettoDsImplTraceIterateBegin(
+ struct PerfettoDsImpl* ds_impl) {
+ DataSourceThreadLocalState** tls =
+ &g_tls_cache[ds_impl->cpp_type.static_state()->index];
+
+ struct PerfettoDsImplTracerIterator ret = {0, nullptr, nullptr};
+ uint32_t cached_instances =
+ ds_impl->cpp_type.valid_instances()->load(std::memory_order_relaxed);
+ if (!cached_instances) {
+ return ret;
+ }
+ bool res =
+ ds_impl->cpp_type.TracePrologue<DataSourceTraits, TracePointTraits>(
+ tls, &cached_instances, &ds_impl->cpp_type);
+ if (!res) {
+ return ret;
+ }
+ DataSourceType::InstancesIterator it =
+ ds_impl->cpp_type.BeginIteration<TracePointTraits>(cached_instances, *tls,
+ &ds_impl->cpp_type);
+ ret.inst_id = it.i;
+ (*tls)->root_tls->cached_instances = it.cached_instances;
+ ret.tracer = reinterpret_cast<struct PerfettoDsTracerImpl*>(it.instance);
+ if (!ret.tracer) {
+ ds_impl->cpp_type.TraceEpilogue(*tls);
+ }
+
+ ret.tls = reinterpret_cast<struct PerfettoDsTlsImpl*>(*tls);
+ return ret;
+}
+
+void PerfettoDsImplTraceIterateNext(
+ struct PerfettoDsImpl* ds_impl,
+ struct PerfettoDsImplTracerIterator* iterator) {
+ auto* tls = reinterpret_cast<DataSourceThreadLocalState*>(iterator->tls);
+
+ DataSourceType::InstancesIterator it;
+ it.i = iterator->inst_id;
+ it.cached_instances = tls->root_tls->cached_instances;
+ it.instance =
+ reinterpret_cast<DataSourceInstanceThreadLocalState*>(iterator->tracer);
+
+ ds_impl->cpp_type.NextIteration<TracePointTraits>(&it, tls,
+ &ds_impl->cpp_type);
+
+ iterator->inst_id = it.i;
+ tls->root_tls->cached_instances = it.cached_instances;
+ iterator->tracer =
+ reinterpret_cast<struct PerfettoDsTracerImpl*>(it.instance);
+
+ if (!iterator->tracer) {
+ ds_impl->cpp_type.TraceEpilogue(tls);
+ }
+}
+
+void PerfettoDsImplTraceIterateBreak(
+ struct PerfettoDsImpl* ds_impl,
+ struct PerfettoDsImplTracerIterator* iterator) {
+ auto* tls = reinterpret_cast<DataSourceThreadLocalState*>(iterator->tls);
+
+ ds_impl->cpp_type.TraceEpilogue(tls);
+}
+
+struct PerfettoStreamWriter PerfettoDsTracerImplPacketBegin(
+ struct PerfettoDsTracerImpl* tracer) {
+ auto* tls_inst =
+ reinterpret_cast<DataSourceInstanceThreadLocalState*>(tracer);
+
+ auto message_handle = tls_inst->trace_writer->NewTracePacket();
+ struct PerfettoStreamWriter ret;
+ protozero::ScatteredStreamWriter* sw = message_handle.TakeStreamWriter();
+ ret.impl = reinterpret_cast<PerfettoStreamWriterImpl*>(sw);
+ perfetto::UpdateStreamWriter(*sw, &ret);
+ return ret;
+}
+
+void PerfettoDsTracerImplPacketEnd(struct PerfettoDsTracerImpl* tracer,
+ struct PerfettoStreamWriter* w) {
+ auto* tls_inst =
+ reinterpret_cast<DataSourceInstanceThreadLocalState*>(tracer);
+ auto* sw = reinterpret_cast<protozero::ScatteredStreamWriter*>(w->impl);
+
+ sw->set_write_ptr(w->write_ptr);
+ tls_inst->trace_writer->FinishTracePacket();
+}
+
+void PerfettoDsTracerImplFlush(struct PerfettoDsTracerImpl* tracer,
+ PerfettoDsTracerOnFlushCb cb,
+ void* user_arg) {
+ auto* tls_inst =
+ reinterpret_cast<DataSourceInstanceThreadLocalState*>(tracer);
+
+ std::function<void()> fn;
+ if (cb != nullptr) {
+ fn = [user_arg, cb]() { cb(user_arg); };
+ }
+ tls_inst->trace_writer->Flush(fn);
+}