Skip to content

Commit

Permalink
Export of internal Abseil changes
Browse files Browse the repository at this point in the history
--
81f95fcf85b75b84f9892c73123501472b9cff33 by Martijn Vels <[email protected]>:

Introduce GetEstimatedMemoryUsage(CordMemoryAccounting::kFairShare)

Memory usage analysis is moved into a separate cord_analysis.cc source.

PiperOrigin-RevId: 416370158

--
6bc7b1348fd27fe53f100c9eabd47f4f2cb9c19c by Abseil Team <[email protected]>:

Support scoped enum in absl::Substitute.

PiperOrigin-RevId: 416345422

--
6399f4f6ae05ebcd67664ebd844902f699ab8ec7 by Abseil Team <[email protected]>:

Correct the computation of contention cycles

Currently, we record contention cycles from the first time a thread started
waiting on a mutex.  Consider a situation in which two threads, T1 and T2, run
a loop at the top of which they acquire a common mutex and release it at the
end of the loop body.  Further assume that T2 is never able to acquire the
mutex as T1 repeatedly acquires and then releases the mutex.  In this case, we
would expect that the reported contention cycles would be increase linearly
over time.  But currently we observe a quadratic behavior in the reported
waiting time as mentioned in b/14684244#comment10.

To fix the issue, this CL records the contention cycles experienced by all the threads woken up when the mutex is released.  Further, contention_start_cycles is set to the current time since the contention cycles for the time already passed has been taken into account.  With this CL, we get a linear increase in the waiting time, the expected behavior.

PiperOrigin-RevId: 416322593

--
149c1637c8a0f1a38e5a8f9f27e5803a2015a554 by Jorg Brown <[email protected]>:

Make Status::EmptyString more efficient by constructing it in global space, rather than on the heap.  See https://godbolt.org/z/8M9n7YqcY for reduced code size.

PiperOrigin-RevId: 416307833

--
3b4562a8be5a3c80077cb67b0a32c97419058380 by Abseil Team <[email protected]>:

Clarify the usage of RegisterMutexProfiler

PiperOrigin-RevId: 416146130
GitOrigin-RevId: 81f95fcf85b75b84f9892c73123501472b9cff33
Change-Id: Iccb72d7ee617e6ebe226a38170d62e0849b43480
  • Loading branch information
