1 /*M/////////////////////////////////////////////////////////////////////////////////////// 2 // 3 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. 4 // 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. 8 // 9 // 10 // License Agreement 11 // For Open Source Computer Vision Library 12 // 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. 16 // 17 // Redistribution and use in source and binary forms, with or without modification, 18 // are permitted provided that the following conditions are met: 19 // 20 // * Redistribution's of source code must retain the above copyright notice, 21 // this list of conditions and the following disclaimer. 22 // 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. 26 // 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. 29 // 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. 40 // 41 //M*/ 42 43 #include "precomp.hpp" 44 45 #define CV_USE_SYSTEM_MALLOC 1 46 47 namespace cv 48 { 49 50 static void* OutOfMemoryError(size_t size) 51 { 52 CV_Error_(CV_StsNoMem, ("Failed to allocate %lu bytes", (unsigned long)size)); 53 return 0; 54 } 55 56 #if CV_USE_SYSTEM_MALLOC 57 58 #if defined WIN32 || defined _WIN32 59 void deleteThreadAllocData() {} 60 #endif 61 62 void* fastMalloc( size_t size ) 63 { 64 uchar* udata = (uchar*)malloc(size + sizeof(void*) + CV_MALLOC_ALIGN); 65 if(!udata) 66 return OutOfMemoryError(size); 67 uchar** adata = alignPtr((uchar**)udata + 1, CV_MALLOC_ALIGN); 68 adata[-1] = udata; 69 return adata; 70 } 71 72 void fastFree(void* ptr) 73 { 74 if(ptr) 75 { 76 uchar* udata = ((uchar**)ptr)[-1]; 77 CV_DbgAssert(udata < (uchar*)ptr && 78 ((uchar*)ptr - udata) <= (ptrdiff_t)(sizeof(void*)+CV_MALLOC_ALIGN)); 79 free(udata); 80 } 81 } 82 83 #else //CV_USE_SYSTEM_MALLOC 84 85 #if 0 86 #define SANITY_CHECK(block) \ 87 CV_Assert(((size_t)(block) & (MEM_BLOCK_SIZE-1)) == 0 && \ 88 (unsigned)(block)->binIdx <= (unsigned)MAX_BIN && \ 89 (block)->signature == MEM_BLOCK_SIGNATURE) 90 #else 91 #define SANITY_CHECK(block) 92 #endif 93 94 #define STAT(stmt) 95 96 #ifdef WIN32 97 #if (_WIN32_WINNT >= 0x0602) 98 #include <synchapi.h> 99 #endif 100 101 struct CriticalSection 102 { 103 CriticalSection() 104 { 105 #if (_WIN32_WINNT >= 0x0600) 106 InitializeCriticalSectionEx(&cs, 1000, 0); 107 #else 108 InitializeCriticalSection(&cs); 109 #endif 110 } 111 ~CriticalSection() { DeleteCriticalSection(&cs); } 112 void lock() { EnterCriticalSection(&cs); } 113 void unlock() { LeaveCriticalSection(&cs); } 114 bool trylock() { return TryEnterCriticalSection(&cs) != 0; } 115 116 CRITICAL_SECTION cs; 117 }; 118 119 void* SystemAlloc(size_t size) 120 { 121 void* ptr = malloc(size); 122 return ptr ? ptr : OutOfMemoryError(size); 123 } 124 125 void SystemFree(void* ptr, size_t) 126 { 127 free(ptr); 128 } 129 #else //WIN32 130 131 #include <sys/mman.h> 132 133 struct CriticalSection 134 { 135 CriticalSection() { pthread_mutex_init(&mutex, 0); } 136 ~CriticalSection() { pthread_mutex_destroy(&mutex); } 137 void lock() { pthread_mutex_lock(&mutex); } 138 void unlock() { pthread_mutex_unlock(&mutex); } 139 bool trylock() { return pthread_mutex_trylock(&mutex) == 0; } 140 141 pthread_mutex_t mutex; 142 }; 143 144 void* SystemAlloc(size_t size) 145 { 146 #ifndef MAP_ANONYMOUS 147 #define MAP_ANONYMOUS MAP_ANON 148 #endif 149 void* ptr = 0; 150 ptr = mmap(ptr, size, (PROT_READ | PROT_WRITE), MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); 151 return ptr != MAP_FAILED ? ptr : OutOfMemoryError(size); 152 } 153 154 void SystemFree(void* ptr, size_t size) 155 { 156 munmap(ptr, size); 157 } 158 #endif //WIN32 159 160 struct AutoLock 161 { 162 AutoLock(CriticalSection& _cs) : cs(&_cs) { cs->lock(); } 163 ~AutoLock() { cs->unlock(); } 164 CriticalSection* cs; 165 }; 166 167 const size_t MEM_BLOCK_SIGNATURE = 0x01234567; 168 const int MEM_BLOCK_SHIFT = 14; 169 const size_t MEM_BLOCK_SIZE = 1 << MEM_BLOCK_SHIFT; 170 const size_t HDR_SIZE = 128; 171 const size_t MAX_BLOCK_SIZE = MEM_BLOCK_SIZE - HDR_SIZE; 172 const int MAX_BIN = 28; 173 174 static const int binSizeTab[MAX_BIN+1] = 175 { 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 128, 160, 192, 256, 320, 384, 480, 544, 672, 768, 176 896, 1056, 1328, 1600, 2688, 4048, 5408, 8128, 16256 }; 177 178 struct MallocTables 179 { 180 void initBinTab() 181 { 182 int i, j = 0, n; 183 for( i = 0; i <= MAX_BIN; i++ ) 184 { 185 n = binSizeTab[i]>>3; 186 for( ; j <= n; j++ ) 187 binIdx[j] = (uchar)i; 188 } 189 } 190 int bin(size_t size) 191 { 192 assert( size <= MAX_BLOCK_SIZE ); 193 return binIdx[(size + 7)>>3]; 194 } 195 196 MallocTables() 197 { 198 initBinTab(); 199 } 200 201 uchar binIdx[MAX_BLOCK_SIZE/8+1]; 202 }; 203 204 MallocTables mallocTables; 205 206 struct Node 207 { 208 Node* next; 209 }; 210 211 struct ThreadData; 212 213 struct Block 214 { 215 Block(Block* _next) 216 { 217 signature = MEM_BLOCK_SIGNATURE; 218 prev = 0; 219 next = _next; 220 privateFreeList = publicFreeList = 0; 221 bumpPtr = endPtr = 0; 222 objSize = 0; 223 threadData = 0; 224 data = (uchar*)this + HDR_SIZE; 225 } 226 227 ~Block() {} 228 229 void init(Block* _prev, Block* _next, int _objSize, ThreadData* _threadData) 230 { 231 prev = _prev; 232 if(prev) 233 prev->next = this; 234 next = _next; 235 if(next) 236 next->prev = this; 237 objSize = _objSize; 238 binIdx = mallocTables.bin(objSize); 239 threadData = _threadData; 240 privateFreeList = publicFreeList = 0; 241 bumpPtr = data; 242 int nobjects = MAX_BLOCK_SIZE/objSize; 243 endPtr = bumpPtr + nobjects*objSize; 244 almostEmptyThreshold = (nobjects + 1)/2; 245 allocated = 0; 246 } 247 248 bool isFilled() const { return allocated > almostEmptyThreshold; } 249 250 size_t signature; 251 Block* prev; 252 Block* next; 253 Node* privateFreeList; 254 Node* publicFreeList; 255 uchar* bumpPtr; 256 uchar* endPtr; 257 uchar* data; 258 ThreadData* threadData; 259 int objSize; 260 int binIdx; 261 int allocated; 262 int almostEmptyThreshold; 263 CriticalSection cs; 264 }; 265 266 struct BigBlock 267 { 268 BigBlock(int bigBlockSize, BigBlock* _next) 269 { 270 first = alignPtr((Block*)(this+1), MEM_BLOCK_SIZE); 271 next = _next; 272 nblocks = (int)(((char*)this + bigBlockSize - (char*)first)/MEM_BLOCK_SIZE); 273 Block* p = 0; 274 for( int i = nblocks-1; i >= 0; i-- ) 275 p = ::new((uchar*)first + i*MEM_BLOCK_SIZE) Block(p); 276 } 277 278 ~BigBlock() 279 { 280 for( int i = nblocks-1; i >= 0; i-- ) 281 ((Block*)((uchar*)first+i*MEM_BLOCK_SIZE))->~Block(); 282 } 283 284 BigBlock* next; 285 Block* first; 286 int nblocks; 287 }; 288 289 struct BlockPool 290 { 291 BlockPool(int _bigBlockSize=1<<20) : pool(0), bigBlockSize(_bigBlockSize) 292 { 293 } 294 295 ~BlockPool() 296 { 297 AutoLock lock(cs); 298 while( pool ) 299 { 300 BigBlock* nextBlock = pool->next; 301 pool->~BigBlock(); 302 SystemFree(pool, bigBlockSize); 303 pool = nextBlock; 304 } 305 } 306 307 Block* alloc() 308 { 309 AutoLock lock(cs); 310 Block* block; 311 if( !freeBlocks ) 312 { 313 BigBlock* bblock = ::new(SystemAlloc(bigBlockSize)) BigBlock(bigBlockSize, pool); 314 assert( bblock != 0 ); 315 freeBlocks = bblock->first; 316 pool = bblock; 317 } 318 block = freeBlocks; 319 freeBlocks = freeBlocks->next; 320 if( freeBlocks ) 321 freeBlocks->prev = 0; 322 STAT(stat.bruttoBytes += MEM_BLOCK_SIZE); 323 return block; 324 } 325 326 void free(Block* block) 327 { 328 AutoLock lock(cs); 329 block->prev = 0; 330 block->next = freeBlocks; 331 freeBlocks = block; 332 STAT(stat.bruttoBytes -= MEM_BLOCK_SIZE); 333 } 334 335 CriticalSection cs; 336 Block* freeBlocks; 337 BigBlock* pool; 338 int bigBlockSize; 339 int blocksPerBigBlock; 340 }; 341 342 BlockPool mallocPool; 343 344 enum { START=0, FREE=1, GC=2 }; 345 346 struct ThreadData 347 { 348 ThreadData() { for(int i = 0; i <= MAX_BIN; i++) bins[i][START] = bins[i][FREE] = bins[i][GC] = 0; } 349 ~ThreadData() 350 { 351 // mark all the thread blocks as abandoned or even release them 352 for( int i = 0; i <= MAX_BIN; i++ ) 353 { 354 Block *bin = bins[i][START], *block = bin; 355 bins[i][START] = bins[i][FREE] = bins[i][GC] = 0; 356 if( block ) 357 { 358 do 359 { 360 Block* next = block->next; 361 int allocated = block->allocated; 362 { 363 AutoLock lock(block->cs); 364 block->next = block->prev = 0; 365 block->threadData = 0; 366 Node *node = block->publicFreeList; 367 for( ; node != 0; node = node->next ) 368 allocated--; 369 } 370 if( allocated == 0 ) 371 mallocPool.free(block); 372 block = next; 373 } 374 while( block != bin ); 375 } 376 } 377 } 378 379 void moveBlockToFreeList( Block* block ) 380 { 381 int i = block->binIdx; 382 Block*& freePtr = bins[i][FREE]; 383 CV_DbgAssert( block->next->prev == block && block->prev->next == block ); 384 if( block != freePtr ) 385 { 386 Block*& gcPtr = bins[i][GC]; 387 if( gcPtr == block ) 388 gcPtr = block->next; 389 if( block->next != block ) 390 { 391 block->prev->next = block->next; 392 block->next->prev = block->prev; 393 } 394 block->next = freePtr->next; 395 block->prev = freePtr; 396 freePtr = block->next->prev = block->prev->next = block; 397 } 398 } 399 400 Block* bins[MAX_BIN+1][3]; 401 402 #ifdef WIN32 403 #ifdef WINCE 404 # define TLS_OUT_OF_INDEXES ((DWORD)0xFFFFFFFF) 405 #endif //WINCE 406 407 static DWORD tlsKey; 408 static ThreadData* get() 409 { 410 ThreadData* data; 411 if( tlsKey == TLS_OUT_OF_INDEXES ) 412 tlsKey = TlsAlloc(); 413 data = (ThreadData*)TlsGetValue(tlsKey); 414 if( !data ) 415 { 416 data = new ThreadData; 417 TlsSetValue(tlsKey, data); 418 } 419 return data; 420 } 421 #else //WIN32 422 static void deleteData(void* data) 423 { 424 delete (ThreadData*)data; 425 } 426 427 static pthread_key_t tlsKey; 428 static ThreadData* get() 429 { 430 ThreadData* data; 431 if( !tlsKey ) 432 pthread_key_create(&tlsKey, deleteData); 433 data = (ThreadData*)pthread_getspecific(tlsKey); 434 if( !data ) 435 { 436 data = new ThreadData; 437 pthread_setspecific(tlsKey, data); 438 } 439 return data; 440 } 441 #endif //WIN32 442 }; 443 444 #ifdef WIN32 445 DWORD ThreadData::tlsKey = TLS_OUT_OF_INDEXES; 446 447 void deleteThreadAllocData() 448 { 449 if( ThreadData::tlsKey != TLS_OUT_OF_INDEXES ) 450 delete (ThreadData*)TlsGetValue( ThreadData::tlsKey ); 451 } 452 453 #else //WIN32 454 pthread_key_t ThreadData::tlsKey = 0; 455 #endif //WIN32 456 457 #if 0 458 static void checkList(ThreadData* tls, int idx) 459 { 460 Block* block = tls->bins[idx][START]; 461 if( !block ) 462 { 463 CV_DbgAssert( tls->bins[idx][FREE] == 0 && tls->bins[idx][GC] == 0 ); 464 } 465 else 466 { 467 bool gcInside = false; 468 bool freeInside = false; 469 do 470 { 471 if( tls->bins[idx][FREE] == block ) 472 freeInside = true; 473 if( tls->bins[idx][GC] == block ) 474 gcInside = true; 475 block = block->next; 476 } 477 while( block != tls->bins[idx][START] ); 478 CV_DbgAssert( gcInside && freeInside ); 479 } 480 } 481 #else 482 #define checkList(tls, idx) 483 #endif 484 485 void* fastMalloc( size_t size ) 486 { 487 if( size > MAX_BLOCK_SIZE ) 488 { 489 size_t size1 = size + sizeof(uchar*)*2 + MEM_BLOCK_SIZE; 490 uchar* udata = (uchar*)SystemAlloc(size1); 491 uchar** adata = alignPtr((uchar**)udata + 2, MEM_BLOCK_SIZE); 492 adata[-1] = udata; 493 adata[-2] = (uchar*)size1; 494 return adata; 495 } 496 497 { 498 ThreadData* tls = ThreadData::get(); 499 int idx = mallocTables.bin(size); 500 Block*& startPtr = tls->bins[idx][START]; 501 Block*& gcPtr = tls->bins[idx][GC]; 502 Block*& freePtr = tls->bins[idx][FREE], *block = freePtr; 503 checkList(tls, idx); 504 size = binSizeTab[idx]; 505 STAT( 506 stat.nettoBytes += size; 507 stat.mallocCalls++; 508 ); 509 uchar* data = 0; 510 511 for(;;) 512 { 513 if( block ) 514 { 515 // try to find non-full block 516 for(;;) 517 { 518 CV_DbgAssert( block->next->prev == block && block->prev->next == block ); 519 if( block->bumpPtr ) 520 { 521 data = block->bumpPtr; 522 if( (block->bumpPtr += size) >= block->endPtr ) 523 block->bumpPtr = 0; 524 break; 525 } 526 527 if( block->privateFreeList ) 528 { 529 data = (uchar*)block->privateFreeList; 530 block->privateFreeList = block->privateFreeList->next; 531 break; 532 } 533 534 if( block == startPtr ) 535 break; 536 block = block->next; 537 } 538 #if 0 539 avg_k += _k; 540 avg_nk++; 541 if( avg_nk == 1000 ) 542 { 543 printf("avg search iters per 1e3 allocs = %g\n", (double)avg_k/avg_nk ); 544 avg_k = avg_nk = 0; 545 } 546 #endif 547 548 freePtr = block; 549 if( !data ) 550 { 551 block = gcPtr; 552 for( int k = 0; k < 2; k++ ) 553 { 554 SANITY_CHECK(block); 555 CV_DbgAssert( block->next->prev == block && block->prev->next == block ); 556 if( block->publicFreeList ) 557 { 558 { 559 AutoLock lock(block->cs); 560 block->privateFreeList = block->publicFreeList; 561 block->publicFreeList = 0; 562 } 563 Node* node = block->privateFreeList; 564 for(;node != 0; node = node->next) 565 --block->allocated; 566 data = (uchar*)block->privateFreeList; 567 block->privateFreeList = block->privateFreeList->next; 568 gcPtr = block->next; 569 if( block->allocated+1 <= block->almostEmptyThreshold ) 570 tls->moveBlockToFreeList(block); 571 break; 572 } 573 block = block->next; 574 } 575 if( !data ) 576 gcPtr = block; 577 } 578 } 579 580 if( data ) 581 break; 582 block = mallocPool.alloc(); 583 block->init(startPtr ? startPtr->prev : block, startPtr ? startPtr : block, (int)size, tls); 584 if( !startPtr ) 585 startPtr = gcPtr = freePtr = block; 586 checkList(tls, block->binIdx); 587 SANITY_CHECK(block); 588 } 589 590 ++block->allocated; 591 return data; 592 } 593 } 594 595 void fastFree( void* ptr ) 596 { 597 if( ((size_t)ptr & (MEM_BLOCK_SIZE-1)) == 0 ) 598 { 599 if( ptr != 0 ) 600 { 601 void* origPtr = ((void**)ptr)[-1]; 602 size_t sz = (size_t)((void**)ptr)[-2]; 603 SystemFree( origPtr, sz ); 604 } 605 return; 606 } 607 608 { 609 ThreadData* tls = ThreadData::get(); 610 Node* node = (Node*)ptr; 611 Block* block = (Block*)((size_t)ptr & -(int)MEM_BLOCK_SIZE); 612 assert( block->signature == MEM_BLOCK_SIGNATURE ); 613 614 if( block->threadData == tls ) 615 { 616 STAT( 617 stat.nettoBytes -= block->objSize; 618 stat.freeCalls++; 619 float ratio = (float)stat.nettoBytes/stat.bruttoBytes; 620 if( stat.minUsageRatio > ratio ) 621 stat.minUsageRatio = ratio; 622 ); 623 624 SANITY_CHECK(block); 625 626 bool prevFilled = block->isFilled(); 627 --block->allocated; 628 if( !block->isFilled() && (block->allocated == 0 || prevFilled) ) 629 { 630 if( block->allocated == 0 ) 631 { 632 int idx = block->binIdx; 633 Block*& startPtr = tls->bins[idx][START]; 634 Block*& freePtr = tls->bins[idx][FREE]; 635 Block*& gcPtr = tls->bins[idx][GC]; 636 637 if( block == block->next ) 638 { 639 CV_DbgAssert( startPtr == block && freePtr == block && gcPtr == block ); 640 startPtr = freePtr = gcPtr = 0; 641 } 642 else 643 { 644 if( freePtr == block ) 645 freePtr = block->next; 646 if( gcPtr == block ) 647 gcPtr = block->next; 648 if( startPtr == block ) 649 startPtr = block->next; 650 block->prev->next = block->next; 651 block->next->prev = block->prev; 652 } 653 mallocPool.free(block); 654 checkList(tls, idx); 655 return; 656 } 657 658 tls->moveBlockToFreeList(block); 659 } 660 node->next = block->privateFreeList; 661 block->privateFreeList = node; 662 } 663 else 664 { 665 AutoLock lock(block->cs); 666 SANITY_CHECK(block); 667 668 node->next = block->publicFreeList; 669 block->publicFreeList = node; 670 if( block->threadData == 0 ) 671 { 672 // take ownership of the abandoned block. 673 // note that it can happen at the same time as 674 // ThreadData::deleteData() marks the blocks as abandoned, 675 // so this part of the algorithm needs to be checked for data races 676 int idx = block->binIdx; 677 block->threadData = tls; 678 Block*& startPtr = tls->bins[idx][START]; 679 680 if( startPtr ) 681 { 682 block->next = startPtr; 683 block->prev = startPtr->prev; 684 block->next->prev = block->prev->next = block; 685 } 686 else 687 startPtr = tls->bins[idx][FREE] = tls->bins[idx][GC] = block; 688 } 689 } 690 } 691 } 692 693 #endif //CV_USE_SYSTEM_MALLOC 694 695 } 696 697 CV_IMPL void* cvAlloc( size_t size ) 698 { 699 return cv::fastMalloc( size ); 700 } 701 702 CV_IMPL void cvFree_( void* ptr ) 703 { 704 cv::fastFree( ptr ); 705 } 706 707 708 /* End of file. */ 709