1 /*M///////////////////////////////////////////////////////////////////////////////////////
3 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
5 // By downloading, copying, installing or using the software you agree to this license.
6 // If you do not agree to this license, do not download, install,
7 // copy or use the software.
11 // For Open Source Computer Vision Library
13 // Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
14 // Copyright (C) 2009, Willow Garage Inc., all rights reserved.
15 // Third party copyrights are property of their respective owners.
17 // Redistribution and use in source and binary forms, with or without modification,
18 // are permitted provided that the following conditions are met:
20 // * Redistribution's of source code must retain the above copyright notice,
21 // this list of conditions and the following disclaimer.
23 // * Redistribution's in binary form must reproduce the above copyright notice,
24 // this list of conditions and the following disclaimer in the documentation
25 // and/or other materials provided with the distribution.
27 // * The name of the copyright holders may not be used to endorse or promote products
28 // derived from this software without specific prior written permission.
30 // This software is provided by the copyright holders and contributors "as is" and
31 // any express or implied warranties, including, but not limited to, the implied
32 // warranties of merchantability and fitness for a particular purpose are disclaimed.
33 // In no event shall the Intel Corporation or contributors be liable for any direct,
34 // indirect, incidental, special, exemplary, or consequential damages
35 // (including, but not limited to, procurement of substitute goods or services;
36 // loss of use, data, or profits; or business interruption) however caused
37 // and on any theory of liability, whether in contract, strict liability,
38 // or tort (including negligence or otherwise) arising in any way out of
39 // the use of this software, even if advised of the possibility of such damage.
45 #define CV_USE_SYSTEM_MALLOC 1
50 static void* OutOfMemoryError(size_t size)
52 CV_Error_(CV_StsNoMem, ("Failed to allocate %lu bytes", (unsigned long)size));
56 #if CV_USE_SYSTEM_MALLOC
58 void deleteThreadAllocData() {}
60 void* fastMalloc( size_t size )
62 uchar* udata = (uchar*)malloc(size + sizeof(void*) + CV_MALLOC_ALIGN);
64 return OutOfMemoryError(size);
65 uchar** adata = alignPtr((uchar**)udata + 1, CV_MALLOC_ALIGN);
70 void fastFree(void* ptr)
74 uchar* udata = ((uchar**)ptr)[-1];
75 CV_DbgAssert(udata < (uchar*)ptr &&
76 ((uchar*)ptr - udata) <= (ptrdiff_t)(sizeof(void*)+CV_MALLOC_ALIGN));
84 #define SANITY_CHECK(block) \
85 CV_Assert(((size_t)(block) & (MEM_BLOCK_SIZE-1)) == 0 && \
86 (unsigned)(block)->binIdx <= (unsigned)MAX_BIN && \
87 (block)->signature == MEM_BLOCK_SIGNATURE)
89 #define SANITY_CHECK(block)
95 struct CriticalSection
97 CriticalSection() { InitializeCriticalSection(&cs); }
98 ~CriticalSection() { DeleteCriticalSection(&cs); }
99 void lock() { EnterCriticalSection(&cs); }
100 void unlock() { LeaveCriticalSection(&cs); }
101 bool trylock() { return TryEnterCriticalSection(&cs) != 0; }
106 void* SystemAlloc(size_t size)
108 void* ptr = malloc(size);
109 return ptr ? ptr : OutOfMemoryError(size);
112 void SystemFree(void* ptr, size_t)
117 struct CriticalSection
119 CriticalSection() { pthread_mutex_init(&mutex, 0); }
120 ~CriticalSection() { pthread_mutex_destroy(&mutex); }
121 void lock() { pthread_mutex_lock(&mutex); }
122 void unlock() { pthread_mutex_unlock(&mutex); }
123 bool trylock() { return pthread_mutex_trylock(&mutex) == 0; }
125 pthread_mutex_t mutex;
128 void* SystemAlloc(size_t size)
130 #ifndef MAP_ANONYMOUS
131 #define MAP_ANONYMOUS MAP_ANON
134 ptr = mmap(ptr, size, (PROT_READ | PROT_WRITE), MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
135 return ptr != MAP_FAILED ? ptr : OutOfMemoryError(size);
138 void SystemFree(void* ptr, size_t size)
146 AutoLock(CriticalSection& _cs) : cs(&_cs) { cs->lock(); }
147 ~AutoLock() { cs->unlock(); }
151 const size_t MEM_BLOCK_SIGNATURE = 0x01234567;
152 const int MEM_BLOCK_SHIFT = 14;
153 const size_t MEM_BLOCK_SIZE = 1 << MEM_BLOCK_SHIFT;
154 const size_t HDR_SIZE = 128;
155 const size_t MAX_BLOCK_SIZE = MEM_BLOCK_SIZE - HDR_SIZE;
156 const int MAX_BIN = 28;
158 static const int binSizeTab[MAX_BIN+1] =
159 { 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 128, 160, 192, 256, 320, 384, 480, 544, 672, 768,
160 896, 1056, 1328, 1600, 2688, 4048, 5408, 8128, 16256 };
167 for( i = 0; i <= MAX_BIN; i++ )
169 n = binSizeTab[i]>>3;
171 binIdx[j] = (uchar)i;
176 assert( size <= MAX_BLOCK_SIZE );
177 return binIdx[(size + 7)>>3];
185 uchar binIdx[MAX_BLOCK_SIZE/8+1];
188 MallocTables mallocTables;
201 signature = MEM_BLOCK_SIGNATURE;
204 privateFreeList = publicFreeList = 0;
205 bumpPtr = endPtr = 0;
208 data = (uchar*)this + HDR_SIZE;
213 void init(Block* _prev, Block* _next, int _objSize, ThreadData* _threadData)
222 binIdx = mallocTables.bin(objSize);
223 threadData = _threadData;
224 privateFreeList = publicFreeList = 0;
226 int nobjects = MAX_BLOCK_SIZE/objSize;
227 endPtr = bumpPtr + nobjects*objSize;
228 almostEmptyThreshold = (nobjects + 1)/2;
232 bool isFilled() const { return allocated > almostEmptyThreshold; }
237 Node* privateFreeList;
238 Node* publicFreeList;
242 ThreadData* threadData;
246 int almostEmptyThreshold;
252 BigBlock(int bigBlockSize, BigBlock* _next)
254 first = alignPtr((Block*)(this+1), MEM_BLOCK_SIZE);
256 nblocks = (int)(((char*)this + bigBlockSize - (char*)first)/MEM_BLOCK_SIZE);
258 for( int i = nblocks-1; i >= 0; i-- )
259 p = ::new((uchar*)first + i*MEM_BLOCK_SIZE) Block(p);
264 for( int i = nblocks-1; i >= 0; i-- )
265 ((Block*)((uchar*)first+i*MEM_BLOCK_SIZE))->~Block();
275 BlockPool(int _bigBlockSize=1<<20) : pool(0), bigBlockSize(_bigBlockSize)
284 BigBlock* nextBlock = pool->next;
286 SystemFree(pool, bigBlockSize);
297 BigBlock* bblock = ::new(SystemAlloc(bigBlockSize)) BigBlock(bigBlockSize, pool);
298 assert( bblock != 0 );
299 freeBlocks = bblock->first;
303 freeBlocks = freeBlocks->next;
305 freeBlocks->prev = 0;
306 STAT(stat.bruttoBytes += MEM_BLOCK_SIZE);
310 void free(Block* block)
314 block->next = freeBlocks;
316 STAT(stat.bruttoBytes -= MEM_BLOCK_SIZE);
323 int blocksPerBigBlock;
326 BlockPool mallocPool;
328 enum { START=0, FREE=1, GC=2 };
332 ThreadData() { for(int i = 0; i <= MAX_BIN; i++) bins[i][START] = bins[i][FREE] = bins[i][GC] = 0; }
335 // mark all the thread blocks as abandoned or even release them
336 for( int i = 0; i <= MAX_BIN; i++ )
338 Block *bin = bins[i][START], *block = bin;
339 bins[i][START] = bins[i][FREE] = bins[i][GC] = 0;
344 Block* next = block->next;
345 int allocated = block->allocated;
347 AutoLock lock(block->cs);
348 block->next = block->prev = 0;
349 block->threadData = 0;
350 Node *node = block->publicFreeList;
351 for( ; node != 0; node = node->next )
355 mallocPool.free(block);
358 while( block != bin );
363 void moveBlockToFreeList( Block* block )
365 int i = block->binIdx;
366 Block*& freePtr = bins[i][FREE];
367 CV_DbgAssert( block->next->prev == block && block->prev->next == block );
368 if( block != freePtr )
370 Block*& gcPtr = bins[i][GC];
373 if( block->next != block )
375 block->prev->next = block->next;
376 block->next->prev = block->prev;
378 block->next = freePtr->next;
379 block->prev = freePtr;
380 freePtr = block->next->prev = block->prev->next = block;
384 Block* bins[MAX_BIN+1][3];
388 # define TLS_OUT_OF_INDEXES ((DWORD)0xFFFFFFFF)
392 static ThreadData* get()
395 if( tlsKey == TLS_OUT_OF_INDEXES )
397 data = (ThreadData*)TlsGetValue(tlsKey);
400 data = new ThreadData;
401 TlsSetValue(tlsKey, data);
406 static void deleteData(void* data)
408 delete (ThreadData*)data;
411 static pthread_key_t tlsKey;
412 static ThreadData* get()
416 pthread_key_create(&tlsKey, deleteData);
417 data = (ThreadData*)pthread_getspecific(tlsKey);
420 data = new ThreadData;
421 pthread_setspecific(tlsKey, data);
429 DWORD ThreadData::tlsKey = TLS_OUT_OF_INDEXES;
431 void deleteThreadAllocData()
433 if( ThreadData::tlsKey != TLS_OUT_OF_INDEXES )
434 delete (ThreadData*)TlsGetValue( ThreadData::tlsKey );
438 pthread_key_t ThreadData::tlsKey = 0;
442 static void checkList(ThreadData* tls, int idx)
444 Block* block = tls->bins[idx][START];
447 CV_DbgAssert( tls->bins[idx][FREE] == 0 && tls->bins[idx][GC] == 0 );
451 bool gcInside = false;
452 bool freeInside = false;
455 if( tls->bins[idx][FREE] == block )
457 if( tls->bins[idx][GC] == block )
461 while( block != tls->bins[idx][START] );
462 CV_DbgAssert( gcInside && freeInside );
466 #define checkList(tls, idx)
469 void* fastMalloc( size_t size )
471 if( size > MAX_BLOCK_SIZE )
473 size_t size1 = size + sizeof(uchar*)*2 + MEM_BLOCK_SIZE;
474 uchar* udata = (uchar*)SystemAlloc(size1);
475 uchar** adata = alignPtr((uchar**)udata + 2, MEM_BLOCK_SIZE);
477 adata[-2] = (uchar*)size1;
482 ThreadData* tls = ThreadData::get();
483 int idx = mallocTables.bin(size);
484 Block*& startPtr = tls->bins[idx][START];
485 Block*& gcPtr = tls->bins[idx][GC];
486 Block*& freePtr = tls->bins[idx][FREE], *block = freePtr;
488 size = binSizeTab[idx];
490 stat.nettoBytes += size;
499 // try to find non-full block
502 CV_DbgAssert( block->next->prev == block && block->prev->next == block );
505 data = block->bumpPtr;
506 if( (block->bumpPtr += size) >= block->endPtr )
511 if( block->privateFreeList )
513 data = (uchar*)block->privateFreeList;
514 block->privateFreeList = block->privateFreeList->next;
518 if( block == startPtr )
527 printf("avg search iters per 1e3 allocs = %g\n", (double)avg_k/avg_nk );
536 for( int k = 0; k < 2; k++ )
539 CV_DbgAssert( block->next->prev == block && block->prev->next == block );
540 if( block->publicFreeList )
543 AutoLock lock(block->cs);
544 block->privateFreeList = block->publicFreeList;
545 block->publicFreeList = 0;
547 Node* node = block->privateFreeList;
548 for(;node != 0; node = node->next)
550 data = (uchar*)block->privateFreeList;
551 block->privateFreeList = block->privateFreeList->next;
553 if( block->allocated+1 <= block->almostEmptyThreshold )
554 tls->moveBlockToFreeList(block);
566 block = mallocPool.alloc();
567 block->init(startPtr ? startPtr->prev : block, startPtr ? startPtr : block, (int)size, tls);
569 startPtr = gcPtr = freePtr = block;
570 checkList(tls, block->binIdx);
579 void fastFree( void* ptr )
581 if( ((size_t)ptr & (MEM_BLOCK_SIZE-1)) == 0 )
585 void* origPtr = ((void**)ptr)[-1];
586 size_t sz = (size_t)((void**)ptr)[-2];
587 SystemFree( origPtr, sz );
593 ThreadData* tls = ThreadData::get();
594 Node* node = (Node*)ptr;
595 Block* block = (Block*)((size_t)ptr & -(int)MEM_BLOCK_SIZE);
596 assert( block->signature == MEM_BLOCK_SIGNATURE );
598 if( block->threadData == tls )
601 stat.nettoBytes -= block->objSize;
603 float ratio = (float)stat.nettoBytes/stat.bruttoBytes;
604 if( stat.minUsageRatio > ratio )
605 stat.minUsageRatio = ratio;
610 bool prevFilled = block->isFilled();
612 if( !block->isFilled() && (block->allocated == 0 || prevFilled) )
614 if( block->allocated == 0 )
616 int idx = block->binIdx;
617 Block*& startPtr = tls->bins[idx][START];
618 Block*& freePtr = tls->bins[idx][FREE];
619 Block*& gcPtr = tls->bins[idx][GC];
621 if( block == block->next )
623 CV_DbgAssert( startPtr == block && freePtr == block && gcPtr == block );
624 startPtr = freePtr = gcPtr = 0;
628 if( freePtr == block )
629 freePtr = block->next;
632 if( startPtr == block )
633 startPtr = block->next;
634 block->prev->next = block->next;
635 block->next->prev = block->prev;
637 mallocPool.free(block);
642 tls->moveBlockToFreeList(block);
644 node->next = block->privateFreeList;
645 block->privateFreeList = node;
649 AutoLock lock(block->cs);
652 node->next = block->publicFreeList;
653 block->publicFreeList = node;
654 if( block->threadData == 0 )
656 // take ownership of the abandoned block.
657 // note that it can happen at the same time as
658 // ThreadData::deleteData() marks the blocks as abandoned,
659 // so this part of the algorithm needs to be checked for data races
660 int idx = block->binIdx;
661 block->threadData = tls;
662 Block*& startPtr = tls->bins[idx][START];
666 block->next = startPtr;
667 block->prev = startPtr->prev;
668 block->next->prev = block->prev->next = block;
671 startPtr = tls->bins[idx][FREE] = tls->bins[idx][GC] = block;
681 CV_IMPL void cvSetMemoryManager( CvAllocFunc, CvFreeFunc, void * )
683 CV_Error( -1, "Custom memory allocator is not supported" );
686 CV_IMPL void* cvAlloc( size_t size )
688 return cv::fastMalloc( size );
691 CV_IMPL void cvFree_( void* ptr )