/src/abseil-cpp/absl/log/internal/vlog_config.h
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright 2022 The Abseil Authors |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | | // you may not use this file except in compliance with the License. |
5 | | // You may obtain a copy of the License at |
6 | | // |
7 | | // https://www.apache.org/licenses/LICENSE-2.0 |
8 | | // |
9 | | // Unless required by applicable law or agreed to in writing, software |
10 | | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | | // See the License for the specific language governing permissions and |
13 | | // limitations under the License. |
14 | | // |
15 | | // ----------------------------------------------------------------------------- |
16 | | // vlog_config.h |
17 | | // ----------------------------------------------------------------------------- |
18 | | // |
19 | | // This header file defines `VLogSite`, a public primitive that represents |
20 | | // a callsite for the `VLOG` family of macros and related libraries. |
21 | | // It also declares and defines multiple internal utilities used to implement |
22 | | // `VLOG`, such as `VLogSiteManager`. |
23 | | |
24 | | #ifndef ABSL_LOG_INTERNAL_VLOG_CONFIG_H_ |
25 | | #define ABSL_LOG_INTERNAL_VLOG_CONFIG_H_ |
26 | | |
27 | | // IWYU pragma: private, include "absl/log/log.h" |
28 | | |
29 | | #include <atomic> |
30 | | #include <cstdint> |
31 | | #include <functional> |
32 | | #include <limits> |
33 | | #include <type_traits> |
34 | | |
35 | | #include "absl/base/attributes.h" |
36 | | #include "absl/base/config.h" |
37 | | #include "absl/base/optimization.h" |
38 | | #include "absl/base/thread_annotations.h" |
39 | | #include "absl/strings/string_view.h" |
40 | | |
41 | | namespace absl { |
42 | | ABSL_NAMESPACE_BEGIN |
43 | | namespace log_internal { |
44 | | |
45 | | class SyntheticBinary; |
46 | | class VLogSite; |
47 | | |
48 | | int RegisterAndInitialize(VLogSite* v); |
49 | | void UpdateVLogSites(); |
50 | | constexpr int kUseFlag = (std::numeric_limits<int16_t>::min)(); |
51 | | |
52 | | // Represents a unique callsite for a `VLOG()` or `VLOG_IS_ON()` call. |
53 | | // |
54 | | // Libraries that provide `VLOG`-like functionality should use this to |
55 | | // efficiently handle --vmodule. |
56 | | // |
57 | | // VLogSite objects must not be destroyed until the program exits. Doing so will |
58 | | // probably yield nasty segfaults in VLogSiteManager::UpdateLogSites(). The |
59 | | // recommendation is to make all such objects function-local statics. |
60 | | class VLogSite final { |
61 | | public: |
62 | | // `f` must not be destroyed until the program exits. |
63 | | explicit constexpr VLogSite(const char* f) |
64 | 0 | : file_(f), v_(kUninitialized), next_(nullptr) {} |
65 | | VLogSite(const VLogSite&) = delete; |
66 | | VLogSite& operator=(const VLogSite&) = delete; |
67 | | |
68 | | // Inlining the function yields a ~3x performance improvement at the cost of a |
69 | | // 1.5x code size increase at the call site. |
70 | | // Takes locks but does not allocate memory. |
71 | | ABSL_ATTRIBUTE_ALWAYS_INLINE |
72 | 0 | bool IsEnabled(int level) { |
73 | 0 | int stale_v = v_.load(std::memory_order_relaxed); |
74 | 0 | if (ABSL_PREDICT_TRUE(level > stale_v)) { |
75 | 0 | return false; |
76 | 0 | } |
77 | 0 |
|
78 | 0 | // We put everything other than the fast path, i.e. vlogging is initialized |
79 | 0 | // but not on, behind an out-of-line function to reduce code size. |
80 | 0 | // "level" is almost always a call-site constant, so we can save a bit |
81 | 0 | // of code space by special-casing for a few common levels. |
82 | 0 | #if ABSL_HAVE_BUILTIN(__builtin_constant_p) || defined(__GNUC__) |
83 | 0 | if (__builtin_constant_p(level)) { |
84 | 0 | if (level == 0) return SlowIsEnabled0(stale_v); |
85 | 0 | if (level == 1) return SlowIsEnabled1(stale_v); |
86 | 0 | if (level == 2) return SlowIsEnabled2(stale_v); |
87 | 0 | if (level == 3) return SlowIsEnabled3(stale_v); |
88 | 0 | if (level == 4) return SlowIsEnabled4(stale_v); |
89 | 0 | if (level == 5) return SlowIsEnabled5(stale_v); |
90 | 0 | } |
91 | 0 | #endif |
92 | 0 | return SlowIsEnabled(stale_v, level); |
93 | 0 | } |
94 | | |
95 | | private: |
96 | | friend int log_internal::RegisterAndInitialize(VLogSite* v); |
97 | | friend void log_internal::UpdateVLogSites(); |
98 | | friend class log_internal::SyntheticBinary; |
99 | | static constexpr int kUninitialized = (std::numeric_limits<int>::max)(); |
100 | | |
101 | | // SlowIsEnabled performs slower checks to determine whether a log site is |
102 | | // enabled. Because it is expected to be called somewhat rarely |
103 | | // (comparatively), it is not inlined to save on code size. |
104 | | // |
105 | | // Prerequisites to calling SlowIsEnabled: |
106 | | // 1) stale_v is uninitialized OR |
107 | | // 2) stale_v is initialized and >= level (meaning we must log). |
108 | | // Takes locks but does not allocate memory. |
109 | | ABSL_ATTRIBUTE_NOINLINE |
110 | | bool SlowIsEnabled(int stale_v, int level); |
111 | | ABSL_ATTRIBUTE_NOINLINE bool SlowIsEnabled0(int stale_v); |
112 | | ABSL_ATTRIBUTE_NOINLINE bool SlowIsEnabled1(int stale_v); |
113 | | ABSL_ATTRIBUTE_NOINLINE bool SlowIsEnabled2(int stale_v); |
114 | | ABSL_ATTRIBUTE_NOINLINE bool SlowIsEnabled3(int stale_v); |
115 | | ABSL_ATTRIBUTE_NOINLINE bool SlowIsEnabled4(int stale_v); |
116 | | ABSL_ATTRIBUTE_NOINLINE bool SlowIsEnabled5(int stale_v); |
117 | | |
118 | | // This object is too size-sensitive to use absl::string_view. |
119 | | const char* const file_; |
120 | | std::atomic<int> v_; |
121 | | std::atomic<VLogSite*> next_; |
122 | | }; |
123 | | static_assert(std::is_trivially_destructible<VLogSite>::value, |
124 | | "VLogSite must be trivially destructible"); |
125 | | |
126 | | // Returns the current verbose log level of `file`. |
127 | | // Does not allocate memory. |
128 | | int VLogLevel(absl::string_view file); |
129 | | |
130 | | // Registers a site `v` to get updated as `vmodule` and `v` change. Also |
131 | | // initializes the site based on their current values, and returns that result. |
132 | | // Does not allocate memory. |
133 | | int RegisterAndInitialize(VLogSite* v); |
134 | | |
135 | | // Allocates memory. |
136 | | void UpdateVLogSites(); |
137 | | |
138 | | // Completely overwrites the saved value of `vmodule`. |
139 | | // Allocates memory. |
140 | | void UpdateVModule(absl::string_view vmodule); |
141 | | |
142 | | // Updates the global verbosity level to `v` and returns the prior value. |
143 | | // Allocates memory. |
144 | | int UpdateGlobalVLogLevel(int v); |
145 | | |
146 | | // Atomically prepends `module_pattern=log_level` to the start of vmodule. |
147 | | // Returns the prior value for `module_pattern` if there was an exact match and |
148 | | // `global_v` otherwise. |
149 | | // Allocates memory. |
150 | | int PrependVModule(absl::string_view module_pattern, int log_level); |
151 | | |
152 | | // Registers `on_update` to be called whenever `v` or `vmodule` change. |
153 | | // Allocates memory. |
154 | | void OnVLogVerbosityUpdate(std::function<void()> cb); |
155 | | |
156 | | // Does not allocate memory. |
157 | | VLogSite* SetVModuleListHeadForTestOnly(VLogSite* v); |
158 | | |
159 | | } // namespace log_internal |
160 | | ABSL_NAMESPACE_END |
161 | | } // namespace absl |
162 | | |
163 | | #endif // ABSL_LOG_INTERNAL_VLOG_CONFIG_H_ |