Index: third_party/tcmalloc/chromium/src/deep-heap-profile.h |
diff --git a/third_party/tcmalloc/chromium/src/deep-heap-profile.h b/third_party/tcmalloc/chromium/src/deep-heap-profile.h |
new file mode 100644 |
index 0000000000000000000000000000000000000000..6638d32010df4f560dfc50507b7529d3bb34d777 |
--- /dev/null |
+++ b/third_party/tcmalloc/chromium/src/deep-heap-profile.h |
@@ -0,0 +1,258 @@ |
+// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+// --- |
+// Author: Sainbayar Sukhbaatar |
+// Dai Mikurube |
+// |
+// This file contains a class DeepHeapProfile and its public function |
+// DeepHeapProfile::FillOrderedProfile() which works as an alternative of |
+// HeapProfileTable::FillOrderedProfile(). |
+// |
+// DeepHeapProfile::FillOrderedProfile() dumps more detailed information about |
+// heap usage, which includes OS-level information such as whether the memory |
+// block is actually in memory, or not. DeepHeapProfile::FillOrderedProfile() |
+// uses logged data in HeapProfileTable as one of its data sources. |
+// DeepHeapProfile works only when its FillOrderedProfile() is called. It has |
+// overhead when dumping, but no overhead when logging. |
+// |
+// It currently works only on Linux. It just delegates to HeapProfileTable in |
+// non-Linux environments. |
+ |
+ |
+#ifndef BASE_DEEP_HEAP_PROFILE_H_ |
+#define BASE_DEEP_HEAP_PROFILE_H_ |
+ |
+#include "config.h" |
+ |
+#if defined(__linux__) |
+#define DEEP_HEAP_PROFILE 1 |
+#endif |
+ |
+#include "addressmap-inl.h" |
+#include "heap-profile-table.h" |
+ |
+class DeepHeapProfile { |
+ public: |
+ typedef HeapProfileTable::Bucket Bucket; |
+ typedef HeapProfileTable::AllocationMap AllocationMap; |
+ typedef HeapProfileTable::AllocValue AllocValue; |
+ typedef HeapProfileTable::Stats Stats; |
+ |
+ // Construct a DeepHeapProfile instance. It works as a wrapper of |
+ // HeapProfileTable. |
+ // |
+ // |heap_profile| is a pointer to HeapProfileTable. DeepHeapProfile reads |
+ // data in |heap_profile| and forwards operations to |heap_profile| if |
+ // DeepHeapProfile is not available (non-Linux). |
+ // |prefix| is a prefix of dumped file names. |
+ DeepHeapProfile(HeapProfileTable* heap_profile, const char* prefix); |
+ ~DeepHeapProfile(); |
+ |
+ // Fill deep profile data into |buffer| of |size|, and return the actual |
+ // size occupied by the dump in |buffer|. It works as an alternative |
+ // of HeapProfileTable::FillOrderedProfile. |
+ // |
+ // The profile buckets are dumped in the decreasing order of currently |
+ // allocated bytes. We do not provision for 0-terminating |buffer|. |
+ int FillOrderedProfile(char buffer[], int buffer_size); |
+ |
+ private: |
+#ifdef DEEP_HEAP_PROFILE |
+ struct DeepBucket { |
+ Bucket* bucket; |
+ size_t committed_size; |
+ int id; // Unique ID of the bucket. |
+ bool is_logged; // True if the stracktrace is logged to a file. |
+ }; |
+ |
+ typedef AddressMap<DeepBucket> DeepBucketMap; |
+ |
+ struct PageState { |
+ bool is_committed; // Currently, we use only this |
+ bool is_present; |
+ bool is_swapped; |
+ bool is_shared; |
+ bool is_mmap; |
+ }; |
+ |
+ class RegionStats { |
+ public: |
+ RegionStats() {} |
+ ~RegionStats() {} |
+ |
+ // Initialize virtual_bytes and committed_bytes. |
+ void Initialize(); |
+ |
+ // Update the RegionStats to include the tallies of virtual_bytes and |
+ // committed_bytes in the region from |first_adress| to |last_address| |
+ // inclusive. |
+ void Record(int pagemap_fd, uint64 first_address, uint64 last_address); |
+ |
+ size_t virtual_bytes() const { return virtual_bytes_; } |
+ size_t committed_bytes() const { return committed_bytes_; } |
+ void set_virtual_bytes(size_t virtual_bytes) { |
+ virtual_bytes_ = virtual_bytes; |
+ } |
+ void set_committed_bytes(size_t committed_bytes) { |
+ committed_bytes_ = committed_bytes; |
+ } |
+ void AddToVirtualBytes(size_t additional_virtual_bytes) { |
+ virtual_bytes_ += additional_virtual_bytes; |
+ } |
+ void AddToCommittedBytes(size_t additional_committed_bytes) { |
+ committed_bytes_ += additional_committed_bytes; |
+ } |
+ |
+ private: |
+ size_t virtual_bytes_; |
+ size_t committed_bytes_; |
+ DISALLOW_COPY_AND_ASSIGN(RegionStats); |
+ }; |
+ |
+ struct GlobalStats { |
+ // All RegionStats members in this class contain the bytes of virtual |
+ // memory and committed memory. |
+ // TODO(dmikurube): These regions should be classified more precisely later |
+ // for more detailed analysis. |
+ |
+ // Total bytes of the process memory. |
+ RegionStats total; |
+ |
+ // Total bytes of memory which is mapped to a file. |
+ // Regions which contain file paths in the last column of /proc/<pid>/maps. |
+ RegionStats file_mapped; |
+ |
+ // Total bytes of memory which is mapped anonymously. |
+ // Regions which contain nothing in the last column of /proc/<pid>/maps. |
+ RegionStats anonymous; |
+ |
+ // Total bytes of memory which is labeled, but not mapped to any file. |
+ // Regions which contain non-path strings in the last column of |
+ // /proc/<pid>/maps. |
+ RegionStats other; |
+ |
+ // Total bytes of mmap'ed regions. |
+ RegionStats record_mmap; |
+ |
+ // Total bytes of malloc'ed regions. |
+ RegionStats record_malloc; |
+ }; |
+ |
+ // Checks if the length of |printed| characters by snprintf is valid. |
+ static bool IsPrintedStringValid(int printed, |
+ int buffer_size, |
+ int used_in_buffer); |
+ |
+ // Clear the is_logged flag in a DeepBucket object as a callback function |
+ // for DeepBucketMap::Iterate(). |
+ static void ClearIsLogged(const void* pointer, |
+ DeepBucket* db, |
+ DeepHeapProfile* deep_profile); |
+ |
+ // Open /proc/pid/pagemap and return its file descriptor. |
+ // File descriptors need to be refreshed after each fork. |
+ static int OpenProcPagemap(); |
+ |
+ // Seek to the offset of the open pagemap file pagemap_fd. |
+ // It returns true if succeeded. Otherwise, it returns false. |
+ static bool SeekProcPagemap(int pagemap_fd, uint64 address); |
+ |
+ // Read a pagemap state from the current pagemap_fd offset. |
+ // It returns true if succeeded. Otherwise, it returns false. |
+ static bool ReadProcPagemap(int pagemap_fd, PageState* state); |
+ |
+ // Returns the number of resident (including swapped) bytes of the memory |
+ // region starting at |first_address| and ending at |last_address| inclusive. |
+ static size_t GetCommittedSize(int pagemap_fd, |
+ uint64 first_address, |
+ uint64 last_address); |
+ |
+ // Write re-formatted /proc/self/maps into a file which has |filename_prefix| |
+ // with using |buffer| of size |buffer_size|. |
+ static void WriteMapsToFile(const char* filename_prefix, |
+ int buffer_size, |
+ char buffer[]); |
+ |
+ // Compute the global statistics from /proc/self/maps and |pagemap_fd|, and |
+ // store the statistics in |stats|. |
+ static void SnapshotGlobalStatsWithoutMalloc(int pagemap_fd, |
+ GlobalStats* stats); |
+ |
+ // Get the DeepBucket object corresponding to the given |bucket|. |
+ // DeepBucket is an extension to Bucket which is declared above. |
+ DeepBucket* GetDeepBucket(Bucket* bucket); |
+ |
+ // Reset committed_size member variables in DeepBucket objects to 0. |
+ void ResetCommittedSize(Bucket** bucket_table); |
+ |
+ // Fill bucket data in |bucket_table| into buffer |buffer| of size |
+ // |buffer_size|, and return the size occupied by the bucket data in |
+ // |buffer|. |bucket_length| is the offset for |buffer| to start filling. |
+ int SnapshotBucketTableWithoutMalloc(Bucket** bucket_table, |
+ int used_in_buffer, |
+ int buffer_size, |
+ char buffer[]); |
+ |
+ // Record both virtual and committed byte counts of malloc and mmap regions |
+ // as callback functions for AllocationMap::Iterate(). |
+ static void RecordAlloc(const void* pointer, |
+ AllocValue* alloc_value, |
+ DeepHeapProfile* deep_profile); |
+ static void RecordMMap(const void* pointer, |
+ AllocValue* alloc_value, |
+ DeepHeapProfile* deep_profile); |
+ void SnapshotAllAllocsWithoutMalloc(); |
+ |
+ // Fill a bucket (a bucket id and its corresponding calling stack) into |
+ // |buffer| of size |buffer_size|. |
+ int FillBucketForBucketFile(const DeepBucket* deep_bucket, |
+ int buffer_size, |
+ char buffer[]); |
+ |
+ // Write a |bucket_table| into a file of |bucket_fd|. |
+ void WriteBucketsTableToBucketFile(Bucket** bucket_table, RawFD bucket_fd); |
+ |
+ // Write both malloc and mmap bucket tables into a "bucket file". |
+ void WriteBucketsToBucketFile(); |
+ |
+ // Fill a |deep_bucket| and its corresponding bucket into |buffer| from the |
+ // offset |used_in_buffer|. Add the sizes to |profile_stats| if it's not |
+ // NULL. |
+ static int UnparseBucket(const DeepBucket& deep_bucket, |
+ const char* extra, |
+ int used_in_buffer, |
+ int buffer_size, |
+ char* buffer, |
+ Stats* profile_stats); |
+ |
+ // Fill statistics of a region into |buffer|. |
+ static int UnparseRegionStats(const RegionStats* stats, |
+ const char* name, |
+ int used_in_buffer, |
+ int buffer_size, |
+ char* buffer); |
+ |
+ // Fill global statistics into |buffer|. |
+ int UnparseGlobalStats(int used_in_buffer, int buffer_size, char* buffer); |
+ |
+ int pagemap_fd_; // File descriptor of /proc/self/pagemap. |
+ |
+ // Process ID of the last dump. This could change by fork. |
+ pid_t most_recent_pid_; |
+ GlobalStats stats_; // Stats about total memory. |
+ int dump_count_; // The number of dumps. |
+ char* filename_prefix_; // Output file prefix. |
+ char* profiler_buffer_; // Buffer we use many times. |
+ |
+ int bucket_id_; |
+ DeepBucketMap* deep_bucket_map_; |
+#endif // DEEP_HEAP_PROFILE |
+ |
+ HeapProfileTable* heap_profile_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(DeepHeapProfile); |
+}; |
+ |
+#endif // BASE_DEEP_HEAP_PROFILE_H_ |