Abseil Team authored and rogeeff committed Dec 15, 2021
1 parent 1065514 commit 52d41a9
Show file tree
Hide file tree
Showing 13 changed files with 564 additions and 197 deletions.
2 changes: 2 additions & 0 deletions CMake/AbseilDll.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,8 @@ set(ABSL_INTERNAL_DLL_FILES
"strings/charconv.cc"
"strings/charconv.h"
"strings/cord.cc"
"strings/cord_analysis.cc"
"strings/cord_analysis.h"
"strings/cord.h"
"strings/escaping.cc"
"strings/escaping.h"
Expand Down
7 changes: 5 additions & 2 deletions absl/status/status.cc
Original file line number Diff line number Diff line change
Expand Up @@ -185,8 +185,11 @@ void Status::ForEachPayload(
}

const std::string* Status::EmptyString() {
static std::string* empty_string = new std::string();
return empty_string;
static union EmptyString {
std::string str;
~EmptyString() {}
} empty = {{}};
return &empty.str;
}

constexpr const char Status::kMovedFromString[];
Expand Down
2 changes: 2 additions & 0 deletions absl/strings/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,8 @@ cc_library(
name = "cord",
srcs = [
"cord.cc",
"cord_analysis.cc",
"cord_analysis.h",
],
hdrs = [
"cord.h",
Expand Down
2 changes: 2 additions & 0 deletions absl/strings/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -834,6 +834,8 @@ absl_cc_library(
"cord.h"
SRCS
"cord.cc"
"cord_analysis.cc"
"cord_analysis.h"
COPTS
${ABSL_DEFAULT_COPTS}
DEPS
Expand Down
114 changes: 0 additions & 114 deletions absl/strings/cord.cc
Original file line number Diff line number Diff line change
Expand Up @@ -469,51 +469,6 @@ static inline bool PrepareAppendRegion(CordRep* root, char** region,
return true;
}

// Computes the memory side of the provided edge which must be a valid data edge
// for a btrtee, i.e., a FLAT, EXTERNAL or SUBSTRING of a FLAT or EXTERNAL node.
static bool RepMemoryUsageDataEdge(const CordRep* rep,
size_t* total_mem_usage) {
size_t maybe_sub_size = 0;
if (ABSL_PREDICT_FALSE(rep->IsSubstring())) {
maybe_sub_size = sizeof(cord_internal::CordRepSubstring);
rep = rep->substring()->child;
}
if (rep->IsFlat()) {
*total_mem_usage += maybe_sub_size + rep->flat()->AllocatedSize();
return true;
}
if (rep->IsExternal()) {
// We don't know anything about the embedded / bound data, but we can safely
// assume it is 'at least' a word / pointer to data. In the future we may
// choose to use the 'data' byte as a tag to identify the types of some
// well-known externals, such as a std::string instance.
*total_mem_usage += maybe_sub_size +
sizeof(cord_internal::CordRepExternalImpl<intptr_t>) +
rep->length;
return true;
}
return false;
}

// If the rep is a leaf, this will increment the value at total_mem_usage and
// will return true.
static bool RepMemoryUsageLeaf(const CordRep* rep, size_t* total_mem_usage) {
if (rep->IsFlat()) {
*total_mem_usage += rep->flat()->AllocatedSize();
return true;
}
if (rep->IsExternal()) {
// We don't know anything about the embedded / bound data, but we can safely
// assume it is 'at least' a word / pointer to data. In the future we may
// choose to use the 'data' byte as a tag to identify the types of some
// well-known externals, such as a std::string instance.
*total_mem_usage +=
sizeof(cord_internal::CordRepExternalImpl<intptr_t>) + rep->length;
return true;
}
return false;
}

void Cord::InlineRep::AssignSlow(const Cord::InlineRep& src) {
assert(&src != this);
assert(is_tree() || src.is_tree());
Expand Down Expand Up @@ -1968,75 +1923,6 @@ static bool VerifyNode(CordRep* root, CordRep* start_node,
return true;
}

// Traverses the tree and computes the total memory allocated.
/* static */ size_t Cord::MemoryUsageAux(const CordRep* rep) {
size_t total_mem_usage = 0;

if (rep->IsCrc()) {
total_mem_usage += sizeof(CordRepCrc);
rep = rep->crc()->child;
}

// Allow a quick exit for the common case that the root is a leaf.
if (RepMemoryUsageLeaf(rep, &total_mem_usage)) {
return total_mem_usage;
}

// Iterate over the tree. cur_node is never a leaf node and leaf nodes will
// never be appended to tree_stack. This reduces overhead from manipulating
// tree_stack.
absl::InlinedVector<const CordRep*, kInlinedVectorSize> tree_stack;
const CordRep* cur_node = rep;
while (true) {
const CordRep* next_node = nullptr;

if (cur_node->IsConcat()) {
total_mem_usage += sizeof(CordRepConcat);
const CordRep* left = cur_node->concat()->left;
if (!RepMemoryUsageLeaf(left, &total_mem_usage)) {
next_node = left;
}

const CordRep* right = cur_node->concat()->right;
if (!RepMemoryUsageLeaf(right, &total_mem_usage)) {
if (next_node) {
tree_stack.push_back(next_node);
}
next_node = right;
}
} else if (cur_node->IsBtree()) {
total_mem_usage += sizeof(CordRepBtree);
const CordRepBtree* node = cur_node->btree();
if (node->height() == 0) {
for (const CordRep* edge : node->Edges()) {
RepMemoryUsageDataEdge(edge, &total_mem_usage);
}
} else {
for (const CordRep* edge : node->Edges()) {
tree_stack.push_back(edge);
}
}
} else {
// Since cur_node is not a leaf or a concat node it must be a substring.
assert(cur_node->IsSubstring());
total_mem_usage += sizeof(CordRepSubstring);
next_node = cur_node->substring()->child;
if (RepMemoryUsageLeaf(next_node, &total_mem_usage)) {
next_node = nullptr;
}
}

if (!next_node) {
if (tree_stack.empty()) {
return total_mem_usage;
}
next_node = tree_stack.back();
tree_stack.pop_back();
}
cur_node = next_node;
}
}

std::ostream& operator<<(std::ostream& out, const Cord& cord) {
for (absl::string_view chunk : cord.Chunks()) {
out.write(chunk.data(), chunk.size());
Expand Down
36 changes: 26 additions & 10 deletions absl/strings/cord.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@
#include "absl/container/inlined_vector.h"
#include "absl/functional/function_ref.h"
#include "absl/meta/type_traits.h"
#include "absl/strings/cord_analysis.h"
#include "absl/strings/internal/cord_internal.h"
#include "absl/strings/internal/cord_rep_btree.h"
#include "absl/strings/internal/cord_rep_btree_reader.h"
Expand All @@ -102,6 +103,20 @@ template <typename Releaser>
Cord MakeCordFromExternal(absl::string_view, Releaser&&);
void CopyCordToString(const Cord& src, std::string* dst);

// Cord memory accounting modes
enum class CordMemoryAccounting {
// Counts the *approximate* number of bytes held in full or in part by this
// Cord (which may not remain the same between invocations). Cords that share
// memory could each be "charged" independently for the same shared memory.
kTotal,

// Counts the *approximate* number of bytes held in full or in part by this
// Cord weighted by the sharing ratio of that data. For example, if some data
// edge is shared by 4 different Cords, then each cord is attributed 1/4th of
// the total memory usage as a 'fair share' of the total memory usage.
kFairShare,
};

// Cord
//
// A Cord is a sequence of characters, designed to be more efficient than a
Expand Down Expand Up @@ -272,11 +287,10 @@ class Cord {

// Cord::EstimatedMemoryUsage()
//
// Returns the *approximate* number of bytes held in full or in part by this
// Cord (which may not remain the same between invocations). Note that Cords
// that share memory could each be "charged" independently for the same shared
// memory.
size_t EstimatedMemoryUsage() const;
// Returns the *approximate* number of bytes held by this cord.
// See CordMemoryAccounting for more information on accounting method used.
size_t EstimatedMemoryUsage(CordMemoryAccounting accounting_method =
CordMemoryAccounting::kTotal) const;

// Cord::Compare()
//
Expand Down Expand Up @@ -890,9 +904,6 @@ class Cord {
};
InlineRep contents_;

// Helper for MemoryUsage().
static size_t MemoryUsageAux(const absl::cord_internal::CordRep* rep);

// Helper for GetFlat() and TryFlat().
static bool GetFlatAux(absl::cord_internal::CordRep* rep,
absl::string_view* fragment);
Expand Down Expand Up @@ -1235,10 +1246,15 @@ inline size_t Cord::size() const {

inline bool Cord::empty() const { return contents_.empty(); }

inline size_t Cord::EstimatedMemoryUsage() const {
inline size_t Cord::EstimatedMemoryUsage(
CordMemoryAccounting accounting_method) const {
size_t result = sizeof(Cord);
if (const absl::cord_internal::CordRep* rep = contents_.tree()) {
result += MemoryUsageAux(rep);
if (accounting_method == CordMemoryAccounting::kFairShare) {
result += cord_internal::GetEstimatedFairShareMemoryUsage(rep);
} else {
result += cord_internal::GetEstimatedMemoryUsage(rep);
}
}
return result;
}
Expand Down
Loading

0 comments on commit 52d41a9

Please sign in to comment.