summaryrefslogtreecommitdiff
path: root/chromium/base/trace_event/category_registry.h
blob: a6439d945950366373c5b2592d2b734b2922f9e5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef BASE_TRACE_EVENT_CATEGORY_REGISTRY_H_
#define BASE_TRACE_EVENT_CATEGORY_REGISTRY_H_

#include <stddef.h>
#include <stdint.h>

#include "base/atomicops.h"
#include "base/base_export.h"
#include "base/logging.h"
#include "base/stl_util.h"
#include "base/trace_event/builtin_categories.h"
#include "base/trace_event/common/trace_event_common.h"
#include "base/trace_event/trace_category.h"
#include "build/build_config.h"

namespace base {
namespace trace_event {

class TraceCategoryTest;
class TraceLog;

// Allows fast and thread-safe acces to the state of all tracing categories.
// All the methods in this class can be concurrently called on multiple threads,
// unless otherwise noted (e.g., GetOrCreateCategoryLocked).
// The reason why this is a fully static class with global state is to allow to
// statically define known categories as global linker-initialized structs,
// without requiring static initializers.
class BASE_EXPORT CategoryRegistry {
 public:
  // Allows for-each iterations over a slice of the categories array.
  class Range {
   public:
    Range(TraceCategory* begin, TraceCategory* end) : begin_(begin), end_(end) {
      DCHECK_LE(begin, end);
    }
    TraceCategory* begin() const { return begin_; }
    TraceCategory* end() const { return end_; }

   private:
    TraceCategory* const begin_;
    TraceCategory* const end_;
  };

  // Known categories.
  static TraceCategory* const kCategoryExhausted;
  static TraceCategory* const kCategoryMetadata;
  static TraceCategory* const kCategoryAlreadyShutdown;

  // Returns a category entry from the Category.state_ptr() pointer.
  // TODO(primiano): trace macros should just keep a pointer to the entire
  // TraceCategory, not just the enabled state pointer. That would remove the
  // need for this function and make everything cleaner at no extra cost (as
  // long as the |state_| is the first field of the struct, which can be
  // guaranteed via static_assert, see TraceCategory ctor).
  static const TraceCategory* GetCategoryByStatePtr(
      const uint8_t* category_state);

  // Returns a category from its name or nullptr if not found.
  // The output |category| argument is an undefinitely lived pointer to the
  // TraceCategory owned by the registry. TRACE_EVENTx macros will cache this
  // pointer and use it for checks in their fast-paths.
  static TraceCategory* GetCategoryByName(const char* category_name);

  // Returns a built-in category from its name or nullptr if not found at
  // compile-time. The return value is an undefinitely lived pointer to the
  // TraceCategory owned by the registry.
  static constexpr TraceCategory* GetBuiltinCategoryByName(
      const char* category_group) {
#if defined(OS_WIN) && defined(COMPONENT_BUILD)
    // The address cannot be evaluated at compile-time in Windows compoment
    // builds.
    return nullptr;
#else
    for (size_t i = 0; i < BuiltinCategories::Size(); ++i) {
      if (StrEqConstexpr(category_group, BuiltinCategories::At(i)))
        return &categories_[i];
    }
    return nullptr;
#endif
  }

  // Returns whether |category| points at one of the meta categories that
  // shouldn't be displayed in the tracing UI.
  static bool IsMetaCategory(const TraceCategory* category);

 private:
  friend class TraceCategoryTest;
  friend class TraceLog;
  using CategoryInitializerFn = void (*)(TraceCategory*);

  // The max number of trace categories that can be recorded.
  static constexpr size_t kMaxCategories = 300;

  // Checks that there is enough space for all builtin categories.
  static_assert(BuiltinCategories::Size() <= kMaxCategories,
                "kMaxCategories must be greater than kNumBuiltinCategories");

  // Only for debugging/testing purposes, is a no-op on release builds.
  static void Initialize();

  // Resets the state of all categories, to clear up the state between tests.
  static void ResetForTesting();

  // Used to get/create a category in the slow-path. If the category exists
  // already, this has the same effect of GetCategoryByName and returns false.
  // If not, a new category is created and the CategoryInitializerFn is invoked
  // before retuning true. The caller must guarantee serialization: either call
  // this method from a single thread or hold a lock when calling this.
  static bool GetOrCreateCategoryLocked(const char* category_name,
                                        CategoryInitializerFn,
                                        TraceCategory**);

  // Allows to iterate over the valid categories in a for-each loop.
  // This includes builtin categories such as __metadata.
  static Range GetAllCategories();

  // Returns whether |category| correctly points at |categories_| array entry.
  static bool IsValidCategoryPtr(const TraceCategory* category);

  // The static array of trace categories.
  static TraceCategory categories_[kMaxCategories];

  // Contains the number of created categories.
  static base::subtle::AtomicWord category_index_;
};

}  // namespace trace_event
}  // namespace base

#endif  // BASE_TRACE_EVENT_CATEGORY_REGISTRY_H_