1 /* 2 * Copyright 2012, The Android Open Source Project 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * * Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * * Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #define LOG_TAG "LinearAllocator" 27 #define LOG_NDEBUG 1 28 29 #include <stdlib.h> 30 #include <utils/LinearAllocator.h> 31 #include <utils/Log.h> 32 33 34 // The ideal size of a page allocation (these need to be multiples of 8) 35 #define INITIAL_PAGE_SIZE ((size_t)4096) // 4kb 36 #define MAX_PAGE_SIZE ((size_t)131072) // 128kb 37 38 // The maximum amount of wasted space we can have per page 39 // Allocations exceeding this will have their own dedicated page 40 // If this is too low, we will malloc too much 41 // Too high, and we may waste too much space 42 // Must be smaller than INITIAL_PAGE_SIZE 43 #define MAX_WASTE_SIZE ((size_t)1024) 44 45 #if ALIGN_DOUBLE 46 #define ALIGN_SZ (sizeof(double)) 47 #else 48 #define ALIGN_SZ (sizeof(int)) 49 #endif 50 51 #define ALIGN(x) ((x + ALIGN_SZ - 1 ) & ~(ALIGN_SZ - 1)) 52 #define ALIGN_PTR(p) ((void*)(ALIGN((size_t)p))) 53 54 #if LOG_NDEBUG 55 #define ADD_ALLOCATION(size) 56 #define RM_ALLOCATION(size) 57 #else 58 #include <utils/Thread.h> 59 #include <utils/Timers.h> 60 static size_t s_totalAllocations = 0; 61 static nsecs_t s_nextLog = 0; 62 static android::Mutex s_mutex; 63 64 static void _logUsageLocked() { 65 nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); 66 if (now > s_nextLog) { 67 s_nextLog = now + milliseconds_to_nanoseconds(10); 68 ALOGV("Total memory usage: %zu kb", s_totalAllocations / 1024); 69 } 70 } 71 72 static void _addAllocation(size_t size) { 73 android::AutoMutex lock(s_mutex); 74 s_totalAllocations += size; 75 _logUsageLocked(); 76 } 77 78 #define ADD_ALLOCATION(size) _addAllocation(size); 79 #define RM_ALLOCATION(size) _addAllocation(-size); 80 #endif 81 82 #define min(x,y) (((x) < (y)) ? (x) : (y)) 83 84 namespace android { 85 86 class LinearAllocator::Page { 87 public: 88 Page* next() { return mNextPage; } 89 void setNext(Page* next) { mNextPage = next; } 90 91 Page() 92 : mNextPage(0) 93 {} 94 95 void* operator new(size_t size, void* buf) { return buf; } 96 97 void* start() { 98 return (void*) (((size_t)this) + sizeof(Page)); 99 } 100 101 void* end(int pageSize) { 102 return (void*) (((size_t)start()) + pageSize); 103 } 104 105 private: 106 Page(const Page& other) {} 107 Page* mNextPage; 108 }; 109 110 LinearAllocator::LinearAllocator() 111 : mPageSize(INITIAL_PAGE_SIZE) 112 , mMaxAllocSize(MAX_WASTE_SIZE) 113 , mNext(0) 114 , mCurrentPage(0) 115 , mPages(0) 116 , mTotalAllocated(0) 117 , mWastedSpace(0) 118 , mPageCount(0) 119 , mDedicatedPageCount(0) {} 120 121 LinearAllocator::~LinearAllocator(void) { 122 Page* p = mPages; 123 while (p) { 124 Page* next = p->next(); 125 p->~Page(); 126 free(p); 127 RM_ALLOCATION(mPageSize); 128 p = next; 129 } 130 } 131 132 void* LinearAllocator::start(Page* p) { 133 return ALIGN_PTR(((size_t*)p) + sizeof(Page)); 134 } 135 136 void* LinearAllocator::end(Page* p) { 137 return ((char*)p) + mPageSize; 138 } 139 140 bool LinearAllocator::fitsInCurrentPage(size_t size) { 141 return mNext && ((char*)mNext + size) <= end(mCurrentPage); 142 } 143 144 void LinearAllocator::ensureNext(size_t size) { 145 if (fitsInCurrentPage(size)) return; 146 147 if (mCurrentPage && mPageSize < MAX_PAGE_SIZE) { 148 mPageSize = min(MAX_PAGE_SIZE, mPageSize * 2); 149 mPageSize = ALIGN(mPageSize); 150 } 151 mWastedSpace += mPageSize; 152 Page* p = newPage(mPageSize); 153 if (mCurrentPage) { 154 mCurrentPage->setNext(p); 155 } 156 mCurrentPage = p; 157 if (!mPages) { 158 mPages = mCurrentPage; 159 } 160 mNext = start(mCurrentPage); 161 } 162 163 void* LinearAllocator::alloc(size_t size) { 164 size = ALIGN(size); 165 if (size > mMaxAllocSize && !fitsInCurrentPage(size)) { 166 ALOGV("Exceeded max size %zu > %zu", size, mMaxAllocSize); 167 // Allocation is too large, create a dedicated page for the allocation 168 Page* page = newPage(size); 169 mDedicatedPageCount++; 170 page->setNext(mPages); 171 mPages = page; 172 if (!mCurrentPage) 173 mCurrentPage = mPages; 174 return start(page); 175 } 176 ensureNext(size); 177 void* ptr = mNext; 178 mNext = ((char*)mNext) + size; 179 mWastedSpace -= size; 180 return ptr; 181 } 182 183 void LinearAllocator::rewindIfLastAlloc(void* ptr, size_t allocSize) { 184 // Don't bother rewinding across pages 185 allocSize = ALIGN(allocSize); 186 if (ptr >= start(mCurrentPage) && ptr < end(mCurrentPage) 187 && ptr == ((char*)mNext - allocSize)) { 188 mTotalAllocated -= allocSize; 189 mWastedSpace += allocSize; 190 mNext = ptr; 191 } 192 } 193 194 LinearAllocator::Page* LinearAllocator::newPage(size_t pageSize) { 195 pageSize = ALIGN(pageSize + sizeof(LinearAllocator::Page)); 196 ADD_ALLOCATION(pageSize); 197 mTotalAllocated += pageSize; 198 mPageCount++; 199 void* buf = malloc(pageSize); 200 return new (buf) Page(); 201 } 202 203 static const char* toSize(size_t value, float& result) { 204 if (value < 2000) { 205 result = value; 206 return "B"; 207 } 208 if (value < 2000000) { 209 result = value / 1024.0f; 210 return "KB"; 211 } 212 result = value / 1048576.0f; 213 return "MB"; 214 } 215 216 void LinearAllocator::dumpMemoryStats(const char* prefix) { 217 float prettySize; 218 const char* prettySuffix; 219 prettySuffix = toSize(mTotalAllocated, prettySize); 220 ALOGD("%sTotal allocated: %.2f%s", prefix, prettySize, prettySuffix); 221 prettySuffix = toSize(mWastedSpace, prettySize); 222 ALOGD("%sWasted space: %.2f%s (%.1f%%)", prefix, prettySize, prettySuffix, 223 (float) mWastedSpace / (float) mTotalAllocated * 100.0f); 224 ALOGD("%sPages %zu (dedicated %zu)", prefix, mPageCount, mDedicatedPageCount); 225 } 226 227 }; // namespace android 228