Home | History | Annotate | Download | only in heap
      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:
     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 
    133 class 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