// Copyright 2019 The Abseil Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "absl/strings/internal/cordz_info.h" #include <cstdint> #include "absl/base/config.h" #include "absl/base/internal/spinlock.h" #include "absl/container/inlined_vector.h" #include "absl/debugging/stacktrace.h" #include "absl/strings/internal/cord_internal.h" #include "absl/strings/internal/cord_rep_btree.h" #include "absl/strings/internal/cord_rep_crc.h" #include "absl/strings/internal/cordz_handle.h" #include "absl/strings/internal/cordz_statistics.h" #include "absl/strings/internal/cordz_update_tracker.h" #include "absl/synchronization/mutex.h" #include "absl/time/clock.h" #include "absl/types/span.h" namespace absl { ABSL_NAMESPACE_BEGIN namespace cord_internal { #ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL constexpr size_t CordzInfo::kMaxStackDepth; #endif ABSL_CONST_INIT CordzInfo::List CordzInfo::global_list_{ … }; namespace { // CordRepAnalyzer performs the analysis of a cord. // // It computes absolute node counts and total memory usage, and an 'estimated // fair share memory usage` statistic. // Conceptually, it divides the 'memory usage' at each location in the 'cord // graph' by the cumulative reference count of that location. The cumulative // reference count is the factored total of all edges leading into that node. // // The top level node is treated specially: we assume the current thread // (typically called from the CordzHandler) to hold a reference purely to // perform a safe analysis, and not being part of the application. So we // subtract 1 from the reference count of the top node to compute the // 'application fair share' excluding the reference of the current thread. // // An example of fair sharing, and why we multiply reference counts: // Assume we have 2 CordReps, both being a Substring referencing a Flat: // CordSubstring A (refcount = 5) --> child Flat C (refcount = 2) // CordSubstring B (refcount = 9) --> child Flat C (refcount = 2) // // Flat C has 2 incoming edges from the 2 substrings (refcount = 2) and is not // referenced directly anywhere else. Translated into a 'fair share', we then // attribute 50% of the memory (memory / refcount = 2) to each incoming edge. // Rep A has a refcount of 5, so we attribute each incoming edge 1 / 5th of the // memory cost below it, i.e.: the fair share of Rep A of the memory used by C // is then 'memory C / (refcount C * refcount A) + (memory A / refcount A)'. // It is also easy to see how all incoming edges add up to 100%. class CordRepAnalyzer { … }; } // namespace CordzInfo* CordzInfo::Head(const CordzSnapshot& snapshot) { … } CordzInfo* CordzInfo::Next(const CordzSnapshot& snapshot) const { … } void CordzInfo::TrackCord(InlineData& cord, MethodIdentifier method, int64_t sampling_stride) { … } void CordzInfo::TrackCord(InlineData& cord, const InlineData& src, MethodIdentifier method) { … } void CordzInfo::MaybeTrackCordImpl(InlineData& cord, const InlineData& src, MethodIdentifier method) { … } CordzInfo::MethodIdentifier CordzInfo::GetParentMethod(const CordzInfo* src) { … } size_t CordzInfo::FillParentStack(const CordzInfo* src, void** stack) { … } CordzInfo::CordzInfo(CordRep* rep, const CordzInfo* src, MethodIdentifier method, int64_t sampling_stride) : … { … } CordzInfo::~CordzInfo() { … } void CordzInfo::Track() { … } void CordzInfo::Untrack() { … } void CordzInfo::Lock(MethodIdentifier method) ABSL_EXCLUSIVE_LOCK_FUNCTION(mutex_) { … } void CordzInfo::Unlock() ABSL_UNLOCK_FUNCTION(mutex_) { … } absl::Span<void* const> CordzInfo::GetStack() const { … } absl::Span<void* const> CordzInfo::GetParentStack() const { … } CordzStatistics CordzInfo::GetCordzStatistics() const { … } } // namespace cord_internal ABSL_NAMESPACE_END } // namespace absl