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