Chromium Code Reviews| 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 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 124 | 124 |
| 125 //---------------------------------------------------------------------- | 125 //---------------------------------------------------------------------- |
| 126 | 126 |
| 127 HeapProfileTable::HeapProfileTable(Allocator alloc, | 127 HeapProfileTable::HeapProfileTable(Allocator alloc, |
| 128 DeAllocator dealloc, | 128 DeAllocator dealloc, |
| 129 bool profile_mmap) | 129 bool profile_mmap) |
| 130 : alloc_(alloc), | 130 : alloc_(alloc), |
| 131 dealloc_(dealloc), | 131 dealloc_(dealloc), |
| 132 bucket_table_(NULL), | 132 bucket_table_(NULL), |
| 133 profile_mmap_(profile_mmap), | 133 profile_mmap_(profile_mmap), |
| 134 profile_self_maps_(true), | |
| 134 num_buckets_(0), | 135 num_buckets_(0), |
| 135 address_map_(NULL) { | 136 address_map_(NULL) { |
| 136 // Make a hash table for buckets. | 137 // Make a hash table for buckets. |
| 137 const int table_bytes = kHashTableSize * sizeof(*bucket_table_); | 138 const int table_bytes = kHashTableSize * sizeof(*bucket_table_); |
| 138 bucket_table_ = static_cast<Bucket**>(alloc_(table_bytes)); | 139 bucket_table_ = static_cast<Bucket**>(alloc_(table_bytes)); |
| 139 memset(bucket_table_, 0, table_bytes); | 140 memset(bucket_table_, 0, table_bytes); |
| 140 | 141 |
| 141 // Make an allocation map. | 142 // Make an allocation map. |
| 142 address_map_ = | 143 address_map_ = |
| 143 new(alloc_(sizeof(AllocationMap))) AllocationMap(alloc_, dealloc_); | 144 new(alloc_(sizeof(AllocationMap))) AllocationMap(alloc_, dealloc_); |
| (...skipping 242 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 386 AllocContextInfo info; | 387 AllocContextInfo info; |
| 387 for (int i = 0; i < num_buckets_; ++i) { | 388 for (int i = 0; i < num_buckets_; ++i) { |
| 388 *static_cast<Stats*>(&info) = *static_cast<Stats*>(list[i]); | 389 *static_cast<Stats*>(&info) = *static_cast<Stats*>(list[i]); |
| 389 info.stack_depth = list[i]->depth; | 390 info.stack_depth = list[i]->depth; |
| 390 info.call_stack = list[i]->stack; | 391 info.call_stack = list[i]->stack; |
| 391 callback(info); | 392 callback(info); |
| 392 } | 393 } |
| 393 dealloc_(list); | 394 dealloc_(list); |
| 394 } | 395 } |
| 395 | 396 |
| 397 void HeapProfileTable::DisableProfileSelfMaps() { | |
| 398 profile_self_maps_ = false; | |
| 399 } | |
| 400 | |
| 396 int HeapProfileTable::FillOrderedProfile(char buf[], int size) const { | 401 int HeapProfileTable::FillOrderedProfile(char buf[], int size) const { |
| 397 Bucket** list = MakeSortedBucketList(); | 402 Bucket** list = MakeSortedBucketList(); |
| 398 | 403 |
| 399 // Our file format is "bucket, bucket, ..., bucket, proc_self_maps_info". | 404 int map_length = 0; |
| 400 // In the cases buf is too small, we'd rather leave out the last | 405 char* map_start = NULL; |
| 401 // buckets than leave out the /proc/self/maps info. To ensure that, | 406 // The data from /proc/self/maps is not required for pseudo-stack profiles |
| 402 // we actually print the /proc/self/maps info first, then move it to | 407 // and increases the size of the profile dumps significantly. |
|
Dai Mikurube (NOT FULLTIME)
2013/07/01 05:47:42
Is maps so large? Is large output so serious? I
James Cook
2013/07/01 16:59:16
There's also a problem where attempting to read /p
James Cook
2013/07/01 22:37:16
The GPU process hang is due to the security sandbo
Dai Mikurube (NOT FULLTIME)
2013/07/02 01:39:06
Ah, makes sense. Sorry that I forgot it. In case o
| |
| 403 // the end of the buffer, then write the bucket info into whatever | 408 if (profile_self_maps_) { |
| 404 // is remaining, and then move the maps info one last time to close | 409 // Our file format is "bucket, bucket, ..., bucket, proc_self_maps_info". |
| 405 // any gaps. Whew! | 410 // In the cases buf is too small, we'd rather leave out the last |
| 406 int map_length = snprintf(buf, size, "%s", kProcSelfMapsHeader); | 411 // buckets than leave out the /proc/self/maps info. To ensure that, |
| 407 if (map_length < 0 || map_length >= size) return 0; | 412 // we actually print the /proc/self/maps info first, then move it to |
| 408 bool dummy; // "wrote_all" -- did /proc/self/maps fit in its entirety? | 413 // the end of the buffer, then write the bucket info into whatever |
| 409 map_length += FillProcSelfMaps(buf + map_length, size - map_length, &dummy); | 414 // is remaining, and then move the maps info one last time to close |
| 410 RAW_DCHECK(map_length <= size, ""); | 415 // any gaps. Whew! |
| 411 char* const map_start = buf + size - map_length; // move to end | 416 map_length = snprintf(buf, size, "%s", kProcSelfMapsHeader); |
| 412 memmove(map_start, buf, map_length); | 417 if (map_length < 0 || map_length >= size) return 0; |
| 413 size -= map_length; | 418 bool dummy; // "wrote_all" -- did /proc/self/maps fit in its entirety? |
| 419 map_length += FillProcSelfMaps(buf + map_length, size - map_length, &dummy); | |
| 420 RAW_DCHECK(map_length <= size, ""); | |
| 421 map_start = buf + size - map_length; // move to end | |
| 422 memmove(map_start, buf, map_length); | |
| 423 size -= map_length; | |
| 424 } | |
| 414 | 425 |
| 415 Stats stats; | 426 Stats stats; |
| 416 memset(&stats, 0, sizeof(stats)); | 427 memset(&stats, 0, sizeof(stats)); |
| 417 int bucket_length = snprintf(buf, size, "%s", kProfileHeader); | 428 int bucket_length = snprintf(buf, size, "%s", kProfileHeader); |
| 418 if (bucket_length < 0 || bucket_length >= size) return 0; | 429 if (bucket_length < 0 || bucket_length >= size) return 0; |
| 419 bucket_length = UnparseBucket(total_, buf, bucket_length, size, | 430 bucket_length = UnparseBucket(total_, buf, bucket_length, size, |
| 420 " heapprofile", &stats); | 431 " heapprofile", &stats); |
| 421 | 432 |
| 422 // Dump the mmap list first. | 433 // Dump the mmap list first. |
| 423 if (profile_mmap_) { | 434 if (profile_mmap_) { |
| 424 BufferArgs buffer(buf, bucket_length, size); | 435 BufferArgs buffer(buf, bucket_length, size); |
| 425 MemoryRegionMap::IterateBuckets<BufferArgs*>(DumpBucketIterator, &buffer); | 436 MemoryRegionMap::IterateBuckets<BufferArgs*>(DumpBucketIterator, &buffer); |
| 426 bucket_length = buffer.buflen; | 437 bucket_length = buffer.buflen; |
| 427 } | 438 } |
| 428 | 439 |
| 429 for (int i = 0; i < num_buckets_; i++) { | 440 for (int i = 0; i < num_buckets_; i++) { |
| 430 bucket_length = UnparseBucket(*list[i], buf, bucket_length, size, "", | 441 bucket_length = UnparseBucket(*list[i], buf, bucket_length, size, "", |
| 431 &stats); | 442 &stats); |
| 432 } | 443 } |
| 433 RAW_DCHECK(bucket_length < size, ""); | 444 RAW_DCHECK(bucket_length < size, ""); |
| 434 | 445 |
| 435 dealloc_(list); | 446 dealloc_(list); |
| 436 | 447 |
| 448 if (!profile_self_maps_) | |
| 449 return bucket_length; | |
| 450 | |
| 437 RAW_DCHECK(buf + bucket_length <= map_start, ""); | 451 RAW_DCHECK(buf + bucket_length <= map_start, ""); |
| 438 memmove(buf + bucket_length, map_start, map_length); // close the gap | 452 memmove(buf + bucket_length, map_start, map_length); // close the gap |
| 439 | 453 |
| 440 return bucket_length + map_length; | 454 return bucket_length + map_length; |
| 441 } | 455 } |
| 442 | 456 |
| 443 // static | 457 // static |
| 444 void HeapProfileTable::DumpBucketIterator(const Bucket* bucket, | 458 void HeapProfileTable::DumpBucketIterator(const Bucket* bucket, |
| 445 BufferArgs* args) { | 459 BufferArgs* args) { |
| 446 args->buflen = UnparseBucket(*bucket, args->buf, args->buflen, args->bufsize, | 460 args->buflen = UnparseBucket(*bucket, args->buf, args->buflen, args->bufsize, |
| (...skipping 294 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 741 char* unused) { | 755 char* unused) { |
| 742 // Perhaps also log the allocation stack trace (unsymbolized) | 756 // Perhaps also log the allocation stack trace (unsymbolized) |
| 743 // on this line in case somebody finds it useful. | 757 // on this line in case somebody finds it useful. |
| 744 RAW_LOG(ERROR, "leaked %"PRIuS" byte object %p", v->bytes, ptr); | 758 RAW_LOG(ERROR, "leaked %"PRIuS" byte object %p", v->bytes, ptr); |
| 745 } | 759 } |
| 746 | 760 |
| 747 void HeapProfileTable::Snapshot::ReportIndividualObjects() { | 761 void HeapProfileTable::Snapshot::ReportIndividualObjects() { |
| 748 char unused; | 762 char unused; |
| 749 map_.Iterate(ReportObject, &unused); | 763 map_.Iterate(ReportObject, &unused); |
| 750 } | 764 } |
| OLD | NEW |