diff options
Diffstat (limited to 'absl/strings/internal/cordz_info.h')
-rw-r--r-- | absl/strings/internal/cordz_info.h | 85 |
1 files changed, 62 insertions, 23 deletions
diff --git a/absl/strings/internal/cordz_info.h b/absl/strings/internal/cordz_info.h index 5345be75..4cf57664 100644 --- a/absl/strings/internal/cordz_info.h +++ b/absl/strings/internal/cordz_info.h @@ -22,6 +22,7 @@ #include "absl/base/config.h" #include "absl/base/thread_annotations.h" #include "absl/strings/internal/cord_internal.h" +#include "absl/strings/internal/cordz_functions.h" #include "absl/strings/internal/cordz_handle.h" #include "absl/strings/internal/cordz_statistics.h" #include "absl/strings/internal/cordz_update_tracker.h" @@ -41,22 +42,37 @@ namespace cord_internal { // and will either be deleted or appended to the global_delete_queue. If it is // placed on the global_delete_queue, the CordzInfo object will be cleaned in // the destructor of a CordzSampleToken object. -class CordzInfo : public CordzHandle { +class ABSL_LOCKABLE CordzInfo : public CordzHandle { public: using MethodIdentifier = CordzUpdateTracker::MethodIdentifier; - // All profiled Cords should be accompanied by a call to TrackCord. // TrackCord creates a CordzInfo instance which tracks important metrics of - // the sampled cord. CordzInfo instances are placed in a global list which is - // used to discover and snapshot all actively tracked cords. - // Callers are responsible for calling UntrackCord() before the tracked Cord - // instance is deleted, or to stop tracking the sampled Cord. - // Callers are also responsible for guarding changes to `rep` through the - // Lock() and Unlock() calls, and calling SetCordRep() if the root of the - // sampled cord changes before the old root has been unreffed and/or deleted. - // `method` identifies the Cord method which initiated the cord to be sampled. - static CordzInfo* TrackCord( - CordRep* rep, MethodIdentifier method = MethodIdentifier::kUnknown); + // a sampled cord, and stores the created CordzInfo instance into `cord'. All + // CordzInfo instances are placed in a global list which is used to discover + // and snapshot all actively tracked cords. Callers are responsible for + // calling UntrackCord() before the tracked Cord instance is deleted, or to + // stop tracking the sampled Cord. Callers are also responsible for guarding + // changes to the 'tree' value of a Cord (InlineData.tree) through the Lock() + // and Unlock() calls. Any change resulting in a new tree value for the cord + // requires a call to SetCordRep() before the old tree has been unreffed + // and/or deleted. `method` identifies the Cord public API method initiating + // the cord to be sampled. + // Requires `cord` to hold a tree, and `cord.cordz_info()` to be null. + static void TrackCord(InlineData& cord, MethodIdentifier method); + + // Identical to TrackCord(), except that this function fills the + // `parent_stack` and `parent_method` properties of the returned CordzInfo + // instance from the provided `src` instance if `src` is sampled. + // This function should be used for sampling 'copy constructed' cords. + static void TrackCord(InlineData& cord, const InlineData& src, + MethodIdentifier method); + + // Maybe sample the cord identified by 'cord' for method 'method'. + // Uses `cordz_should_profile` to randomly pick cords to be sampled, and if + // so, invokes `TrackCord` to start sampling `cord`. + static void MaybeTrackCord(InlineData& cord, MethodIdentifier method); + static void MaybeTrackCord(InlineData& cord, const InlineData& src, + MethodIdentifier method); // Stops tracking changes for a sampled cord, and deletes the provided info. // This function must be called before the sampled cord instance is deleted, @@ -65,14 +81,6 @@ class CordzInfo : public CordzHandle { // CordInfo instance is being held by a concurrent collection thread. static void UntrackCord(CordzInfo* cordz_info); - // Identical to TrackCord(), except that this function fills the - // `parent_stack` and `parent_method` properties of the returned CordzInfo - // instance from the provided `src` instance if `src` is not null. - // This function should be used for sampling 'copy constructed' cords. - static CordzInfo* TrackCord( - CordRep* rep, const CordzInfo* src, - MethodIdentifier method = MethodIdentifier::kUnknown); - CordzInfo() = delete; CordzInfo(const CordzInfo&) = delete; CordzInfo& operator=(const CordzInfo&) = delete; @@ -92,6 +100,9 @@ class CordzInfo : public CordzHandle { // then this method will delete this CordzInfo instance. void Unlock() ABSL_UNLOCK_FUNCTION(mutex_); + // Asserts that this CordzInfo instance is locked. + void AssertHeld() ABSL_ASSERT_EXCLUSIVE_LOCK(mutex_); + // Updates the `rep' property of this instance. This methods is invoked by // Cord logic each time the root node of a sampled Cord changes, and before // the old root reference count is deleted. This guarantees that collection @@ -136,6 +147,9 @@ class CordzInfo : public CordzHandle { MethodIdentifier method); ~CordzInfo() override; + void Track(); + void Untrack(); + // Returns the parent method from `src`, which is either `parent_method_` or // `method_` depending on `parent_method_` being kUnknown. // Returns kUnknown if `src` is null. @@ -147,9 +161,6 @@ class CordzInfo : public CordzHandle { // Returns 0 if `src` is null. static int FillParentStack(const CordzInfo* src, void** stack); - void Track(); - void Untrack(); - // 'Unsafe' head/next/prev accessors not requiring the lock being held. // These are used exclusively for iterations (Head / Next) where we enforce // a token being held, so reading an 'old' / deleted pointer is fine. @@ -184,6 +195,34 @@ class CordzInfo : public CordzHandle { std::atomic<int64_t> size_{0}; }; +inline ABSL_ATTRIBUTE_ALWAYS_INLINE void CordzInfo::MaybeTrackCord( + InlineData& cord, MethodIdentifier method) { + if (ABSL_PREDICT_FALSE(cordz_should_profile())) { + TrackCord(cord, method); + } +} + +inline ABSL_ATTRIBUTE_ALWAYS_INLINE void CordzInfo::MaybeTrackCord( + InlineData& cord, const InlineData& src, MethodIdentifier method) { + if (ABSL_PREDICT_FALSE(cordz_should_profile())) { + TrackCord(cord, src, method); + } +} + +inline void CordzInfo::AssertHeld() ABSL_ASSERT_EXCLUSIVE_LOCK(mutex_) { +#ifndef NDEBUG + mutex_.AssertHeld(); +#endif +} + +inline void CordzInfo::SetCordRep(CordRep* rep) { + AssertHeld(); + rep_ = rep; + if (rep) { + size_.store(rep->length); + } +} + } // namespace cord_internal ABSL_NAMESPACE_END } // namespace absl |