Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(124)

Side by Side Diff: third_party/tcmalloc/chromium/src/deep-heap-profile.cc

Issue 13299002: Fix MMAP_LIST in dumps by deep-heap-profile again. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « third_party/tcmalloc/chromium/src/deep-heap-profile.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 <algorithm>
14 #include <fcntl.h> 14 #include <fcntl.h>
15 #include <sys/stat.h> 15 #include <sys/stat.h>
16 #include <sys/types.h> 16 #include <sys/types.h>
17 #ifdef HAVE_UNISTD_H 17 #ifdef HAVE_UNISTD_H
18 #include <unistd.h> // for getpagesize and getpid 18 #include <unistd.h> // for getpagesize and getpid
19 #endif // HAVE_UNISTD_H 19 #endif // HAVE_UNISTD_H
20 20
21 #include "base/cycleclock.h" 21 #include "base/cycleclock.h"
22 #include "base/sysinfo.h" 22 #include "base/sysinfo.h"
23 #include "internal_logging.h" // for ASSERT, etc 23 #include "internal_logging.h" // for ASSERT, etc
24 #include "memory_region_map.h"
25 24
26 static const int kProfilerBufferSize = 1 << 20; 25 static const int kProfilerBufferSize = 1 << 20;
27 static const int kHashTableSize = 179999; // Same as heap-profile-table.cc. 26 static const int kHashTableSize = 179999; // Same as heap-profile-table.cc.
28 27
29 static const int PAGEMAP_BYTES = 8; 28 static const int PAGEMAP_BYTES = 8;
30 static const uint64 MAX_ADDRESS = kuint64max; 29 static const uint64 MAX_ADDRESS = kuint64max;
31 30
32 // Tag strings in heap profile dumps. 31 // Tag strings in heap profile dumps.
33 static const char kProfileHeader[] = "heap profile: "; 32 static const char kProfileHeader[] = "heap profile: ";
34 static const char kProfileVersion[] = "DUMP_DEEP_6"; 33 static const char kProfileVersion[] = "DUMP_DEEP_6";
(...skipping 560 matching lines...) Expand 10 before | Expand all | Expand 10 after
595 void DeepHeapProfile::RegionStats::Unparse(const char* name, 594 void DeepHeapProfile::RegionStats::Unparse(const char* name,
596 TextBuffer* buffer) { 595 TextBuffer* buffer) {
597 buffer->AppendString(name, 25); 596 buffer->AppendString(name, 25);
598 buffer->AppendChar(' '); 597 buffer->AppendChar(' ');
599 buffer->AppendLong(virtual_bytes_, 12); 598 buffer->AppendLong(virtual_bytes_, 12);
600 buffer->AppendChar(' '); 599 buffer->AppendChar(' ');
601 buffer->AppendLong(committed_bytes_, 12); 600 buffer->AppendLong(committed_bytes_, 12);
602 buffer->AppendString("\n", 0); 601 buffer->AppendString("\n", 0);
603 } 602 }
604 603
604 // Snapshots all virtual memory mappging stats by merging mmap(2) records from
605 // MemoryRegionMap and /proc/maps, the OS-level memory mapping information.
606 // Memory regions described in /proc/maps, but which are not created by mmap,
607 // are accounted as "unhooked" memory regions.
608 //
609 // This function assumes that every memory region created by mmap is covered
610 // by VMA(s) described in /proc/maps except for http://crbug.com/189114.
611 // Note that memory regions created with mmap don't align with borders of VMAs
612 // in /proc/maps. In other words, a memory region by mmap can cut across many
613 // VMAs. Also, of course a VMA can include many memory regions by mmap.
614 // It means that the following situation happens:
615 //
616 // => Virtual address
617 // <----- VMA #1 -----><----- VMA #2 ----->...<----- VMA #3 -----><- VMA #4 ->
618 // ..< mmap #1 >.<- mmap #2 -><- mmap #3 ->...<- mmap #4 ->..<-- mmap #5 -->..
619 //
620 // It can happen easily as permission can be changed by mprotect(2) for a part
621 // of a memory region. A change in permission splits VMA(s).
622 //
623 // To deal with the situation, this function iterates over MemoryRegionMap and
624 // /proc/maps independently. The iterator for MemoryRegionMap is initialized
625 // at the top outside the loop for /proc/maps, and it goes forward inside the
626 // loop while comparing their addresses.
627 //
605 // TODO(dmikurube): Eliminate dynamic memory allocation caused by snprintf. 628 // TODO(dmikurube): Eliminate dynamic memory allocation caused by snprintf.
606 void DeepHeapProfile::GlobalStats::SnapshotMaps( 629 void DeepHeapProfile::GlobalStats::SnapshotMaps(
607 const MemoryResidenceInfoGetterInterface* memory_residence_info_getter, 630 const MemoryResidenceInfoGetterInterface* memory_residence_info_getter,
608 DeepHeapProfile* deep_profile, 631 DeepHeapProfile* deep_profile,
609 TextBuffer* mmap_dump_buffer) { 632 TextBuffer* mmap_dump_buffer) {
610 MemoryRegionMap::LockHolder lock_holder; 633 MemoryRegionMap::LockHolder lock_holder;
611 ProcMapsIterator::Buffer procmaps_iter_buffer; 634 ProcMapsIterator::Buffer procmaps_iter_buffer;
612 ProcMapsIterator procmaps_iter(0, &procmaps_iter_buffer); 635 ProcMapsIterator procmaps_iter(0, &procmaps_iter_buffer);
613 uint64 first_address, last_address, offset; 636 uint64 vma_start_addr, vma_last_addr, offset;
614 int64 inode; 637 int64 inode;
615 char* flags; 638 char* flags;
616 char* filename; 639 char* filename;
617 enum MapsRegionType type; 640 enum MapsRegionType type;
618 for (int i = 0; i < NUMBER_OF_MAPS_REGION_TYPES; ++i) { 641 for (int i = 0; i < NUMBER_OF_MAPS_REGION_TYPES; ++i) {
619 all_[i].Initialize(); 642 all_[i].Initialize();
620 unhooked_[i].Initialize(); 643 unhooked_[i].Initialize();
621 } 644 }
622 profiled_mmap_.Initialize(); 645 profiled_mmap_.Initialize();
623 646
624 MemoryRegionMap::RegionIterator mmap_iter = 647 MemoryRegionMap::RegionIterator mmap_iter =
625 MemoryRegionMap::BeginRegionLocked(); 648 MemoryRegionMap::BeginRegionLocked();
649 DeepBucket* deep_bucket = GetInformationOfMemoryRegion(
650 mmap_iter, memory_residence_info_getter, deep_profile);
626 651
627 while (procmaps_iter.Next(&first_address, &last_address, 652 while (procmaps_iter.Next(&vma_start_addr, &vma_last_addr,
628 &flags, &offset, &inode, &filename)) { 653 &flags, &offset, &inode, &filename)) {
629 if (mmap_dump_buffer) { 654 if (mmap_dump_buffer) {
630 char buffer[1024]; 655 char buffer[1024];
631 int written = procmaps_iter.FormatLine(buffer, sizeof(buffer), 656 int written = procmaps_iter.FormatLine(buffer, sizeof(buffer),
632 first_address, last_address, flags, 657 vma_start_addr, vma_last_addr,
633 offset, inode, filename, 0); 658 flags, offset, inode, filename, 0);
634 mmap_dump_buffer->AppendString(buffer, 0); 659 mmap_dump_buffer->AppendString(buffer, 0);
635 } 660 }
636 661
637 // 'last_address' should be the last inclusive address of the region. 662 // 'vma_last_addr' should be the last inclusive address of the region.
638 last_address -= 1; 663 vma_last_addr -= 1;
639 if (strcmp("[vsyscall]", filename) == 0) { 664 if (strcmp("[vsyscall]", filename) == 0) {
640 continue; // Reading pagemap will fail in [vsyscall]. 665 continue; // Reading pagemap will fail in [vsyscall].
641 } 666 }
642 667
643 type = ABSENT; 668 type = ABSENT;
644 if (filename[0] == '/') { 669 if (filename[0] == '/') {
645 if (flags[2] == 'x') 670 if (flags[2] == 'x')
646 type = FILE_EXEC; 671 type = FILE_EXEC;
647 else 672 else
648 type = FILE_NONEXEC; 673 type = FILE_NONEXEC;
649 } else if (filename[0] == '\0' || filename[0] == '\n') { 674 } else if (filename[0] == '\0' || filename[0] == '\n') {
650 type = ANONYMOUS; 675 type = ANONYMOUS;
651 } else if (strcmp(filename, "[stack]") == 0) { 676 } else if (strcmp(filename, "[stack]") == 0) {
652 type = STACK; 677 type = STACK;
653 } else { 678 } else {
654 type = OTHER; 679 type = OTHER;
655 } 680 }
656 all_[type].Record( 681 all_[type].Record(
657 memory_residence_info_getter, first_address, last_address); 682 memory_residence_info_getter, vma_start_addr, vma_last_addr);
658 683
659 // TODO(dmikurube): Stop double-counting pagemap. 684 // TODO(dmikurube): Stop double-counting pagemap.
660 // Counts unhooked memory regions in /proc/<pid>/maps.
661 if (MemoryRegionMap::IsRecordingLocked()) { 685 if (MemoryRegionMap::IsRecordingLocked()) {
662 // It assumes that every mmap'ed region is included in one maps line. 686 uint64 cursor = vma_start_addr;
663 uint64 cursor = first_address;
664 bool first = true; 687 bool first = true;
665 688
689 // Iterates over MemoryRegionMap until the iterator moves out of the VMA.
666 do { 690 do {
667 Bucket* bucket = NULL;
668 DeepBucket* deep_bucket = NULL;
669 if (!first) { 691 if (!first) {
670 size_t committed = deep_profile->memory_residence_info_getter_->
671 CommittedSize(mmap_iter->start_addr, mmap_iter->end_addr - 1);
672 // TODO(dmikurube): Store a reference to the bucket in region.
673 Bucket* bucket = MemoryRegionMap::GetBucket(
674 mmap_iter->call_stack_depth, mmap_iter->call_stack);
675 DeepBucket* deep_bucket = NULL;
676 if (bucket != NULL) {
677 deep_bucket = deep_profile->deep_table_.Lookup(
678 bucket,
679 #if defined(TYPE_PROFILING)
680 NULL, // No type information for mmap'ed memory regions.
681 #endif
682 /* is_mmap */ true);
683 }
684
685 if (deep_bucket != NULL)
686 deep_bucket->committed_size += committed;
687 profiled_mmap_.AddToVirtualBytes(
688 mmap_iter->end_addr - mmap_iter->start_addr);
689 profiled_mmap_.AddToCommittedBytes(committed);
690
691 cursor = mmap_iter->end_addr; 692 cursor = mmap_iter->end_addr;
692 ++mmap_iter; 693 ++mmap_iter;
693 // Don't break here even if mmap_iter == EndRegionLocked(). 694 // Don't break here even if mmap_iter == EndRegionLocked().
695
696 if (mmap_iter != MemoryRegionMap::EndRegionLocked()) {
697 deep_bucket = GetInformationOfMemoryRegion(
698 mmap_iter, memory_residence_info_getter, deep_profile);
699 }
694 } 700 }
695 first = false; 701 first = false;
696 702
697 uint64 last_address_of_unhooked; 703 uint64 last_address_of_unhooked;
698 // If the next mmap entry is away from the current maps line. 704 // If the next mmap entry is away from the current VMA.
699 if (mmap_iter == MemoryRegionMap::EndRegionLocked() || 705 if (mmap_iter == MemoryRegionMap::EndRegionLocked() ||
700 mmap_iter->start_addr > last_address) { 706 mmap_iter->start_addr > vma_last_addr) {
701 last_address_of_unhooked = last_address; 707 last_address_of_unhooked = vma_last_addr;
702 } else { 708 } else {
703 last_address_of_unhooked = mmap_iter->start_addr - 1; 709 last_address_of_unhooked = mmap_iter->start_addr - 1;
704 } 710 }
705 711
706 if (last_address_of_unhooked + 1 > cursor) { 712 if (last_address_of_unhooked + 1 > cursor) {
707 RAW_CHECK(cursor >= first_address, 713 RAW_CHECK(cursor >= vma_start_addr,
708 "Wrong calculation for unhooked"); 714 "Wrong calculation for unhooked");
709 RAW_CHECK(last_address_of_unhooked <= last_address, 715 RAW_CHECK(last_address_of_unhooked <= vma_last_addr,
710 "Wrong calculation for unhooked"); 716 "Wrong calculation for unhooked");
711 uint64 committed_size = unhooked_[type].Record( 717 uint64 committed_size = unhooked_[type].Record(
712 memory_residence_info_getter, 718 memory_residence_info_getter,
713 cursor, 719 cursor,
714 last_address_of_unhooked); 720 last_address_of_unhooked);
715 if (mmap_dump_buffer) { 721 if (mmap_dump_buffer) {
716 mmap_dump_buffer->AppendString(" ", 0); 722 mmap_dump_buffer->AppendString(" ", 0);
717 mmap_dump_buffer->AppendPtr(cursor, 0); 723 mmap_dump_buffer->AppendPtr(cursor, 0);
718 mmap_dump_buffer->AppendString(" - ", 0); 724 mmap_dump_buffer->AppendString(" - ", 0);
719 mmap_dump_buffer->AppendPtr(last_address_of_unhooked + 1, 0); 725 mmap_dump_buffer->AppendPtr(last_address_of_unhooked + 1, 0);
720 mmap_dump_buffer->AppendString(" unhooked ", 0); 726 mmap_dump_buffer->AppendString(" unhooked ", 0);
721 mmap_dump_buffer->AppendString(kMapsRegionTypeDict[type], 0); 727 mmap_dump_buffer->AppendString(kMapsRegionTypeDict[type], 0);
722 mmap_dump_buffer->AppendString(" ", 0); 728 mmap_dump_buffer->AppendString(" ", 0);
723 mmap_dump_buffer->AppendInt64(committed_size, 0); 729 mmap_dump_buffer->AppendInt64(committed_size, 0);
724 mmap_dump_buffer->AppendString("\n", 0); 730 mmap_dump_buffer->AppendString("\n", 0);
725 } 731 }
726 cursor = last_address_of_unhooked + 1; 732 cursor = last_address_of_unhooked + 1;
727 } 733 }
728 734
729 if (mmap_iter != MemoryRegionMap::EndRegionLocked() && 735 if (mmap_iter != MemoryRegionMap::EndRegionLocked() &&
730 mmap_iter->start_addr <= last_address && 736 mmap_iter->start_addr <= vma_last_addr &&
731 mmap_dump_buffer) { 737 mmap_dump_buffer) {
732 bool trailing = mmap_iter->start_addr < first_address; 738 bool trailing = mmap_iter->start_addr < vma_start_addr;
733 bool continued = mmap_iter->end_addr - 1 > last_address; 739 bool continued = mmap_iter->end_addr - 1 > vma_last_addr;
734 mmap_dump_buffer->AppendString(trailing ? " (" : " ", 0); 740 mmap_dump_buffer->AppendString(trailing ? " (" : " ", 0);
735 mmap_dump_buffer->AppendPtr(mmap_iter->start_addr, 0); 741 mmap_dump_buffer->AppendPtr(mmap_iter->start_addr, 0);
736 mmap_dump_buffer->AppendString(trailing ? ")" : " ", 0); 742 mmap_dump_buffer->AppendString(trailing ? ")" : " ", 0);
737 mmap_dump_buffer->AppendString("-", 0); 743 mmap_dump_buffer->AppendString("-", 0);
738 mmap_dump_buffer->AppendString(continued ? "(" : " ", 0); 744 mmap_dump_buffer->AppendString(continued ? "(" : " ", 0);
739 mmap_dump_buffer->AppendPtr(mmap_iter->end_addr, 0); 745 mmap_dump_buffer->AppendPtr(mmap_iter->end_addr, 0);
740 mmap_dump_buffer->AppendString(continued ? ")" : " ", 0); 746 mmap_dump_buffer->AppendString(continued ? ")" : " ", 0);
741 mmap_dump_buffer->AppendString(" hooked ", 0); 747 mmap_dump_buffer->AppendString(" hooked ", 0);
742 mmap_dump_buffer->AppendString(kMapsRegionTypeDict[type], 0); 748 mmap_dump_buffer->AppendString(kMapsRegionTypeDict[type], 0);
743 mmap_dump_buffer->AppendString(" @ ", 0); 749 mmap_dump_buffer->AppendString(" @ ", 0);
744 if (deep_bucket != NULL) { 750 if (deep_bucket != NULL) {
745 mmap_dump_buffer->AppendInt(deep_bucket->id, 0); 751 mmap_dump_buffer->AppendInt(deep_bucket->id, 0);
746 } else { 752 } else {
747 mmap_dump_buffer->AppendInt(0, 0); 753 mmap_dump_buffer->AppendInt(0, 0);
748 } 754 }
749 mmap_dump_buffer->AppendString("\n", 0); 755 mmap_dump_buffer->AppendString("\n", 0);
750 } 756 }
751 } while (mmap_iter != MemoryRegionMap::EndRegionLocked() && 757 } while (mmap_iter != MemoryRegionMap::EndRegionLocked() &&
752 mmap_iter->end_addr - 1 <= last_address); 758 mmap_iter->end_addr - 1 <= vma_last_addr);
753 } 759 }
754 } 760 }
755 761
756 // TODO(dmikurube): Investigate and fix http://crbug.com/189114. 762 // TODO(dmikurube): Investigate and fix http://crbug.com/189114.
757 // 763 //
758 // The total committed memory usage in all_ (from /proc/<pid>/maps) is 764 // The total committed memory usage in all_ (from /proc/<pid>/maps) is
759 // sometimes smaller than the sum of the committed mmap'ed addresses and 765 // sometimes smaller than the sum of the committed mmap'ed addresses and
760 // unhooked regions. Within our observation, the difference was only 4KB 766 // unhooked regions. Within our observation, the difference was only 4KB
761 // in committed usage, zero in reserved virtual addresses 767 // in committed usage, zero in reserved virtual addresses
762 // 768 //
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
850 alloc_value->bucket(), 856 alloc_value->bucket(),
851 #if defined(TYPE_PROFILING) 857 #if defined(TYPE_PROFILING)
852 LookupType(pointer), 858 LookupType(pointer),
853 #endif 859 #endif
854 /* is_mmap */ false); 860 /* is_mmap */ false);
855 deep_bucket->committed_size += committed; 861 deep_bucket->committed_size += committed;
856 deep_profile->stats_.profiled_malloc_.AddToVirtualBytes(alloc_value->bytes); 862 deep_profile->stats_.profiled_malloc_.AddToVirtualBytes(alloc_value->bytes);
857 deep_profile->stats_.profiled_malloc_.AddToCommittedBytes(committed); 863 deep_profile->stats_.profiled_malloc_.AddToCommittedBytes(committed);
858 } 864 }
859 865
866 DeepHeapProfile::DeepBucket*
867 DeepHeapProfile::GlobalStats::GetInformationOfMemoryRegion(
868 const MemoryRegionMap::RegionIterator& mmap_iter,
869 const MemoryResidenceInfoGetterInterface* memory_residence_info_getter,
870 DeepHeapProfile* deep_profile) {
871 size_t committed = deep_profile->memory_residence_info_getter_->
872 CommittedSize(mmap_iter->start_addr, mmap_iter->end_addr - 1);
873
874 // TODO(dmikurube): Store a reference to the bucket in region.
875 Bucket* bucket = MemoryRegionMap::GetBucket(
876 mmap_iter->call_stack_depth, mmap_iter->call_stack);
877 DeepBucket* deep_bucket = NULL;
878 if (bucket != NULL) {
879 deep_bucket = deep_profile->deep_table_.Lookup(
880 bucket,
881 #if defined(TYPE_PROFILING)
882 NULL, // No type information for memory regions by mmap.
883 #endif
884 /* is_mmap */ true);
885 if (deep_bucket != NULL)
886 deep_bucket->committed_size += committed;
887 }
888
889 profiled_mmap_.AddToVirtualBytes(
890 mmap_iter->end_addr - mmap_iter->start_addr);
891 profiled_mmap_.AddToCommittedBytes(committed);
892
893 return deep_bucket;
894 }
895
860 // static 896 // static
861 void DeepHeapProfile::WriteProcMaps(const char* prefix, 897 void DeepHeapProfile::WriteProcMaps(const char* prefix,
862 int buffer_size, 898 int buffer_size,
863 char raw_buffer[]) { 899 char raw_buffer[]) {
864 char filename[100]; 900 char filename[100];
865 snprintf(filename, sizeof(filename), 901 snprintf(filename, sizeof(filename),
866 "%s.%05d.maps", prefix, static_cast<int>(getpid())); 902 "%s.%05d.maps", prefix, static_cast<int>(getpid()));
867 903
868 RawFD fd = RawOpenForWriting(filename); 904 RawFD fd = RawOpenForWriting(filename);
869 RAW_DCHECK(fd != kIllegalRawFD, ""); 905 RAW_DCHECK(fd != kIllegalRawFD, "");
(...skipping 14 matching lines...) Expand all
884 } 920 }
885 921
886 DeepHeapProfile::~DeepHeapProfile() { 922 DeepHeapProfile::~DeepHeapProfile() {
887 } 923 }
888 924
889 int DeepHeapProfile::FillOrderedProfile(char raw_buffer[], int buffer_size) { 925 int DeepHeapProfile::FillOrderedProfile(char raw_buffer[], int buffer_size) {
890 return heap_profile_->FillOrderedProfile(raw_buffer, buffer_size); 926 return heap_profile_->FillOrderedProfile(raw_buffer, buffer_size);
891 } 927 }
892 928
893 #endif // DEEP_HEAP_PROFILE 929 #endif // DEEP_HEAP_PROFILE
OLDNEW
« no previous file with comments | « third_party/tcmalloc/chromium/src/deep-heap-profile.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698