Skip to content

Commit

Permalink
Instrument StackTraceFilter to count the number of slots used and num…
Browse files Browse the repository at this point in the history
…ber of replacements.

This does not change how the algorithm functions, but does add some mild
contention when there are collisions in the StackTraceFilter.

An implicit metric is the number of stacks Add-ed is equal to
GuardedPageAllocator::SuccessfulAllocations().  (emitted as "Successful
Allocations" (mallocz/) and "successful_allocations" (mallocz.proto).
PiperOrigin-RevId: 570751434
Change-Id: Ie06c038f937a6a2c128f2973a08bd5df02747ad6
  • Loading branch information
kda authored and copybara-github committed Oct 4, 2023
1 parent 10e3f89 commit 3ee73f3
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 1 deletion.
9 changes: 8 additions & 1 deletion tcmalloc/guarded_page_allocator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -184,13 +184,16 @@ void GuardedPageAllocator::Print(Printer* out) {
"Slots Currently Allocated: %zu\n"
"Slots Currently Quarantined: %zu\n"
"Maximum Slots Allocated: %zu / %zu\n"
"StackTraceFilter Max Slots Used: %zu\n"
"StackTraceFilter Replacement Inserts: %zu\n"
"PARAMETER tcmalloc_guarded_sample_parameter %d\n"
// TODO(b/263387812): remove when experiment is finished
"PARAMETER tcmalloc_improved_guarded_sampling %d\n",
num_allocation_requests_ - num_failed_allocations_,
num_failed_allocations_, num_alloced_pages_,
total_pages_ - num_alloced_pages_, num_alloced_pages_max_,
max_alloced_pages_, GetChainedRate(),
max_alloced_pages_, tc_globals.stacktrace_filter().max_slots_used(),
tc_globals.stacktrace_filter().replacement_inserts(), GetChainedRate(),
Parameters::improved_guarded_sampling());
}

Expand All @@ -204,6 +207,10 @@ void GuardedPageAllocator::PrintInPbtxt(PbtxtRegion* gwp_asan) {
total_pages_ - num_alloced_pages_);
gwp_asan->PrintI64("max_slots_allocated", num_alloced_pages_max_);
gwp_asan->PrintI64("allocated_slot_limit", max_alloced_pages_);
gwp_asan->PrintI64("stack_trace_filter_max_slots_used",
tc_globals.stacktrace_filter().max_slots_used());
gwp_asan->PrintI64("stack_trace_filter_replacement_inserts",
tc_globals.stacktrace_filter().replacement_inserts());
gwp_asan->PrintI64("tcmalloc_guarded_sample_parameter", GetChainedRate());
// TODO(b/263387812): remove when experiment is finished
gwp_asan->PrintI64("tcmalloc_improved_guarded_sampling",
Expand Down
13 changes: 13 additions & 0 deletions tcmalloc/internal/stacktrace_filter.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,20 @@ class StackTraceFilter {

size_t Count(const StackTrace& stacktrace) const;
void Add(const StackTrace& stacktrace);
size_t max_slots_used() const {
return max_slots_used_.load(std::memory_order_relaxed);
}
size_t replacement_inserts() const {
return replacement_inserts_.load(std::memory_order_relaxed);
}

private:
constexpr static size_t kMask = 0xFF;
constexpr static size_t kHashCountLimit = kMask;
constexpr static int kSize = kMask + 1;
std::atomic<size_t> stack_hashes_with_count_[kSize]{0};
std::atomic<size_t> max_slots_used_{0};
std::atomic<size_t> replacement_inserts_{0};

inline size_t HashOfStackTrace(const StackTrace& stacktrace) const {
return absl::HashOf(
Expand Down Expand Up @@ -100,6 +108,11 @@ inline void StackTraceFilter::Add(const StackTrace& stacktrace) {
stack_hashes_with_count_[stack_hash % kSize].store(
(stack_hash & ~kMask) | count, std::memory_order_relaxed);
} else {
if (existing_stack_hash_with_count == 0) {
max_slots_used_.fetch_add(1, std::memory_order_relaxed);
} else {
replacement_inserts_.fetch_add(1, std::memory_order_relaxed);
}
// New stack_hash being placed in (unoccupied entry || existing entry)
stack_hashes_with_count_[stack_hash % kSize].store(
(stack_hash & ~kMask) | 1, std::memory_order_relaxed);
Expand Down
16 changes: 16 additions & 0 deletions tcmalloc/internal/stacktrace_filter_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -170,32 +170,48 @@ TEST_F(StackTraceFilterTest, CountNew) {
TEST_F(StackTraceFilterTest, CountDifferent) {
InitializeColliderStackTrace();
filter_.Add(stacktrace1_);
EXPECT_EQ(1, filter_.max_slots_used());
EXPECT_EQ(0, filter_.replacement_inserts());
EXPECT_EQ(0, filter_.Count(collider_stacktrace_));
}

TEST_F(StackTraceFilterTest, Add) {
filter_.Add(stacktrace1_);
EXPECT_EQ(1, filter_.max_slots_used());
EXPECT_EQ(0, filter_.replacement_inserts());
EXPECT_EQ(1, filter_.Count(stacktrace1_));
filter_.Add(stacktrace1_);
EXPECT_EQ(1, filter_.max_slots_used());
EXPECT_EQ(0, filter_.replacement_inserts());
EXPECT_EQ(2, filter_.Count(stacktrace1_));
}

TEST_F(StackTraceFilterTest, AddCountLimitReached) {
while (count(stacktrace1_) < filter_hash_count_limit()) {
filter_.Add(stacktrace1_);
}
EXPECT_EQ(1, filter_.max_slots_used());
EXPECT_EQ(0, filter_.replacement_inserts());
EXPECT_EQ(filter_hash_count_limit(), filter_.Count(stacktrace1_));
filter_.Add(stacktrace1_);
EXPECT_EQ(1, filter_.max_slots_used());
EXPECT_EQ(0, filter_.replacement_inserts());
EXPECT_EQ(filter_hash_count_limit(), filter_.Count(stacktrace1_));
}

TEST_F(StackTraceFilterTest, AddReplace) {
InitializeColliderStackTrace();
filter_.Add(stacktrace1_);
EXPECT_EQ(1, filter_.max_slots_used());
EXPECT_EQ(0, filter_.replacement_inserts());
EXPECT_EQ(1, filter_.Count(stacktrace1_));
filter_.Add(stacktrace1_);
EXPECT_EQ(1, filter_.max_slots_used());
EXPECT_EQ(0, filter_.replacement_inserts());
EXPECT_EQ(2, filter_.Count(stacktrace1_));
filter_.Add(collider_stacktrace_);
EXPECT_EQ(1, filter_.max_slots_used());
EXPECT_EQ(1, filter_.replacement_inserts());
EXPECT_EQ(0, filter_.Count(stacktrace1_));
EXPECT_EQ(1, filter_.Count(collider_stacktrace_));
}
Expand Down

0 comments on commit 3ee73f3

Please sign in to comment.