--- /dev/null
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkBenchmark.h"
+#include "SkCanvas.h"
+#include "SkPaint.h"
+#include "SkRandom.h"
+#include "SkChunkAlloc.h"
+#include "SkString.h"
+
+class ChunkAllocBench : public SkBenchmark {
+ SkString fName;
+ size_t fMinSize;
+
+ enum {
+ N = SkBENCHLOOP(1000)
+ };
+public:
+ ChunkAllocBench(void* param, size_t minSize) : INHERITED(param) {
+ fMinSize = minSize;
+ fName.printf("chunkalloc_%d", minSize);
+ }
+
+protected:
+ virtual const char* onGetName() SK_OVERRIDE {
+ return fName.c_str();
+ }
+
+ virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
+ size_t inc = fMinSize >> 4;
+ SkASSERT(inc > 0);
+ size_t total = fMinSize * 64;
+
+ SkChunkAlloc alloc(fMinSize);
+
+ for (int i = 0; i < N; ++i) {
+ size_t size = 0;
+ int calls = 0;
+ while (size < total) {
+ alloc.allocThrow(inc);
+ size += inc;
+ calls += 1;
+ }
+ alloc.reset();
+ }
+ }
+
+private:
+ typedef SkBenchmark INHERITED;
+};
+
+static SkBenchmark* F0(void* p) { return new ChunkAllocBench(p, 64); }
+static SkBenchmark* F1(void* p) { return new ChunkAllocBench(p, 8*1024); }
+
+static BenchRegistry gR0(F0);
+static BenchRegistry gR1(F1);
+
'../bench/InterpBench.cpp',
'../bench/MathBench.cpp',
'../bench/MatrixBench.cpp',
+ '../bench/MemoryBench.cpp',
'../bench/MutexBench.cpp',
'../bench/PathBench.cpp',
'../bench/PathIterBench.cpp',
SkChunkAlloc(size_t minSize);
~SkChunkAlloc();
- /** Free up all allocated blocks. This invalidates all returned
- pointers.
- */
+ /**
+ * Free up all allocated blocks. This invalidates all returned
+ * pointers.
+ */
void reset();
- /** Reuse all allocated blocks. This invalidates all returned
- pointers (like reset) but doesn't necessarily free up all
- of the privately allocated blocks. This is more efficient
- if you plan to reuse the allocator multiple times.
- */
- void reuse();
-
enum AllocFailType {
kReturnNil_AllocFailType,
kThrow_AllocFailType
size_t unalloc(void* ptr);
size_t totalCapacity() const { return fTotalCapacity; }
+ int blockCount() const { return fBlockCount; }
/**
* Returns true if the specified address is within one of the chunks, and
private:
struct Block;
+
Block* fBlock;
size_t fMinSize;
- Block* fPool;
+ size_t fChunkSize;
size_t fTotalCapacity;
+ int fBlockCount;
Block* newBlock(size_t bytes, AllocFailType ftype);
};
-
/*
* Copyright 2006 The Android Open Source Project
*
* found in the LICENSE file.
*/
-
#include "SkChunkAlloc.h"
+// Don't malloc any chunks smaller than this
+#define MIN_CHUNKALLOC_BLOCK_SIZE 1024
+
+// Return the new min blocksize given the current value
+static size_t increase_next_size(size_t size) {
+ return size + (size >> 1);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
struct SkChunkAlloc::Block {
Block* fNext;
size_t fFreeSize;
return reinterpret_cast<char*>(this + 1);
}
- void freeChain() { // this can be null
- Block* block = this;
+ static void FreeChain(Block* block) {
while (block) {
Block* next = block->fNext;
sk_free(block);
}
};
- Block* tail() {
- Block* block = this;
- if (block) {
- for (;;) {
- Block* next = block->fNext;
- if (NULL == next) {
- break;
- }
- block = next;
- }
- }
- return block;
- }
-
bool contains(const void* addr) const {
const char* ptr = reinterpret_cast<const char*>(addr);
return ptr >= (const char*)(this + 1) && ptr < fFreePtr;
}
};
-SkChunkAlloc::SkChunkAlloc(size_t minSize)
- : fBlock(NULL), fMinSize(SkAlign4(minSize)), fPool(NULL), fTotalCapacity(0)
-{
+///////////////////////////////////////////////////////////////////////////////
+
+SkChunkAlloc::SkChunkAlloc(size_t minSize) {
+ if (minSize < MIN_CHUNKALLOC_BLOCK_SIZE) {
+ minSize = MIN_CHUNKALLOC_BLOCK_SIZE;
+ }
+
+ fBlock = NULL;
+ fMinSize = minSize;
+ fChunkSize = fMinSize;
+ fTotalCapacity = 0;
+ fBlockCount = 0;
}
SkChunkAlloc::~SkChunkAlloc() {
}
void SkChunkAlloc::reset() {
- fBlock->freeChain();
- fBlock = NULL;
- fPool->freeChain();
- fPool = NULL;
- fTotalCapacity = 0;
-}
-
-void SkChunkAlloc::reuse() {
- if (fPool && fBlock) {
- fPool->tail()->fNext = fBlock;
- }
- fPool = fBlock;
+ Block::FreeChain(fBlock);
fBlock = NULL;
+ fChunkSize = fMinSize; // reset to our initial minSize
fTotalCapacity = 0;
+ fBlockCount = 0;
}
SkChunkAlloc::Block* SkChunkAlloc::newBlock(size_t bytes, AllocFailType ftype) {
- Block* block = fPool;
-
- if (block && bytes <= block->fFreeSize) {
- fPool = block->fNext;
- return block;
- }
-
size_t size = bytes;
- if (size < fMinSize)
- size = fMinSize;
+ if (size < fChunkSize) {
+ size = fChunkSize;
+ }
- block = (Block*)sk_malloc_flags(sizeof(Block) + size,
+ Block* block = (Block*)sk_malloc_flags(sizeof(Block) + size,
ftype == kThrow_AllocFailType ? SK_MALLOC_THROW : 0);
if (block) {
block->fFreePtr = block->startOfData();
fTotalCapacity += size;
+ fBlockCount += 1;
+
+ fChunkSize = increase_next_size(fChunkSize);
}
return block;
}
}
SkASSERT(block && bytes <= block->fFreeSize);
- void* ptr = block->fFreePtr;
+ char* ptr = block->fFreePtr;
block->fFreeSize -= bytes;
- block->fFreePtr += bytes;
+ block->fFreePtr = ptr + bytes;
return ptr;
}
-
/*
* Copyright 2011 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
+
#include "Test.h"
+#include "SkChunkAlloc.h"
#include "SkUtils.h"
+static void test_chunkalloc(skiatest::Reporter* reporter) {
+ size_t min = 256;
+ SkChunkAlloc alloc(min);
+
+ REPORTER_ASSERT(reporter, 0 == alloc.totalCapacity());
+ REPORTER_ASSERT(reporter, 0 == alloc.blockCount());
+ REPORTER_ASSERT(reporter, !alloc.contains(NULL));
+ REPORTER_ASSERT(reporter, !alloc.contains(reporter));
+
+ alloc.reset();
+ REPORTER_ASSERT(reporter, 0 == alloc.totalCapacity());
+ REPORTER_ASSERT(reporter, 0 == alloc.blockCount());
+
+ size_t size = min >> 1;
+ void* ptr = alloc.allocThrow(size);
+ REPORTER_ASSERT(reporter, alloc.totalCapacity() >= size);
+ REPORTER_ASSERT(reporter, alloc.blockCount() > 0);
+ REPORTER_ASSERT(reporter, alloc.contains(ptr));
+
+ alloc.reset();
+ REPORTER_ASSERT(reporter, !alloc.contains(ptr));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
static void set_zero(void* dst, size_t bytes) {
char* ptr = (char*)dst;
for (size_t i = 0; i < bytes; ++i) {
static void TestMemset(skiatest::Reporter* reporter) {
test_16(reporter);
test_32(reporter);
+
+ test_chunkalloc(reporter);
};
#include "TestClassDef.h"