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