| // 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. |
| // |
| |
| #ifndef TRACE_INTERNAL_EVENT_INTERNAL_H_ |
| #define TRACE_INTERNAL_EVENT_INTERNAL_H_ |
| |
| #include <zircon/compiler.h> |
| #include <zircon/syscalls.h> |
| |
| #include <trace-engine/instrumentation.h> |
| #include <trace/internal/event_args.h> |
| |
| __BEGIN_CDECLS |
| |
| // Variable used to refer to the current trace context. |
| #define TRACE_INTERNAL_CONTEXT __trace_context |
| |
| // Variable used to hold call-site cache state. |
| #define TRACE_INTERNAL_SITE_STATE __trace_site_state |
| |
| // Variable used to refer to the current trace category's string ref. |
| #define TRACE_INTERNAL_CATEGORY_REF __trace_category_ref |
| |
| // Variable used to contain the array of arguments. |
| #define TRACE_INTERNAL_ARGS __trace_args |
| |
| // Number of arguments recorded in |TRACE_INTERNAL_ARGS|. |
| // TODO(PT-67): Rename this, conventions says TRACE_NUM_ARGS should call this. |
| #define TRACE_INTERNAL_NUM_ARGS (sizeof(TRACE_INTERNAL_ARGS) / sizeof(TRACE_INTERNAL_ARGS[0])) |
| |
| // BEGIN SECTION OF DEPRECATED MACROS, USED BY EXTERNAL CODE |
| // TODO(PT-67): These will be replaced with the NEW_ versions when all existing |
| // code is cleaned up to not use these. |
| |
| // 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_HOLD_ARG(var_name, idx, name_literal, arg_value) \ |
| const auto& arg##idx = (arg_value); |
| #define TRACE_INTERNAL_MAKE_ARG(var_name, idx, name_literal, arg_value) \ |
| { .name_ref = {.encoded_value = 0, .inline_string = (name_literal)}, \ |
| .value = ::trace::internal::MakeArgumentValue(arg##idx) } |
| #else |
| #define TRACE_INTERNAL_MAKE_ARG(var_name, idx, name_literal, arg_value) \ |
| { .name_ref = {.encoded_value = 0, .inline_string = (name_literal)}, \ |
| .value = (arg_value) } |
| #endif // __cplusplus |
| |
| #ifdef __cplusplus |
| #define TRACE_INTERNAL_DECLARE_ARGS(args...) \ |
| TRACE_INTERNAL_APPLY_PAIRWISE(TRACE_INTERNAL_HOLD_ARG, ignore, args) \ |
| trace_arg_t TRACE_INTERNAL_ARGS[] = { \ |
| TRACE_INTERNAL_APPLY_PAIRWISE_CSV(TRACE_INTERNAL_MAKE_ARG, ignore, args)}; \ |
| static_assert(TRACE_INTERNAL_NUM_ARGS <= TRACE_MAX_ARGS, "too many args") |
| #else |
| #define TRACE_INTERNAL_DECLARE_ARGS(args...) \ |
| trace_arg_t TRACE_INTERNAL_ARGS[] = { \ |
| TRACE_INTERNAL_APPLY_PAIRWISE_CSV(TRACE_INTERNAL_MAKE_ARG, ignore, args)}; \ |
| static_assert(TRACE_INTERNAL_NUM_ARGS <= TRACE_MAX_ARGS, "too many args") |
| #endif // __cplusplus |
| |
| // END SECTION OF DEPRECATED MACROS, USED BY EXTERNAL CODE |
| |
| // 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 |
| |
| #define TRACE_INTERNAL_SCOPE_ARGS_LABEL(scope) TRACE_INTERNAL_SCOPE_ARGS_LABEL_(scope) |
| #define TRACE_INTERNAL_SCOPE_ARGS_LABEL_(scope) scope##_args |
| |
| // 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_NEW_DECLARE_ARGS(TRACE_INTERNAL_CONTEXT, \ |
| TRACE_INTERNAL_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_NEW_DECLARE_ARGS(TRACE_INTERNAL_CONTEXT, \ |
| TRACE_INTERNAL_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 { \ |
| static trace_site_t TRACE_INTERNAL_SITE_STATE; \ |
| trace_string_ref_t TRACE_INTERNAL_CATEGORY_REF; \ |
| trace_context_t* TRACE_INTERNAL_CONTEXT = \ |
| trace_acquire_context_for_category_cached( \ |
| (category_literal), &TRACE_INTERNAL_SITE_STATE, \ |
| &TRACE_INTERNAL_CATEGORY_REF); \ |
| if (unlikely(TRACE_INTERNAL_CONTEXT)) { \ |
| TRACE_INTERNAL_NEW_DECLARE_ARGS(TRACE_INTERNAL_CONTEXT, \ |
| TRACE_INTERNAL_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_NEW_DECLARE_ARGS(TRACE_INTERNAL_CONTEXT, \ |
| TRACE_INTERNAL_ARGS, \ |
| args); \ |
| stmt; \ |
| } \ |
| } while (0) |
| #endif // NTRACE |
| |
| #define TRACE_INTERNAL_INSTANT(category_literal, name_literal, scope, args...) \ |
| do { \ |
| 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); \ |
| } while (0) |
| |
| #define TRACE_INTERNAL_COUNTER(category_literal, name_literal, counter_id, args...) \ |
| do { \ |
| 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); \ |
| } while (0) |
| |
| #define TRACE_INTERNAL_DURATION_BEGIN(category_literal, name_literal, args...) \ |
| do { \ |
| 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); \ |
| } while (0) |
| |
| #define TRACE_INTERNAL_DURATION_END(category_literal, name_literal, args...) \ |
| do { \ |
| 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); \ |
| } while (0) |
| |
| #ifndef NTRACE |
| // TODO(fmeawad): The generated code for this macro is too big (PT-87) |
| #define TRACE_INTERNAL_DECLARE_DURATION_SCOPE(variable, args_variable, category_literal, \ |
| name_literal, args...) \ |
| TRACE_INTERNAL_ALLOCATE_ARGS(args_variable, args); \ |
| __attribute__((cleanup(trace_internal_cleanup_duration_scope))) \ |
| trace_internal_duration_scope_t variable; \ |
| do { \ |
| static trace_site_t TRACE_INTERNAL_SITE_STATE; \ |
| trace_string_ref_t TRACE_INTERNAL_CATEGORY_REF; \ |
| trace_context_t* TRACE_INTERNAL_CONTEXT = \ |
| trace_acquire_context_for_category_cached((category_literal), \ |
| &TRACE_INTERNAL_SITE_STATE, \ |
| &TRACE_INTERNAL_CATEGORY_REF); \ |
| if (unlikely(TRACE_INTERNAL_CONTEXT)) { \ |
| TRACE_INTERNAL_INIT_ARGS(args_variable, args); \ |
| trace_release_context(TRACE_INTERNAL_CONTEXT); \ |
| trace_internal_make_duration_scope(&variable, (category_literal), (name_literal), \ |
| args_variable, \ |
| sizeof(args_variable) / sizeof(args_variable[0])); \ |
| } else { \ |
| variable.start_time = 0; \ |
| } \ |
| } while (0) |
| |
| #define TRACE_INTERNAL_DURATION_(scope_label, scope_category_literal, scope_name_literal, args...) \ |
| TRACE_INTERNAL_DECLARE_DURATION_SCOPE(scope_label, TRACE_INTERNAL_SCOPE_ARGS_LABEL(scope_label), \ |
| scope_category_literal, scope_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...) \ |
| do { \ |
| 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); \ |
| } while (0) |
| |
| #define TRACE_INTERNAL_ASYNC_INSTANT(category_literal, name_literal, async_id, args...) \ |
| do { \ |
| 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); \ |
| } while (0) |
| |
| #define TRACE_INTERNAL_ASYNC_END(category_literal, name_literal, async_id, args...) \ |
| do { \ |
| 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); \ |
| } while (0) |
| |
| #define TRACE_INTERNAL_FLOW_BEGIN(category_literal, name_literal, flow_id, args...) \ |
| do { \ |
| 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); \ |
| } while (0) |
| |
| #define TRACE_INTERNAL_FLOW_STEP(category_literal, name_literal, flow_id, args...) \ |
| do { \ |
| 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); \ |
| } while (0) |
| |
| #define TRACE_INTERNAL_FLOW_END(category_literal, name_literal, flow_id, args...) \ |
| do { \ |
| 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); \ |
| } while (0) |
| |
| #define TRACE_INTERNAL_KERNEL_OBJECT(handle, args...) \ |
| do { \ |
| 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); \ |
| } while (0) |
| |
| #define TRACE_INTERNAL_BLOB(type, name, blob, blob_size) \ |
| do { \ |
| trace_context_t* TRACE_INTERNAL_CONTEXT = \ |
| trace_acquire_context(); \ |
| if (unlikely(TRACE_INTERNAL_CONTEXT)) { \ |
| trace_internal_write_blob_record_and_release_context( \ |
| TRACE_INTERNAL_CONTEXT, \ |
| (type), (name), (blob), (blob_size)); \ |
| } \ |
| } while (0) |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| // When "destroyed" (by the cleanup attribute), writes a duration event. |
| typedef struct trace_internal_duration_scope { |
| const char* category_literal; |
| const char* name_literal; |
| trace_ticks_t start_time; |
| trace_arg_t* args; |
| size_t num_args; |
| } trace_internal_duration_scope_t; |
| |
| 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, |
| 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, |
| 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, |
| 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, |
| trace_arg_t* args, size_t num_args); |
| |
| void trace_internal_write_duration_event_record( |
| const trace_internal_duration_scope_t* scope); |
| |
| 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, |
| 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, |
| 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, |
| 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, |
| 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, |
| 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, |
| 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, |
| trace_arg_t* args, size_t num_args); |
| |
| void trace_internal_write_blob_record_and_release_context( |
| trace_context_t* context, |
| trace_blob_type_t type, |
| const char* name_literal, |
| const void* blob, size_t blob_size); |
| |
| #ifndef NTRACE |
| |
| static inline void trace_internal_make_duration_scope( |
| trace_internal_duration_scope_t* scope, |
| const char* category_literal, const char* name_literal, |
| trace_arg_t* args, size_t num_args) { |
| scope->category_literal = category_literal; |
| scope->name_literal = name_literal; |
| scope->start_time = zx_ticks_get(); |
| scope->args = args; |
| scope->num_args = num_args; |
| } |
| |
| static inline void trace_internal_cleanup_duration_scope( |
| trace_internal_duration_scope_t* scope) { |
| // Check if the scope has been initialized. It can be un-initialized if |
| // tracing started after the scope was created or tracing is off. |
| if (likely(scope->start_time == 0)) |
| return; |
| trace_internal_write_duration_event_record(scope); |
| } |
| #endif // NTRACE |
| |
| __END_CDECLS |
| |
| #endif // TRACE_INTERNAL_EVENT_INTERNAL_H_ |