diff options
author | Abseil Team <absl-team@google.com> | 2020-10-12 10:33:47 -0700 |
---|---|---|
committer | Derek Mauro <dmauro@google.com> | 2020-10-12 13:39:27 -0400 |
commit | 4b2fbb4adba905eede6c61b4494acfdb660a3bb7 (patch) | |
tree | d9de8cc04a7794a9269273a94ddda146fa0b67cf /absl/flags | |
parent | e493d6acb426542ec90db9baf749d0c521ed3302 (diff) | |
download | abseil-4b2fbb4adba905eede6c61b4494acfdb660a3bb7.tar.gz abseil-4b2fbb4adba905eede6c61b4494acfdb660a3bb7.tar.bz2 abseil-4b2fbb4adba905eede6c61b4494acfdb660a3bb7.zip |
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')
-rw-r--r-- | absl/flags/BUILD.bazel | 2 | ||||
-rw-r--r-- | absl/flags/flag_benchmark.cc | 33 | ||||
-rw-r--r-- | absl/flags/internal/registry.h | 5 | ||||
-rw-r--r-- | absl/flags/parse.cc | 5 | ||||
-rw-r--r-- | absl/flags/reflection.cc | 68 |
5 files changed, 86 insertions, 27 deletions
diff --git a/absl/flags/BUILD.bazel b/absl/flags/BUILD.bazel index 9de9e223..2bd94780 100644 --- a/absl/flags/BUILD.bazel +++ b/absl/flags/BUILD.bazel @@ -381,6 +381,8 @@ cc_binary( deps = [ ":flag", ":marshalling", + ":parse", + ":reflection", "//absl/strings", "//absl/time", "//absl/types:optional", diff --git a/absl/flags/flag_benchmark.cc b/absl/flags/flag_benchmark.cc index 7b52c9bc..9982b604 100644 --- a/absl/flags/flag_benchmark.cc +++ b/absl/flags/flag_benchmark.cc @@ -20,6 +20,8 @@ #include "absl/flags/flag.h" #include "absl/flags/marshalling.h" +#include "absl/flags/parse.h" +#include "absl/flags/reflection.h" #include "absl/strings/string_view.h" #include "absl/time/time.h" #include "absl/types/optional.h" @@ -103,6 +105,23 @@ std::string AbslUnparseFlag(const UDT&) { return ""; } BENCHMARKED_TYPES(FLAG_DEF) +// Register thousands of flags to bloat up the size of the registry. +// This mimics real life production binaries. +#define DEFINE_FLAG_0(name) ABSL_FLAG(int, name, 0, ""); +#define DEFINE_FLAG_1(name) DEFINE_FLAG_0(name##0) DEFINE_FLAG_0(name##1) +#define DEFINE_FLAG_2(name) DEFINE_FLAG_1(name##0) DEFINE_FLAG_1(name##1) +#define DEFINE_FLAG_3(name) DEFINE_FLAG_2(name##0) DEFINE_FLAG_2(name##1) +#define DEFINE_FLAG_4(name) DEFINE_FLAG_3(name##0) DEFINE_FLAG_3(name##1) +#define DEFINE_FLAG_5(name) DEFINE_FLAG_4(name##0) DEFINE_FLAG_4(name##1) +#define DEFINE_FLAG_6(name) DEFINE_FLAG_5(name##0) DEFINE_FLAG_5(name##1) +#define DEFINE_FLAG_7(name) DEFINE_FLAG_6(name##0) DEFINE_FLAG_6(name##1) +#define DEFINE_FLAG_8(name) DEFINE_FLAG_7(name##0) DEFINE_FLAG_7(name##1) +#define DEFINE_FLAG_9(name) DEFINE_FLAG_8(name##0) DEFINE_FLAG_8(name##1) +#define DEFINE_FLAG_10(name) DEFINE_FLAG_9(name##0) DEFINE_FLAG_9(name##1) +#define DEFINE_FLAG_11(name) DEFINE_FLAG_10(name##0) DEFINE_FLAG_10(name##1) +#define DEFINE_FLAG_12(name) DEFINE_FLAG_11(name##0) DEFINE_FLAG_11(name##1) +DEFINE_FLAG_12(bloat_flag_); + namespace { #define BM_GetFlag(T) \ @@ -115,6 +134,20 @@ namespace { BENCHMARKED_TYPES(BM_GetFlag) +void BM_ThreadedFindCommandLineFlag(benchmark::State& state) { + char dummy[] = "dummy"; + char* argv[] = {dummy}; + // We need to ensure that flags have been parsed. That is where the registry + // is finalized. + absl::ParseCommandLine(1, argv); + + for (auto s : state) { + benchmark::DoNotOptimize( + absl::FindCommandLineFlag("bloat_flag_010101010101")); + } +} +BENCHMARK(BM_ThreadedFindCommandLineFlag)->ThreadRange(1, 16); + } // namespace #define InvokeGetFlag(T) \ diff --git a/absl/flags/internal/registry.h b/absl/flags/internal/registry.h index 1df2db79..a8d9eb9c 100644 --- a/absl/flags/internal/registry.h +++ b/absl/flags/internal/registry.h @@ -30,9 +30,6 @@ namespace absl { ABSL_NAMESPACE_BEGIN namespace flags_internal { -// Executes specified visitor for each non-retired flag in the registry. -// Requires the caller hold the registry lock. -void ForEachFlagUnlocked(std::function<void(CommandLineFlag&)> visitor); // Executes specified visitor for each non-retired flag in the registry. While // callback are executed, the registry is locked and can't be changed. void ForEachFlag(std::function<void(CommandLineFlag&)> visitor); @@ -41,6 +38,8 @@ void ForEachFlag(std::function<void(CommandLineFlag&)> visitor); bool RegisterCommandLineFlag(CommandLineFlag&); +void FinalizeRegistry(); + //----------------------------------------------------------------------------- // Retired registrations: // diff --git a/absl/flags/parse.cc b/absl/flags/parse.cc index 4f4bb3d5..1835a837 100644 --- a/absl/flags/parse.cc +++ b/absl/flags/parse.cc @@ -611,6 +611,11 @@ std::vector<char*> ParseCommandLineImpl(int argc, char* argv[], OnUndefinedFlag on_undef_flag) { ABSL_INTERNAL_CHECK(argc > 0, "Missing argv[0]"); + // Once parsing has started we will not have more flag registrations. + // If we did, they would be missing during parsing, which is a problem on + // itself. + flags_internal::FinalizeRegistry(); + // This routine does not return anything since we abort on failure. CheckDefaultValuesParsingRoundtrip(); 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); } // -------------------------------------------------------------------- |