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