Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .bazelrc
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ build --cxxopt='-std=c++17'
test --test_output=errors

# Disable noisy warnings from dependencies.
build --per_file_copt=-external/.*@-w
build --host_per_file_copt=-external/.*@-w
build --per_file_copt=external/.*@-w
build --host_per_file_copt=external/.*@-w

# Disable noisy warnings in TCMalloc.
build:clang --copt=-Wno-nullability-completeness
Expand Down
4 changes: 0 additions & 4 deletions tcmalloc/allocation_sample.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,6 @@ class AllocationSampleList {
}

void ReportMalloc(const struct StackTrace& sample) {
// Check that StackTrace was zero-initialized so we don't leak uninitialized
// memory (potentially holding cryptographic material) into core dumps.
TC_CHECK(sample.depth == kMaxStackDepth ||
sample.stack[sample.depth] == nullptr);
AllocationGuardSpinLockHolder h(lock_);
AllocationSample* cur = first_;
while (cur != nullptr) {
Expand Down
95 changes: 3 additions & 92 deletions tcmalloc/huge_page_filler_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -242,43 +242,19 @@ class FakeResidency : public Residency {
class FakeClock {
public:
FakeClock() = default;
[[nodiscard]] static int64_t now() {
now_calls_.fetch_add(1, std::memory_order_relaxed);
return clock_.load(std::memory_order_relaxed);
}
[[nodiscard]] static double freq() {
freq_calls_.fetch_add(1, std::memory_order_relaxed);
return absl::ToDoubleNanoseconds(absl::Seconds(2));
}
static int64_t now() { return clock_.load(std::memory_order_relaxed); }
static double freq() { return absl::ToDoubleNanoseconds(absl::Seconds(2)); }
static void Advance(absl::Duration d) {
clock_.fetch_add(static_cast<int64_t>(absl::ToDoubleSeconds(d) * freq()),
std::memory_order_relaxed);
}
static void ResetClock() {
clock_.store(1234, std::memory_order_relaxed);
now_calls_.store(0, std::memory_order_relaxed);
freq_calls_.store(0, std::memory_order_relaxed);
}
[[nodiscard]] static size_t now_calls() {
return now_calls_.load(std::memory_order_relaxed);
}
[[nodiscard]] static size_t freq_calls() {
return freq_calls_.load(std::memory_order_relaxed);
}
static void ResetCalls() {
now_calls_.store(0, std::memory_order_relaxed);
freq_calls_.store(0, std::memory_order_relaxed);
}
static void ResetClock() { clock_.store(1234, std::memory_order_relaxed); }

private:
static std::atomic<int64_t> clock_;
static std::atomic<size_t> now_calls_;
static std::atomic<size_t> freq_calls_;
};

std::atomic<int64_t> FakeClock::clock_{1234};
std::atomic<size_t> FakeClock::now_calls_{0};
std::atomic<size_t> FakeClock::freq_calls_{0};

class MockCollapse final : public MemoryModifyFunction {
public:
Expand Down Expand Up @@ -679,71 +655,6 @@ class FillerTestWithSubreleaseUnbacked : public FillerTest {
: FillerTest(SubreleaseUnbackedMode::kEnabled) {}
};

// TODO(b/73749855): Reduce the count of clock_.now() and clock_.freq() calls.
TEST_F(FillerTest, ClockCalls) {
SpanAllocInfo info = {.objects_per_span = 1,
.density = AccessDensityPrediction::kSparse};

// 1. TryGet on empty filler (miss).
FakeClock::ResetCalls();
{
PageHeapSpinLockHolder l;
auto res = filler_.TryGet(Length(1), info);
EXPECT_EQ(res.pt, nullptr);
}
EXPECT_EQ(FakeClock::now_calls(), 0);
EXPECT_EQ(FakeClock::freq_calls(), 0);

auto* pt = new PageTracker(GetBacking(), /*was_donated=*/false, 0);
PageId page1;
{
PageHeapSpinLockHolder l;
page1 = pt->Get(Length(1), info).page;
filler_.Contribute(pt, /*donated=*/false, info);
}

// 2. TryGet on available hugepage (hit).
// TODO(b/73749855): Reduce the number of clock calls.
FakeClock::ResetCalls();
PageTracker* alloc_pt;
PageId page2;
{
PageHeapSpinLockHolder l;
auto res = filler_.TryGet(Length(1), info);
alloc_pt = res.pt;
page2 = res.page;
}
EXPECT_EQ(alloc_pt, pt);
EXPECT_EQ(FakeClock::now_calls(), 2);
EXPECT_EQ(FakeClock::freq_calls(), 0);

// 3. Put (partially freed hugepage).
// TODO(b/73749855): Reduce the number of clock calls.
FakeClock::ResetCalls();
PageTracker* put_res1;
{
PageHeapSpinLockHolder l;
put_res1 = filler_.Put(alloc_pt, Range(page2, Length(1)), info);
}
EXPECT_EQ(put_res1, nullptr);
EXPECT_EQ(FakeClock::now_calls(), 1);
EXPECT_EQ(FakeClock::freq_calls(), 0);

// 4. Put (fully freed hugepage).
// TODO(b/73749855): Reduce the number of clock calls.
FakeClock::ResetCalls();
PageTracker* put_res2;
{
PageHeapSpinLockHolder l;
put_res2 = filler_.Put(pt, Range(page1, Length(1)), info);
}
EXPECT_EQ(put_res2, pt);
EXPECT_EQ(FakeClock::now_calls(), 2);
EXPECT_EQ(FakeClock::freq_calls(), 1);

delete pt;
}

TEST_F(FillerTest, Density) {
absl::BitGen rng;
// Start with a really annoying setup: some hugepages half empty (randomly)
Expand Down
2 changes: 2 additions & 0 deletions tcmalloc/internal/delay_injection.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ class ScopedDelay {
__asm__ __volatile__("yield\n");
#endif
}
#else
(void)delay_cycles;
#endif
}
~ScopedDelay() = default;
Expand Down
6 changes: 2 additions & 4 deletions tcmalloc/internal/logging.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,11 +91,9 @@ struct StackTrace {
// for residency analysis such as for peakheapz.
void* span_start_address = nullptr;

uintptr_t depth = 0; // Number of PC values stored in array below
uintptr_t depth; // Number of PC values stored in array below
// Place stack as last member because it might not all be accessed.
// Zero-initialized so uninitialized stack memory (which might contain
// cryptographic secrets) is not leaked into the heap and hence core dumps.
void* stack[kMaxStackDepth] = {};
void* stack[kMaxStackDepth];
};

#define TC_LOG(msg, ...) \
Expand Down
5 changes: 2 additions & 3 deletions tcmalloc/internal/percpu_tcmalloc.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,14 @@
#include "tcmalloc/internal/prefetch.h"
#include "tcmalloc/internal/sysinfo.h"

#if defined(__GNUC__) && !defined(__clang__) && defined(__x86_64__)
#if defined(__GNUC__) && __GNUC__ >= 14 && !defined(__clang__) && \
defined(__x86_64__)
// Work around https://gcc.gnu.org/bugzilla/show_bug.cgi?id=125526
// by force-loading the address of the thread-local rseq_cs_addr into
// a register instead of giving it as a "m" constraint.
//
// TODO: Remove this when GCC releases a fixed version.
#define TCMALLOC_INTERNAL_PERCPU_USE_TLS_WORKAROUND 1
#else
#define TCMALLOC_INTERNAL_PERCPU_USE_TLS_WORKAROUND 0
#endif

GOOGLE_MALLOC_SECTION_BEGIN
Expand Down
19 changes: 15 additions & 4 deletions tcmalloc/page_allocator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,21 @@ PageAllocator::PageAllocator() {
TC_CHECK_LE(part, std::size(choices_));
}

void PageAllocator::ShrinkToUsageLimitSlow(Length n) {
void PageAllocator::ShrinkToUsageLimit(Length n, bool may_have_grown) {
#ifdef TCMALLOC_INTERNAL_LEGACY_LOCKING
const bool check_stats = true;
#else
#ifndef NDEBUG
const bool check_stats = true;
#else
const bool check_stats = may_have_grown;
#endif // NDEBUG
#endif // TCMALLOC_INTERNAL_LEGACY_LOCKING

if (!check_stats) {
return;
}

BackingStats s = stats();
const size_t backed =
s.system_bytes - s.unmapped_bytes + tc_globals.metadata_bytes();
Expand All @@ -99,7 +113,6 @@ void PageAllocator::ShrinkToUsageLimitSlow(Length n) {
// occur if we allocate space for many objects preemptively and only later
// sample them (incrementing sampled_objects_size_).

over_limit_ = false;
if (limits_[kSoft] == std::numeric_limits<size_t>::max()) {
// Limits are not set.
return;
Expand Down Expand Up @@ -148,8 +161,6 @@ void PageAllocator::ShrinkToUsageLimitSlow(Length n) {
hard_limit);
}

over_limit_ = true;

// Print logs once.
static bool warned = false;
if (warned) return;
Expand Down
17 changes: 1 addition & 16 deletions tcmalloc/page_allocator.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,19 +141,7 @@ class PageAllocator {
// If we have a usage limit set, ensure we're not violating it from our latest
// allocation.
void ShrinkToUsageLimit(Length n, bool may_have_grown)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(pageheap_lock) {
#if defined(TCMALLOC_INTERNAL_LEGACY_LOCKING) || !defined(NDEBUG)
const bool check_stats = true;
#else
const bool check_stats = may_have_grown || over_limit_;
#endif

if (!check_stats) {
return;
}

ShrinkToUsageLimitSlow(n);
}
ABSL_EXCLUSIVE_LOCKS_REQUIRED(pageheap_lock);

void TreatHugepageTrackers(EnableCollapse enable_collapse)
ABSL_LOCKS_EXCLUDED(pageheap_lock);
Expand Down Expand Up @@ -207,8 +195,6 @@ class PageAllocator {
MemoryTag tag);
static void InvokeReleaseHookSlow(Length num_pages, Length released,
PageReleaseReason reason);
ABSL_ATTRIBUTE_NOINLINE void ShrinkToUsageLimitSlow(Length n)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(pageheap_lock);
bool ShrinkHardBy(Length page, LimitKind limit_kind)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(pageheap_lock);

Expand All @@ -232,7 +218,6 @@ class PageAllocator {
Algorithm alg_;
bool has_cold_impl_;
bool sampled_partition_active_;
bool over_limit_ ABSL_GUARDED_BY(pageheap_lock) = false;

// Max size of backed spans we will attempt to maintain.
// Crash if we can't maintain below limits_[kHard], which is guaranteed to be
Expand Down
60 changes: 0 additions & 60 deletions tcmalloc/page_allocator_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -251,66 +251,6 @@ TEST_F(PageAllocatorTest, b270916852) {
Parameters::set_hpaa_subrelease(old_subrelease);
}

TEST_F(PageAllocatorTest, ShrinkFailureStickyTest) {
// Turn off subrelease so that we take the ShrinkHardBy path.
const bool old_subrelease = Parameters::hpaa_subrelease();
Parameters::set_hpaa_subrelease(false);

constexpr SpanAllocInfo kSpanInfo = {/*objects_per_span=*/1,
AccessDensityPrediction::kSparse};
Span* normal1 = New(kPagesPerHugePage / 4, kSpanInfo, MemoryTag::kNormal);
Span* normal2 = New(kPagesPerHugePage / 4, kSpanInfo, MemoryTag::kNormal);
Span* sampled = New(kPagesPerHugePage / 2, kSpanInfo, MemoryTag::kSampled);

BackingStats stats;
{
PageHeapSpinLockHolder l;
stats = allocator_.stats();
}
EXPECT_EQ(stats.system_bytes, 2 * kHugePageSize);
EXPECT_EQ(stats.free_bytes, kHugePageSize);
EXPECT_EQ(stats.unmapped_bytes, 0);

// Choose a limit so that we hit and we are not able to satisfy it.
const size_t metadata_bytes = []() {
PageHeapSpinLockHolder l;
return tc_globals.metadata_bytes();
}();
allocator_.set_limit(metadata_bytes + (3 * kPagesPerHugePage / 4).in_bytes(),
PageAllocator::kSoft);
EXPECT_EQ(1, allocator_.limit_hits(PageAllocator::kSoft));
EXPECT_EQ(
0, allocator_.successful_shrinks_after_limit_hit(PageAllocator::kSoft));
// Now delete normal1 so that memory can be released to get under limit.
// normal2 is still alive on that hugepage, so HugePageFiller::Put does
// not unback the hugepage automatically.
Delete(normal1, kSpanInfo, MemoryTag::kNormal);

// A subsequent allocation with may_have_grown == false should attempt to
// shrink until below the limit.
{
PageHeapSpinLockHolder l;
allocator_.ShrinkToUsageLimit(Length(0), /*may_have_grown=*/false);
}
EXPECT_EQ(2, allocator_.limit_hits(PageAllocator::kSoft));
EXPECT_EQ(
1, allocator_.successful_shrinks_after_limit_hit(PageAllocator::kSoft));

// Now that we are below the limit, a subsequent call with may_have_grown ==
// false should not attempt to shrink.
{
PageHeapSpinLockHolder l;
allocator_.ShrinkToUsageLimit(Length(0), /*may_have_grown=*/false);
}
EXPECT_EQ(2, allocator_.limit_hits(PageAllocator::kSoft));
EXPECT_EQ(
1, allocator_.successful_shrinks_after_limit_hit(PageAllocator::kSoft));

Delete(normal2, kSpanInfo, MemoryTag::kNormal);
Delete(sampled, kSpanInfo, MemoryTag::kSampled);
Parameters::set_hpaa_subrelease(old_subrelease);
}

struct HookRecord {
size_t start_page_index;
size_t n;
Expand Down
2 changes: 2 additions & 0 deletions tcmalloc/testing/alloc_at_least_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
#include <stdlib.h>

int main(int argc, char** argv) {
(void)argc;
(void)argv;
int exit_code = EXIT_SUCCESS;
alloc_result_t result = alloc_at_least(127);
if (result.ptr == NULL || result.size < 127) {
Expand Down
Loading