• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2016 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef BASE_TRACE_EVENT_CATEGORY_REGISTRY_H_
6 #define BASE_TRACE_EVENT_CATEGORY_REGISTRY_H_
7 
8 #include <stddef.h>
9 #include <stdint.h>
10 
11 #include <atomic>
12 
13 #include "base/base_export.h"
14 #include "base/check_op.h"
15 #include "base/containers/span.h"
16 #include "base/memory/raw_ptr.h"
17 #include "base/trace_event/builtin_categories.h"
18 #include "base/trace_event/common/trace_event_common.h"
19 #include "base/trace_event/trace_category.h"
20 #include "build/build_config.h"
21 
22 namespace base {
23 namespace trace_event {
24 
25 class TraceCategoryTest;
26 class TraceLog;
27 
28 // Allows fast and thread-safe acces to the state of all tracing categories.
29 // All the methods in this class can be concurrently called on multiple threads,
30 // unless otherwise noted (e.g., GetOrCreateCategoryLocked).
31 // The reason why this is a fully static class with global state is to allow to
32 // statically define known categories as global linker-initialized structs,
33 // without requiring static initializers.
34 class BASE_EXPORT CategoryRegistry {
35  public:
36   // Known categories.
37   static TraceCategory* const kCategoryExhausted;
38   static TraceCategory* const kCategoryMetadata;
39   static TraceCategory* const kCategoryAlreadyShutdown;
40 
41   // Returns a category entry from the Category.state_ptr() pointer.
42   // TODO(primiano): trace macros should just keep a pointer to the entire
43   // TraceCategory, not just the enabled state pointer. That would remove the
44   // need for this function and make everything cleaner at no extra cost (as
45   // long as the |state_| is the first field of the struct, which can be
46   // guaranteed via static_assert, see TraceCategory ctor).
47   static const TraceCategory* GetCategoryByStatePtr(
48       const uint8_t* category_state);
49 
50   // Returns a category from its name or nullptr if not found.
51   // The output |category| argument is an undefinitely lived pointer to the
52   // TraceCategory owned by the registry. TRACE_EVENTx macros will cache this
53   // pointer and use it for checks in their fast-paths.
54   static TraceCategory* GetCategoryByName(const char* category_name);
55 
56   // Returns a built-in category from its name or nullptr if not found at
57   // compile-time. The return value is an undefinitely lived pointer to the
58   // TraceCategory owned by the registry.
GetBuiltinCategoryByName(const char * category_group)59   static constexpr TraceCategory* GetBuiltinCategoryByName(
60       const char* category_group) {
61 #if BUILDFLAG(IS_WIN) && defined(COMPONENT_BUILD)
62     // The address cannot be evaluated at compile-time in Windows component
63     // builds.
64     return nullptr;
65 #else
66     for (size_t i = 0; i < BuiltinCategories::Size(); ++i) {
67       if (StrEqConstexpr(category_group, BuiltinCategories::At(i)))
68         return &categories_[i];
69     }
70     return nullptr;
71 #endif
72   }
73 
74   // Returns whether |category| points at one of the meta categories that
75   // shouldn't be displayed in the tracing UI.
76   static bool IsMetaCategory(const TraceCategory* category);
77 
78  private:
79   friend class TraceCategoryTest;
80   friend class TraceLog;
81   using CategoryInitializerFn = void (*)(TraceCategory*);
82 
83   // The max number of trace categories that can be recorded.
84   static constexpr size_t kMaxCategories = 350;
85 
86   // Checks that there is enough space for all builtin categories.
87   static_assert(BuiltinCategories::Size() <= kMaxCategories,
88                 "kMaxCategories must be greater than kNumBuiltinCategories");
89 
90   // Only for debugging/testing purposes, is a no-op on release builds.
91   static void Initialize();
92 
93   // Resets the state of all categories, to clear up the state between tests.
94   static void ResetForTesting();
95 
96   // Used to get/create a category in the slow-path. If the category exists
97   // already, this has the same effect of GetCategoryByName and returns false.
98   // If not, a new category is created and the CategoryInitializerFn is invoked
99   // before retuning true. The caller must guarantee serialization: either call
100   // this method from a single thread or hold a lock when calling this.
101   static bool GetOrCreateCategoryLocked(const char* category_name,
102                                         CategoryInitializerFn,
103                                         TraceCategory**);
104 
105   // Allows to iterate over the valid categories in a for-each loop.
106   // This includes builtin categories such as __metadata.
107   static base::span<TraceCategory> GetAllCategories();
108 
109   // Returns whether |category| correctly points at |categories_| array entry.
110   static bool IsValidCategoryPtr(const TraceCategory* category);
111 
112   // The static array of trace categories.
113   static TraceCategory categories_[kMaxCategories];
114 
115   // Contains the number of created categories.
116   static std::atomic<size_t> category_index_;
117 };
118 
119 }  // namespace trace_event
120 }  // namespace base
121 
122 #endif  // BASE_TRACE_EVENT_CATEGORY_REGISTRY_H_
123