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