Add some debug flags to auto growth allocator (#21766)
* add some debug flags to auto growth allocator, test=develop * add comments about auto growth, test=develop1.6.2
parent
c50ebeac12
commit
aa4d6a5d6c
@ -0,0 +1,168 @@
|
||||
// Copyright (c) 2019 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "paddle/fluid/memory/allocation/auto_growth_best_fit_allocator.h"
|
||||
#include <cstdlib>
|
||||
#include <vector>
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
DECLARE_bool(free_idle_chunk);
|
||||
DECLARE_bool(free_when_no_cache_hit);
|
||||
|
||||
namespace paddle {
|
||||
namespace memory {
|
||||
namespace allocation {
|
||||
|
||||
class RecordedAllocator : public Allocator {
|
||||
protected:
|
||||
Allocation *AllocateImpl(size_t size) override {
|
||||
allocated_size_ += size;
|
||||
return new Allocation(malloc(size), size, platform::CPUPlace());
|
||||
}
|
||||
|
||||
void FreeImpl(Allocation *allocation) {
|
||||
allocated_size_ -= allocation->size();
|
||||
free(allocation->ptr());
|
||||
delete allocation;
|
||||
}
|
||||
|
||||
public:
|
||||
size_t AllocatedSize() const { return allocated_size_; }
|
||||
|
||||
private:
|
||||
size_t allocated_size_{0};
|
||||
};
|
||||
|
||||
static void TestFreeIdleChunk(bool free_idle_chunk,
|
||||
bool free_when_no_cache_hit) {
|
||||
FLAGS_free_idle_chunk = free_idle_chunk;
|
||||
FLAGS_free_when_no_cache_hit = free_when_no_cache_hit;
|
||||
auto recorded_allocator = std::make_shared<RecordedAllocator>();
|
||||
size_t alignment = 4096;
|
||||
size_t memory_size = 8192;
|
||||
auto ag_allocator = std::make_shared<AutoGrowthBestFitAllocator>(
|
||||
recorded_allocator, alignment);
|
||||
|
||||
for (size_t i = 0; i < 10; ++i) {
|
||||
auto allocation = ag_allocator->Allocate(memory_size);
|
||||
ASSERT_EQ(recorded_allocator->AllocatedSize(), memory_size + alignment);
|
||||
allocation.reset();
|
||||
if (free_idle_chunk) {
|
||||
ASSERT_EQ(recorded_allocator->AllocatedSize(), 0UL);
|
||||
} else {
|
||||
ASSERT_EQ(recorded_allocator->AllocatedSize(), memory_size + alignment);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class LimitedResourceAllocator : public Allocator {
|
||||
public:
|
||||
explicit LimitedResourceAllocator(size_t capacity) : capacity_(capacity) {}
|
||||
|
||||
size_t AllocatedSize() const { return allocated_size_; }
|
||||
|
||||
protected:
|
||||
Allocation *AllocateImpl(size_t size) override {
|
||||
if (allocated_size_ + size > capacity_) {
|
||||
throw BadAlloc("", __FILE__, __LINE__);
|
||||
}
|
||||
|
||||
allocated_size_ += size;
|
||||
return new Allocation(malloc(size), size, platform::CPUPlace());
|
||||
}
|
||||
|
||||
void FreeImpl(Allocation *allocation) {
|
||||
allocated_size_ -= allocation->size();
|
||||
free(allocation->ptr());
|
||||
delete allocation;
|
||||
}
|
||||
|
||||
private:
|
||||
size_t allocated_size_{0};
|
||||
const size_t capacity_;
|
||||
};
|
||||
|
||||
static void TestFreeWhenNoCacheHit(bool free_when_no_cache_hit) {
|
||||
FLAGS_free_idle_chunk = false;
|
||||
FLAGS_free_when_no_cache_hit = free_when_no_cache_hit;
|
||||
size_t alignment = 256;
|
||||
size_t base_memory_size = 4096;
|
||||
|
||||
/*
|
||||
* Suppose that we have 3 memory allocation request, that is:
|
||||
* - allocate x1, and then free x1
|
||||
* - allocate x2, and then free x2
|
||||
* - allocate x3, and then free x3
|
||||
*
|
||||
* where:
|
||||
* - x1 + alignment < x2
|
||||
* - x2 + alignment < x3
|
||||
* - x1 + x2 <= memory_capacity < x1 + x2 + x3
|
||||
*
|
||||
* In this unittest, we obtain memory_capacity by
|
||||
* ((x1 + x2) + (x1 + x2 + x3) / 2 = x1 + x2 + x3 / 2.
|
||||
*
|
||||
* In this case, when FLAGS_free_when_no_cache_hit is true,
|
||||
* the cached memory size when each allocation request ends
|
||||
* would be: x1 + alignment, x2 + alignment, x3 + alignment.
|
||||
*
|
||||
* When FLAGS_free_when_no_cache_hit is false, the cached
|
||||
* memory size when each allocation request ends would be:
|
||||
* x1 + alignment, x1 + x2 + 2 * alignment, x3 + alignment.
|
||||
*/
|
||||
std::vector<size_t> allocate_size = {base_memory_size,
|
||||
base_memory_size + alignment * 2,
|
||||
base_memory_size + alignment * 4};
|
||||
size_t memory_capacity =
|
||||
allocate_size[0] + allocate_size[1] + allocate_size[2] / 2;
|
||||
|
||||
auto underlying_allocator =
|
||||
std::make_shared<LimitedResourceAllocator>(memory_capacity);
|
||||
auto ag_allocator = std::make_shared<AutoGrowthBestFitAllocator>(
|
||||
underlying_allocator, alignment);
|
||||
|
||||
ag_allocator->Allocate(allocate_size[0]);
|
||||
ASSERT_EQ(underlying_allocator->AllocatedSize(),
|
||||
allocate_size[0] + alignment);
|
||||
|
||||
ag_allocator->Allocate(allocate_size[1]);
|
||||
if (free_when_no_cache_hit) {
|
||||
ASSERT_EQ(underlying_allocator->AllocatedSize(),
|
||||
allocate_size[1] + alignment);
|
||||
} else {
|
||||
ASSERT_EQ(underlying_allocator->AllocatedSize(),
|
||||
allocate_size[0] + allocate_size[1] + 2 * alignment);
|
||||
}
|
||||
|
||||
ag_allocator->Allocate(allocate_size[2]);
|
||||
ASSERT_EQ(underlying_allocator->AllocatedSize(),
|
||||
allocate_size[2] + alignment);
|
||||
}
|
||||
|
||||
TEST(test_auto_growth_allocator, test_free_idle_chunk) {
|
||||
for (auto free_idle_chunk : {false, true}) {
|
||||
for (auto free_when_no_cache_hit : {false, true}) {
|
||||
TestFreeIdleChunk(free_idle_chunk, free_when_no_cache_hit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(test_auto_growth_allocator, test_free_when_no_cache_hit) {
|
||||
TestFreeWhenNoCacheHit(false);
|
||||
TestFreeWhenNoCacheHit(true);
|
||||
}
|
||||
|
||||
} // namespace allocation
|
||||
} // namespace memory
|
||||
} // namespace paddle
|
Loading…
Reference in new issue