| // Copyright 2018 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. |
| |
| #ifndef SRC_LIB_CALLBACK_TRACE_CALLBACK_H_ |
| #define SRC_LIB_CALLBACK_TRACE_CALLBACK_H_ |
| |
| #include <lib/fit/defer.h> |
| #include <lib/fit/function.h> |
| #include <lib/syslog/cpp/macros.h> |
| #include <lib/trace/event.h> |
| |
| #include <cstring> |
| #include <functional> |
| #include <utility> |
| |
| namespace callback { |
| |
| namespace internal { |
| |
| template <typename C> |
| class TracingLambda { |
| public: |
| TracingLambda(C callback, uint64_t id, const char* category, const char* name, |
| const char* callback_name) |
| : id_(id), |
| category_(category), |
| name_(name), |
| callback_name_(callback_name), |
| callback_(std::move(callback)), |
| did_run_or_moved_out_(false), |
| trace_enabled_(true) {} |
| |
| explicit TracingLambda(C callback) |
| : id_(0u), |
| category_(nullptr), |
| name_(nullptr), |
| callback_name_(nullptr), |
| callback_(std::move(callback)), |
| did_run_or_moved_out_(false), |
| trace_enabled_(false) {} |
| |
| // Copy constructor so that the resulting callback can be used as an |
| // fit::function, but acts as a move constructor. Only the last copy is valid. |
| TracingLambda(TracingLambda&& other) noexcept |
| : id_(other.id_), |
| category_(other.category_), |
| name_(other.name_), |
| callback_name_(other.callback_name_), |
| callback_(std::move(other.callback_)), |
| did_run_or_moved_out_(other.did_run_or_moved_out_), |
| trace_enabled_(other.trace_enabled_) { |
| FX_DCHECK(!other.did_run_or_moved_out_); |
| other.did_run_or_moved_out_ = true; |
| } |
| |
| ~TracingLambda() { |
| if (!did_run_or_moved_out_ && trace_enabled_) { |
| TRACE_ASYNC_END(category_, name_, id_, "NotRun", true); |
| } |
| } |
| |
| template <typename... ArgType> |
| auto operator()(ArgType&&... args) const { |
| FX_DCHECK(!did_run_or_moved_out_); |
| did_run_or_moved_out_ = true; |
| if (trace_enabled_) { |
| TRACE_ASYNC_END(category_, name_, id_); |
| TRACE_ASYNC_BEGIN(category_, callback_name_, id_); |
| } |
| auto guard = fit::defer([trace_enabled = trace_enabled_, id = id_, category = category_, |
| callback_name = callback_name_] { |
| if (trace_enabled) { |
| TRACE_ASYNC_END(category, callback_name, id); |
| } |
| }); |
| |
| return callback_(std::forward<ArgType>(args)...); |
| } |
| |
| private: |
| const uint64_t id_; |
| const char* const category_; |
| const char* const name_; |
| const char* const callback_name_; |
| mutable C callback_; |
| mutable bool did_run_or_moved_out_; |
| bool trace_enabled_; |
| |
| FXL_DISALLOW_COPY_AND_ASSIGN(TracingLambda); |
| }; |
| |
| // NOLINT suppresses check about 'args' being unused. It might be used in the |
| // future if TRACE_CALLBACK (see below) is used providing additional arguments. |
| template <typename C, typename... ArgType> |
| auto TraceCallback(C callback, const char* category, const char* name, const char* callback_name, |
| ArgType... args) { // NOLINT |
| uint64_t id = TRACE_NONCE(); |
| TRACE_ASYNC_BEGIN(category, name, id, std::forward<ArgType>(args)...); |
| return TracingLambda<C>(std::move(callback), id, category, name, callback_name); |
| } |
| |
| template <typename C> |
| auto TraceCallback(C callback) { |
| return TracingLambda<C>(std::move(callback)); |
| } |
| |
| // Identity functions. This is used to ensure that a C string is a compile time |
| // constant in conjunction with __builtin_strlen. |
| template <size_t S> |
| constexpr const char* CheckConstantCString(const char* value) { |
| return value; |
| } |
| |
| } // namespace internal |
| } // namespace callback |
| |
| // Wraps the given callback so that it's traced using async tracing from the |
| // time it's wrapped to the time it completes. Can be used only for callbacks |
| // that will be called at most once. |
| #define TRACE_CALLBACK(cb, category, name, args...) \ |
| ([&]() mutable { \ |
| auto trace_local_cb__ = cb; \ |
| return (TRACE_ENABLED() \ |
| ? ::callback::internal::TraceCallback( \ |
| std::move(trace_local_cb__), \ |
| ::callback::internal::CheckConstantCString<__builtin_strlen(category)>( \ |
| category), \ |
| ::callback::internal::CheckConstantCString<__builtin_strlen(name)>(name), \ |
| name "_callback", ##args) \ |
| : ::callback::internal::TraceCallback(std::move(trace_local_cb__))); \ |
| }()) |
| |
| #endif // SRC_LIB_CALLBACK_TRACE_CALLBACK_H_ |