diff options
-rw-r--r-- | bench/MemoryBench.cpp | 105 | ||||
-rw-r--r-- | gyp/tests.gyp | 1 | ||||
-rw-r--r-- | include/core/SkTypes.h | 10 | ||||
-rw-r--r-- | src/core/SkMemory_stdlib.cpp | 267 | ||||
-rw-r--r-- | src/ports/SkMemory_malloc.cpp | 34 | ||||
-rw-r--r-- | src/ports/SkMemory_mozalloc.cpp | 8 | ||||
-rw-r--r-- | tests/MemoryTest.cpp | 12 |
7 files changed, 156 insertions, 281 deletions
diff --git a/bench/MemoryBench.cpp b/bench/MemoryBench.cpp index 6e8e4a8588..418e149f80 100644 --- a/bench/MemoryBench.cpp +++ b/bench/MemoryBench.cpp @@ -52,3 +52,108 @@ private: DEF_BENCH( return new ChunkAllocBench(64); ) DEF_BENCH( return new ChunkAllocBench(8*1024); ) + +static int* calloc(size_t num) { + return (int*)sk_calloc_throw(num*sizeof(int)); +} + +static int* malloc_bzero(size_t num) { + const size_t bytes = num*sizeof(int); + int* ints = (int*)sk_malloc_throw(bytes); + sk_bzero(ints, bytes); + return ints; +} + +class ZerosBench : public SkBenchmark { + size_t fNum; + bool fRead; + bool fWrite; + bool fUseCalloc; + SkString fName; +public: + ZerosBench(size_t num, bool read, bool write, bool useCalloc) + : fNum(num) + , fRead(read) + , fWrite(write) + , fUseCalloc(useCalloc) { + fName.printf("memory_%s", useCalloc ? "calloc" : "malloc_bzero"); + if (read && write) { + fName.appendf("_rw"); + } else if (read) { + fName.appendf("_r"); + } else if (write) { + fName.appendf("_w"); + } + fName.appendf("_"SK_SIZE_T_SPECIFIER, num); + fIsRendering = false; + } + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return fName.c_str(); + } + + virtual void onDraw(SkCanvas*) SK_OVERRIDE { + for (int i = 0; i < this->getLoops(); i++) { + int* zeros = fUseCalloc ? calloc(fNum) : malloc_bzero(fNum); + if (fRead) { + volatile int x = 15; + for (size_t j = 0; j < fNum; j++) { + x ^= zeros[j]; + } + } + if (fWrite) { + for (size_t j = 0; j < fNum; j++) { + zeros[j] = 15; + } + } + sk_free(zeros); + } + } +}; + +// zero count r w useCalloc? +DEF_BENCH(return new ZerosBench(1024*1024, 0, 0, 0)) +DEF_BENCH(return new ZerosBench(1024*1024, 0, 0, 1)) +DEF_BENCH(return new ZerosBench(1024*1024, 0, 1, 0)) +DEF_BENCH(return new ZerosBench(1024*1024, 0, 1, 1)) +DEF_BENCH(return new ZerosBench(1024*1024, 1, 0, 0)) +DEF_BENCH(return new ZerosBench(1024*1024, 1, 0, 1)) +DEF_BENCH(return new ZerosBench(1024*1024, 1, 1, 0)) +DEF_BENCH(return new ZerosBench(1024*1024, 1, 1, 1)) + +DEF_BENCH(return new ZerosBench(256*1024, 0, 0, 0)) +DEF_BENCH(return new ZerosBench(256*1024, 0, 0, 1)) +DEF_BENCH(return new ZerosBench(256*1024, 0, 1, 0)) +DEF_BENCH(return new ZerosBench(256*1024, 0, 1, 1)) +DEF_BENCH(return new ZerosBench(256*1024, 1, 0, 0)) +DEF_BENCH(return new ZerosBench(256*1024, 1, 0, 1)) +DEF_BENCH(return new ZerosBench(256*1024, 1, 1, 0)) +DEF_BENCH(return new ZerosBench(256*1024, 1, 1, 1)) + +DEF_BENCH(return new ZerosBench(4*1024, 0, 0, 0)) +DEF_BENCH(return new ZerosBench(4*1024, 0, 0, 1)) +DEF_BENCH(return new ZerosBench(4*1024, 0, 1, 0)) +DEF_BENCH(return new ZerosBench(4*1024, 0, 1, 1)) +DEF_BENCH(return new ZerosBench(4*1024, 1, 0, 0)) +DEF_BENCH(return new ZerosBench(4*1024, 1, 0, 1)) +DEF_BENCH(return new ZerosBench(4*1024, 1, 1, 0)) +DEF_BENCH(return new ZerosBench(4*1024, 1, 1, 1)) + +DEF_BENCH(return new ZerosBench(300, 0, 0, 0)) +DEF_BENCH(return new ZerosBench(300, 0, 0, 1)) +DEF_BENCH(return new ZerosBench(300, 0, 1, 0)) +DEF_BENCH(return new ZerosBench(300, 0, 1, 1)) +DEF_BENCH(return new ZerosBench(300, 1, 0, 0)) +DEF_BENCH(return new ZerosBench(300, 1, 0, 1)) +DEF_BENCH(return new ZerosBench(300, 1, 1, 0)) +DEF_BENCH(return new ZerosBench(300, 1, 1, 1)) + +DEF_BENCH(return new ZerosBench(4, 0, 0, 0)) +DEF_BENCH(return new ZerosBench(4, 0, 0, 1)) +DEF_BENCH(return new ZerosBench(4, 0, 1, 0)) +DEF_BENCH(return new ZerosBench(4, 0, 1, 1)) +DEF_BENCH(return new ZerosBench(4, 1, 0, 0)) +DEF_BENCH(return new ZerosBench(4, 1, 0, 1)) +DEF_BENCH(return new ZerosBench(4, 1, 1, 0)) +DEF_BENCH(return new ZerosBench(4, 1, 1, 1)) diff --git a/gyp/tests.gyp b/gyp/tests.gyp index 43acd94818..c67e578727 100644 --- a/gyp/tests.gyp +++ b/gyp/tests.gyp @@ -81,6 +81,7 @@ '../tests/MathTest.cpp', '../tests/MatrixTest.cpp', '../tests/Matrix44Test.cpp', + '../tests/MemoryTest.cpp', '../tests/MemsetTest.cpp', '../tests/MetaDataTest.cpp', '../tests/MipMapTest.cpp', diff --git a/include/core/SkTypes.h b/include/core/SkTypes.h index 039369119e..f2245184e6 100644 --- a/include/core/SkTypes.h +++ b/include/core/SkTypes.h @@ -49,7 +49,7 @@ enum { }; /** Return a block of memory (at least 4-byte aligned) of at least the specified size. If the requested memory cannot be returned, either - return null (if SK_MALLOC_TEMP bit is clear) or call sk_throw() + return null (if SK_MALLOC_TEMP bit is clear) or throw an exception (if SK_MALLOC_TEMP bit is set). To free the memory, call sk_free(). */ SK_API extern void* sk_malloc_flags(size_t size, unsigned flags); @@ -64,6 +64,14 @@ SK_API extern void* sk_realloc_throw(void* buffer, size_t size); */ SK_API extern void sk_free(void*); +/** Much like calloc: returns a pointer to at least size zero bytes, or NULL on failure. + */ +SK_API extern void* sk_calloc(size_t size); + +/** Same as sk_calloc, but throws an exception instead of returning NULL on failure. + */ +SK_API extern void* sk_calloc_throw(size_t size); + // bzero is safer than memset, but we can't rely on it, so... sk_bzero() static inline void sk_bzero(void* buffer, size_t size) { memset(buffer, 0, size); diff --git a/src/core/SkMemory_stdlib.cpp b/src/core/SkMemory_stdlib.cpp deleted file mode 100644 index fa13e9cb7b..0000000000 --- a/src/core/SkMemory_stdlib.cpp +++ /dev/null @@ -1,267 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkTypes.h" -#include <stdio.h> -#include <stdlib.h> - -#ifdef SK_DEBUG - #define SK_TAG_BLOCKS - // #define SK_TRACK_ALLOC // enable to see a printf for every alloc/free - // #define SK_CHECK_TAGS // enable to double-check debugging link list -#endif - -#ifdef SK_TAG_BLOCKS - -#include "SkThread.h" - -// size this (as a multiple of 4) so that the total offset to the internal data -// is at least a multiple of 8 (since some clients of our malloc may require -// that. -static const char kBlockHeaderTag[] = { 's', 'k', 'i', 'a', '1', '2', '3', '4' }; -static const char kBlockTrailerTag[] = { 'a', 'i', 'k', 's' }; -#define kByteFill 0xCD -#define kDeleteFill 0xEF - -static SkBaseMutex& get_block_mutex() { - static SkMutex* gBlockMutex; - if (NULL == gBlockMutex) { - gBlockMutex = new SkMutex; - } - return *gBlockMutex; -} - -static struct SkBlockHeader* gHeader; - -struct SkBlockHeader { - SkBlockHeader* fNext; -#ifdef SK_CHECK_TAGS - SkBlockHeader** fTop; // set to verify in debugger that block was alloc'd / freed with same gHeader - SkBlockHeader* fPrevious; // set to see in debugger previous block when corruption happens -#endif - size_t fSize; - char fHeader[sizeof(kBlockHeaderTag)]; - // data goes here. The offset to this point must be a multiple of 8 - char fTrailer[sizeof(kBlockTrailerTag)]; - - void* add(size_t realSize) - { - SkAutoMutexAcquire ac(get_block_mutex()); - InMutexValidate(); - fNext = gHeader; -#ifdef SK_CHECK_TAGS - fTop = &gHeader; - fPrevious = NULL; - if (fNext != NULL) - fNext->fPrevious = this; -#endif - gHeader = this; - fSize = realSize; - memcpy(fHeader, kBlockHeaderTag, sizeof(kBlockHeaderTag)); - void* result = fTrailer; - void* trailer = (char*)result + realSize; - memcpy(trailer, kBlockTrailerTag, sizeof(kBlockTrailerTag)); - return result; - } - - static void Dump() - { - SkAutoMutexAcquire ac(get_block_mutex()); - InMutexValidate(); - SkBlockHeader* header = gHeader; - int count = 0; - size_t size = 0; - while (header != NULL) { - char scratch[256]; - char* pos = scratch; - size_t size = header->fSize; - int* data = (int*)(void*)header->fTrailer; - pos += sprintf(pos, "%p 0x%08zx (%7zd) ", - data, size, size); - size >>= 2; - size_t ints = size > 4 ? 4 : size; - size_t index; - for (index = 0; index < ints; index++) - pos += sprintf(pos, "0x%08x ", data[index]); - pos += sprintf(pos, " ("); - for (index = 0; index < ints; index++) - pos += sprintf(pos, "%g ", data[index] / 65536.0f); - if (ints > 0) - --pos; - pos += sprintf(pos, ") \""); - size_t chars = size > 16 ? 16 : size; - char* chPtr = (char*) data; - for (index = 0; index < chars; index++) { - char ch = chPtr[index]; - pos += sprintf(pos, "%c", ch >= ' ' && ch < 0x7f ? ch : '?'); - } - pos += sprintf(pos, "\""); - SkDebugf("%s\n", scratch); - count++; - size += header->fSize; - header = header->fNext; - } - SkDebugf("--- count %d size 0x%08x (%zd) ---\n", count, size, size); - } - - void remove() const - { - SkAutoMutexAcquire ac(get_block_mutex()); - SkBlockHeader** findPtr = &gHeader; - do { - SkBlockHeader* find = *findPtr; - SkASSERT(find != NULL); - if (find == this) { - *findPtr = fNext; - break; - } - findPtr = &find->fNext; - } while (true); - InMutexValidate(); - SkASSERT(memcmp(fHeader, kBlockHeaderTag, sizeof(kBlockHeaderTag)) == 0); - const char* trailer = fTrailer + fSize; - SkASSERT(memcmp(trailer, kBlockTrailerTag, sizeof(kBlockTrailerTag)) == 0); - } - - static void Validate() - { - SkAutoMutexAcquire ac(get_block_mutex()); - InMutexValidate(); - } - -private: - static void InMutexValidate() - { - SkBlockHeader* header = gHeader; - while (header != NULL) { - SkASSERT(memcmp(header->fHeader, kBlockHeaderTag, sizeof(kBlockHeaderTag)) == 0); - char* trailer = header->fTrailer + header->fSize; - SkASSERT(memcmp(trailer, kBlockTrailerTag, sizeof(kBlockTrailerTag)) == 0); - header = header->fNext; - } - } -}; - -void ValidateHeap(); -void ValidateHeap() -{ - SkBlockHeader::Validate(); -} -#else -void ValidateHeap() {} -#endif - -void sk_throw() -{ - SkDEBUGFAIL("sk_throw"); - abort(); -} - -void sk_out_of_memory(void) -{ - SkDEBUGFAIL("sk_out_of_memory"); - abort(); -} - -void* sk_malloc_throw(size_t size) -{ - return sk_malloc_flags(size, SK_MALLOC_THROW); -} - -void* sk_realloc_throw(void* addr, size_t size) -{ -#ifdef SK_TAG_BLOCKS - ValidateHeap(); - if (addr != NULL) { - SkBlockHeader* header = (SkBlockHeader*) - ((char*)addr - SK_OFFSETOF(SkBlockHeader, fTrailer)); - header->remove(); -#ifdef SK_TRACK_ALLOC - printf("sk_realloc_throw %p oldSize=%zd\n", addr, header->fSize); -#endif - addr = header; - } - size_t realSize = size; - if (size) - size += sizeof(SkBlockHeader); -#endif - - void* p = realloc(addr, size); - if (size == 0) - { - ValidateHeap(); - return p; - } - - if (p == NULL) - sk_throw(); -#ifdef SK_TAG_BLOCKS - else - { - SkBlockHeader* header = (SkBlockHeader*) p; - p = header->add(realSize); -#ifdef SK_TRACK_ALLOC - printf("sk_realloc_throw %p size=%zd\n", p, realSize); -#endif - } -#endif - ValidateHeap(); - return p; -} - -void sk_free(void* p) -{ - if (p) - { - ValidateHeap(); -#ifdef SK_TAG_BLOCKS - SkBlockHeader* header = (SkBlockHeader*) - ((char*)p - SK_OFFSETOF(SkBlockHeader, fTrailer)); - header->remove(); -#ifdef SK_TRACK_ALLOC - printf("sk_free %p size=%zd\n", p, header->fSize); -#endif - size_t size = header->fSize + sizeof(SkBlockHeader); - memset(header, kDeleteFill, size); - p = header; -#endif - ValidateHeap(); - free(p); - ValidateHeap(); - } -} - -void* sk_malloc_flags(size_t size, unsigned flags) -{ - ValidateHeap(); -#ifdef SK_TAG_BLOCKS - size_t realSize = size; - size += sizeof(SkBlockHeader); -#endif - - void* p = malloc(size); - if (p == NULL) - { - if (flags & SK_MALLOC_THROW) - sk_throw(); - } -#ifdef SK_TAG_BLOCKS - else - { - SkBlockHeader* header = (SkBlockHeader*) p; - p = header->add(realSize); - memset(p, kByteFill, realSize); -#ifdef SK_TRACK_ALLOC - printf("sk_malloc_flags %p size=%zd\n", p, realSize); -#endif - } -#endif - ValidateHeap(); - return p; -} diff --git a/src/ports/SkMemory_malloc.cpp b/src/ports/SkMemory_malloc.cpp index 73b56079a6..6db65a8524 100644 --- a/src/ports/SkMemory_malloc.cpp +++ b/src/ports/SkMemory_malloc.cpp @@ -9,6 +9,14 @@ #include <stdio.h> #include <stdlib.h> +static inline void* throwOnFailure(size_t size, void* p) { + if (size > 0 && p == NULL) { + // If we've got a NULL here, the only reason we should have failed is running out of RAM. + sk_out_of_memory(); + } + return p; +} + void sk_throw() { SkDEBUGFAIL("sk_throw"); abort(); @@ -24,14 +32,7 @@ void* sk_malloc_throw(size_t size) { } void* sk_realloc_throw(void* addr, size_t size) { - void* p = realloc(addr, size); - if (size == 0) { - return p; - } - if (p == NULL) { - sk_throw(); - } - return p; + return throwOnFailure(size, realloc(addr, size)); } void sk_free(void* p) { @@ -42,10 +43,17 @@ void sk_free(void* p) { void* sk_malloc_flags(size_t size, unsigned flags) { void* p = malloc(size); - if (p == NULL) { - if (flags & SK_MALLOC_THROW) { - sk_throw(); - } + if (flags & SK_MALLOC_THROW) { + return throwOnFailure(size, p); + } else { + return p; } - return p; +} + +void* sk_calloc(size_t size) { + return calloc(size, 1); +} + +void* sk_calloc_throw(size_t size) { + return throwOnFailure(size, sk_calloc(size)); } diff --git a/src/ports/SkMemory_mozalloc.cpp b/src/ports/SkMemory_mozalloc.cpp index 2c049b2a03..4ca9312671 100644 --- a/src/ports/SkMemory_mozalloc.cpp +++ b/src/ports/SkMemory_mozalloc.cpp @@ -37,3 +37,11 @@ void sk_free(void* p) { void* sk_malloc_flags(size_t size, unsigned flags) { return (flags & SK_MALLOC_THROW) ? moz_xmalloc(size) : moz_malloc(size); } + +void* sk_calloc(size_t size) { + return moz_calloc(size, 1); +} + +void* sk_calloc_throw(size_t size) { + return moz_xcalloc(size, 1); +} diff --git a/tests/MemoryTest.cpp b/tests/MemoryTest.cpp new file mode 100644 index 0000000000..4c3216b83b --- /dev/null +++ b/tests/MemoryTest.cpp @@ -0,0 +1,12 @@ +#include "Test.h" +#include "TestClassDef.h" + +DEF_TEST(memory_calloc, reporter) { + const size_t kNum = 200; + char* zeros = (char*)sk_calloc_throw(kNum*sizeof(char)); + + for (size_t i = 0; i < kNum; i++) { + REPORTER_ASSERT(reporter, 0 == zeros[i]); + } + sk_free(zeros); +} |