blob: 90c86ae34c2ce3770225b79be302ef4f6ac0466d [file] [log] [blame]
/*
* 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 <stdlib.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_msg.h"
#include "perfetto/public/pb_utils.h"
#include "perfetto/public/protos/trace/trace_packet.pzc.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);
}
// Used to write a TracePacket on a data source instance. Stores the writer and
// the TracePacket message.
struct PerfettoDsRootTracePacket {
struct PerfettoPbMsgWriter writer;
struct perfetto_protos_TracePacket msg;
};
// Initializes `root` to write a new packet to the data source instance pointed
// by `iterator`.
static inline void PerfettoDsTracerPacketBegin(
struct PerfettoDsTracerIterator* iterator,
struct PerfettoDsRootTracePacket* root) {
root->writer.writer = PerfettoDsTracerImplPacketBegin(iterator->impl.tracer);
PerfettoPbMsgInit(&root->msg.msg, &root->writer);
}
// Finishes writing the packet pointed by `root` on the data source instance
// pointer by `iterator`.
static inline void PerfettoDsTracerPacketEnd(
struct PerfettoDsTracerIterator* iterator,
struct PerfettoDsRootTracePacket* root) {
PerfettoPbMsgFinalize(&root->msg.msg);
PerfettoDsTracerImplPacketEnd(iterator->impl.tracer, &root->writer.writer);
}
static inline void PerfettoDsTracerFlush(
struct PerfettoDsTracerIterator* iterator,
PerfettoDsTracerOnFlushCb cb,
void* ctx) {
PerfettoDsTracerImplFlush(iterator->impl.tracer, cb, ctx);
}
#endif // INCLUDE_PERFETTO_PUBLIC_DATA_SOURCE_H_