summaryrefslogtreecommitdiff
path: root/absl/flags/reflection.cc
diff options
context:
space:
mode:
authorGravatar Abseil Team <absl-team@google.com>2020-10-12 10:33:47 -0700
committerGravatar Derek Mauro <dmauro@google.com>2020-10-12 13:39:27 -0400
commit4b2fbb4adba905eede6c61b4494acfdb660a3bb7 (patch)
treed9de8cc04a7794a9269273a94ddda146fa0b67cf /absl/flags/reflection.cc
parente493d6acb426542ec90db9baf749d0c521ed3302 (diff)
Export of internal Abseil changes
-- a5af5874c1c5cc02bd2a748d455321f82b6f2a93 by Andy Getzendanner <durandal@google.com>: fix compile fails with asan and -Wredundant-decls Import of https://github.com/abseil/abseil-cpp/pull/801 PiperOrigin-RevId: 336693223 -- ed9df42ab2b742386c6692c2bed015374c919d9c by Derek Mauro <dmauro@google.com>: Fix integer conversion warning Fixes #814 PiperOrigin-RevId: 336651814 -- 0ab4c23884e72dce17b67c1eb520f9dbb802565d by Derek Mauro <dmauro@google.com>: Internal change PiperOrigin-RevId: 336585378 -- eba0e3dccd52a6e91bcff84075bef0affc650b74 by Matt Kulukundis <kfm@google.com>: Add bitset operations to Futex helper. PiperOrigin-RevId: 336409368 -- 8b0709a8b4500bf5f0af4b602d76a298d81645e8 by Abseil Team <absl-team@google.com>: Fix code indentation in a comment. PiperOrigin-RevId: 336368167 -- bc3961c87a7e7760c10319a5b0349c279f7ae3ad by Samuel Benzaquen <sbenza@google.com>: Improve performance of the registry: - Reduce contention - Reduce memory usage for each flag by `6*sizeof(void*)`. - Replace one immortal allocation per-flag with a single one for all the flags - Slightly improve single-threaded performance by avoiding the std::map indirections. PiperOrigin-RevId: 336365904 -- 264ad9f28f935aad8b6b1437f8bf804fa9104346 by Abseil Team <absl-team@google.com>: Fix typo in comment on absl::Condition. PiperOrigin-RevId: 336311680 -- b5b808a8c75ca0df7b09eff9a423ec171d80f771 by Derek Mauro <dmauro@google.com>: Add missing Apache license headers PiperOrigin-RevId: 336294980 -- 89446c3a4793df8b95060385cf3e219357c3db1d by Andy Soffer <asoffer@google.com>: Internal changes PiperOrigin-RevId: 336287465 -- 57c8be4e294881bc79a6a44b8e4bf7ecbb19b9b9 by Matt Kulukundis <kfm@google.com>: Extract Futex from an implementation detail of Wait to a private interface. PiperOrigin-RevId: 336123209 GitOrigin-RevId: a5af5874c1c5cc02bd2a748d455321f82b6f2a93 Change-Id: Ie5a0ebe28e571814e3e11d4c05ca308523ccf311
Diffstat (limited to 'absl/flags/reflection.cc')
-rw-r--r--absl/flags/reflection.cc68
1 files changed, 44 insertions, 24 deletions
diff --git a/absl/flags/reflection.cc b/absl/flags/reflection.cc
index d7060221..c6bf8aab 100644
--- a/absl/flags/reflection.cc
+++ b/absl/flags/reflection.cc
@@ -17,6 +17,7 @@
#include <assert.h>
+#include <atomic>
#include <map>
#include <string>
@@ -56,21 +57,23 @@ class FlagRegistry {
// Returns the flag object for the specified name, or nullptr if not found.
// Will emit a warning if a 'retired' flag is specified.
- CommandLineFlag* FindFlagLocked(absl::string_view name);
+ CommandLineFlag* FindFlag(absl::string_view name);
static FlagRegistry& GlobalRegistry(); // returns a singleton registry
private:
friend class flags_internal::FlagSaverImpl; // reads all the flags in order
// to copy them
- friend void ForEachFlagUnlocked(
- std::function<void(CommandLineFlag&)> visitor);
+ friend void ForEachFlag(std::function<void(CommandLineFlag&)> visitor);
+ friend void FinalizeRegistry();
- // The map from name to flag, for FindFlagLocked().
+ // The map from name to flag, for FindFlag().
using FlagMap = std::map<absl::string_view, CommandLineFlag*>;
using FlagIterator = FlagMap::iterator;
using FlagConstIterator = FlagMap::const_iterator;
FlagMap flags_;
+ std::vector<CommandLineFlag*> flat_flags_;
+ std::atomic<bool> finalized_flags_{false};
absl::Mutex lock_;
@@ -79,15 +82,6 @@ class FlagRegistry {
FlagRegistry& operator=(const FlagRegistry&);
};
-CommandLineFlag* FlagRegistry::FindFlagLocked(absl::string_view name) {
- FlagConstIterator i = flags_.find(name);
- if (i == flags_.end()) {
- return nullptr;
- }
-
- return i->second;
-}
-
namespace {
class FlagRegistryLock {
@@ -101,8 +95,24 @@ class FlagRegistryLock {
} // namespace
+CommandLineFlag* FlagRegistry::FindFlag(absl::string_view name) {
+ if (finalized_flags_.load(std::memory_order_acquire)) {
+ // We could save some gcus here if we make `Name()` be non-virtual.
+ // We could move the `const char*` name to the base class.
+ auto it = std::partition_point(
+ flat_flags_.begin(), flat_flags_.end(),
+ [=](CommandLineFlag* f) { return f->Name() < name; });
+ if (it != flat_flags_.end() && (*it)->Name() == name) return *it;
+ }
+
+ FlagRegistryLock frl(*this);
+ auto it = flags_.find(name);
+ return it != flags_.end() ? it->second : nullptr;
+}
+
void FlagRegistry::RegisterFlag(CommandLineFlag& flag) {
FlagRegistryLock registry_lock(*this);
+
std::pair<FlagIterator, bool> ins =
flags_.insert(FlagMap::value_type(flag.Name(), &flag));
if (ins.second == false) { // means the name was already in the map
@@ -152,18 +162,15 @@ FlagRegistry& FlagRegistry::GlobalRegistry() {
// --------------------------------------------------------------------
-void ForEachFlagUnlocked(std::function<void(CommandLineFlag&)> visitor) {
+void ForEachFlag(std::function<void(CommandLineFlag&)> visitor) {
FlagRegistry& registry = FlagRegistry::GlobalRegistry();
- for (FlagRegistry::FlagConstIterator i = registry.flags_.begin();
- i != registry.flags_.end(); ++i) {
- visitor(*i->second);
+
+ if (registry.finalized_flags_.load(std::memory_order_acquire)) {
+ for (const auto& i : registry.flat_flags_) visitor(*i);
}
-}
-void ForEachFlag(std::function<void(CommandLineFlag&)> visitor) {
- FlagRegistry& registry = FlagRegistry::GlobalRegistry();
FlagRegistryLock frl(registry);
- ForEachFlagUnlocked(visitor);
+ for (const auto& i : registry.flags_) visitor(*i.second);
}
// --------------------------------------------------------------------
@@ -173,6 +180,21 @@ bool RegisterCommandLineFlag(CommandLineFlag& flag) {
return true;
}
+void FinalizeRegistry() {
+ auto& registry = FlagRegistry::GlobalRegistry();
+ FlagRegistryLock frl(registry);
+ if (registry.finalized_flags_.load(std::memory_order_relaxed)) {
+ // Was already finalized. Ignore the second time.
+ return;
+ }
+ registry.flat_flags_.reserve(registry.flags_.size());
+ for (const auto& f : registry.flags_) {
+ registry.flat_flags_.push_back(f.second);
+ }
+ registry.flags_.clear();
+ registry.finalized_flags_.store(true, std::memory_order_release);
+}
+
// --------------------------------------------------------------------
namespace {
@@ -298,9 +320,7 @@ CommandLineFlag* FindCommandLineFlag(absl::string_view name) {
if (name.empty()) return nullptr;
flags_internal::FlagRegistry& registry =
flags_internal::FlagRegistry::GlobalRegistry();
- flags_internal::FlagRegistryLock frl(registry);
-
- return registry.FindFlagLocked(name);
+ return registry.FindFlag(name);
}
// --------------------------------------------------------------------