OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // --- | 5 // --- |
6 // Author: Sainbayar Sukhbaatar | 6 // Author: Sainbayar Sukhbaatar |
7 // Dai Mikurube | 7 // Dai Mikurube |
8 // | 8 // |
9 | 9 |
10 #include "deep-heap-profile.h" | 10 #include "deep-heap-profile.h" |
11 | 11 |
12 #ifdef DEEP_HEAP_PROFILE | 12 #ifdef DEEP_HEAP_PROFILE |
13 #include <algorithm> | |
13 #include <fcntl.h> | 14 #include <fcntl.h> |
14 #include <sys/stat.h> | 15 #include <sys/stat.h> |
15 #include <sys/types.h> | 16 #include <sys/types.h> |
16 #ifdef HAVE_UNISTD_H | 17 #ifdef HAVE_UNISTD_H |
17 #include <unistd.h> // for getpagesize and getpid | 18 #include <unistd.h> // for getpagesize and getpid |
18 #endif // HAVE_UNISTD_H | 19 #endif // HAVE_UNISTD_H |
19 | 20 |
20 #include "base/cycleclock.h" | 21 #include "base/cycleclock.h" |
21 #include "base/sysinfo.h" | 22 #include "base/sysinfo.h" |
22 | 23 |
23 static const int kProfilerBufferSize = 1 << 20; | 24 static const int kProfilerBufferSize = 1 << 20; |
24 static const int kHashTableSize = 179999; // The same as heap-profile-table.cc. | 25 static const int kHashTableSize = 179999; // The same as heap-profile-table.cc. |
25 | 26 |
26 static const int PAGEMAP_BYTES = 8; | 27 static const int PAGEMAP_BYTES = 8; |
27 static const uint64 MAX_ADDRESS = kuint64max; | 28 static const uint64 MAX_ADDRESS = kuint64max; |
28 | 29 |
29 // Header strings of the dumped heap profile. | 30 // Header strings of the dumped heap profile. |
30 static const char kProfileHeader[] = "heap profile: "; | 31 static const char kProfileHeader[] = "heap profile: "; |
31 static const char kProfileVersion[] = "DUMP_DEEP_3"; | 32 static const char kProfileVersion[] = "DUMP_DEEP_4"; |
32 static const char kGlobalStatsHeader[] = "GLOBAL_STATS:\n"; | 33 static const char kGlobalStatsHeader[] = "GLOBAL_STATS:\n"; |
33 static const char kMMapStacktraceHeader[] = "MMAP_STACKTRACES:\n"; | 34 static const char kMMapStacktraceHeader[] = "MMAP_STACKTRACES:\n"; |
34 static const char kAllocStacktraceHeader[] = "MALLOC_STACKTRACES:\n"; | 35 static const char kAllocStacktraceHeader[] = "MALLOC_STACKTRACES:\n"; |
35 static const char kProcSelfMapsHeader[] = "\nMAPPED_LIBRARIES:\n"; | 36 static const char kProcSelfMapsHeader[] = "\nMAPPED_LIBRARIES:\n"; |
36 | 37 |
37 static const char kVirtualLabel[] = "virtual"; | 38 static const char kVirtualLabel[] = "virtual"; |
38 static const char kCommittedLabel[] = "committed"; | 39 static const char kCommittedLabel[] = "committed"; |
39 | 40 |
40 DeepHeapProfile::DeepHeapProfile(HeapProfileTable* heap_profile, | 41 DeepHeapProfile::DeepHeapProfile(HeapProfileTable* heap_profile, |
41 const char* prefix) | 42 const char* prefix) |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
82 deep_bucket_map_->Iterate(ClearIsLogged, this); | 83 deep_bucket_map_->Iterate(ClearIsLogged, this); |
83 | 84 |
84 // Write maps into a .maps file with using the global buffer. | 85 // Write maps into a .maps file with using the global buffer. |
85 WriteMapsToFile(filename_prefix_, kProfilerBufferSize, profiler_buffer_); | 86 WriteMapsToFile(filename_prefix_, kProfilerBufferSize, profiler_buffer_); |
86 } | 87 } |
87 | 88 |
88 // Reset committed sizes of buckets. | 89 // Reset committed sizes of buckets. |
89 ResetCommittedSize(heap_profile_->alloc_table_); | 90 ResetCommittedSize(heap_profile_->alloc_table_); |
90 ResetCommittedSize(heap_profile_->mmap_table_); | 91 ResetCommittedSize(heap_profile_->mmap_table_); |
91 | 92 |
92 SnapshotGlobalStatsWithoutMalloc(pagemap_fd_, &stats_); | 93 // Allocate a list for mmap'ed regions. |
93 size_t anonymous_committed = stats_.anonymous.committed_bytes(); | 94 num_mmap_allocations_ = 0; |
95 heap_profile_->mmap_address_map_->Iterate(CountMMap, this); | |
96 mmap_list_length_ = 0; | |
97 mmap_list_ = reinterpret_cast<MMapListEntry*>(heap_profile_->alloc_( | |
98 sizeof(MMapListEntry) * num_mmap_allocations_)); | |
99 | |
100 // Touch all the allocated pages. Touching is required to avoid new page | |
101 // commitment while filling the list in SnapshotGlobalStatsWithoutMalloc. | |
102 for (int i = 0; | |
103 i < num_mmap_allocations_; | |
104 i += getpagesize() / 2 / sizeof(MMapListEntry)) | |
105 mmap_list_[i].first_address = 0; | |
106 mmap_list_[num_mmap_allocations_ - 1].last_address = 0; | |
107 | |
108 SnapshotGlobalStatsWithoutMalloc(pagemap_fd_, &stats_, NULL, 0); | |
109 size_t anonymous_committed = stats_.all[ANONYMOUS].committed_bytes(); | |
94 | 110 |
95 // Note: Try to minimize the number of calls to malloc in the following | 111 // Note: Try to minimize the number of calls to malloc in the following |
96 // region, up until we call WriteBucketsToBucketFile(), near the end of this | 112 // region, up until we call WriteBucketsToBucketFile(), near the end of this |
97 // function. Calling malloc in the region may make a gap between the | 113 // function. Calling malloc in the region may make a gap between the |
98 // observed size and actual memory allocation. The gap is less than or equal | 114 // observed size and actual memory allocation. The gap is less than or equal |
99 // to the size of allocated memory in the region. Calls to malloc won't | 115 // to the size of allocated memory in the region. Calls to malloc won't |
100 // break anything, but can add some noise to the recorded information. | 116 // break anything, but can add some noise to the recorded information. |
101 // TODO(dmikurube): Eliminate dynamic memory allocation caused by snprintf. | 117 // TODO(dmikurube): Eliminate dynamic memory allocation caused by snprintf. |
102 // glibc's snprintf internally allocates memory by alloca normally, but it | 118 // glibc's snprintf internally allocates memory by alloca normally, but it |
103 // allocates memory by malloc if large memory is required. | 119 // allocates memory by malloc if large memory is required. |
104 | 120 |
105 // Record committed sizes. | 121 // Record committed sizes. |
106 SnapshotAllAllocsWithoutMalloc(); | 122 SnapshotAllAllocsWithoutMalloc(); |
107 | 123 |
108 // Check if committed bytes changed during SnapshotAllAllocsWithoutMalloc. | 124 // Check if committed bytes changed during SnapshotAllAllocsWithoutMalloc. |
109 SnapshotGlobalStatsWithoutMalloc(pagemap_fd_, &stats_); | 125 SnapshotGlobalStatsWithoutMalloc(pagemap_fd_, &stats_, |
126 mmap_list_, mmap_list_length_); | |
110 #ifndef NDEBUG | 127 #ifndef NDEBUG |
111 size_t committed_difference = | 128 size_t committed_difference = |
112 stats_.anonymous.committed_bytes() - anonymous_committed; | 129 stats_.all[ANONYMOUS].committed_bytes() - anonymous_committed; |
113 if (committed_difference != 0) { | 130 if (committed_difference != 0) { |
114 RAW_LOG(0, "Difference in committed size: %ld", committed_difference); | 131 RAW_LOG(0, "Difference in committed size: %ld", committed_difference); |
115 } | 132 } |
116 #endif | 133 #endif |
117 | 134 |
118 // Start filling buffer with the ordered profile. | 135 // Start filling buffer with the ordered profile. |
119 int printed = snprintf(buffer, buffer_size, | 136 int printed = snprintf(buffer, buffer_size, |
120 "%s%s\n", kProfileHeader, kProfileVersion); | 137 "%s%s\n", kProfileHeader, kProfileVersion); |
121 if (IsPrintedStringValid(printed, buffer_size, 0)) { | 138 if (IsPrintedStringValid(printed, buffer_size, 0)) { |
122 return 0; | 139 return 0; |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
172 // Fill buffer with stack trace buckets of allocated regions. | 189 // Fill buffer with stack trace buckets of allocated regions. |
173 used_in_buffer = SnapshotBucketTableWithoutMalloc(heap_profile_->alloc_table_, | 190 used_in_buffer = SnapshotBucketTableWithoutMalloc(heap_profile_->alloc_table_, |
174 used_in_buffer, | 191 used_in_buffer, |
175 buffer_size, | 192 buffer_size, |
176 buffer); | 193 buffer); |
177 | 194 |
178 RAW_DCHECK(used_in_buffer < buffer_size, ""); | 195 RAW_DCHECK(used_in_buffer < buffer_size, ""); |
179 | 196 |
180 // Note: Memory snapshots are complete, and malloc may again be used freely. | 197 // Note: Memory snapshots are complete, and malloc may again be used freely. |
181 | 198 |
199 heap_profile_->dealloc_(mmap_list_); | |
200 mmap_list_ = NULL; | |
201 | |
182 // Write the bucket listing into a .bucket file. | 202 // Write the bucket listing into a .bucket file. |
183 WriteBucketsToBucketFile(); | 203 WriteBucketsToBucketFile(); |
184 | 204 |
185 #ifndef NDEBUG | 205 #ifndef NDEBUG |
186 int64 elapsed_cycles = CycleClock::Now() - starting_cycles; | 206 int64 elapsed_cycles = CycleClock::Now() - starting_cycles; |
187 double elapsed_seconds = elapsed_cycles / CyclesPerSecond(); | 207 double elapsed_seconds = elapsed_cycles / CyclesPerSecond(); |
188 RAW_LOG(0, "Time spent on DeepProfiler: %.3f sec\n", elapsed_seconds); | 208 RAW_LOG(0, "Time spent on DeepProfiler: %.3f sec\n", elapsed_seconds); |
189 #endif | 209 #endif |
190 | 210 |
191 return used_in_buffer; | 211 return used_in_buffer; |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
269 int page_size = getpagesize(); | 289 int page_size = getpagesize(); |
270 uint64 page_address = (first_address / page_size) * page_size; | 290 uint64 page_address = (first_address / page_size) * page_size; |
271 size_t committed_size = 0; | 291 size_t committed_size = 0; |
272 | 292 |
273 SeekProcPagemap(pagemap_fd, first_address); | 293 SeekProcPagemap(pagemap_fd, first_address); |
274 | 294 |
275 // Check every page on which the allocation resides. | 295 // Check every page on which the allocation resides. |
276 while (page_address <= last_address) { | 296 while (page_address <= last_address) { |
277 // Read corresponding physical page. | 297 // Read corresponding physical page. |
278 PageState state; | 298 PageState state; |
299 // TODO(dmikurube): Read pagemap in bulk for speed. | |
279 if (ReadProcPagemap(pagemap_fd, &state) == false) { | 300 if (ReadProcPagemap(pagemap_fd, &state) == false) { |
280 // We can't read the last region (e.g vsyscall). | 301 // We can't read the last region (e.g vsyscall). |
281 #ifndef NDEBUG | 302 #ifndef NDEBUG |
282 RAW_LOG(0, "pagemap read failed @ %#llx %"PRId64" bytes", | 303 RAW_LOG(0, "pagemap read failed @ %#llx %"PRId64" bytes", |
283 first_address, last_address - first_address + 1); | 304 first_address, last_address - first_address + 1); |
284 #endif | 305 #endif |
285 return 0; | 306 return 0; |
286 } | 307 } |
287 | 308 |
288 if (state.is_committed) { | 309 if (state.is_committed) { |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
327 RAW_DCHECK(wrote_all, ""); | 348 RAW_DCHECK(wrote_all, ""); |
328 RAW_DCHECK(map_length <= buffer_size, ""); | 349 RAW_DCHECK(map_length <= buffer_size, ""); |
329 RawWrite(maps_fd, buffer, map_length); | 350 RawWrite(maps_fd, buffer, map_length); |
330 RawClose(maps_fd); | 351 RawClose(maps_fd); |
331 } | 352 } |
332 | 353 |
333 // TODO(dmikurube): Eliminate dynamic memory allocation caused by snprintf. | 354 // TODO(dmikurube): Eliminate dynamic memory allocation caused by snprintf. |
334 // ProcMapsIterator uses snprintf internally in construction. | 355 // ProcMapsIterator uses snprintf internally in construction. |
335 // static | 356 // static |
336 void DeepHeapProfile::SnapshotGlobalStatsWithoutMalloc(int pagemap_fd, | 357 void DeepHeapProfile::SnapshotGlobalStatsWithoutMalloc(int pagemap_fd, |
337 GlobalStats* stats) { | 358 GlobalStats* stats, |
359 MMapListEntry* mmap_list, | |
360 int mmap_list_length) { | |
338 ProcMapsIterator::Buffer iterator_buffer; | 361 ProcMapsIterator::Buffer iterator_buffer; |
339 ProcMapsIterator iterator(0, &iterator_buffer); | 362 ProcMapsIterator iterator(0, &iterator_buffer); |
340 uint64 first_address, last_address, offset; | 363 uint64 first_address, last_address, offset; |
341 int64 unused_inode; | 364 int64 unused_inode; |
342 char* flags; | 365 char* flags; |
343 char* filename; | 366 char* filename; |
367 int mmap_list_index = 0; | |
368 enum MapsRegionType type; | |
344 | 369 |
345 stats->total.Initialize(); | 370 for (int i = 0; i < NUMBER_OF_MAPS_REGION_TYPES; ++i) { |
346 stats->file_mapped.Initialize(); | 371 stats->all[i].Initialize(); |
347 stats->anonymous.Initialize(); | 372 stats->nonprofiled[i].Initialize(); |
348 stats->other.Initialize(); | 373 } |
349 | 374 |
350 while (iterator.Next(&first_address, &last_address, | 375 while (iterator.Next(&first_address, &last_address, |
351 &flags, &offset, &unused_inode, &filename)) { | 376 &flags, &offset, &unused_inode, &filename)) { |
352 // 'last_address' should be the last inclusive address of the region. | 377 // 'last_address' should be the last inclusive address of the region. |
353 last_address -= 1; | 378 last_address -= 1; |
354 if (strcmp("[vsyscall]", filename) == 0) { | 379 if (strcmp("[vsyscall]", filename) == 0) { |
355 continue; // Reading pagemap will fail in [vsyscall]. | 380 continue; // Reading pagemap will fail in [vsyscall]. |
356 } | 381 } |
357 | 382 |
358 stats->total.Record(pagemap_fd, first_address, last_address); | 383 type = ABSENT; |
384 if (filename[0] == '/') { | |
385 if (flags[2] == 'x') | |
386 type = FILE_EXEC; | |
387 else | |
388 type = FILE_NONEXEC; | |
389 } else if (filename[0] == '\0' || filename[0] == '\n') { | |
390 type = ANONYMOUS; | |
391 } else if (strcmp(filename, "[stack]") == 0) { | |
392 type = STACK; | |
393 } else { | |
394 type = OTHER; | |
395 } | |
396 stats->all[type].Record(pagemap_fd, first_address, last_address); | |
359 | 397 |
360 if (filename[0] == '/') { | 398 // TODO(dmikurube): Avoid double-counting of pagemap. |
361 stats->file_mapped.Record(pagemap_fd, first_address, last_address); | 399 // Counts nonprofiled memory regions in /proc/<pid>/maps. |
362 } else if (filename[0] == '\0' || filename[0] == '\n') { | 400 if (mmap_list != NULL) { |
363 stats->anonymous.Record(pagemap_fd, first_address, last_address); | 401 // It assumes that every mmap'ed region is included in one maps line. |
364 } else { | 402 uint64 cursor = first_address; |
365 stats->other.Record(pagemap_fd, first_address, last_address); | 403 bool first = true; |
404 | |
405 do { | |
406 if (!first) { | |
407 mmap_list[mmap_list_index].type = type; | |
408 cursor = mmap_list[mmap_list_index].last_address + 1; | |
409 ++mmap_list_index; | |
410 } | |
411 first = false; | |
412 | |
413 uint64 last_address_of_nonprofiled; | |
414 // If the next mmap entry is away from the current maps line. | |
415 if (mmap_list_index >= mmap_list_length || | |
416 mmap_list[mmap_list_index].first_address > last_address) { | |
417 last_address_of_nonprofiled = last_address; | |
418 } else { | |
419 last_address_of_nonprofiled = | |
420 mmap_list[mmap_list_index].first_address - 1; | |
421 } | |
422 | |
423 if (last_address_of_nonprofiled + 1 > cursor) { | |
424 stats->nonprofiled[type].Record( | |
425 pagemap_fd, cursor, last_address_of_nonprofiled); | |
426 cursor = last_address_of_nonprofiled + 1; | |
427 } | |
428 } while (mmap_list_index < mmap_list_length && | |
429 mmap_list[mmap_list_index].last_address <= last_address); | |
366 } | 430 } |
367 } | 431 } |
368 } | 432 } |
369 | 433 |
370 DeepHeapProfile::DeepBucket* DeepHeapProfile::GetDeepBucket(Bucket* bucket) { | 434 DeepHeapProfile::DeepBucket* DeepHeapProfile::GetDeepBucket(Bucket* bucket) { |
371 DeepBucket* found = deep_bucket_map_->FindMutable(bucket); | 435 DeepBucket* found = deep_bucket_map_->FindMutable(bucket); |
372 if (found != NULL) | 436 if (found != NULL) |
373 return found; | 437 return found; |
374 | 438 |
375 DeepBucket created; | 439 DeepBucket created; |
(...skipping 29 matching lines...) Expand all Loading... | |
405 continue; // Skip empty buckets. | 469 continue; // Skip empty buckets. |
406 } | 470 } |
407 const DeepBucket* deep_bucket = GetDeepBucket(bucket); | 471 const DeepBucket* deep_bucket = GetDeepBucket(bucket); |
408 used_in_buffer = UnparseBucket( | 472 used_in_buffer = UnparseBucket( |
409 *deep_bucket, "", used_in_buffer, buffer_size, buffer, NULL); | 473 *deep_bucket, "", used_in_buffer, buffer_size, buffer, NULL); |
410 } | 474 } |
411 } | 475 } |
412 return used_in_buffer; | 476 return used_in_buffer; |
413 } | 477 } |
414 | 478 |
479 // static | |
480 bool DeepHeapProfile::ByFirstAddress(const MMapListEntry& a, | |
481 const MMapListEntry& b) { | |
482 return a.first_address < b.first_address; | |
483 } | |
484 | |
485 // static | |
486 void DeepHeapProfile::CountMMap(const void* pointer, | |
487 AllocValue* alloc_value, | |
488 DeepHeapProfile* deep_profile) { | |
489 ++deep_profile->num_mmap_allocations_; | |
490 } | |
491 | |
415 void DeepHeapProfile::RecordAlloc(const void* pointer, | 492 void DeepHeapProfile::RecordAlloc(const void* pointer, |
416 AllocValue* alloc_value, | 493 AllocValue* alloc_value, |
417 DeepHeapProfile* deep_profile) { | 494 DeepHeapProfile* deep_profile) { |
418 uint64 address = reinterpret_cast<uintptr_t>(pointer); | 495 uint64 address = reinterpret_cast<uintptr_t>(pointer); |
419 size_t committed = GetCommittedSize(deep_profile->pagemap_fd_, | 496 size_t committed = GetCommittedSize(deep_profile->pagemap_fd_, |
420 address, address + alloc_value->bytes - 1); | 497 address, address + alloc_value->bytes - 1); |
421 | 498 |
422 DeepBucket* deep_bucket = deep_profile->GetDeepBucket(alloc_value->bucket()); | 499 DeepBucket* deep_bucket = deep_profile->GetDeepBucket(alloc_value->bucket()); |
423 deep_bucket->committed_size += committed; | 500 deep_bucket->committed_size += committed; |
424 deep_profile->stats_.record_malloc.AddToVirtualBytes(alloc_value->bytes); | 501 deep_profile->stats_.profiled_malloc.AddToVirtualBytes(alloc_value->bytes); |
425 deep_profile->stats_.record_malloc.AddToCommittedBytes(committed); | 502 deep_profile->stats_.profiled_malloc.AddToCommittedBytes(committed); |
426 } | 503 } |
427 | 504 |
428 void DeepHeapProfile::RecordMMap(const void* pointer, | 505 void DeepHeapProfile::RecordMMap(const void* pointer, |
429 AllocValue* alloc_value, | 506 AllocValue* alloc_value, |
430 DeepHeapProfile* deep_profile) { | 507 DeepHeapProfile* deep_profile) { |
431 uint64 address = reinterpret_cast<uintptr_t>(pointer); | 508 uint64 address = reinterpret_cast<uintptr_t>(pointer); |
432 size_t committed = GetCommittedSize(deep_profile->pagemap_fd_, | 509 size_t committed = GetCommittedSize(deep_profile->pagemap_fd_, |
433 address, address + alloc_value->bytes - 1); | 510 address, address + alloc_value->bytes - 1); |
434 | 511 |
435 DeepBucket* deep_bucket = deep_profile->GetDeepBucket(alloc_value->bucket()); | 512 DeepBucket* deep_bucket = deep_profile->GetDeepBucket(alloc_value->bucket()); |
436 deep_bucket->committed_size += committed; | 513 deep_bucket->committed_size += committed; |
437 deep_profile->stats_.record_mmap.AddToVirtualBytes(alloc_value->bytes); | 514 deep_profile->stats_.profiled_mmap.AddToVirtualBytes(alloc_value->bytes); |
438 deep_profile->stats_.record_mmap.AddToCommittedBytes(committed); | 515 deep_profile->stats_.profiled_mmap.AddToCommittedBytes(committed); |
516 | |
517 if (deep_profile->mmap_list_length_ < deep_profile->num_mmap_allocations_) { | |
518 deep_profile->mmap_list_[deep_profile->mmap_list_length_].first_address = | |
519 address; | |
520 deep_profile->mmap_list_[deep_profile->mmap_list_length_].last_address = | |
521 address - 1 + alloc_value->bytes; | |
522 deep_profile->mmap_list_[deep_profile->mmap_list_length_].type = ABSENT; | |
523 ++deep_profile->mmap_list_length_; | |
524 } else { | |
525 RAW_LOG(0, "Unexpected number of mmap entries: %d/%d", | |
526 deep_profile->mmap_list_length_, | |
527 deep_profile->num_mmap_allocations_); | |
528 } | |
439 } | 529 } |
440 | 530 |
441 void DeepHeapProfile::SnapshotAllAllocsWithoutMalloc() { | 531 void DeepHeapProfile::SnapshotAllAllocsWithoutMalloc() { |
442 stats_.record_mmap.Initialize(); | 532 stats_.profiled_mmap.Initialize(); |
443 stats_.record_malloc.Initialize(); | 533 stats_.profiled_malloc.Initialize(); |
444 | 534 |
445 // malloc allocations. | 535 // malloc allocations. |
446 heap_profile_->alloc_address_map_->Iterate(RecordAlloc, this); | 536 heap_profile_->alloc_address_map_->Iterate(RecordAlloc, this); |
447 | 537 |
448 // mmap allocations. | 538 // mmap allocations. |
449 heap_profile_->mmap_address_map_->Iterate(RecordMMap, this); | 539 heap_profile_->mmap_address_map_->Iterate(RecordMMap, this); |
540 std::sort(mmap_list_, mmap_list_ + mmap_list_length_, ByFirstAddress); | |
450 } | 541 } |
451 | 542 |
452 int DeepHeapProfile::FillBucketForBucketFile(const DeepBucket* deep_bucket, | 543 int DeepHeapProfile::FillBucketForBucketFile(const DeepBucket* deep_bucket, |
453 int buffer_size, | 544 int buffer_size, |
454 char buffer[]) { | 545 char buffer[]) { |
455 const Bucket* bucket = deep_bucket->bucket; | 546 const Bucket* bucket = deep_bucket->bucket; |
456 int printed = snprintf(buffer, buffer_size, "%05d", deep_bucket->id); | 547 int printed = snprintf(buffer, buffer_size, "%05d", deep_bucket->id); |
457 if (IsPrintedStringValid(printed, buffer_size, 0)) { | 548 if (IsPrintedStringValid(printed, buffer_size, 0)) { |
458 return 0; | 549 return 0; |
459 } | 550 } |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
552 | 643 |
553 return used_in_buffer; | 644 return used_in_buffer; |
554 } | 645 } |
555 | 646 |
556 int DeepHeapProfile::UnparseRegionStats(const RegionStats* stats, | 647 int DeepHeapProfile::UnparseRegionStats(const RegionStats* stats, |
557 const char* name, | 648 const char* name, |
558 int used_in_buffer, | 649 int used_in_buffer, |
559 int buffer_size, | 650 int buffer_size, |
560 char* buffer) { | 651 char* buffer) { |
561 int printed = snprintf(buffer + used_in_buffer, buffer_size - used_in_buffer, | 652 int printed = snprintf(buffer + used_in_buffer, buffer_size - used_in_buffer, |
562 "%15s %10ld %10ld\n", | 653 "%25s %12ld %12ld\n", |
563 name, stats->virtual_bytes(), | 654 name, stats->virtual_bytes(), |
564 stats->committed_bytes()); | 655 stats->committed_bytes()); |
565 if (IsPrintedStringValid(printed, buffer_size, used_in_buffer)) { | 656 if (IsPrintedStringValid(printed, buffer_size, used_in_buffer)) { |
566 return used_in_buffer; | 657 return used_in_buffer; |
567 } | 658 } |
568 used_in_buffer += printed; | 659 used_in_buffer += printed; |
569 | 660 |
570 return used_in_buffer; | 661 return used_in_buffer; |
571 } | 662 } |
572 | 663 |
573 int DeepHeapProfile::UnparseGlobalStats(int used_in_buffer, | 664 int DeepHeapProfile::UnparseGlobalStats(int used_in_buffer, |
574 int buffer_size, | 665 int buffer_size, |
575 char* buffer) { | 666 char* buffer) { |
576 int printed = snprintf(buffer + used_in_buffer, buffer_size - used_in_buffer, | 667 RegionStats all_total; |
577 "%15s %10s %10s\n", "", | 668 RegionStats nonprofiled_total; |
669 for (int i = 0; i < NUMBER_OF_MAPS_REGION_TYPES; ++i) { | |
670 all_total.AddAnotherRegionStat(stats_.all[i]); | |
671 nonprofiled_total.AddAnotherRegionStat(stats_.nonprofiled[i]); | |
672 } | |
673 int printed = snprintf( | |
674 buffer + used_in_buffer, buffer_size - used_in_buffer, | |
675 "# total (%lu) %c= profiled-mmap (%lu) + nonprofiled-* (%lu)\n", | |
676 all_total.committed_bytes(), | |
677 all_total.committed_bytes() == | |
678 stats_.profiled_mmap.committed_bytes() + | |
679 nonprofiled_total.committed_bytes() ? '=' : '!', | |
680 stats_.profiled_mmap.committed_bytes(), | |
681 nonprofiled_total.committed_bytes()); | |
682 if (IsPrintedStringValid(printed, buffer_size, used_in_buffer)) { | |
683 return used_in_buffer; | |
684 } | |
685 used_in_buffer += printed; | |
686 | |
687 printed = snprintf(buffer + used_in_buffer, buffer_size - used_in_buffer, | |
688 "%25s %12s %12s\n", "", | |
578 kVirtualLabel, kCommittedLabel); | 689 kVirtualLabel, kCommittedLabel); |
579 if (IsPrintedStringValid(printed, buffer_size, used_in_buffer)) { | 690 if (IsPrintedStringValid(printed, buffer_size, used_in_buffer)) { |
580 return used_in_buffer; | 691 return used_in_buffer; |
581 } | 692 } |
582 used_in_buffer += printed; | 693 used_in_buffer += printed; |
583 | 694 |
584 used_in_buffer = UnparseRegionStats(&(stats_.total), "total", | 695 used_in_buffer = UnparseRegionStats(&(all_total), |
585 used_in_buffer, buffer_size, buffer); | 696 "total", used_in_buffer, buffer_size, buffer); |
586 used_in_buffer = UnparseRegionStats(&(stats_.file_mapped), "file mapped", | 697 used_in_buffer = UnparseRegionStats(&(stats_.all[FILE_EXEC]), |
587 used_in_buffer, buffer_size, buffer); | 698 "file-exec", used_in_buffer, buffer_size, buffer); |
588 used_in_buffer = UnparseRegionStats(&(stats_.anonymous), "anonymous", | 699 used_in_buffer = UnparseRegionStats(&(stats_.all[FILE_NONEXEC]), |
589 used_in_buffer, buffer_size, buffer); | 700 "file-nonexec", used_in_buffer, buffer_size, buffer); |
590 used_in_buffer = UnparseRegionStats(&(stats_.other), "other", | 701 used_in_buffer = UnparseRegionStats(&(stats_.all[ANONYMOUS]), |
591 used_in_buffer, buffer_size, buffer); | 702 "anonymous", used_in_buffer, buffer_size, buffer); |
592 used_in_buffer = UnparseRegionStats(&(stats_.record_mmap), "mmap", | 703 used_in_buffer = UnparseRegionStats(&(stats_.all[STACK]), |
593 used_in_buffer, buffer_size, buffer); | 704 "stack", used_in_buffer, buffer_size, buffer); |
594 used_in_buffer = UnparseRegionStats(&(stats_.record_malloc), "tcmalloc", | 705 used_in_buffer = UnparseRegionStats(&(stats_.all[OTHER]), |
595 used_in_buffer, buffer_size, buffer); | 706 "other", used_in_buffer, buffer_size, buffer); |
707 used_in_buffer = UnparseRegionStats(&(nonprofiled_total), | |
708 "nonprofiled-total", used_in_buffer, buffer_size, buffer); | |
709 used_in_buffer = UnparseRegionStats(&(stats_.nonprofiled[ABSENT]), | |
710 "nonprofiled-absent", used_in_buffer, buffer_size, buffer); | |
711 used_in_buffer = UnparseRegionStats(&(stats_.nonprofiled[ANONYMOUS]), | |
712 "nonprofiled-anonymous", used_in_buffer, buffer_size, buffer); | |
713 used_in_buffer = UnparseRegionStats(&(stats_.nonprofiled[FILE_EXEC]), | |
714 "nonprofiled-file-exec", used_in_buffer, buffer_size, buffer); | |
715 used_in_buffer = UnparseRegionStats(&(stats_.nonprofiled[FILE_NONEXEC]), | |
716 "nonprofiled-file-nonexec", used_in_buffer, buffer_size, buffer); | |
717 used_in_buffer = UnparseRegionStats(&(stats_.nonprofiled[STACK]), | |
718 "nonprofiled-stack", used_in_buffer, buffer_size, buffer); | |
719 used_in_buffer = UnparseRegionStats(&(stats_.nonprofiled[OTHER]), | |
720 "nonprofiled-other", used_in_buffer, buffer_size, buffer); | |
721 used_in_buffer = UnparseRegionStats(&(stats_.profiled_mmap), | |
722 "profiled-mmap", used_in_buffer, buffer_size, buffer); | |
723 used_in_buffer = UnparseRegionStats(&(stats_.profiled_malloc), | |
724 "profiled-malloc", used_in_buffer, buffer_size, buffer); | |
Dai Mikurube (NOT FULLTIME)
2012/04/12 12:20:24
This part may be to be considered to simplify.
| |
596 return used_in_buffer; | 725 return used_in_buffer; |
597 } | 726 } |
598 #else // DEEP_HEAP_PROFILE | 727 #else // DEEP_HEAP_PROFILE |
599 | 728 |
600 DeepHeapProfile::DeepHeapProfile(HeapProfileTable* heap_profile, | 729 DeepHeapProfile::DeepHeapProfile(HeapProfileTable* heap_profile, |
601 const char* prefix) | 730 const char* prefix) |
602 : heap_profile_(heap_profile) { | 731 : heap_profile_(heap_profile) { |
603 } | 732 } |
604 | 733 |
605 DeepHeapProfile::~DeepHeapProfile() { | 734 DeepHeapProfile::~DeepHeapProfile() { |
606 } | 735 } |
607 | 736 |
608 int DeepHeapProfile::FillOrderedProfile(char buffer[], int buffer_size) { | 737 int DeepHeapProfile::FillOrderedProfile(char buffer[], int buffer_size) { |
609 return heap_profile_->FillOrderedProfile(buffer, buffer_size); | 738 return heap_profile_->FillOrderedProfile(buffer, buffer_size); |
610 } | 739 } |
611 | 740 |
612 #endif // DEEP_HEAP_PROFILE | 741 #endif // DEEP_HEAP_PROFILE |
OLD | NEW |