blob: b5d40885f01465a0662f5b886ee6173fe861fff1 [file] [log] [blame]
// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Internal declarations used by the C tracing macros.
// This is not part of the public API: use <trace/event.h> instead.
//
#pragma once
#include <assert.h>
#include <zircon/compiler.h>
#include <trace-engine/instrumentation.h>
#include <trace/pairs_internal.h>
__BEGIN_CDECLS
// Variable used to refer to the current trace context.
#define TRACE_INTERNAL_CONTEXT __trace_context
// Variable used to refer to the current trace category's string ref.
#define TRACE_INTERNAL_CATEGORY_REF __trace_category_ref
// Makes a string literal string ref.
#define TRACE_INTERNAL_MAKE_LITERAL_STRING_REF(string_literal_value) \
(trace_context_make_registered_string_literal( \
TRACE_INTERNAL_CONTEXT, (string_literal_value)))
// Makes a trace argument.
#ifdef __cplusplus
#define TRACE_INTERNAL_MAKE_ARG(name_literal, value) \
(trace_make_arg(TRACE_INTERNAL_MAKE_LITERAL_STRING_REF(name_literal), \
::trace::internal::MakeArgumentValue(value)))
#else
#define TRACE_INTERNAL_MAKE_ARG(name_literal, value) \
(trace_make_arg(TRACE_INTERNAL_MAKE_LITERAL_STRING_REF(name_literal), \
(value)))
#endif // __cplusplus
// Declares an array of arguments and initializes it.
#define TRACE_INTERNAL_ARGS __trace_args
#define TRACE_INTERNAL_NUM_ARGS (sizeof(TRACE_INTERNAL_ARGS) / sizeof(TRACE_INTERNAL_ARGS[0]))
#define TRACE_INTERNAL_DECLARE_ARGS(args...) \
const trace_arg_t TRACE_INTERNAL_ARGS[] = { \
TRACE_INTERNAL_APPLY_PAIRWISE(TRACE_INTERNAL_MAKE_ARG, args)}; \
static_assert(TRACE_INTERNAL_NUM_ARGS <= TRACE_MAX_ARGS, "too many args")
// Obtains a unique identifier name within the containing scope.
#define TRACE_INTERNAL_SCOPE_LABEL() TRACE_INTERNAL_SCOPE_LABEL_(__COUNTER__)
#define TRACE_INTERNAL_SCOPE_LABEL_(token) TRACE_INTERNAL_SCOPE_LABEL__(token)
#define TRACE_INTERNAL_SCOPE_LABEL__(token) __trace_scope_##token
// Scaffolding for a trace macro that does not have a category.
#ifndef NTRACE
#define TRACE_INTERNAL_SIMPLE_RECORD(stmt, args...) \
do { \
trace_context_t* TRACE_INTERNAL_CONTEXT = \
trace_acquire_context(); \
if (unlikely(TRACE_INTERNAL_CONTEXT)) { \
TRACE_INTERNAL_DECLARE_ARGS(args); \
stmt; \
} \
} while (0)
#else
#define TRACE_INTERNAL_SIMPLE_RECORD(stmt, args...) \
do { \
if (0) { \
trace_context_t* TRACE_INTERNAL_CONTEXT = 0; \
TRACE_INTERNAL_DECLARE_ARGS(args); \
stmt; \
} \
} while (0)
#endif // NTRACE
// Scaffolding for a trace macro that has a category (such as a trace event).
#ifndef NTRACE
#define TRACE_INTERNAL_EVENT_RECORD(category_literal, stmt, args...) \
do { \
trace_string_ref_t TRACE_INTERNAL_CATEGORY_REF; \
trace_context_t* TRACE_INTERNAL_CONTEXT = \
trace_acquire_context_for_category( \
(category_literal), \
&TRACE_INTERNAL_CATEGORY_REF); \
if (unlikely(TRACE_INTERNAL_CONTEXT)) { \
TRACE_INTERNAL_DECLARE_ARGS(args); \
stmt; \
} \
} while (0)
#else
#define TRACE_INTERNAL_EVENT_RECORD(category_literal, stmt, args...) \
do { \
if (0) { \
trace_string_ref_t TRACE_INTERNAL_CATEGORY_REF; \
trace_context_t* TRACE_INTERNAL_CONTEXT = 0; \
TRACE_INTERNAL_DECLARE_ARGS(args); \
stmt; \
} \
} while (0)
#endif // NTRACE
#define TRACE_INTERNAL_INSTANT(category_literal, name_literal, scope, args...) \
TRACE_INTERNAL_EVENT_RECORD( \
(category_literal), \
trace_internal_write_instant_event_record_and_release_context( \
TRACE_INTERNAL_CONTEXT, \
&TRACE_INTERNAL_CATEGORY_REF, \
(name_literal), (scope), TRACE_INTERNAL_ARGS, TRACE_INTERNAL_NUM_ARGS), \
args)
#define TRACE_INTERNAL_COUNTER(category_literal, name_literal, counter_id, args...) \
TRACE_INTERNAL_EVENT_RECORD( \
(category_literal), \
trace_internal_write_counter_event_record_and_release_context( \
TRACE_INTERNAL_CONTEXT, \
&TRACE_INTERNAL_CATEGORY_REF, \
(name_literal), (counter_id), TRACE_INTERNAL_ARGS, TRACE_INTERNAL_NUM_ARGS), \
args)
#define TRACE_INTERNAL_DURATION_BEGIN(category_literal, name_literal, args...) \
TRACE_INTERNAL_EVENT_RECORD( \
(category_literal), \
trace_internal_write_duration_begin_event_record_and_release_context( \
TRACE_INTERNAL_CONTEXT, \
&TRACE_INTERNAL_CATEGORY_REF, \
(name_literal), TRACE_INTERNAL_ARGS, TRACE_INTERNAL_NUM_ARGS), \
args)
#define TRACE_INTERNAL_DURATION_END(category_literal, name_literal, args...) \
TRACE_INTERNAL_EVENT_RECORD( \
(category_literal), \
trace_internal_write_duration_end_event_record_and_release_context( \
TRACE_INTERNAL_CONTEXT, \
&TRACE_INTERNAL_CATEGORY_REF, \
(name_literal), TRACE_INTERNAL_ARGS, TRACE_INTERNAL_NUM_ARGS), \
args)
#ifndef NTRACE
#define TRACE_INTERNAL_DECLARE_DURATION_SCOPE(variable, category_literal, name_literal) \
__attribute__((cleanup(trace_internal_cleanup_duration_scope))) \
trace_internal_duration_scope_t variable; \
trace_internal_make_duration_scope(&variable, (category_literal), (name_literal))
#define TRACE_INTERNAL_DURATION_(scope_label, scope_category_literal, scope_name_literal, args...) \
TRACE_INTERNAL_DECLARE_DURATION_SCOPE(scope_label, scope_category_literal, scope_name_literal); \
TRACE_INTERNAL_DURATION_BEGIN(scope_label.category_literal, scope_label.name_literal, args)
#define TRACE_INTERNAL_DURATION_(scope_label, scope_category_literal, scope_name_literal, args...) \
TRACE_INTERNAL_DECLARE_DURATION_SCOPE(scope_label, scope_category_literal, scope_name_literal); \
TRACE_INTERNAL_DURATION_BEGIN(scope_label.category_literal, scope_label.name_literal, args)
#define TRACE_INTERNAL_DURATION(category_literal, name_literal, args...) \
TRACE_INTERNAL_DURATION_(TRACE_INTERNAL_SCOPE_LABEL(), (category_literal), (name_literal), args)
#else
#define TRACE_INTERNAL_DURATION(category_literal, name_literal, args...) \
TRACE_INTERNAL_DURATION_BEGIN((category_literal), (name_literal), args)
#endif // NTRACE
#define TRACE_INTERNAL_ASYNC_BEGIN(category_literal, name_literal, async_id, args...) \
TRACE_INTERNAL_EVENT_RECORD( \
(category_literal), \
trace_internal_write_async_begin_event_record_and_release_context( \
TRACE_INTERNAL_CONTEXT, \
&TRACE_INTERNAL_CATEGORY_REF, \
(name_literal), (async_id), TRACE_INTERNAL_ARGS, TRACE_INTERNAL_NUM_ARGS), \
args)
#define TRACE_INTERNAL_ASYNC_INSTANT(category_literal, name_literal, async_id, args...) \
TRACE_INTERNAL_EVENT_RECORD( \
(category_literal), \
trace_internal_write_async_instant_event_record_and_release_context( \
TRACE_INTERNAL_CONTEXT, \
&TRACE_INTERNAL_CATEGORY_REF, \
(name_literal), (async_id), TRACE_INTERNAL_ARGS, TRACE_INTERNAL_NUM_ARGS), \
args)
#define TRACE_INTERNAL_ASYNC_END(category_literal, name_literal, async_id, args...) \
TRACE_INTERNAL_EVENT_RECORD( \
(category_literal), \
trace_internal_write_async_end_event_record_and_release_context( \
TRACE_INTERNAL_CONTEXT, \
&TRACE_INTERNAL_CATEGORY_REF, \
(name_literal), (async_id), TRACE_INTERNAL_ARGS, TRACE_INTERNAL_NUM_ARGS), \
args)
#define TRACE_INTERNAL_FLOW_BEGIN(category_literal, name_literal, flow_id, args...) \
TRACE_INTERNAL_EVENT_RECORD( \
(category_literal), \
trace_internal_write_flow_begin_event_record_and_release_context( \
TRACE_INTERNAL_CONTEXT, \
&TRACE_INTERNAL_CATEGORY_REF, \
(name_literal), (flow_id), TRACE_INTERNAL_ARGS, TRACE_INTERNAL_NUM_ARGS), \
args)
#define TRACE_INTERNAL_FLOW_STEP(category_literal, name_literal, flow_id, args...) \
TRACE_INTERNAL_EVENT_RECORD( \
(category_literal), \
trace_internal_write_flow_step_event_record_and_release_context( \
TRACE_INTERNAL_CONTEXT, \
&TRACE_INTERNAL_CATEGORY_REF, \
(name_literal), (flow_id), TRACE_INTERNAL_ARGS, TRACE_INTERNAL_NUM_ARGS), \
args)
#define TRACE_INTERNAL_FLOW_END(category_literal, name_literal, flow_id, args...) \
TRACE_INTERNAL_EVENT_RECORD( \
(category_literal), \
trace_internal_write_flow_end_event_record_and_release_context( \
TRACE_INTERNAL_CONTEXT, \
&TRACE_INTERNAL_CATEGORY_REF, \
(name_literal), (flow_id), TRACE_INTERNAL_ARGS, TRACE_INTERNAL_NUM_ARGS), \
args)
#define TRACE_INTERNAL_KERNEL_OBJECT(handle, args...) \
TRACE_INTERNAL_SIMPLE_RECORD( \
trace_internal_write_kernel_object_record_for_handle_and_release_context( \
TRACE_INTERNAL_CONTEXT, \
(handle), TRACE_INTERNAL_ARGS, TRACE_INTERNAL_NUM_ARGS), \
args)
void trace_internal_write_instant_event_record_and_release_context(
trace_context_t* context,
const trace_string_ref_t* category_ref,
const char* name_literal,
trace_scope_t scope,
const trace_arg_t* args, size_t num_args);
void trace_internal_write_counter_event_record_and_release_context(
trace_context_t* context,
const trace_string_ref_t* category_ref,
const char* name_literal,
uint64_t counter_id,
const trace_arg_t* args, size_t num_args);
void trace_internal_write_duration_begin_event_record_and_release_context(
trace_context_t* context,
const trace_string_ref_t* category_ref,
const char* name_literal,
const trace_arg_t* args, size_t num_args);
void trace_internal_write_duration_end_event_record_and_release_context(
trace_context_t* context,
const trace_string_ref_t* category_ref,
const char* name_literal,
const trace_arg_t* args, size_t num_args);
void trace_internal_write_async_begin_event_record_and_release_context(
trace_context_t* context,
const trace_string_ref_t* category_ref,
const char* name_literal,
trace_async_id_t async_id,
const trace_arg_t* args, size_t num_args);
void trace_internal_write_async_instant_event_record_and_release_context(
trace_context_t* context,
const trace_string_ref_t* category_ref,
const char* name_literal,
trace_async_id_t async_id,
const trace_arg_t* args, size_t num_args);
void trace_internal_write_async_end_event_record_and_release_context(
trace_context_t* context,
const trace_string_ref_t* category_ref,
const char* name_literal,
trace_async_id_t async_id,
const trace_arg_t* args, size_t num_args);
void trace_internal_write_flow_begin_event_record_and_release_context(
trace_context_t* context,
const trace_string_ref_t* category_ref,
const char* name_literal,
trace_flow_id_t flow_id,
const trace_arg_t* args, size_t num_args);
void trace_internal_write_flow_step_event_record_and_release_context(
trace_context_t* context,
const trace_string_ref_t* category_ref,
const char* name_literal,
trace_flow_id_t flow_id,
const trace_arg_t* args, size_t num_args);
void trace_internal_write_flow_end_event_record_and_release_context(
trace_context_t* context,
const trace_string_ref_t* category_ref,
const char* name_literal,
trace_flow_id_t flow_id,
const trace_arg_t* args, size_t num_args);
void trace_internal_write_kernel_object_record_for_handle_and_release_context(
trace_context_t* context,
zx_handle_t handle,
const trace_arg_t* args, size_t num_args);
#ifndef NTRACE
// When "destroyed" (by the cleanup attribute), writes a duration end event.
typedef struct {
const char* category_literal;
const char* name_literal;
} trace_internal_duration_scope_t;
static inline void trace_internal_make_duration_scope(
trace_internal_duration_scope_t* scope,
const char* category_literal, const char* name_literal) {
scope->category_literal = category_literal;
scope->name_literal = name_literal;
}
static inline void trace_internal_cleanup_duration_scope(
trace_internal_duration_scope_t* scope) {
TRACE_INTERNAL_DURATION_END(scope->category_literal, scope->name_literal);
}
#endif // NTRACE
__END_CDECLS
#ifdef __cplusplus
#include <fbl/type_support.h>
namespace trace {
namespace internal {
// Helps construct trace argument values using SFINAE to coerce types.
template <typename T, typename Enable = void>
struct ArgumentValueMaker;
template <>
struct ArgumentValueMaker<trace_arg_value_t> {
static trace_arg_value_t Make(trace_arg_value_t value) {
return value;
}
};
template <>
struct ArgumentValueMaker<decltype(nullptr)> {
static trace_arg_value_t Make(decltype(nullptr) value) {
return trace_make_null_arg_value();
}
};
template <typename T>
struct ArgumentValueMaker<
T,
typename fbl::enable_if<fbl::is_signed_integer<T>::value &&
(sizeof(T) <= sizeof(int32_t))>::type> {
static trace_arg_value_t Make(int32_t value) {
return trace_make_int32_arg_value(value);
}
};
template <typename T>
struct ArgumentValueMaker<
T,
typename fbl::enable_if<fbl::is_unsigned_integer<T>::value &&
(sizeof(T) <= sizeof(uint32_t))>::type> {
static trace_arg_value_t Make(uint32_t value) {
return trace_make_uint32_arg_value(value);
}
};
template <typename T>
struct ArgumentValueMaker<
T,
typename fbl::enable_if<fbl::is_signed_integer<T>::value &&
(sizeof(T) > sizeof(int32_t)) &&
(sizeof(T) <= sizeof(int64_t))>::type> {
static trace_arg_value_t Make(int64_t value) {
return trace_make_int64_arg_value(value);
}
};
template <typename T>
struct ArgumentValueMaker<
T,
typename fbl::enable_if<fbl::is_unsigned_integer<T>::value &&
(sizeof(T) > sizeof(uint32_t)) &&
(sizeof(T) <= sizeof(uint64_t))>::type> {
static trace_arg_value_t Make(uint64_t value) {
return trace_make_uint64_arg_value(value);
}
};
template <typename T>
struct ArgumentValueMaker<T, typename fbl::enable_if<fbl::is_enum<T>::value>::type> {
using UnderlyingType = typename fbl::underlying_type<T>::type;
static trace_arg_value_t Make(UnderlyingType value) {
return ArgumentValueMaker<UnderlyingType>::Make(value);
}
};
template <typename T>
struct ArgumentValueMaker<
T,
typename fbl::enable_if<fbl::is_floating_point<T>::value>::type> {
static trace_arg_value_t Make(double value) {
return trace_make_double_arg_value(value);
}
};
template <size_t n>
struct ArgumentValueMaker<char[n]> {
static trace_arg_value_t Make(const char* value) {
return trace_make_string_arg_value(
trace_make_inline_string_ref(value, n));
}
};
template <>
struct ArgumentValueMaker<const char*> {
static trace_arg_value_t Make(const char* value) {
return trace_make_string_arg_value(
trace_make_inline_c_string_ref(value));
}
};
// Works for the following types:
// - fbl::String
// - fbl::StringPiece
// - std::string
// - std::stringview
DECLARE_HAS_MEMBER_FN(has_data, data);
DECLARE_HAS_MEMBER_FN(has_length, length);
template <typename T>
struct ArgumentValueMaker<T,
typename fbl::enable_if<has_data<T>::value &&
has_length<T>::value>::type> {
static trace_arg_value_t Make(const T& value) {
return trace_make_string_arg_value(
trace_make_inline_string_ref(value.data(), value.length()));
}
};
template <typename T>
struct ArgumentValueMaker<T*> {
static trace_arg_value_t Make(const T* pointer) {
return trace_make_pointer_arg_value(reinterpret_cast<uintptr_t>(pointer));
}
};
template <typename T>
trace_arg_value_t MakeArgumentValue(const T& value) {
return ArgumentValueMaker<T>::Make(value);
}
} // namespace internal
} // namespace trace
#endif // __cplusplus