OLD | NEW |
---|---|
1 /* Copyright (c) 2006, Google Inc. | 1 /* Copyright (c) 2006, 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 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
140 int MemoryRegionMap::max_stack_depth_ = 0; | 140 int MemoryRegionMap::max_stack_depth_ = 0; |
141 MemoryRegionMap::RegionSet* MemoryRegionMap::regions_ = NULL; | 141 MemoryRegionMap::RegionSet* MemoryRegionMap::regions_ = NULL; |
142 LowLevelAlloc::Arena* MemoryRegionMap::arena_ = NULL; | 142 LowLevelAlloc::Arena* MemoryRegionMap::arena_ = NULL; |
143 SpinLock MemoryRegionMap::lock_(SpinLock::LINKER_INITIALIZED); | 143 SpinLock MemoryRegionMap::lock_(SpinLock::LINKER_INITIALIZED); |
144 SpinLock MemoryRegionMap::owner_lock_( // ACQUIRED_AFTER(lock_) | 144 SpinLock MemoryRegionMap::owner_lock_( // ACQUIRED_AFTER(lock_) |
145 SpinLock::LINKER_INITIALIZED); | 145 SpinLock::LINKER_INITIALIZED); |
146 int MemoryRegionMap::recursion_count_ = 0; // GUARDED_BY(owner_lock_) | 146 int MemoryRegionMap::recursion_count_ = 0; // GUARDED_BY(owner_lock_) |
147 pthread_t MemoryRegionMap::lock_owner_tid_; // GUARDED_BY(owner_lock_) | 147 pthread_t MemoryRegionMap::lock_owner_tid_; // GUARDED_BY(owner_lock_) |
148 int64 MemoryRegionMap::map_size_ = 0; | 148 int64 MemoryRegionMap::map_size_ = 0; |
149 int64 MemoryRegionMap::unmap_size_ = 0; | 149 int64 MemoryRegionMap::unmap_size_ = 0; |
150 MemoryRegionMap::Bucket** MemoryRegionMap::bucket_table_ = NULL; | |
151 int MemoryRegionMap::num_buckets_ = 0; | |
152 int MemoryRegionMap::saved_buckets_count_ = 0; | |
153 MemoryRegionMap::Bucket MemoryRegionMap::saved_buckets_[20]; | |
154 const void* MemoryRegionMap::saved_buckets_keys_[20][kMaxStackDepth]; | |
150 | 155 |
151 // ========================================================================= // | 156 // ========================================================================= // |
152 | 157 |
153 // Simple hook into execution of global object constructors, | 158 // Simple hook into execution of global object constructors, |
154 // so that we do not call pthread_self() when it does not yet work. | 159 // so that we do not call pthread_self() when it does not yet work. |
155 static bool libpthread_initialized = false; | 160 static bool libpthread_initialized = false; |
156 static bool initializer = (libpthread_initialized = true, true); | 161 static bool initializer = (libpthread_initialized = true, true); |
157 | 162 |
158 static inline bool current_thread_is(pthread_t should_be) { | 163 static inline bool current_thread_is(pthread_t should_be) { |
159 // Before main() runs, there's only one thread, so we're always that thread | 164 // Before main() runs, there's only one thread, so we're always that thread |
(...skipping 15 matching lines...) Expand all Loading... | |
175 // We use RegionSetRep with noop c-tor so that global construction | 180 // We use RegionSetRep with noop c-tor so that global construction |
176 // does not interfere. | 181 // does not interfere. |
177 static MemoryRegionMap::RegionSetRep regions_rep; | 182 static MemoryRegionMap::RegionSetRep regions_rep; |
178 | 183 |
179 // ========================================================================= // | 184 // ========================================================================= // |
180 | 185 |
181 // Has InsertRegionLocked been called recursively | 186 // Has InsertRegionLocked been called recursively |
182 // (or rather should we *not* use regions_ to record a hooked mmap). | 187 // (or rather should we *not* use regions_ to record a hooked mmap). |
183 static bool recursive_insert = false; | 188 static bool recursive_insert = false; |
184 | 189 |
185 void MemoryRegionMap::Init(int max_stack_depth) { | 190 void MemoryRegionMap::Init(int max_stack_depth, bool use_buckets) { |
186 RAW_VLOG(10, "MemoryRegionMap Init"); | 191 RAW_VLOG(10, "MemoryRegionMap Init"); |
187 RAW_CHECK(max_stack_depth >= 0, ""); | 192 RAW_CHECK(max_stack_depth >= 0, ""); |
188 // Make sure we don't overflow the memory in region stacks: | 193 // Make sure we don't overflow the memory in region stacks: |
189 RAW_CHECK(max_stack_depth <= kMaxStackDepth, | 194 RAW_CHECK(max_stack_depth <= kMaxStackDepth, |
190 "need to increase kMaxStackDepth?"); | 195 "need to increase kMaxStackDepth?"); |
191 Lock(); | 196 Lock(); |
192 client_count_ += 1; | 197 client_count_ += 1; |
193 max_stack_depth_ = max(max_stack_depth_, max_stack_depth); | 198 max_stack_depth_ = max(max_stack_depth_, max_stack_depth); |
194 if (client_count_ > 1) { | 199 if (client_count_ > 1) { |
195 // not first client: already did initialization-proper | 200 // not first client: already did initialization-proper |
(...skipping 11 matching lines...) Expand all Loading... | |
207 // recursive_insert allows us to buffer info about these mmap calls. | 212 // recursive_insert allows us to buffer info about these mmap calls. |
208 // Note that Init() can be (and is) sometimes called | 213 // Note that Init() can be (and is) sometimes called |
209 // already from within an mmap/sbrk hook. | 214 // already from within an mmap/sbrk hook. |
210 recursive_insert = true; | 215 recursive_insert = true; |
211 arena_ = LowLevelAlloc::NewArena(0, LowLevelAlloc::DefaultArena()); | 216 arena_ = LowLevelAlloc::NewArena(0, LowLevelAlloc::DefaultArena()); |
212 recursive_insert = false; | 217 recursive_insert = false; |
213 HandleSavedRegionsLocked(&InsertRegionLocked); // flush the buffered ones | 218 HandleSavedRegionsLocked(&InsertRegionLocked); // flush the buffered ones |
214 // Can't instead use HandleSavedRegionsLocked(&DoInsertRegionLocked) before | 219 // Can't instead use HandleSavedRegionsLocked(&DoInsertRegionLocked) before |
215 // recursive_insert = false; as InsertRegionLocked will also construct | 220 // recursive_insert = false; as InsertRegionLocked will also construct |
216 // regions_ on demand for us. | 221 // regions_ on demand for us. |
222 if (use_buckets) { | |
223 const int table_bytes = kHashTableSize * sizeof(*bucket_table_); | |
224 recursive_insert = true; | |
225 bucket_table_ = reinterpret_cast<Bucket**>( | |
226 MyAllocator::Allocate(table_bytes)); | |
227 recursive_insert = false; | |
228 memset(bucket_table_, 0, table_bytes); | |
229 num_buckets_ = 0; | |
230 } | |
217 Unlock(); | 231 Unlock(); |
218 RAW_VLOG(10, "MemoryRegionMap Init done"); | 232 RAW_VLOG(10, "MemoryRegionMap Init done"); |
219 } | 233 } |
220 | 234 |
221 bool MemoryRegionMap::Shutdown() { | 235 bool MemoryRegionMap::Shutdown() { |
222 RAW_VLOG(10, "MemoryRegionMap Shutdown"); | 236 RAW_VLOG(10, "MemoryRegionMap Shutdown"); |
223 Lock(); | 237 Lock(); |
224 RAW_CHECK(client_count_ > 0, ""); | 238 RAW_CHECK(client_count_ > 0, ""); |
225 client_count_ -= 1; | 239 client_count_ -= 1; |
226 if (client_count_ != 0) { // not last client; need not really shutdown | 240 if (client_count_ != 0) { // not last client; need not really shutdown |
227 Unlock(); | 241 Unlock(); |
228 RAW_VLOG(10, "MemoryRegionMap Shutdown decrement done"); | 242 RAW_VLOG(10, "MemoryRegionMap Shutdown decrement done"); |
229 return true; | 243 return true; |
230 } | 244 } |
245 if (bucket_table_ != NULL) { | |
246 for (int i = 0; i < kHashTableSize; i++) { | |
247 for (Bucket* x = bucket_table_[i]; x != 0; /**/) { | |
248 Bucket* b = x; | |
249 x = x->next; | |
250 MyAllocator::Free(b->stack, 0); | |
251 MyAllocator::Free(b, 0); | |
252 } | |
253 } | |
254 MyAllocator::Free(bucket_table_, 0); | |
255 num_buckets_ = 0; | |
256 bucket_table_ = NULL; | |
257 } | |
231 RAW_CHECK(MallocHook::RemoveMmapHook(&MmapHook), ""); | 258 RAW_CHECK(MallocHook::RemoveMmapHook(&MmapHook), ""); |
232 RAW_CHECK(MallocHook::RemoveMremapHook(&MremapHook), ""); | 259 RAW_CHECK(MallocHook::RemoveMremapHook(&MremapHook), ""); |
233 RAW_CHECK(MallocHook::RemoveSbrkHook(&SbrkHook), ""); | 260 RAW_CHECK(MallocHook::RemoveSbrkHook(&SbrkHook), ""); |
234 RAW_CHECK(MallocHook::RemoveMunmapHook(&MunmapHook), ""); | 261 RAW_CHECK(MallocHook::RemoveMunmapHook(&MunmapHook), ""); |
235 if (regions_) regions_->~RegionSet(); | 262 if (regions_) regions_->~RegionSet(); |
236 regions_ = NULL; | 263 regions_ = NULL; |
237 bool deleted_arena = LowLevelAlloc::DeleteArena(arena_); | 264 bool deleted_arena = LowLevelAlloc::DeleteArena(arena_); |
238 if (deleted_arena) { | 265 if (deleted_arena) { |
239 arena_ = 0; | 266 arena_ = 0; |
240 } else { | 267 } else { |
241 RAW_LOG(WARNING, "Can't delete LowLevelAlloc arena: it's being used"); | 268 RAW_LOG(WARNING, "Can't delete LowLevelAlloc arena: it's being used"); |
242 } | 269 } |
243 Unlock(); | 270 Unlock(); |
244 RAW_VLOG(10, "MemoryRegionMap Shutdown done"); | 271 RAW_VLOG(10, "MemoryRegionMap Shutdown done"); |
245 return deleted_arena; | 272 return deleted_arena; |
246 } | 273 } |
247 | 274 |
275 bool MemoryRegionMap::IsWorking() { | |
276 RAW_VLOG(10, "MemoryRegionMap IsWorking"); | |
277 Lock(); | |
278 bool is_working = (client_count_ > 0); | |
279 Unlock(); | |
280 RAW_VLOG(10, "MemoryRegionMap IsWorking done"); | |
281 return is_working; | |
282 } | |
283 | |
248 // Invariants (once libpthread_initialized is true): | 284 // Invariants (once libpthread_initialized is true): |
249 // * While lock_ is not held, recursion_count_ is 0 (and | 285 // * While lock_ is not held, recursion_count_ is 0 (and |
250 // lock_owner_tid_ is the previous owner, but we don't rely on | 286 // lock_owner_tid_ is the previous owner, but we don't rely on |
251 // that). | 287 // that). |
252 // * recursion_count_ and lock_owner_tid_ are only written while | 288 // * recursion_count_ and lock_owner_tid_ are only written while |
253 // both lock_ and owner_lock_ are held. They may be read under | 289 // both lock_ and owner_lock_ are held. They may be read under |
254 // just owner_lock_. | 290 // just owner_lock_. |
255 // * At entry and exit of Lock() and Unlock(), the current thread | 291 // * At entry and exit of Lock() and Unlock(), the current thread |
256 // owns lock_ iff pthread_equal(lock_owner_tid_, pthread_self()) | 292 // owns lock_ iff pthread_equal(lock_owner_tid_, pthread_self()) |
257 // && recursion_count_ > 0. | 293 // && recursion_count_ > 0. |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
329 reinterpret_cast<void*>(region->start_addr), | 365 reinterpret_cast<void*>(region->start_addr), |
330 reinterpret_cast<void*>(region->end_addr)); | 366 reinterpret_cast<void*>(region->end_addr)); |
331 const_cast<Region*>(region)->set_is_stack(); // now we know | 367 const_cast<Region*>(region)->set_is_stack(); // now we know |
332 // cast is safe (set_is_stack does not change the set ordering key) | 368 // cast is safe (set_is_stack does not change the set ordering key) |
333 *result = *region; // create *result as an independent copy | 369 *result = *region; // create *result as an independent copy |
334 } | 370 } |
335 Unlock(); | 371 Unlock(); |
336 return region != NULL; | 372 return region != NULL; |
337 } | 373 } |
338 | 374 |
375 MemoryRegionMap::Bucket* MemoryRegionMap::GetBucket(int depth, | |
376 const void* const key[]) { | |
377 // Make hash-value | |
378 uintptr_t h = 0; | |
379 for (int i = 0; i < depth; i++) { | |
380 h += reinterpret_cast<uintptr_t>(key[i]); | |
381 h += h << 10; | |
382 h ^= h >> 6; | |
383 } | |
384 h += h << 3; | |
385 h ^= h >> 11; | |
386 | |
387 // Lookup stack trace in table | |
388 unsigned int buck = ((unsigned int) h) % kHashTableSize; | |
389 for (Bucket* b = bucket_table_[buck]; b != 0; b = b->next) { | |
390 if ((b->hash == h) && | |
391 (b->depth == depth) && | |
392 std::equal(key, key + depth, b->stack)) { | |
393 return b; | |
394 } | |
395 } | |
396 | |
397 // Create new bucket | |
398 const size_t key_size = sizeof(key[0]) * depth; | |
399 Bucket* b; | |
400 if (recursive_insert) { // recursion: save in saved_buckets_ | |
401 const void** kcopy = saved_buckets_keys_[saved_buckets_count_]; | |
402 std::copy(key, key + depth, kcopy); | |
403 b = &saved_buckets_[saved_buckets_count_]; | |
404 memset(b, 0, sizeof(*b)); | |
405 ++saved_buckets_count_; | |
406 b->stack = kcopy; | |
407 b->next = NULL; | |
408 } else { | |
409 recursive_insert = true; | |
410 const void** kcopy = reinterpret_cast<const void**>( | |
411 MyAllocator::Allocate(key_size)); | |
412 recursive_insert = false; | |
413 std::copy(key, key + depth, kcopy); | |
414 recursive_insert = true; | |
415 b = reinterpret_cast<Bucket*>( | |
416 MyAllocator::Allocate(sizeof(Bucket))); | |
417 recursive_insert = false; | |
418 memset(b, 0, sizeof(*b)); | |
419 b->stack = kcopy; | |
420 b->next = bucket_table_[buck]; | |
421 } | |
422 b->hash = h; | |
423 b->depth = depth; | |
424 bucket_table_[buck] = b; | |
425 ++num_buckets_; | |
426 return b; | |
427 } | |
428 | |
339 MemoryRegionMap::RegionIterator MemoryRegionMap::BeginRegionLocked() { | 429 MemoryRegionMap::RegionIterator MemoryRegionMap::BeginRegionLocked() { |
340 RAW_CHECK(LockIsHeld(), "should be held (by this thread)"); | 430 RAW_CHECK(LockIsHeld(), "should be held (by this thread)"); |
341 RAW_CHECK(regions_ != NULL, ""); | 431 RAW_CHECK(regions_ != NULL, ""); |
342 return regions_->begin(); | 432 return regions_->begin(); |
343 } | 433 } |
344 | 434 |
345 MemoryRegionMap::RegionIterator MemoryRegionMap::EndRegionLocked() { | 435 MemoryRegionMap::RegionIterator MemoryRegionMap::EndRegionLocked() { |
346 RAW_CHECK(LockIsHeld(), "should be held (by this thread)"); | 436 RAW_CHECK(LockIsHeld(), "should be held (by this thread)"); |
347 RAW_CHECK(regions_ != NULL, ""); | 437 RAW_CHECK(regions_ != NULL, ""); |
348 return regions_->end(); | 438 return regions_->end(); |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
397 while (saved_regions_count > 0) { | 487 while (saved_regions_count > 0) { |
398 // Making a local-var copy of the region argument to insert_func | 488 // Making a local-var copy of the region argument to insert_func |
399 // including its stack (w/o doing any memory allocations) is important: | 489 // including its stack (w/o doing any memory allocations) is important: |
400 // in many cases the memory in saved_regions | 490 // in many cases the memory in saved_regions |
401 // will get written-to during the (*insert_func)(r) call below. | 491 // will get written-to during the (*insert_func)(r) call below. |
402 Region r = saved_regions[--saved_regions_count]; | 492 Region r = saved_regions[--saved_regions_count]; |
403 (*insert_func)(r); | 493 (*insert_func)(r); |
404 } | 494 } |
405 } | 495 } |
406 | 496 |
497 inline void MemoryRegionMap::HandleSavedBucketsLocked() { | |
498 while (saved_buckets_count_ > 0) { | |
499 Bucket b = saved_buckets_[--saved_buckets_count_]; | |
500 unsigned int buck = ((unsigned int) b.hash) % kHashTableSize; | |
501 bool is_found = false; | |
502 for (Bucket* found = bucket_table_[buck]; found != 0; found = found->next) { | |
503 if ((found->hash == b.hash) && (found->depth == b.depth) && | |
504 std::equal(b.stack, b.stack + b.depth, found->stack)) { | |
505 found->allocs += b.allocs; | |
506 found->alloc_size += b.alloc_size; | |
507 found->frees += b.frees; | |
508 found->free_size += b.free_size; | |
509 is_found = true; | |
510 break; | |
511 } | |
512 } | |
513 if (is_found) continue; | |
514 | |
515 const size_t key_size = sizeof(b.stack[0]) * b.depth; | |
516 const void** kcopy = reinterpret_cast<const void**>( | |
517 MyAllocator::Allocate(key_size)); | |
518 std::copy(b.stack, b.stack + b.depth, kcopy); | |
519 Bucket* new_b = reinterpret_cast<Bucket*>( | |
520 MyAllocator::Allocate(sizeof(Bucket))); | |
521 memset(new_b, 0, sizeof(*new_b)); | |
522 new_b->hash = b.hash; | |
523 new_b->depth = b.depth; | |
524 new_b->stack = kcopy; | |
525 new_b->next = bucket_table_[buck]; | |
526 bucket_table_[buck] = new_b; | |
527 ++num_buckets_; | |
528 } | |
529 } | |
530 | |
407 inline void MemoryRegionMap::InsertRegionLocked(const Region& region) { | 531 inline void MemoryRegionMap::InsertRegionLocked(const Region& region) { |
408 RAW_CHECK(LockIsHeld(), "should be held (by this thread)"); | 532 RAW_CHECK(LockIsHeld(), "should be held (by this thread)"); |
409 // We can be called recursively, because RegionSet constructor | 533 // We can be called recursively, because RegionSet constructor |
410 // and DoInsertRegionLocked() (called below) can call the allocator. | 534 // and DoInsertRegionLocked() (called below) can call the allocator. |
411 // recursive_insert tells us if that's the case. When this happens, | 535 // recursive_insert tells us if that's the case. When this happens, |
412 // region insertion information is recorded in saved_regions[], | 536 // region insertion information is recorded in saved_regions[], |
413 // and taken into account when the recursion unwinds. | 537 // and taken into account when the recursion unwinds. |
414 // Do the insert: | 538 // Do the insert: |
415 if (recursive_insert) { // recursion: save in saved_regions | 539 if (recursive_insert) { // recursion: save in saved_regions |
416 RAW_VLOG(12, "Saving recursive insert of region %p..%p from %p", | 540 RAW_VLOG(12, "Saving recursive insert of region %p..%p from %p", |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
461 RAW_VLOG(10, "New global region %p..%p from %p", | 585 RAW_VLOG(10, "New global region %p..%p from %p", |
462 reinterpret_cast<void*>(region.start_addr), | 586 reinterpret_cast<void*>(region.start_addr), |
463 reinterpret_cast<void*>(region.end_addr), | 587 reinterpret_cast<void*>(region.end_addr), |
464 reinterpret_cast<void*>(region.caller())); | 588 reinterpret_cast<void*>(region.caller())); |
465 // Note: none of the above allocates memory. | 589 // Note: none of the above allocates memory. |
466 Lock(); // recursively lock | 590 Lock(); // recursively lock |
467 map_size_ += size; | 591 map_size_ += size; |
468 InsertRegionLocked(region); | 592 InsertRegionLocked(region); |
469 // This will (eventually) allocate storage for and copy over the stack data | 593 // This will (eventually) allocate storage for and copy over the stack data |
470 // from region.call_stack_data_ that is pointed by region.call_stack(). | 594 // from region.call_stack_data_ that is pointed by region.call_stack(). |
595 if (bucket_table_ != NULL) { | |
596 Bucket* b = GetBucket(depth, region.call_stack); | |
597 ++b->allocs; | |
598 b->alloc_size += size; | |
599 if (!recursive_insert) { | |
600 recursive_insert = true; | |
601 HandleSavedBucketsLocked(); | |
602 recursive_insert = false; | |
603 } | |
604 } | |
471 Unlock(); | 605 Unlock(); |
472 } | 606 } |
473 | 607 |
474 void MemoryRegionMap::RecordRegionRemoval(const void* start, size_t size) { | 608 void MemoryRegionMap::RecordRegionRemoval(const void* start, size_t size) { |
475 Lock(); | 609 Lock(); |
476 if (recursive_insert) { | 610 if (recursive_insert) { |
477 // First remove the removed region from saved_regions, if it's | 611 // First remove the removed region from saved_regions, if it's |
478 // there, to prevent overrunning saved_regions in recursive | 612 // there, to prevent overrunning saved_regions in recursive |
479 // map/unmap call sequences, and also from later inserting regions | 613 // map/unmap call sequences, and also from later inserting regions |
480 // which have already been unmapped. | 614 // which have already been unmapped. |
481 uintptr_t start_addr = reinterpret_cast<uintptr_t>(start); | 615 uintptr_t start_addr = reinterpret_cast<uintptr_t>(start); |
482 uintptr_t end_addr = start_addr + size; | 616 uintptr_t end_addr = start_addr + size; |
483 int put_pos = 0; | 617 int put_pos = 0; |
484 int old_count = saved_regions_count; | 618 int old_count = saved_regions_count; |
485 for (int i = 0; i < old_count; ++i, ++put_pos) { | 619 for (int i = 0; i < old_count; ++i, ++put_pos) { |
486 Region& r = saved_regions[i]; | 620 Region& r = saved_regions[i]; |
487 if (r.start_addr == start_addr && r.end_addr == end_addr) { | 621 if (r.start_addr == start_addr && r.end_addr == end_addr) { |
488 // An exact match, so it's safe to remove. | 622 // An exact match, so it's safe to remove. |
623 RecordRegionRemovalInBucket(r.call_stack_depth, r.call_stack, size); | |
489 --saved_regions_count; | 624 --saved_regions_count; |
490 --put_pos; | 625 --put_pos; |
491 RAW_VLOG(10, ("Insta-Removing saved region %p..%p; " | 626 RAW_VLOG(10, ("Insta-Removing saved region %p..%p; " |
492 "now have %d saved regions"), | 627 "now have %d saved regions"), |
493 reinterpret_cast<void*>(start_addr), | 628 reinterpret_cast<void*>(start_addr), |
494 reinterpret_cast<void*>(end_addr), | 629 reinterpret_cast<void*>(end_addr), |
495 saved_regions_count); | 630 saved_regions_count); |
496 } else { | 631 } else { |
497 if (put_pos < i) { | 632 if (put_pos < i) { |
498 saved_regions[put_pos] = saved_regions[i]; | 633 saved_regions[put_pos] = saved_regions[i]; |
(...skipping 24 matching lines...) Expand all Loading... | |
523 region != regions_->end() && region->start_addr < end_addr; | 658 region != regions_->end() && region->start_addr < end_addr; |
524 /*noop*/) { | 659 /*noop*/) { |
525 RAW_VLOG(13, "Looking at region %p..%p", | 660 RAW_VLOG(13, "Looking at region %p..%p", |
526 reinterpret_cast<void*>(region->start_addr), | 661 reinterpret_cast<void*>(region->start_addr), |
527 reinterpret_cast<void*>(region->end_addr)); | 662 reinterpret_cast<void*>(region->end_addr)); |
528 if (start_addr <= region->start_addr && | 663 if (start_addr <= region->start_addr && |
529 region->end_addr <= end_addr) { // full deletion | 664 region->end_addr <= end_addr) { // full deletion |
530 RAW_VLOG(12, "Deleting region %p..%p", | 665 RAW_VLOG(12, "Deleting region %p..%p", |
531 reinterpret_cast<void*>(region->start_addr), | 666 reinterpret_cast<void*>(region->start_addr), |
532 reinterpret_cast<void*>(region->end_addr)); | 667 reinterpret_cast<void*>(region->end_addr)); |
668 RecordRegionRemovalInBucket(region->call_stack_depth, region->call_stack, | |
669 region->end_addr - region->start_addr); | |
533 RegionSet::iterator d = region; | 670 RegionSet::iterator d = region; |
534 ++region; | 671 ++region; |
535 regions_->erase(d); | 672 regions_->erase(d); |
536 continue; | 673 continue; |
537 } else if (region->start_addr < start_addr && | 674 } else if (region->start_addr < start_addr && |
538 end_addr < region->end_addr) { // cutting-out split | 675 end_addr < region->end_addr) { // cutting-out split |
539 RAW_VLOG(12, "Splitting region %p..%p in two", | 676 RAW_VLOG(12, "Splitting region %p..%p in two", |
540 reinterpret_cast<void*>(region->start_addr), | 677 reinterpret_cast<void*>(region->start_addr), |
541 reinterpret_cast<void*>(region->end_addr)); | 678 reinterpret_cast<void*>(region->end_addr)); |
679 RecordRegionRemovalInBucket(region->call_stack_depth, region->call_stack, | |
680 end_addr - start_addr); | |
542 // Make another region for the start portion: | 681 // Make another region for the start portion: |
543 // The new region has to be the start portion because we can't | 682 // The new region has to be the start portion because we can't |
544 // just modify region->end_addr as it's the sorting key. | 683 // just modify region->end_addr as it's the sorting key. |
545 Region r = *region; | 684 Region r = *region; |
546 r.set_end_addr(start_addr); | 685 r.set_end_addr(start_addr); |
547 InsertRegionLocked(r); | 686 InsertRegionLocked(r); |
548 // cut *region from start: | 687 // cut *region from start: |
549 const_cast<Region&>(*region).set_start_addr(end_addr); | 688 const_cast<Region&>(*region).set_start_addr(end_addr); |
550 } else if (end_addr > region->start_addr && | 689 } else if (end_addr > region->start_addr && |
551 start_addr <= region->start_addr) { // cut from start | 690 start_addr <= region->start_addr) { // cut from start |
552 RAW_VLOG(12, "Start-chopping region %p..%p", | 691 RAW_VLOG(12, "Start-chopping region %p..%p", |
553 reinterpret_cast<void*>(region->start_addr), | 692 reinterpret_cast<void*>(region->start_addr), |
554 reinterpret_cast<void*>(region->end_addr)); | 693 reinterpret_cast<void*>(region->end_addr)); |
694 RecordRegionRemovalInBucket(region->call_stack_depth, region->call_stack, | |
695 end_addr - region->start_addr); | |
555 const_cast<Region&>(*region).set_start_addr(end_addr); | 696 const_cast<Region&>(*region).set_start_addr(end_addr); |
556 } else if (start_addr > region->start_addr && | 697 } else if (start_addr > region->start_addr && |
557 start_addr < region->end_addr) { // cut from end | 698 start_addr < region->end_addr) { // cut from end |
558 RAW_VLOG(12, "End-chopping region %p..%p", | 699 RAW_VLOG(12, "End-chopping region %p..%p", |
559 reinterpret_cast<void*>(region->start_addr), | 700 reinterpret_cast<void*>(region->start_addr), |
560 reinterpret_cast<void*>(region->end_addr)); | 701 reinterpret_cast<void*>(region->end_addr)); |
702 RecordRegionRemovalInBucket(region->call_stack_depth, region->call_stack, | |
703 region->end_addr - start_addr); | |
561 // Can't just modify region->end_addr (it's the sorting key): | 704 // Can't just modify region->end_addr (it's the sorting key): |
562 Region r = *region; | 705 Region r = *region; |
563 r.set_end_addr(start_addr); | 706 r.set_end_addr(start_addr); |
564 RegionSet::iterator d = region; | 707 RegionSet::iterator d = region; |
565 ++region; | 708 ++region; |
566 // It's safe to erase before inserting since r is independent of *d: | 709 // It's safe to erase before inserting since r is independent of *d: |
567 // r contains an own copy of the call stack: | 710 // r contains an own copy of the call stack: |
568 regions_->erase(d); | 711 regions_->erase(d); |
569 InsertRegionLocked(r); | 712 InsertRegionLocked(r); |
570 continue; | 713 continue; |
571 } | 714 } |
572 ++region; | 715 ++region; |
573 } | 716 } |
574 RAW_VLOG(12, "Removed region %p..%p; have %"PRIuS" regions", | 717 RAW_VLOG(12, "Removed region %p..%p; have %"PRIuS" regions", |
575 reinterpret_cast<void*>(start_addr), | 718 reinterpret_cast<void*>(start_addr), |
576 reinterpret_cast<void*>(end_addr), | 719 reinterpret_cast<void*>(end_addr), |
577 regions_->size()); | 720 regions_->size()); |
578 if (VLOG_IS_ON(12)) LogAllLocked(); | 721 if (VLOG_IS_ON(12)) LogAllLocked(); |
579 unmap_size_ += size; | 722 unmap_size_ += size; |
580 Unlock(); | 723 Unlock(); |
581 } | 724 } |
582 | 725 |
726 void MemoryRegionMap::RecordRegionRemovalInBucket(int depth, | |
727 const void* const stack[], | |
728 size_t size) { | |
729 if (bucket_table_ == NULL) return; | |
730 | |
Alexander Potapenko
2013/03/07 14:50:52
I suggest to remove this newline since the functio
Dai Mikurube (NOT FULLTIME)
2013/03/07 17:14:24
Done.
| |
731 Bucket* b = GetBucket(depth, stack); | |
732 ++b->frees; | |
733 b->free_size += size; | |
734 } | |
735 | |
583 void MemoryRegionMap::MmapHook(const void* result, | 736 void MemoryRegionMap::MmapHook(const void* result, |
584 const void* start, size_t size, | 737 const void* start, size_t size, |
585 int prot, int flags, | 738 int prot, int flags, |
586 int fd, off_t offset) { | 739 int fd, off_t offset) { |
587 // TODO(maxim): replace all 0x%"PRIxS" by %p when RAW_VLOG uses a safe | 740 // TODO(maxim): replace all 0x%"PRIxS" by %p when RAW_VLOG uses a safe |
588 // snprintf reimplementation that does not malloc to pretty-print NULL | 741 // snprintf reimplementation that does not malloc to pretty-print NULL |
589 RAW_VLOG(10, "MMap = 0x%"PRIxPTR" of %"PRIuS" at %"PRIu64" " | 742 RAW_VLOG(10, "MMap = 0x%"PRIxPTR" of %"PRIuS" at %"PRIu64" " |
590 "prot %d flags %d fd %d offs %"PRId64, | 743 "prot %d flags %d fd %d offs %"PRId64, |
591 reinterpret_cast<uintptr_t>(result), size, | 744 reinterpret_cast<uintptr_t>(result), size, |
592 reinterpret_cast<uint64>(start), prot, flags, fd, | 745 reinterpret_cast<uint64>(start), prot, flags, fd, |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
643 r != regions_->end(); ++r) { | 796 r != regions_->end(); ++r) { |
644 RAW_LOG(INFO, "Memory region 0x%"PRIxPTR"..0x%"PRIxPTR" " | 797 RAW_LOG(INFO, "Memory region 0x%"PRIxPTR"..0x%"PRIxPTR" " |
645 "from 0x%"PRIxPTR" stack=%d", | 798 "from 0x%"PRIxPTR" stack=%d", |
646 r->start_addr, r->end_addr, r->caller(), r->is_stack); | 799 r->start_addr, r->end_addr, r->caller(), r->is_stack); |
647 RAW_CHECK(previous < r->end_addr, "wow, we messed up the set order"); | 800 RAW_CHECK(previous < r->end_addr, "wow, we messed up the set order"); |
648 // this must be caused by uncontrolled recursive operations on regions_ | 801 // this must be caused by uncontrolled recursive operations on regions_ |
649 previous = r->end_addr; | 802 previous = r->end_addr; |
650 } | 803 } |
651 RAW_LOG(INFO, "End of regions list"); | 804 RAW_LOG(INFO, "End of regions list"); |
652 } | 805 } |
OLD | NEW |