| OLD | NEW |
| 1 // Copyright 2015 the V8 project authors. All rights reserved. | 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 | 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 #ifndef V8_HEAP_OBJECT_STATS_H_ | 5 #ifndef V8_HEAP_OBJECT_STATS_H_ |
| 6 #define V8_HEAP_OBJECT_STATS_H_ | 6 #define V8_HEAP_OBJECT_STATS_H_ |
| 7 | 7 |
| 8 #include "src/heap/heap.h" | 8 #include "src/heap/heap.h" |
| 9 #include "src/heap/objects-visiting.h" | 9 #include "src/heap/objects-visiting.h" |
| 10 #include "src/objects.h" | 10 #include "src/objects.h" |
| 11 | 11 |
| 12 namespace v8 { | 12 namespace v8 { |
| 13 namespace internal { | 13 namespace internal { |
| 14 | 14 |
| 15 class ObjectStats { | 15 class ObjectStats { |
| 16 public: | 16 public: |
| 17 explicit ObjectStats(Heap* heap) : heap_(heap) {} | 17 explicit ObjectStats(Heap* heap) : heap_(heap) { ClearObjectStats(); } |
| 18 | 18 |
| 19 // ObjectStats are kept in two arrays, counts and sizes. Related stats are | 19 // ObjectStats are kept in two arrays, counts and sizes. Related stats are |
| 20 // stored in a contiguous linear buffer. Stats groups are stored one after | 20 // stored in a contiguous linear buffer. Stats groups are stored one after |
| 21 // another. | 21 // another. |
| 22 enum { | 22 enum { |
| 23 FIRST_CODE_KIND_SUB_TYPE = LAST_TYPE + 1, | 23 FIRST_CODE_KIND_SUB_TYPE = LAST_TYPE + 1, |
| 24 FIRST_FIXED_ARRAY_SUB_TYPE = | 24 FIRST_FIXED_ARRAY_SUB_TYPE = |
| 25 FIRST_CODE_KIND_SUB_TYPE + Code::NUMBER_OF_KINDS, | 25 FIRST_CODE_KIND_SUB_TYPE + Code::NUMBER_OF_KINDS, |
| 26 FIRST_CODE_AGE_SUB_TYPE = | 26 FIRST_CODE_AGE_SUB_TYPE = |
| 27 FIRST_FIXED_ARRAY_SUB_TYPE + LAST_FIXED_ARRAY_SUB_TYPE + 1, | 27 FIRST_FIXED_ARRAY_SUB_TYPE + LAST_FIXED_ARRAY_SUB_TYPE + 1, |
| 28 OBJECT_STATS_COUNT = FIRST_CODE_AGE_SUB_TYPE + Code::kCodeAgeCount + 1 | 28 OBJECT_STATS_COUNT = FIRST_CODE_AGE_SUB_TYPE + Code::kCodeAgeCount + 1 |
| 29 }; | 29 }; |
| 30 | 30 |
| 31 void ClearObjectStats(bool clear_last_time_stats = false); | 31 void ClearObjectStats(bool clear_last_time_stats = false); |
| 32 | 32 |
| 33 void TraceObjectStats(); | |
| 34 void TraceObjectStat(const char* name, int count, int size, double time); | |
| 35 void CheckpointObjectStats(); | 33 void CheckpointObjectStats(); |
| 34 void PrintJSON(const char* key); |
| 36 | 35 |
| 37 void RecordObjectStats(InstanceType type, size_t size) { | 36 void RecordObjectStats(InstanceType type, size_t size) { |
| 38 DCHECK(type <= LAST_TYPE); | 37 DCHECK(type <= LAST_TYPE); |
| 39 object_counts_[type]++; | 38 object_counts_[type]++; |
| 40 object_sizes_[type] += size; | 39 object_sizes_[type] += size; |
| 40 size_histogram_[type][HistogramIndexFromSize(size)]++; |
| 41 } | 41 } |
| 42 | 42 |
| 43 void RecordCodeSubTypeStats(int code_sub_type, int code_age, size_t size) { | 43 void RecordCodeSubTypeStats(int code_sub_type, int code_age, size_t size) { |
| 44 int code_sub_type_index = FIRST_CODE_KIND_SUB_TYPE + code_sub_type; | 44 int code_sub_type_index = FIRST_CODE_KIND_SUB_TYPE + code_sub_type; |
| 45 int code_age_index = | 45 int code_age_index = |
| 46 FIRST_CODE_AGE_SUB_TYPE + code_age - Code::kFirstCodeAge; | 46 FIRST_CODE_AGE_SUB_TYPE + code_age - Code::kFirstCodeAge; |
| 47 DCHECK(code_sub_type_index >= FIRST_CODE_KIND_SUB_TYPE && | 47 DCHECK(code_sub_type_index >= FIRST_CODE_KIND_SUB_TYPE && |
| 48 code_sub_type_index < FIRST_CODE_AGE_SUB_TYPE); | 48 code_sub_type_index < FIRST_CODE_AGE_SUB_TYPE); |
| 49 DCHECK(code_age_index >= FIRST_CODE_AGE_SUB_TYPE && | 49 DCHECK(code_age_index >= FIRST_CODE_AGE_SUB_TYPE && |
| 50 code_age_index < OBJECT_STATS_COUNT); | 50 code_age_index < OBJECT_STATS_COUNT); |
| 51 object_counts_[code_sub_type_index]++; | 51 object_counts_[code_sub_type_index]++; |
| 52 object_sizes_[code_sub_type_index] += size; | 52 object_sizes_[code_sub_type_index] += size; |
| 53 object_counts_[code_age_index]++; | 53 object_counts_[code_age_index]++; |
| 54 object_sizes_[code_age_index] += size; | 54 object_sizes_[code_age_index] += size; |
| 55 const int idx = HistogramIndexFromSize(size); |
| 56 size_histogram_[code_sub_type_index][idx]++; |
| 57 size_histogram_[code_age_index][idx]++; |
| 55 } | 58 } |
| 56 | 59 |
| 57 void RecordFixedArraySubTypeStats(int array_sub_type, size_t size) { | 60 void RecordFixedArraySubTypeStats(int array_sub_type, size_t size, |
| 61 size_t over_allocated) { |
| 58 DCHECK(array_sub_type <= LAST_FIXED_ARRAY_SUB_TYPE); | 62 DCHECK(array_sub_type <= LAST_FIXED_ARRAY_SUB_TYPE); |
| 59 object_counts_[FIRST_FIXED_ARRAY_SUB_TYPE + array_sub_type]++; | 63 object_counts_[FIRST_FIXED_ARRAY_SUB_TYPE + array_sub_type]++; |
| 60 object_sizes_[FIRST_FIXED_ARRAY_SUB_TYPE + array_sub_type] += size; | 64 object_sizes_[FIRST_FIXED_ARRAY_SUB_TYPE + array_sub_type] += size; |
| 65 size_histogram_[FIRST_FIXED_ARRAY_SUB_TYPE + array_sub_type] |
| 66 [HistogramIndexFromSize(size)]++; |
| 67 over_allocated_[FIRST_FIXED_ARRAY_SUB_TYPE + array_sub_type] += |
| 68 over_allocated; |
| 69 over_allocated_histogram_[FIRST_FIXED_ARRAY_SUB_TYPE + array_sub_type] |
| 70 [HistogramIndexFromSize(over_allocated)]++; |
| 61 } | 71 } |
| 62 | 72 |
| 63 size_t object_count_last_gc(size_t index) { | 73 size_t object_count_last_gc(size_t index) { |
| 64 return object_counts_last_time_[index]; | 74 return object_counts_last_time_[index]; |
| 65 } | 75 } |
| 66 | 76 |
| 67 size_t object_size_last_gc(size_t index) { | 77 size_t object_size_last_gc(size_t index) { |
| 68 return object_sizes_last_time_[index]; | 78 return object_sizes_last_time_[index]; |
| 69 } | 79 } |
| 70 | 80 |
| 71 Isolate* isolate(); | 81 Isolate* isolate(); |
| 72 Heap* heap() { return heap_; } | 82 Heap* heap() { return heap_; } |
| 73 | 83 |
| 74 private: | 84 private: |
| 85 static const int kFirstBucketShift = 5; // <=32 |
| 86 static const int kLastBucketShift = 19; // >512k |
| 87 static const int kFirstBucket = 1 << kFirstBucketShift; |
| 88 static const int kLastBucket = 1 << kLastBucketShift; |
| 89 static const int kNumberOfBuckets = kLastBucketShift - kFirstBucketShift; |
| 90 |
| 91 int HistogramIndexFromSize(size_t size) { |
| 92 if (size == 0) return 0; |
| 93 int idx = |
| 94 static_cast<int>(log2(static_cast<double>(size))) - kFirstBucketShift; |
| 95 return idx < 0 ? 0 : idx; |
| 96 } |
| 97 |
| 75 Heap* heap_; | 98 Heap* heap_; |
| 76 | 99 // Object counts and used memory by InstanceType. |
| 77 // Object counts and used memory by InstanceType | |
| 78 size_t object_counts_[OBJECT_STATS_COUNT]; | 100 size_t object_counts_[OBJECT_STATS_COUNT]; |
| 79 size_t object_counts_last_time_[OBJECT_STATS_COUNT]; | 101 size_t object_counts_last_time_[OBJECT_STATS_COUNT]; |
| 80 size_t object_sizes_[OBJECT_STATS_COUNT]; | 102 size_t object_sizes_[OBJECT_STATS_COUNT]; |
| 81 size_t object_sizes_last_time_[OBJECT_STATS_COUNT]; | 103 size_t object_sizes_last_time_[OBJECT_STATS_COUNT]; |
| 104 // Approximation of overallocated memory by InstanceType. |
| 105 size_t over_allocated_[OBJECT_STATS_COUNT]; |
| 106 // Detailed histograms by InstanceType. |
| 107 size_t size_histogram_[OBJECT_STATS_COUNT][kNumberOfBuckets]; |
| 108 size_t over_allocated_histogram_[OBJECT_STATS_COUNT][kNumberOfBuckets]; |
| 82 }; | 109 }; |
| 83 | 110 |
| 84 class ObjectStatsCollector { | 111 class ObjectStatsCollector { |
| 85 public: | 112 public: |
| 86 static void CollectStatistics(StaticVisitorBase::VisitorId id, Map* map, | 113 static void CollectStatistics(ObjectStats* stats, HeapObject* obj); |
| 114 |
| 115 private: |
| 116 static void RecordMapDetails(ObjectStats* stats, Heap* heap, HeapObject* obj); |
| 117 static void RecordCodeDetails(ObjectStats* stats, Heap* heap, |
| 87 HeapObject* obj); | 118 HeapObject* obj); |
| 88 static void CollectFixedArrayStatistics(HeapObject* obj); | 119 static void RecordSharedFunctionInfoDetails(ObjectStats* stats, Heap* heap, |
| 120 HeapObject* obj); |
| 121 static void RecordFixedArrayDetails(ObjectStats* stats, Heap* heap, |
| 122 HeapObject* obj); |
| 89 | 123 |
| 90 static void CountFixedArray(FixedArrayBase* fixed_array, | 124 static void RecordJSObjectDetails(ObjectStats* stats, Heap* heap, |
| 91 FixedArraySubInstanceType fast_type, | 125 JSObject* object); |
| 92 FixedArraySubInstanceType dictionary_type); | 126 static void RecordJSWeakCollectionDetails(ObjectStats* stats, Heap* heap, |
| 93 static void RecordMapStats(Map* map, HeapObject* obj); | 127 JSWeakCollection* obj); |
| 94 static void RecordCodeStats(Map* map, HeapObject* obj); | |
| 95 static void RecordSharedFunctionInfoStats(Map* map, HeapObject* obj); | |
| 96 static void RecordFixedArrayStats(Map* map, HeapObject* obj); | |
| 97 }; | |
| 98 | |
| 99 class MarkCompactObjectStatsVisitor | |
| 100 : public StaticMarkingVisitor<MarkCompactObjectStatsVisitor> { | |
| 101 public: | |
| 102 static void Initialize(VisitorDispatchTable<Callback>* original); | |
| 103 | |
| 104 template <VisitorId id> | |
| 105 static inline void Visit(Map* map, HeapObject* obj); | |
| 106 }; | |
| 107 | |
| 108 class IncrementalMarkingObjectStatsVisitor | |
| 109 : public StaticMarkingVisitor<IncrementalMarkingObjectStatsVisitor> { | |
| 110 public: | |
| 111 static void Initialize(VisitorDispatchTable<Callback>* original); | |
| 112 | |
| 113 template <VisitorId id> | |
| 114 static inline void Visit(Map* map, HeapObject* obj); | |
| 115 }; | 128 }; |
| 116 | 129 |
| 117 } // namespace internal | 130 } // namespace internal |
| 118 } // namespace v8 | 131 } // namespace v8 |
| 119 | 132 |
| 120 #endif // V8_HEAP_OBJECT_STATS_H_ | 133 #endif // V8_HEAP_OBJECT_STATS_H_ |
| OLD | NEW |