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 tcmalloc/global_stats.cc
Original file line number Diff line number Diff line change
Expand Up @@ -182,8 +182,8 @@ void ExtractStats(TCMallocStats& r, uint64_t* absl_nullable class_count,
if (report_residence) {
auto resident_bytes = tc_globals.pagemap_residence();
r.pagemap_root_bytes_res = resident_bytes;
TC_ASSERT_GE(r.metadata_bytes, r.pagemap_bytes);
r.metadata_bytes = r.metadata_bytes - r.pagemap_bytes + resident_bytes;
TC_ASSERT_GE(r.metadata_bytes, sizeof(PageMap));
r.metadata_bytes = r.metadata_bytes - sizeof(PageMap) + resident_bytes;
} else {
r.pagemap_root_bytes_res = 0;
}
Expand Down
45 changes: 45 additions & 0 deletions tcmalloc/stats_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,12 @@
#include "absl/base/internal/cycleclock.h"
#include "absl/time/clock.h"
#include "absl/time/time.h"
#include "tcmalloc/global_stats.h"
#include "tcmalloc/huge_pages.h"
#include "tcmalloc/internal/logging.h"
#include "tcmalloc/pagemap.h"
#include "tcmalloc/pages.h"
#include "tcmalloc/static_vars.h"
#include "tcmalloc/testing/testutil.h"

namespace tcmalloc {
Expand Down Expand Up @@ -177,6 +180,48 @@ TEST(ClockTest, ClockTicks) {
EXPECT_GE(actual * 1.01, measured) << actual;
}

TEST(GlobalStatsTest, PageMapMemoryAccounted) {
TCMallocStats before;
ExtractTCMallocStats(before, /*report_residence=*/true);
const size_t pagemap_bytes_before = []() {
PageHeapSpinLockHolder l;
return tc_globals.pagemap().bytes();
}();

// Ensure several distant pages that require allocating new internal and leaf
// nodes in the PageMap radix tree.
const PageId p1{100000000};
const PageId p2{200000000};
{
PageHeapSpinLockHolder l;
ASSERT_TRUE(tc_globals.pagemap().Ensure(Range(p1, Length(1))));
ASSERT_TRUE(tc_globals.pagemap().Ensure(Range(p2, Length(1))));
}
const size_t pagemap_bytes_after = []() {
PageHeapSpinLockHolder l;
return tc_globals.pagemap().bytes();
}();
ASSERT_GT(pagemap_bytes_after, pagemap_bytes_before);
const size_t pagemap_increase = pagemap_bytes_after - pagemap_bytes_before;

TCMallocStats after;
ExtractTCMallocStats(after, /*report_residence=*/true);

// Metadata bytes must properly account for newly allocated pagemap
// nodes/leaves.
EXPECT_GE(after.metadata_bytes, before.metadata_bytes + pagemap_increase);

TCMallocStats without_residence;
ExtractTCMallocStats(without_residence, /*report_residence=*/false);

// The difference in metadata bytes between reporting residence or not should
// only reflect unresident portions of the pagemap root and per-CPU slabs,
// not the entire pagemap dynamically allocated memory.
EXPECT_GE(after.metadata_bytes, without_residence.metadata_bytes -
sizeof(PageMap) -
after.percpu_metadata_bytes);
}

} // namespace
} // namespace tcmalloc_internal
} // namespace tcmalloc
Loading