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
15namespace v8 {
16namespace internal {
17
18class ObjectStats {
19 public:
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
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
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
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
85  size_t object_count_last_gc(size_t index) {
86    return object_counts_last_time_[index];
87  }
88
89  size_t object_size_last_gc(size_t index) {
90    return object_sizes_last_time_[index];
91  }
92
93  Isolate* isolate();
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
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
133class ObjectStatsCollector {
134 public:
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