1 // Copyright 2015 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef V8_HEAP_OBJECT_STATS_H_ 6 #define V8_HEAP_OBJECT_STATS_H_ 7 8 #include <set> 9 10 #include "src/base/ieee754.h" 11 #include "src/heap/heap.h" 12 #include "src/heap/objects-visiting.h" 13 #include "src/objects.h" 14 15 namespace v8 { 16 namespace internal { 17 18 class ObjectStats { 19 public: ObjectStats(Heap * heap)20 explicit ObjectStats(Heap* heap) : heap_(heap) { ClearObjectStats(); } 21 22 // ObjectStats are kept in two arrays, counts and sizes. Related stats are 23 // stored in a contiguous linear buffer. Stats groups are stored one after 24 // another. 25 enum { 26 FIRST_CODE_KIND_SUB_TYPE = LAST_TYPE + 1, 27 FIRST_FIXED_ARRAY_SUB_TYPE = 28 FIRST_CODE_KIND_SUB_TYPE + Code::NUMBER_OF_KINDS, 29 FIRST_CODE_AGE_SUB_TYPE = 30 FIRST_FIXED_ARRAY_SUB_TYPE + LAST_FIXED_ARRAY_SUB_TYPE + 1, 31 OBJECT_STATS_COUNT = FIRST_CODE_AGE_SUB_TYPE + Code::kCodeAgeCount + 1 32 }; 33 34 void ClearObjectStats(bool clear_last_time_stats = false); 35 36 void CheckpointObjectStats(); 37 void PrintJSON(const char* key); 38 void Dump(std::stringstream& stream); 39 RecordObjectStats(InstanceType type,size_t size)40 void RecordObjectStats(InstanceType type, size_t size) { 41 DCHECK(type <= LAST_TYPE); 42 object_counts_[type]++; 43 object_sizes_[type] += size; 44 size_histogram_[type][HistogramIndexFromSize(size)]++; 45 } 46 RecordCodeSubTypeStats(int code_sub_type,int code_age,size_t size)47 void RecordCodeSubTypeStats(int code_sub_type, int code_age, size_t size) { 48 int code_sub_type_index = FIRST_CODE_KIND_SUB_TYPE + code_sub_type; 49 int code_age_index = 50 FIRST_CODE_AGE_SUB_TYPE + code_age - Code::kFirstCodeAge; 51 DCHECK(code_sub_type_index >= FIRST_CODE_KIND_SUB_TYPE && 52 code_sub_type_index < FIRST_CODE_AGE_SUB_TYPE); 53 DCHECK(code_age_index >= FIRST_CODE_AGE_SUB_TYPE && 54 code_age_index < OBJECT_STATS_COUNT); 55 object_counts_[code_sub_type_index]++; 56 object_sizes_[code_sub_type_index] += size; 57 object_counts_[code_age_index]++; 58 object_sizes_[code_age_index] += size; 59 const int idx = HistogramIndexFromSize(size); 60 size_histogram_[code_sub_type_index][idx]++; 61 size_histogram_[code_age_index][idx]++; 62 } 63 RecordFixedArraySubTypeStats(FixedArrayBase * array,int array_sub_type,size_t size,size_t over_allocated)64 bool RecordFixedArraySubTypeStats(FixedArrayBase* array, int array_sub_type, 65 size_t size, size_t over_allocated) { 66 auto it = visited_fixed_array_sub_types_.insert(array); 67 if (!it.second) return false; 68 DCHECK(array_sub_type <= LAST_FIXED_ARRAY_SUB_TYPE); 69 object_counts_[FIRST_FIXED_ARRAY_SUB_TYPE + array_sub_type]++; 70 object_sizes_[FIRST_FIXED_ARRAY_SUB_TYPE + array_sub_type] += size; 71 size_histogram_[FIRST_FIXED_ARRAY_SUB_TYPE + array_sub_type] 72 [HistogramIndexFromSize(size)]++; 73 if (over_allocated > 0) { 74 over_allocated_[FIRST_FIXED_ARRAY_SUB_TYPE + array_sub_type] += 75 over_allocated; 76 over_allocated_histogram_[FIRST_FIXED_ARRAY_SUB_TYPE + array_sub_type] 77 [HistogramIndexFromSize(over_allocated)]++; 78 over_allocated_[InstanceType::FIXED_ARRAY_TYPE] += over_allocated; 79 over_allocated_histogram_[InstanceType::FIXED_ARRAY_TYPE] 80 [HistogramIndexFromSize(over_allocated)]++; 81 } 82 return true; 83 } 84 object_count_last_gc(size_t index)85 size_t object_count_last_gc(size_t index) { 86 return object_counts_last_time_[index]; 87 } 88 object_size_last_gc(size_t index)89 size_t object_size_last_gc(size_t index) { 90 return object_sizes_last_time_[index]; 91 } 92 93 Isolate* isolate(); heap()94 Heap* heap() { return heap_; } 95 96 private: 97 static const int kFirstBucketShift = 5; // <=32 98 static const int kLastBucketShift = 19; // >512k 99 static const int kFirstBucket = 1 << kFirstBucketShift; 100 static const int kLastBucket = 1 << kLastBucketShift; 101 static const int kNumberOfBuckets = kLastBucketShift - kFirstBucketShift + 1; 102 103 void PrintKeyAndId(const char* key, int gc_count); 104 // The following functions are excluded from inline to reduce the overall 105 // binary size of VB. On x64 this save around 80KB. 106 V8_NOINLINE void PrintInstanceTypeJSON(const char* key, int gc_count, 107 const char* name, int index); 108 V8_NOINLINE void DumpInstanceTypeData(std::stringstream& stream, 109 const char* name, int index); 110 HistogramIndexFromSize(size_t size)111 int HistogramIndexFromSize(size_t size) { 112 if (size == 0) return 0; 113 int idx = static_cast<int>(base::ieee754::log2(static_cast<double>(size))) - 114 kFirstBucketShift; 115 return idx < 0 ? 0 : idx; 116 } 117 118 Heap* heap_; 119 // Object counts and used memory by InstanceType. 120 size_t object_counts_[OBJECT_STATS_COUNT]; 121 size_t object_counts_last_time_[OBJECT_STATS_COUNT]; 122 size_t object_sizes_[OBJECT_STATS_COUNT]; 123 size_t object_sizes_last_time_[OBJECT_STATS_COUNT]; 124 // Approximation of overallocated memory by InstanceType. 125 size_t over_allocated_[OBJECT_STATS_COUNT]; 126 // Detailed histograms by InstanceType. 127 size_t size_histogram_[OBJECT_STATS_COUNT][kNumberOfBuckets]; 128 size_t over_allocated_histogram_[OBJECT_STATS_COUNT][kNumberOfBuckets]; 129 130 std::set<FixedArrayBase*> visited_fixed_array_sub_types_; 131 }; 132 133 class ObjectStatsCollector { 134 public: ObjectStatsCollector(Heap * heap,ObjectStats * stats)135 ObjectStatsCollector(Heap* heap, ObjectStats* stats) 136 : heap_(heap), stats_(stats) {} 137 138 void CollectGlobalStatistics(); 139 void CollectStatistics(HeapObject* obj); 140 141 private: 142 class CompilationCacheTableVisitor; 143 144 void RecordBytecodeArrayDetails(BytecodeArray* obj); 145 void RecordCodeDetails(Code* code); 146 void RecordFixedArrayDetails(FixedArray* array); 147 void RecordJSCollectionDetails(JSObject* obj); 148 void RecordJSFunctionDetails(JSFunction* function); 149 void RecordJSObjectDetails(JSObject* object); 150 void RecordJSWeakCollectionDetails(JSWeakCollection* obj); 151 void RecordMapDetails(Map* map); 152 void RecordScriptDetails(Script* obj); 153 void RecordTemplateInfoDetails(TemplateInfo* obj); 154 void RecordSharedFunctionInfoDetails(SharedFunctionInfo* sfi); 155 156 bool RecordFixedArrayHelper(HeapObject* parent, FixedArray* array, 157 int subtype, size_t overhead); 158 void RecursivelyRecordFixedArrayHelper(HeapObject* parent, FixedArray* array, 159 int subtype); 160 template <class HashTable> 161 void RecordHashTableHelper(HeapObject* parent, HashTable* array, int subtype); 162 Heap* heap_; 163 ObjectStats* stats_; 164 165 friend class ObjectStatsCollector::CompilationCacheTableVisitor; 166 }; 167 168 } // namespace internal 169 } // namespace v8 170 171 #endif // V8_HEAP_OBJECT_STATS_H_ 172