diff options
author | pliard@chromium.org <pliard@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-12-25 18:24:46 +0000 |
---|---|---|
committer | pliard@chromium.org <pliard@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-12-25 18:24:46 +0000 |
commit | 73786be789262f72114030ccba586d898184a1ba (patch) | |
tree | 0394c9d8d3eb09d49ede314b742120f7ee470f32 /base/memory | |
parent | ad65a3ee540552ecca50ebbf9382f1a4c718d383 (diff) | |
download | chromium_src-73786be789262f72114030ccba586d898184a1ba.zip chromium_src-73786be789262f72114030ccba586d898184a1ba.tar.gz chromium_src-73786be789262f72114030ccba586d898184a1ba.tar.bz2 |
Make size of ashmem regions based on device's physical memory.
Ashmem regions created by the ashmem allocator used to be fixed to 32 MBytes
which can be a little small for high-end devices.
This change makes the allocator create ashmem regions of those sizes:
- 64 MBytes for 512 MBytes devices
- 128 MBytes for 1 GByte devices
- 256 MBytes for 2 GBytes...
This also adds an error code path in case ashmem creation fails which may
happen if the address space is too fragmented. In this case the allocator
repetitively retries by dividing the ashmem region size by 2 until the ashmem
region reaches 32 MBytes (which is the minimum).
TBR=bulach@chromium.org
Review URL: https://codereview.chromium.org/119923002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@242497 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/memory')
-rw-r--r-- | base/memory/discardable_memory_allocator_android.cc | 34 | ||||
-rw-r--r-- | base/memory/discardable_memory_allocator_android.h | 12 | ||||
-rw-r--r-- | base/memory/discardable_memory_allocator_android_unittest.cc | 26 | ||||
-rw-r--r-- | base/memory/discardable_memory_android.cc | 17 |
4 files changed, 61 insertions, 28 deletions
diff --git a/base/memory/discardable_memory_allocator_android.cc b/base/memory/discardable_memory_allocator_android.cc index 5e10817..a0a3aff 100644 --- a/base/memory/discardable_memory_allocator_android.cc +++ b/base/memory/discardable_memory_allocator_android.cc @@ -44,6 +44,8 @@ namespace { // issues. const size_t kMaxChunkFragmentationBytes = 4096 - 1; +const size_t kMinAshmemRegionSize = 32 * 1024 * 1024; + } // namespace namespace internal { @@ -104,6 +106,7 @@ class DiscardableMemoryAllocator::AshmemRegion { size_t size, const std::string& name, DiscardableMemoryAllocator* allocator) { + DCHECK_EQ(size, internal::AlignToNextPage(size)); int fd; void* base; if (!internal::CreateAshmemRegion(name.c_str(), size, &fd, &base)) @@ -364,8 +367,12 @@ DiscardableMemoryAllocator::DiscardableAshmemChunk::~DiscardableAshmemChunk() { ashmem_region_->OnChunkDeletion(address_, size_); } -DiscardableMemoryAllocator::DiscardableMemoryAllocator(const std::string& name) - : name_(name) { +DiscardableMemoryAllocator::DiscardableMemoryAllocator( + const std::string& name, + size_t ashmem_region_size) + : name_(name), + ashmem_region_size_(std::max(kMinAshmemRegionSize, ashmem_region_size)) { + DCHECK_GE(ashmem_region_size_, kMinAshmemRegionSize); } DiscardableMemoryAllocator::~DiscardableMemoryAllocator() { @@ -389,16 +396,21 @@ scoped_ptr<DiscardableMemory> DiscardableMemoryAllocator::Allocate( if (memory) return memory.Pass(); } - scoped_ptr<AshmemRegion> new_region( - AshmemRegion::Create( - std::max(static_cast<size_t>(kMinAshmemRegionSize), aligned_size), - name_.c_str(), this)); - if (!new_region) { - // TODO(pliard): consider adding an histogram to see how often this happens. - return scoped_ptr<DiscardableMemory>(); + // The creation of the (large) ashmem region might fail if the address space + // is too fragmented. In case creation fails the allocator retries by + // repetitively dividing the size by 2. + const size_t min_region_size = std::max(kMinAshmemRegionSize, aligned_size); + for (size_t region_size = std::max(ashmem_region_size_, aligned_size); + region_size >= min_region_size; region_size /= 2) { + scoped_ptr<AshmemRegion> new_region( + AshmemRegion::Create(region_size, name_.c_str(), this)); + if (!new_region) + continue; + ashmem_regions_.push_back(new_region.release()); + return ashmem_regions_.back()->Allocate_Locked(size, aligned_size); } - ashmem_regions_.push_back(new_region.release()); - return ashmem_regions_.back()->Allocate_Locked(size, aligned_size); + // TODO(pliard): consider adding an histogram to see how often this happens. + return scoped_ptr<DiscardableMemory>(); } void DiscardableMemoryAllocator::DeleteAshmemRegion_Locked( diff --git a/base/memory/discardable_memory_allocator_android.h b/base/memory/discardable_memory_allocator_android.h index 7991656..7ced405 100644 --- a/base/memory/discardable_memory_allocator_android.h +++ b/base/memory/discardable_memory_allocator_android.h @@ -32,13 +32,12 @@ namespace internal { // discardable_memory.h for DiscardableMemory's threading guarantees. class BASE_EXPORT_PRIVATE DiscardableMemoryAllocator { public: - // Exposed for testing. - enum { - kMinAshmemRegionSize = 32 * 1024 * 1024, - }; - // Note that |name| is only used for debugging/measurement purposes. - explicit DiscardableMemoryAllocator(const std::string& name); + // |ashmem_region_size| is the size that will be used to create the underlying + // ashmem regions and is expected to be greater or equal than 32 MBytes. + DiscardableMemoryAllocator(const std::string& name, + size_t ashmem_region_size); + ~DiscardableMemoryAllocator(); // Note that the allocator must outlive the returned DiscardableMemory @@ -53,6 +52,7 @@ class BASE_EXPORT_PRIVATE DiscardableMemoryAllocator { base::ThreadChecker thread_checker_; const std::string name_; + const size_t ashmem_region_size_; base::Lock lock_; ScopedVector<AshmemRegion> ashmem_regions_; diff --git a/base/memory/discardable_memory_allocator_android_unittest.cc b/base/memory/discardable_memory_allocator_android_unittest.cc index 97cf5d4..ae95d5d 100644 --- a/base/memory/discardable_memory_allocator_android_unittest.cc +++ b/base/memory/discardable_memory_allocator_android_unittest.cc @@ -20,13 +20,14 @@ namespace internal { const char kAllocatorName[] = "allocator-for-testing"; +const size_t kAshmemRegionSizeForTesting = 32 * 1024 * 1024; const size_t kPageSize = 4096; -const size_t kMinAshmemRegionSize = - DiscardableMemoryAllocator::kMinAshmemRegionSize; class DiscardableMemoryAllocatorTest : public testing::Test { protected: - DiscardableMemoryAllocatorTest() : allocator_(kAllocatorName) {} + DiscardableMemoryAllocatorTest() + : allocator_(kAllocatorName, kAshmemRegionSizeForTesting) { + } DiscardableMemoryAllocator allocator_; }; @@ -45,6 +46,19 @@ TEST_F(DiscardableMemoryAllocatorTest, Basic) { WriteToDiscardableMemory(memory.get(), size); } +TEST_F(DiscardableMemoryAllocatorTest, + AshmemRegionsAreNotSmallerThanRequestedSize) { + const size_t size = std::numeric_limits<size_t>::max() - kPageSize + 1; + // The creation of the underlying ashmem region is expected to fail since + // there should not be enough room in the address space. When ashmem creation + // fails, the allocator repetitively retries by dividing the size by 2. This + // size should not be smaller than the size the user requested so the + // allocation here should just fail (and not succeed with the minimum ashmem + // region size). + scoped_ptr<DiscardableMemory> memory(allocator_.Allocate(size)); + ASSERT_FALSE(memory); +} + TEST_F(DiscardableMemoryAllocatorTest, LargeAllocation) { // Note that large allocations should just use DiscardableMemoryAndroidSimple // instead. @@ -211,15 +225,15 @@ TEST_F(DiscardableMemoryAllocatorTest, TEST_F(DiscardableMemoryAllocatorTest, UseMultipleAshmemRegions) { // Leave one page untouched at the end of the ashmem region. - const size_t size = kMinAshmemRegionSize - kPageSize; + const size_t size = kAshmemRegionSizeForTesting - kPageSize; scoped_ptr<DiscardableMemory> memory1(allocator_.Allocate(size)); ASSERT_TRUE(memory1); WriteToDiscardableMemory(memory1.get(), size); scoped_ptr<DiscardableMemory> memory2( - allocator_.Allocate(kMinAshmemRegionSize)); + allocator_.Allocate(kAshmemRegionSizeForTesting)); ASSERT_TRUE(memory2); - WriteToDiscardableMemory(memory2.get(), kMinAshmemRegionSize); + WriteToDiscardableMemory(memory2.get(), kAshmemRegionSizeForTesting); // The last page of the first ashmem region should be used for this // allocation. scoped_ptr<DiscardableMemory> memory3(allocator_.Allocate(kPageSize)); diff --git a/base/memory/discardable_memory_android.cc b/base/memory/discardable_memory_android.cc index 7e84967..519aa8d 100644 --- a/base/memory/discardable_memory_android.cc +++ b/base/memory/discardable_memory_android.cc @@ -11,6 +11,7 @@ #include <limits> +#include "base/android/sys_utils.h" #include "base/basictypes.h" #include "base/compiler_specific.h" #include "base/file_util.h" @@ -31,7 +32,8 @@ const char kAshmemAllocatorName[] = "DiscardableMemoryAllocator"; struct GlobalContext { GlobalContext() : ashmem_fd_limit(GetSoftFDLimit()), - allocator(kAshmemAllocatorName), + allocator(kAshmemAllocatorName, + GetOptimalAshmemRegionSizeForAllocator()), ashmem_fd_count_(0) { } @@ -63,6 +65,14 @@ struct GlobalContext { return limit_info.rlim_cur / 4; } + // Returns 64 MBytes for a 512 MBytes device, 128 MBytes for 1024 MBytes... + static size_t GetOptimalAshmemRegionSizeForAllocator() { + // Note that this may do some I/O (without hitting the disk though) so it + // should not be called on the critical path. + return internal::AlignToNextPage( + base::android::SysUtils::AmountOfPhysicalMemoryKB() * 1024 / 8); + } + int ashmem_fd_count_; }; @@ -231,11 +241,8 @@ scoped_ptr<DiscardableMemory> DiscardableMemory::CreateLockedMemory( // rather than DiscardableMemoryAndroidSimple). Moreover keeping the lock // acquired for the whole allocation would cause a deadlock when the allocator // tries to create an ashmem region. - const size_t kAllocatorRegionSize = - internal::DiscardableMemoryAllocator::kMinAshmemRegionSize; GlobalContext* const global_context = g_context.Pointer(); - if (aligned_size >= kAllocatorRegionSize || - GetCurrentNumberOfAshmemFDs() < 0.9 * global_context->ashmem_fd_limit) { + if (GetCurrentNumberOfAshmemFDs() < 0.9 * global_context->ashmem_fd_limit) { int fd; void* address; if (internal::CreateAshmemRegion("", aligned_size, &fd, &address)) { |