blob: f54823801cb105b56c2a526d27c48328450eeaa2 [file] [log] [blame]
/*
* 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_TE_MACROS_H_
#define INCLUDE_PERFETTO_PUBLIC_TE_MACROS_H_
#include <assert.h>
#include "perfetto/public/abi/track_event_hl_abi.h"
#include "perfetto/public/track_event.h"
// This header defines the PERFETTO_TE macros and its possible params (at the
// end of the file). The rest of the file contains internal implementation
// details of the macros, which are subject to change at any time.
//
// The macro uses the High level ABI to emit track events.
#define PERFETTO_I_TE_STATIC_ASSERT_NUM_PARAMS_( \
NAME_AND_TYPE1, NAME_AND_TYPE2, EXTRA1, EXTRA2, EXTRA3, EXTRA4, SENTINEL, \
...) \
static_assert((SENTINEL) == 0, \
"Too many arguments for PERFETTO_TE " \
"macro")
// Fails to compile if there are too many params and they don't fit into
// PerfettoTeHlMacroParams.
#define PERFETTO_I_TE_STATIC_ASSERT_NUM_PARAMS(...) \
PERFETTO_I_TE_STATIC_ASSERT_NUM_PARAMS_(__VA_ARGS__, 0, 0, 0, 0, 0, 0)
#define PERFETTO_I_TE_LIMIT_4__(NAME_AND_TYPE1, NAME_AND_TYPE2, EXTRA1, \
EXTRA2, EXTRA3, EXTRA4, ...) \
NAME_AND_TYPE1, NAME_AND_TYPE2, EXTRA1, EXTRA2, EXTRA3, EXTRA4
#define PERFETTO_I_TE_LIMIT_4_(MACRO, ARGS) MACRO ARGS
#define PERFETTO_I_TE_LIMIT_4(...) \
PERFETTO_I_TE_LIMIT_4_(PERFETTO_I_TE_LIMIT_4__, (__VA_ARGS__))
// In C we have to use a compound literal. In C++ we can use a regular
// initializer.
#ifndef __cplusplus
#define PERFETTO_I_TE_HL_MACRO_PARAMS_PREAMBLE (struct PerfettoTeHlMacroParams)
#else
#define PERFETTO_I_TE_HL_MACRO_PARAMS_PREAMBLE
#endif
// Provides an initializer for `struct PerfettoTeHlMacroParams` and sets all the
// unused extra fields to PERFETTO_NULL.
#define PERFETTO_I_TE_HL_MACRO_PARAMS(...) \
PERFETTO_I_TE_HL_MACRO_PARAMS_PREAMBLE { \
PERFETTO_I_TE_LIMIT_4(__VA_ARGS__, PERFETTO_NULL, PERFETTO_NULL, \
PERFETTO_NULL, PERFETTO_NULL, PERFETTO_NULL, \
PERFETTO_NULL) \
}
#ifndef __cplusplus
#define PERFETTO_I_TE_COMPOUND_LITERAL_ADDR(STRUCT, ...) \
&(struct STRUCT)__VA_ARGS__
#define PERFETTO_I_TE_EXTRA(STRUCT, ...) \
((struct PerfettoTeHlExtra*)PERFETTO_I_TE_COMPOUND_LITERAL_ADDR( \
STRUCT, __VA_ARGS__))
#else
#define PERFETTO_I_TE_COMPOUND_LITERAL_ADDR(STRUCT, ...) \
&(STRUCT{} = STRUCT __VA_ARGS__)
#define PERFETTO_I_TE_EXTRA(STRUCT, ...) \
reinterpret_cast<struct PerfettoTeHlExtra*>( \
PERFETTO_I_TE_COMPOUND_LITERAL_ADDR(STRUCT, __VA_ARGS__))
#endif
struct PerfettoTeHlMacroNameAndType {
const char* name;
int32_t type;
};
struct PerfettoTeHlMacroParams {
struct PerfettoTeHlMacroNameAndType name_and_type;
struct PerfettoTeHlExtra* extra1;
struct PerfettoTeHlExtra* extra2;
struct PerfettoTeHlExtra* extra3;
struct PerfettoTeHlExtra* extra4;
};
static inline void PerfettoTeHlCall(struct PerfettoTeCategoryImpl* cat,
struct PerfettoTeHlMacroParams params) {
struct PerfettoTeHlExtra* perfetto_i_extra_data = PERFETTO_NULL;
if (params.extra1) {
params.extra1->next = perfetto_i_extra_data;
perfetto_i_extra_data = params.extra1;
}
if (params.extra2) {
params.extra2->next = perfetto_i_extra_data;
perfetto_i_extra_data = params.extra2;
}
if (params.extra3) {
params.extra3->next = perfetto_i_extra_data;
perfetto_i_extra_data = params.extra3;
}
if (params.extra4) {
params.extra4->next = perfetto_i_extra_data;
perfetto_i_extra_data = params.extra4;
}
PerfettoTeHlEmitImpl(cat, params.name_and_type.type,
params.name_and_type.name, perfetto_i_extra_data);
}
// Instead of a previously registered category, this macro can be used to
// specify that the category will be provided dynamically as a param.
#define PERFETTO_TE_DYNAMIC_CATEGORY PerfettoTeRegisteredDynamicCategory()
// -------------------------------------------------
// Possible types of event for the PERFETTO_TE macro
// -------------------------------------------------
// Begins a slice named `const char* NAME` on a track.
#define PERFETTO_TE_SLICE_BEGIN(NAME) \
{ NAME, PERFETTO_TE_TYPE_SLICE_BEGIN }
// Ends the last slice opened on a track.
#define PERFETTO_TE_SLICE_END() \
{ PERFETTO_NULL, PERFETTO_TE_TYPE_SLICE_END }
// Reports an instant event named `const char* NAME`.
#define PERFETTO_TE_INSTANT(NAME) \
{ NAME, PERFETTO_TE_TYPE_INSTANT }
// Reports the value of a counter. The counter value must be specified
// separately on another param with PERFETTO_TE_INT_COUNTER() or
// PERFETTO_TE_DOUBLE_COUNTER().
#define PERFETTO_TE_COUNTER() \
{ PERFETTO_NULL, PERFETTO_TE_TYPE_COUNTER }
// -------------------------------------------------
// Possible types of event for the PERFETTO_TE macro
// -------------------------------------------------
// The value (`C`) of an integer counter. A separate parameter must describe the
// counter track this refers to. This should only be used for events with
// type PERFETTO_TE_COUNTER().
#define PERFETTO_TE_INT_COUNTER(C) \
PERFETTO_I_TE_EXTRA( \
PerfettoTeHlExtraCounterInt64, \
{{PERFETTO_TE_HL_EXTRA_TYPE_COUNTER_INT64, PERFETTO_NULL}, C})
// The value (`C`) of a floating point. A separate parameter must describe the
// counter track this refers to. This should only be used for events with type
// PERFETTO_TE_COUNTER().
#define PERFETTO_TE_DOUBLE_COUNTER(C) \
PERFETTO_I_TE_EXTRA( \
PerfettoTeHlExtraCounterDouble, \
{{PERFETTO_TE_HL_EXTRA_TYPE_COUNTER_DOUBLE, PERFETTO_NULL}, C})
// Uses the timestamp `struct PerfettoTeTimestamp T` to report this event. If
// this is not specified, PERFETTO_TE() reads the current timestamp with
// PerfettoTeGetTimestamp().
#define PERFETTO_TE_TIMESTAMP(T) \
PERFETTO_I_TE_EXTRA( \
PerfettoTeHlExtraTimestamp, \
{{PERFETTO_TE_HL_EXTRA_TYPE_TIMESTAMP, PERFETTO_NULL}, T})
// Specifies that the current track for this event is
// `struct PerfettoTeRegisteredTrack* T`, which must have been previously
// registered.
#define PERFETTO_TE_REGISTERED_TRACK(T) \
PERFETTO_I_TE_EXTRA( \
PerfettoTeHlExtraRegisteredTrack, \
{{PERFETTO_TE_HL_EXTRA_TYPE_REGISTERED_TRACK, PERFETTO_NULL}, \
&(T)->impl})
// Specifies that the current track for this event is a track named `const char
// *NAME`, child of a track whose uuid is `PARENT_UUID`. `NAME`, `uint64_t ID`
// and `PARENT_UUID` uniquely identify a track. Common values for `PARENT_UUID`
// include PerfettoTeProcessTrackUuid(), PerfettoTeThreadTrackUuid() or
// PerfettoTeGlobalTrackUuid().
#define PERFETTO_TE_NAMED_TRACK(NAME, ID, PARENT_UUID) \
PERFETTO_I_TE_EXTRA(PerfettoTeHlExtraNamedTrack, \
{{PERFETTO_TE_HL_EXTRA_TYPE_NAMED_TRACK, PERFETTO_NULL}, \
NAME, \
ID, \
PARENT_UUID})
// When PERFETTO_TE_DYNAMIC_CATEGORY is used, this is used to specify `const
// char* S` as a category name.
#define PERFETTO_TE_DYNAMIC_CATEGORY_STRING(S) \
PERFETTO_I_TE_EXTRA( \
PerfettoTeHlExtraDynamicCategory, \
{{PERFETTO_TE_HL_EXTRA_TYPE_DYNAMIC_CATEGORY, PERFETTO_NULL}, \
PERFETTO_I_TE_COMPOUND_LITERAL_ADDR( \
PerfettoTeCategoryDescriptor, \
{S, PERFETTO_NULL, PERFETTO_NULL, 0})})
// Adds the debug annotation named `const char * NAME` with value `bool VALUE`.
#define PERFETTO_TE_ARG_BOOL(NAME, VALUE) \
PERFETTO_I_TE_EXTRA( \
PerfettoTeHlExtraDebugArgBool, \
{{PERFETTO_TE_HL_EXTRA_TYPE_DEBUG_ARG_BOOL, PERFETTO_NULL}, \
NAME, \
VALUE})
// Adds the debug annotation named `const char * NAME` with value `uint64_t
// VALUE`.
#define PERFETTO_TE_ARG_UINT64(NAME, VALUE) \
PERFETTO_I_TE_EXTRA( \
PerfettoTeHlExtraDebugArgUint64, \
{{PERFETTO_TE_HL_EXTRA_TYPE_DEBUG_ARG_UINT64, PERFETTO_NULL}, \
NAME, \
VALUE})
// Adds the debug annotation named `const char * NAME` with value `int64_t
// VALUE`.
#define PERFETTO_TE_ARG_INT64(NAME, VALUE) \
PERFETTO_I_TE_EXTRA( \
PerfettoTeHlExtraDebugArgInt64, \
{{PERFETTO_TE_HL_EXTRA_TYPE_DEBUG_ARG_INT64, PERFETTO_NULL}, \
NAME, \
VALUE})
// Adds the debug annotation named `const char * NAME` with value `double
// VALUE`.
#define PERFETTO_TE_ARG_DOUBLE(NAME, VALUE) \
PERFETTO_I_TE_EXTRA( \
PerfettoTeHlExtraDebugArgDouble, \
{{PERFETTO_TE_HL_EXTRA_TYPE_DEBUG_ARG_DOUBLE, PERFETTO_NULL}, \
NAME, \
VALUE})
// Adds the debug annotation named `const char * NAME` with value `const char*
// VALUE`.
#define PERFETTO_TE_ARG_STRING(NAME, VALUE) \
PERFETTO_I_TE_EXTRA( \
PerfettoTeHlExtraDebugArgString, \
{{PERFETTO_TE_HL_EXTRA_TYPE_DEBUG_ARG_STRING, PERFETTO_NULL}, \
NAME, \
VALUE})
// Adds the debug annotation named `const char * NAME` with value `void* VALUE`.
#define PERFETTO_TE_ARG_POINTER(NAME, VALUE) \
PERFETTO_I_TE_EXTRA( \
PerfettoTeHlExtraDebugArgPointer, \
{{PERFETTO_TE_HL_EXTRA_TYPE_DEBUG_ARG_POINTER, PERFETTO_NULL}, \
NAME, \
VALUE})
// Specifies that this event is part (or starts) a "flow" (i.e. a link among
// different events). The flow is identified by `struct PerfettoTeFlow VALUE`.
#define PERFETTO_TE_FLOW(VALUE) \
PERFETTO_I_TE_EXTRA( \
PerfettoTeHlExtraFlow, \
{{PERFETTO_TE_HL_EXTRA_TYPE_FLOW, PERFETTO_NULL}, (VALUE).id})
// Specifies that this event terminates a "flow" (i.e. a link among different
// events). The flow is identified by `struct PerfettoTeFlow VALUE`.
#define PERFETTO_TE_TERMINATING_FLOW(VALUE) \
PERFETTO_I_TE_EXTRA( \
PerfettoTeHlExtraFlow, \
{{PERFETTO_TE_HL_EXTRA_TYPE_TERMINATING_FLOW, PERFETTO_NULL}, \
(VALUE).id})
// Flushes the shared memory buffer and makes sure that all the previous events
// emitted by this thread are visibile in the central tracing buffer.
#define PERFETTO_TE_FLUSH() \
PERFETTO_I_TE_EXTRA(PerfettoTeHlExtra, \
{PERFETTO_TE_HL_EXTRA_TYPE_FLUSH, PERFETTO_NULL})
// Turns off interning for event names.
#define PERFETTO_TE_NO_INTERN() \
PERFETTO_I_TE_EXTRA(PerfettoTeHlExtra, \
{PERFETTO_TE_HL_EXTRA_TYPE_NO_INTERN, PERFETTO_NULL})
// ----------------------------------
// The main PERFETTO_TE tracing macro
// ----------------------------------
//
// If tracing is active and the passed tracing category is enabled, adds an
// entry in the tracing stream of the perfetto track event data source.
// Parameters:
// * `CAT`: The tracing category (it should be a struct
// PerfettoTeCategory object). It can be
// PERFETTO_TE_DYNAMIC_CATEGORY for dynamic categories (the dynamic category
// name should be passed later with)
// * The type of the event. It can be one of:
// * PERFETTO_TE_SLICE_BEGIN(name)
// * PERFETTO_TE_SLICE_END()
// * PERFETTO_TE_INSTANT()
// * PERFETTO_TE_COUNTER()
// * `...`: One or more (up to 4) macro parameters from the above list that
// specify the data to be traced.
//
// Examples:
//
// PERFETTO_TE(category, PERFETTO_TE_SLICE_BEGIN("name"),
// PERFETTO_TE_ARG_UINT64("extra_arg", 42));
// PERFETTO_TE(category, PERFETTO_TE_SLICE_END());
// PERFETTO_TE(category, PERFETTO_TE_COUNTER(),
// PERFETTO_TE_REGISTERED_TRACK(&mycounter),
// PERFETTO_TE_INT_COUNTER(79));
// PERFETTO_TE(PERFETTO_TE_DYNAMIC_CATEGORY, PERFETTO_TE_INSTANT("instant"),
// PERFETTO_TE_DYNAMIC_CATEGORY_STRING("category"));
//
#define PERFETTO_TE(CAT, ...) \
do { \
if (PERFETTO_UNLIKELY(PERFETTO_ATOMIC_LOAD_EXPLICIT( \
(CAT).enabled, PERFETTO_MEMORY_ORDER_RELAXED))) { \
PERFETTO_I_TE_STATIC_ASSERT_NUM_PARAMS(__VA_ARGS__); \
PerfettoTeHlCall((CAT).impl, \
PERFETTO_I_TE_HL_MACRO_PARAMS(__VA_ARGS__)); \
} \
} while (0)
#endif // INCLUDE_PERFETTO_PUBLIC_TE_MACROS_H_