| OLD | NEW |
| 1 // Copyright (c) 2008, Google Inc. | 1 // Copyright (c) 2008, Google Inc. |
| 2 // All rights reserved. | 2 // All rights reserved. |
| 3 // | 3 // |
| 4 // Redistribution and use in source and binary forms, with or without | 4 // Redistribution and use in source and binary forms, with or without |
| 5 // modification, are permitted provided that the following conditions are | 5 // modification, are permitted provided that the following conditions are |
| 6 // met: | 6 // met: |
| 7 // | 7 // |
| 8 // * Redistributions of source code must retain the above copyright | 8 // * Redistributions of source code must retain the above copyright |
| 9 // notice, this list of conditions and the following disclaimer. | 9 // notice, this list of conditions and the following disclaimer. |
| 10 // * Redistributions in binary form must reproduce the above | 10 // * Redistributions in binary form must reproduce the above |
| (...skipping 13 matching lines...) Expand all Loading... |
| 24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 29 | 29 |
| 30 // --- | 30 // --- |
| 31 // Author: Ken Ashcraft <opensource@google.com> | 31 // Author: Ken Ashcraft <opensource@google.com> |
| 32 | 32 |
| 33 #include <config.h> | 33 #include <config.h> |
| 34 #ifdef HAVE_INTTYPES_H | |
| 35 #include <inttypes.h> | |
| 36 #endif | |
| 37 #include <algorithm> // for min and max | |
| 38 #include "thread_cache.h" | 34 #include "thread_cache.h" |
| 35 #include <string.h> // for memcpy |
| 36 #include <algorithm> // for max, min |
| 37 #include "base/commandlineflags.h" // for SpinLockHolder |
| 38 #include "base/spinlock.h" // for SpinLockHolder |
| 39 #include "central_freelist.h" // for CentralFreeListPadded |
| 39 #include "maybe_threads.h" | 40 #include "maybe_threads.h" |
| 40 | 41 |
| 41 using std::min; | 42 using std::min; |
| 42 using std::max; | 43 using std::max; |
| 43 | 44 |
| 44 DEFINE_int64(tcmalloc_max_total_thread_cache_bytes, | 45 DEFINE_int64(tcmalloc_max_total_thread_cache_bytes, |
| 45 EnvToInt64("TCMALLOC_MAX_TOTAL_THREAD_CACHE_BYTES", 16<<20), | 46 EnvToInt64("TCMALLOC_MAX_TOTAL_THREAD_CACHE_BYTES", |
| 47 kDefaultOverallThreadCacheSize), |
| 46 "Bound on the total amount of bytes allocated to " | 48 "Bound on the total amount of bytes allocated to " |
| 47 "thread caches. This bound is not strict, so it is possible " | 49 "thread caches. This bound is not strict, so it is possible " |
| 48 "for the cache to go over this bound in certain circumstances. "); | 50 "for the cache to go over this bound in certain circumstances. "); |
| 49 | 51 |
| 50 namespace tcmalloc { | 52 namespace tcmalloc { |
| 51 | 53 |
| 52 static bool phinited = false; | 54 static bool phinited = false; |
| 53 | 55 |
| 54 volatile size_t ThreadCache::per_thread_cache_size_ = kMaxThreadCacheSize; | 56 volatile size_t ThreadCache::per_thread_cache_size_ = kMaxThreadCacheSize; |
| 55 size_t ThreadCache::overall_thread_cache_size_ = kDefaultOverallThreadCacheSize; | 57 size_t ThreadCache::overall_thread_cache_size_ = kDefaultOverallThreadCacheSize; |
| (...skipping 248 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 304 Static::InitStaticVars(); | 306 Static::InitStaticVars(); |
| 305 threadcache_allocator.Init(); | 307 threadcache_allocator.Init(); |
| 306 phinited = 1; | 308 phinited = 1; |
| 307 } | 309 } |
| 308 } | 310 } |
| 309 | 311 |
| 310 void ThreadCache::InitTSD() { | 312 void ThreadCache::InitTSD() { |
| 311 ASSERT(!tsd_inited_); | 313 ASSERT(!tsd_inited_); |
| 312 perftools_pthread_key_create(&heap_key_, DestroyThreadCache); | 314 perftools_pthread_key_create(&heap_key_, DestroyThreadCache); |
| 313 tsd_inited_ = true; | 315 tsd_inited_ = true; |
| 314 | |
| 315 // We may have used a fake pthread_t for the main thread. Fix it. | |
| 316 pthread_t zero; | |
| 317 memset(&zero, 0, sizeof(zero)); | |
| 318 SpinLockHolder h(Static::pageheap_lock()); | |
| 319 for (ThreadCache* h = thread_heaps_; h != NULL; h = h->next_) { | |
| 320 if (h->tid_ == zero) { | |
| 321 h->tid_ = pthread_self(); | |
| 322 } | |
| 323 } | |
| 324 } | 316 } |
| 325 | 317 |
| 326 ThreadCache* ThreadCache::CreateCacheIfNecessary() { | 318 ThreadCache* ThreadCache::CreateCacheIfNecessary() { |
| 327 // Initialize per-thread data if necessary | 319 // Initialize per-thread data if necessary |
| 328 ThreadCache* heap = NULL; | 320 ThreadCache* heap = NULL; |
| 329 { | 321 { |
| 330 SpinLockHolder h(Static::pageheap_lock()); | 322 SpinLockHolder h(Static::pageheap_lock()); |
| 331 | 323 // On very old libc's, this call may crash if it happens too |
| 332 // Early on in glibc's life, we cannot even call pthread_self() | 324 // early. No libc using NPTL should be affected. If there |
| 333 pthread_t me; | 325 // is a crash here, we could use code (on linux, at least) |
| 334 if (!tsd_inited_) { | 326 // to detect NPTL vs LinuxThreads: |
| 335 memset(&me, 0, sizeof(me)); | 327 // http://www.redhat.com/archives/phil-list/2003-April/msg00038.html |
| 336 } else { | 328 // If we detect not-NPTL, we could execute the old code from |
| 337 me = pthread_self(); | 329 // http://google-perftools.googlecode.com/svn/tags/google-perftools-1.7/sr
c/thread_cache.cc |
| 338 } | 330 // that avoids calling pthread_self too early. The problem with |
| 331 // that code is it caused a race condition when tcmalloc is linked |
| 332 // in statically and other libraries spawn threads before main. |
| 333 const pthread_t me = pthread_self(); |
| 339 | 334 |
| 340 // This may be a recursive malloc call from pthread_setspecific() | 335 // This may be a recursive malloc call from pthread_setspecific() |
| 341 // In that case, the heap for this thread has already been created | 336 // In that case, the heap for this thread has already been created |
| 342 // and added to the linked list. So we search for that first. | 337 // and added to the linked list. So we search for that first. |
| 343 for (ThreadCache* h = thread_heaps_; h != NULL; h = h->next_) { | 338 for (ThreadCache* h = thread_heaps_; h != NULL; h = h->next_) { |
| 344 if (h->tid_ == me) { | 339 if (h->tid_ == me) { |
| 345 heap = h; | 340 heap = h; |
| 346 break; | 341 break; |
| 347 } | 342 } |
| 348 } | 343 } |
| (...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 498 void ThreadCache::set_overall_thread_cache_size(size_t new_size) { | 493 void ThreadCache::set_overall_thread_cache_size(size_t new_size) { |
| 499 // Clip the value to a reasonable range | 494 // Clip the value to a reasonable range |
| 500 if (new_size < kMinThreadCacheSize) new_size = kMinThreadCacheSize; | 495 if (new_size < kMinThreadCacheSize) new_size = kMinThreadCacheSize; |
| 501 if (new_size > (1<<30)) new_size = (1<<30); // Limit to 1GB | 496 if (new_size > (1<<30)) new_size = (1<<30); // Limit to 1GB |
| 502 overall_thread_cache_size_ = new_size; | 497 overall_thread_cache_size_ = new_size; |
| 503 | 498 |
| 504 RecomputePerThreadCacheSize(); | 499 RecomputePerThreadCacheSize(); |
| 505 } | 500 } |
| 506 | 501 |
| 507 } // namespace tcmalloc | 502 } // namespace tcmalloc |
| OLD | NEW |