| /* | 
 |  * Copyright (C) 2019 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_TRACING_TRACK_EVENT_H_ | 
 | #define INCLUDE_PERFETTO_TRACING_TRACK_EVENT_H_ | 
 |  | 
 | #include "perfetto/base/time.h" | 
 | #include "perfetto/tracing/internal/track_event_data_source.h" | 
 | #include "perfetto/tracing/internal/track_event_internal.h" | 
 | #include "perfetto/tracing/internal/track_event_macros.h" | 
 | #include "perfetto/tracing/string_helpers.h" | 
 | #include "perfetto/tracing/track.h" | 
 | #include "perfetto/tracing/track_event_category_registry.h" | 
 | #include "protos/perfetto/trace/track_event/track_event.pbzero.h" | 
 |  | 
 | #include <type_traits> | 
 |  | 
 | // This file contains a set of macros designed for instrumenting applications | 
 | // with track event trace points. While the underlying TrackEvent API can also | 
 | // be used directly, doing so efficiently requires some care (e.g., to avoid | 
 | // evaluating arguments while tracing is disabled). These types of optimizations | 
 | // are abstracted away by the macros below. | 
 | // | 
 | // ================ | 
 | // Quickstart guide | 
 | // ================ | 
 | // | 
 | //   To add track events to your application, first define your categories in, | 
 | //   e.g., my_tracing.h: | 
 | // | 
 | //       PERFETTO_DEFINE_CATEGORIES( | 
 | //           perfetto::Category("base"), | 
 | //           perfetto::Category("v8"), | 
 | //           perfetto::Category("cc")); | 
 | // | 
 | //   Then in a single .cc file, e.g., my_tracing.cc: | 
 | // | 
 | //       #include "my_tracing.h" | 
 | //       PERFETTO_TRACK_EVENT_STATIC_STORAGE(); | 
 | // | 
 | //   Finally, register track events at startup, after which you can record | 
 | //   events with the TRACE_EVENT macros: | 
 | // | 
 | //       #include "my_tracing.h" | 
 | // | 
 | //       int main() { | 
 | //         perfetto::TrackEvent::Register(); | 
 | // | 
 | //         // A basic track event with just a name. | 
 | //         TRACE_EVENT("category", "MyEvent"); | 
 | // | 
 | //         // A track event with (up to two) debug annotations. | 
 | //         TRACE_EVENT("category", "MyEvent", "parameter", 42); | 
 | // | 
 | //         // A track event with a strongly typed parameter. | 
 | //         TRACE_EVENT("category", "MyEvent", [](perfetto::EventContext ctx) { | 
 | //           ctx.event()->set_foo(42); | 
 | //           ctx.event()->set_bar(.5f); | 
 | //         }); | 
 | //       } | 
 | // | 
 | //  Note that track events must be nested consistently, i.e., the following is | 
 | //  not allowed: | 
 | // | 
 | //    TRACE_EVENT_BEGIN("a", "bar", ...); | 
 | //    TRACE_EVENT_BEGIN("b", "foo", ...); | 
 | //    TRACE_EVENT_END("a");  // "foo" must be closed before "bar". | 
 | //    TRACE_EVENT_END("b"); | 
 | // | 
 | // ==================== | 
 | // Implementation notes | 
 | // ==================== | 
 | // | 
 | // The track event library consists of the following layers and components. The | 
 | // classes the internal namespace shouldn't be considered part of the public | 
 | // API. | 
 | //                    .--------------------------------. | 
 | //               .----|  TRACE_EVENT                   |----. | 
 | //      write   |     |   - App instrumentation point  |     |  write | 
 | //      event   |     '--------------------------------'     |  arguments | 
 | //              V                                            V | 
 | //  .----------------------------------.    .-----------------------------. | 
 | //  | TrackEvent                       |    | EventContext                | | 
 | //  |  - Registry of event categories  |    |  - One track event instance | | 
 | //  '----------------------------------'    '-----------------------------' | 
 | //              |                                            | | 
 | //              |                                            | look up | 
 | //              | is                                         | interning ids | 
 | //              V                                            V | 
 | //  .----------------------------------.    .-----------------------------. | 
 | //  | internal::TrackEventDataSource   |    | TrackEventInternedDataIndex | | 
 | //  | - Perfetto data source           |    | - Corresponds to a field in | | 
 | //  | - Has TrackEventIncrementalState |    |   in interned_data.proto    | | 
 | //  '----------------------------------'    '-----------------------------' | 
 | //              |                  |                         ^ | 
 | //              |                  |       owns (1:many)     | | 
 | //              | write event      '-------------------------' | 
 | //              V | 
 | //  .----------------------------------. | 
 | //  | internal::TrackEventInternal     | | 
 | //  | - Outlined code to serialize     | | 
 | //  |   one track event                | | 
 | //  '----------------------------------' | 
 | // | 
 |  | 
 | // Each compilation unit can be in exactly one track event namespace, | 
 | // allowing the overall program to use multiple track event data sources and | 
 | // category lists if necessary. Use this macro to select the namespace for the | 
 | // current compilation unit. | 
 | // | 
 | // If the program uses multiple track event namespaces, category & track event | 
 | // registration (see quickstart above) needs to happen for both namespaces | 
 | // separately. | 
 | #ifndef PERFETTO_TRACK_EVENT_NAMESPACE | 
 | #define PERFETTO_TRACK_EVENT_NAMESPACE perfetto | 
 | #endif | 
 |  | 
 | // Deprecated; see perfetto::Category(). | 
 | #define PERFETTO_CATEGORY(name) \ | 
 |   ::perfetto::Category { #name } | 
 |  | 
 | // Internal helpers for determining if a given category is defined at build or | 
 | // runtime. | 
 | namespace PERFETTO_TRACK_EVENT_NAMESPACE { | 
 | namespace internal { | 
 |  | 
 | // By default no statically defined categories are dynamic, but this can be | 
 | // overridden with PERFETTO_DEFINE_TEST_CATEGORY_PREFIXES. | 
 | template <typename... T> | 
 | constexpr bool IsDynamicCategory(const char*) { | 
 |   return false; | 
 | } | 
 |  | 
 | // Explicitly dynamic categories are always dynamic. | 
 | constexpr bool IsDynamicCategory(const ::perfetto::DynamicCategory&) { | 
 |   return true; | 
 | } | 
 |  | 
 | }  // namespace internal | 
 | }  // namespace PERFETTO_TRACK_EVENT_NAMESPACE | 
 |  | 
 | // Normally all categories are defined statically at build-time (see | 
 | // PERFETTO_DEFINE_CATEGORIES). However, some categories are only used for | 
 | // testing, and we shouldn't publish them to the tracing service or include them | 
 | // in a production binary. Use this macro to define a list of prefixes for these | 
 | // types of categories. Note that trace points using these categories will be | 
 | // slightly less efficient compared to regular trace points. | 
 | #define PERFETTO_DEFINE_TEST_CATEGORY_PREFIXES(...)                       \ | 
 |   namespace PERFETTO_TRACK_EVENT_NAMESPACE {                              \ | 
 |   namespace internal {                                                    \ | 
 |   template <>                                                             \ | 
 |   constexpr bool IsDynamicCategory(const char* name) {                    \ | 
 |     return ::perfetto::internal::IsStringInPrefixList(name, __VA_ARGS__); \ | 
 |   }                                                                       \ | 
 |   } /* namespace internal */                                              \ | 
 |   } /* namespace PERFETTO_TRACK_EVENT_NAMESPACE */                        \ | 
 |   PERFETTO_INTERNAL_SWALLOW_SEMICOLON() | 
 |  | 
 | // Register the set of available categories by passing a list of categories to | 
 | // this macro: PERFETTO_CATEGORY(cat1), PERFETTO_CATEGORY(cat2), ... | 
 | #define PERFETTO_DEFINE_CATEGORIES(...)                        \ | 
 |   namespace PERFETTO_TRACK_EVENT_NAMESPACE {                   \ | 
 |   /* The list of category names */                             \ | 
 |   PERFETTO_INTERNAL_DECLARE_CATEGORIES(__VA_ARGS__)            \ | 
 |   /* The track event data source for this set of categories */ \ | 
 |   PERFETTO_INTERNAL_DECLARE_TRACK_EVENT_DATA_SOURCE();         \ | 
 |   } /* namespace PERFETTO_TRACK_EVENT_NAMESPACE */             \ | 
 |   PERFETTO_DECLARE_DATA_SOURCE_STATIC_MEMBERS(                 \ | 
 |       PERFETTO_TRACK_EVENT_NAMESPACE::TrackEvent,              \ | 
 |       perfetto::internal::TrackEventDataSourceTraits) | 
 |  | 
 | // Allocate storage for each category by using this macro once per track event | 
 | // namespace. | 
 | #define PERFETTO_TRACK_EVENT_STATIC_STORAGE()      \ | 
 |   namespace PERFETTO_TRACK_EVENT_NAMESPACE {       \ | 
 |   PERFETTO_INTERNAL_CATEGORY_STORAGE()             \ | 
 |   } /* namespace PERFETTO_TRACK_EVENT_NAMESPACE */ \ | 
 |   PERFETTO_DEFINE_DATA_SOURCE_STATIC_MEMBERS(      \ | 
 |       PERFETTO_TRACK_EVENT_NAMESPACE::TrackEvent,  \ | 
 |       perfetto::internal::TrackEventDataSourceTraits) | 
 |  | 
 | // Ignore GCC warning about a missing argument for a variadic macro parameter. | 
 | #if defined(__GNUC__) || defined(__clang__) | 
 | #pragma GCC system_header | 
 | #endif | 
 |  | 
 | // Begin a slice under |category| with the title |name|. Both strings must be | 
 | // static constants. The track event is only recorded if |category| is enabled | 
 | // for a tracing session. | 
 | // | 
 | // The slice is thread-scoped (i.e., written to the default track of the current | 
 | // thread) unless overridden with a custom track object (see Track). | 
 | // | 
 | // |name| must be a string with static lifetime (i.e., the same | 
 | // address must not be used for a different event name in the future). If you | 
 | // want to use a dynamically allocated name, do this: | 
 | // | 
 | //  TRACE_EVENT("category", nullptr, [&](perfetto::EventContext ctx) { | 
 | //    ctx.event()->set_name(dynamic_name); | 
 | //  }); | 
 | // | 
 | // The following optional arguments can be passed to `TRACE_EVENT` to add extra | 
 | // information to events: | 
 | // | 
 | //  TRACE_EVENT("cat", "name"[, track][, timestamp][, lambda]); | 
 | // | 
 | //  TRACE_EVENT("cat", "name"[, track][, timestamp] | 
 | //                           [, "debug_name1", debug_value1] | 
 | //                           [, "debug_name2", debug_value2]); | 
 | // | 
 | // Some examples of valid combinations: | 
 | // | 
 | // 1. A lambda for writing custom TrackEvent fields: | 
 | // | 
 | //   TRACE_EVENT("category", "Name", [&](perfetto::EventContext ctx) { | 
 | //     ctx.event()->set_custom_value(...); | 
 | //   }); | 
 | // | 
 | // 2. A timestamp and a lambda: | 
 | // | 
 | //   TRACE_EVENT("category", "Name", time_in_nanoseconds, | 
 | //       [&](perfetto::EventContext ctx) { | 
 | //     ctx.event()->set_custom_value(...); | 
 | //   }); | 
 | // | 
 | //   |time_in_nanoseconds| should be an uint64_t by default. See | 
 | //   |ConvertTimestampToTraceTimeNs| on how to use custom timestamp types. | 
 | // | 
 | // 3. Up to two debug annotations: | 
 | // | 
 | //   TRACE_EVENT("category", "Name", "arg", value); | 
 | //   TRACE_EVENT("category", "Name", "arg", value, "arg2", value2); | 
 | // | 
 | //   See |TracedValue| for recording custom types as debug annotations. | 
 | // | 
 | // 4. An overridden track: | 
 | // | 
 | //   TRACE_EVENT("category", "Name", perfetto::Track(1234)); | 
 | // | 
 | //   See |Track| for other types of tracks which may be used. | 
 | // | 
 | // 5. A track and a lambda: | 
 | // | 
 | //   TRACE_EVENT("category", "Name", perfetto::Track(1234), | 
 | //       [&](perfetto::EventContext ctx) { | 
 | //     ctx.event()->set_custom_value(...); | 
 | //   }); | 
 | // | 
 | // 6. A track and a timestamp: | 
 | // | 
 | //   TRACE_EVENT("category", "Name", perfetto::Track(1234), | 
 | //       time_in_nanoseconds); | 
 | // | 
 | // 7. A track, a timestamp and a lambda: | 
 | // | 
 | //   TRACE_EVENT("category", "Name", perfetto::Track(1234), | 
 | //       time_in_nanoseconds, [&](perfetto::EventContext ctx) { | 
 | //     ctx.event()->set_custom_value(...); | 
 | //   }); | 
 | // | 
 | // 8. A track and up to two debug annotions: | 
 | // | 
 | //   TRACE_EVENT("category", "Name", perfetto::Track(1234), | 
 | //       "arg", value); | 
 | //   TRACE_EVENT("category", "Name", perfetto::Track(1234), | 
 | //       "arg", value, "arg2", value2); | 
 | // | 
 | #define TRACE_EVENT_BEGIN(category, name, ...)               \ | 
 |   PERFETTO_INTERNAL_TRACK_EVENT(                             \ | 
 |       category, ::perfetto::internal::GetStaticString(name), \ | 
 |       ::perfetto::protos::pbzero::TrackEvent::TYPE_SLICE_BEGIN, ##__VA_ARGS__) | 
 |  | 
 | // End a slice under |category|. | 
 | #define TRACE_EVENT_END(category, ...) \ | 
 |   PERFETTO_INTERNAL_TRACK_EVENT(       \ | 
 |       category, /*name=*/nullptr,      \ | 
 |       ::perfetto::protos::pbzero::TrackEvent::TYPE_SLICE_END, ##__VA_ARGS__) | 
 |  | 
 | // Begin a slice which gets automatically closed when going out of scope. | 
 | #define TRACE_EVENT(category, name, ...) \ | 
 |   PERFETTO_INTERNAL_SCOPED_TRACK_EVENT(category, name, ##__VA_ARGS__) | 
 |  | 
 | // Emit a slice which has zero duration. | 
 | #define TRACE_EVENT_INSTANT(category, name, ...)             \ | 
 |   PERFETTO_INTERNAL_TRACK_EVENT(                             \ | 
 |       category, ::perfetto::internal::GetStaticString(name), \ | 
 |       ::perfetto::protos::pbzero::TrackEvent::TYPE_INSTANT, ##__VA_ARGS__) | 
 |  | 
 | // Efficiently determine if the given static or dynamic trace category or | 
 | // category group is enabled for tracing. | 
 | #define TRACE_EVENT_CATEGORY_ENABLED(category) \ | 
 |   PERFETTO_INTERNAL_CATEGORY_ENABLED(category) | 
 |  | 
 | // Time-varying numeric data can be recorded with the TRACE_COUNTER macro: | 
 | // | 
 | //   TRACE_COUNTER("cat", counter_track[, timestamp], value); | 
 | // | 
 | // For example, to record a single value for a counter called "MyCounter": | 
 | // | 
 | //   TRACE_COUNTER("category", "MyCounter", 1234.5); | 
 | // | 
 | // This data is displayed as a counter track in the Perfetto UI. | 
 | // | 
 | // Both integer and floating point counter values are supported. Counters can | 
 | // also be annotated with additional information such as units, for example, for | 
 | // tracking the rendering framerate in terms of frames per second or "fps": | 
 | // | 
 | //   TRACE_COUNTER("category", perfetto::CounterTrack("Framerate", "fps"), 120); | 
 | // | 
 | // As another example, a memory counter that records bytes but accepts samples | 
 | // as kilobytes (to reduce trace binary size) can be defined like this: | 
 | // | 
 | //   perfetto::CounterTrack memory_track = perfetto::CounterTrack("Memory") | 
 | //       .set_unit("bytes") | 
 | //       .set_multiplier(1024); | 
 | //   TRACE_COUNTER("category", memory_track, 4 /* = 4096 bytes */); | 
 | // | 
 | // See /protos/perfetto/trace/track_event/counter_descriptor.proto | 
 | // for the full set of attributes for a counter track. | 
 | // | 
 | // To record a counter value at a specific point in time (instead of the current | 
 | // time), you can pass in a custom timestamp: | 
 | // | 
 | //   // First record the current time and counter value. | 
 | //   uint64_t timestamp = perfetto::TrackEvent::GetTraceTimeNs(); | 
 | //   int64_t value = 1234; | 
 | // | 
 | //   // Later, emit a sample at that point in time. | 
 | //   TRACE_COUNTER("category", "MyCounter", timestamp, value); | 
 | // | 
 | #define TRACE_COUNTER(category, track, ...)                 \ | 
 |   PERFETTO_INTERNAL_TRACK_EVENT(                            \ | 
 |       category, /*name=*/nullptr,                           \ | 
 |       ::perfetto::protos::pbzero::TrackEvent::TYPE_COUNTER, \ | 
 |       ::perfetto::CounterTrack(track), ##__VA_ARGS__) | 
 |  | 
 | // TODO(skyostil): Add flow events. | 
 |  | 
 | #endif  // INCLUDE_PERFETTO_TRACING_TRACK_EVENT_H_ |