Skip to content

Commit

Permalink
fix: Fix 0 reclaimable bytes handling in priority reclaiming
Browse files Browse the repository at this point in the history
  • Loading branch information
tanjialiang committed Dec 21, 2024
1 parent 9265fbf commit e236295
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 4 deletions.
7 changes: 3 additions & 4 deletions velox/common/memory/MemoryArbitrator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,8 @@ uint64_t MemoryReclaimer::reclaim(
auto child = entry.second.lock();
if (child != nullptr) {
const auto reclaimableBytesOpt = child->reclaimableBytes();
if (!reclaimableBytesOpt.has_value()) {
if (!reclaimableBytesOpt.has_value() ||
reclaimableBytesOpt.value() == 0) {
nonReclaimableCandidates.push_back(Candidate{std::move(child), 0});
continue;
}
Expand All @@ -282,9 +283,7 @@ uint64_t MemoryReclaimer::reclaim(

uint64_t reclaimedBytes{0};
for (const auto& candidate : candidates) {
if (candidate.reclaimableBytes == 0) {
break;
}
VELOX_CHECK_NE(candidate.reclaimableBytes, 0);
const auto bytes = candidate.pool->reclaim(targetBytes, maxWaitMs, stats);
reclaimedBytes += bytes;
if (targetBytes != 0) {
Expand Down
34 changes: 34 additions & 0 deletions velox/exec/tests/MemoryReclaimerTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,40 @@ TEST_F(MemoryReclaimerTest, reclaimerPriorities) {
}
}

TEST_F(MemoryReclaimerTest, reclaimerPrioritiesWithZeroUsage) {
// This test makes sure the reclaim continues to lower priority reclaimers
// even if the higher priority ones have nothing to reclaim.
auto rootPool = memory::memoryManager()->addRootPool(
"reclaimerPriorities", kMaxMemory, exec::MemoryReclaimer::create());
std::vector<std::shared_ptr<MemoryPool>> leafPools;

const uint32_t kNumChildren = 10;
const uint64_t kPoolMemoryBytes = 1024;
std::vector<int32_t> priorityOrder;
priorityOrder.reserve(kNumChildren);
ReclaimCallback reclaimerCb = [&](MemoryPool* pool) {
auto* mockReclaimer = dynamic_cast<MockMemoryReclaimer*>(pool->reclaimer());
ASSERT_TRUE(mockReclaimer != nullptr);
priorityOrder.push_back(mockReclaimer->priority());
};

for (uint32_t i = 0; i < kNumChildren; ++i) {
auto reclaimer = MockMemoryReclaimer::create(
kPoolMemoryBytes,
i % 5 == 0 ? kPoolMemoryBytes : 0,
reclaimerCb,
i / 5);
leafPools.push_back(rootPool->addLeafChild(
fmt::format("leaf-{}", i), true, std::move(reclaimer)));
}

memory::ScopedMemoryArbitrationContext context(rootPool.get());
memory::MemoryReclaimer::Stats stats;
rootPool->reclaim(2 * kPoolMemoryBytes, 0, stats);

ASSERT_EQ(priorityOrder.size(), 2);
}

TEST_F(MemoryReclaimerTest, multiLevelReclaimerPriorities) {
// Following tree structure is built with priorities
// rootPool
Expand Down

0 comments on commit e236295

Please sign in to comment.