Home | History | Annotate | Download | only in extensions
      1 // Copyright 2012 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 #include "src/extensions/statistics-extension.h"
      6 
      7 #include "src/counters.h"
      8 #include "src/heap/heap-inl.h"
      9 #include "src/isolate.h"
     10 
     11 namespace v8 {
     12 namespace internal {
     13 
     14 const char* const StatisticsExtension::kSource =
     15     "native function getV8Statistics();";
     16 
     17 
     18 v8::Local<v8::FunctionTemplate> StatisticsExtension::GetNativeFunctionTemplate(
     19     v8::Isolate* isolate, v8::Local<v8::String> str) {
     20   DCHECK(strcmp(*v8::String::Utf8Value(str), "getV8Statistics") == 0);
     21   return v8::FunctionTemplate::New(isolate, StatisticsExtension::GetCounters);
     22 }
     23 
     24 
     25 static void AddCounter(v8::Isolate* isolate,
     26                        v8::Local<v8::Object> object,
     27                        StatsCounter* counter,
     28                        const char* name) {
     29   if (counter->Enabled()) {
     30     object->Set(isolate->GetCurrentContext(),
     31                 v8::String::NewFromUtf8(isolate, name, NewStringType::kNormal)
     32                     .ToLocalChecked(),
     33                 v8::Number::New(isolate, *counter->GetInternalPointer()))
     34         .FromJust();
     35   }
     36 }
     37 
     38 static void AddNumber(v8::Isolate* isolate, v8::Local<v8::Object> object,
     39                       double value, const char* name) {
     40   object
     41       ->Set(isolate->GetCurrentContext(),
     42             v8::String::NewFromUtf8(isolate, name, NewStringType::kNormal)
     43                 .ToLocalChecked(),
     44             v8::Number::New(isolate, value))
     45       .FromJust();
     46 }
     47 
     48 
     49 static void AddNumber64(v8::Isolate* isolate,
     50                         v8::Local<v8::Object> object,
     51                         int64_t value,
     52                         const char* name) {
     53   object->Set(isolate->GetCurrentContext(),
     54               v8::String::NewFromUtf8(isolate, name, NewStringType::kNormal)
     55                   .ToLocalChecked(),
     56               v8::Number::New(isolate, static_cast<double>(value))).FromJust();
     57 }
     58 
     59 
     60 void StatisticsExtension::GetCounters(
     61     const v8::FunctionCallbackInfo<v8::Value>& args) {
     62   Isolate* isolate = reinterpret_cast<Isolate*>(args.GetIsolate());
     63   Heap* heap = isolate->heap();
     64 
     65   if (args.Length() > 0) {  // GC if first argument evaluates to true.
     66     if (args[0]->IsBoolean() &&
     67         args[0]
     68             ->BooleanValue(args.GetIsolate()->GetCurrentContext())
     69             .FromMaybe(false)) {
     70       heap->CollectAllGarbage(Heap::kNoGCFlags,
     71                               GarbageCollectionReason::kCountersExtension);
     72     }
     73   }
     74 
     75   Counters* counters = isolate->counters();
     76   v8::Local<v8::Object> result = v8::Object::New(args.GetIsolate());
     77 
     78   struct StatisticsCounter {
     79     v8::internal::StatsCounter* counter;
     80     const char* name;
     81   };
     82   const StatisticsCounter counter_list[] = {
     83 #define ADD_COUNTER(name, caption) \
     84   { counters->name(), #name }      \
     85   ,
     86 
     87       STATS_COUNTER_LIST_1(ADD_COUNTER) STATS_COUNTER_LIST_2(ADD_COUNTER)
     88 #undef ADD_COUNTER
     89 #define ADD_COUNTER(name)                            \
     90   { counters->count_of_##name(), "count_of_" #name } \
     91   , {counters->size_of_##name(), "size_of_" #name},
     92 
     93           INSTANCE_TYPE_LIST(ADD_COUNTER)
     94 #undef ADD_COUNTER
     95 #define ADD_COUNTER(name)                                                \
     96   { counters->count_of_CODE_TYPE_##name(), "count_of_CODE_TYPE_" #name } \
     97   , {counters->size_of_CODE_TYPE_##name(), "size_of_CODE_TYPE_" #name},
     98 
     99               CODE_KIND_LIST(ADD_COUNTER)
    100 #undef ADD_COUNTER
    101 #define ADD_COUNTER(name)                                                    \
    102   { counters->count_of_FIXED_ARRAY_##name(), "count_of_FIXED_ARRAY_" #name } \
    103   , {counters->size_of_FIXED_ARRAY_##name(), "size_of_FIXED_ARRAY_" #name},
    104 
    105                   FIXED_ARRAY_SUB_INSTANCE_TYPE_LIST(ADD_COUNTER)
    106 #undef ADD_COUNTER
    107   };  // End counter_list array.
    108 
    109   for (size_t i = 0; i < arraysize(counter_list); i++) {
    110     AddCounter(args.GetIsolate(), result, counter_list[i].counter,
    111                counter_list[i].name);
    112   }
    113 
    114   struct StatisticNumber {
    115     size_t number;
    116     const char* name;
    117   };
    118 
    119   const StatisticNumber numbers[] = {
    120       {heap->memory_allocator()->Size(), "total_committed_bytes"},
    121       {heap->new_space()->Size(), "new_space_live_bytes"},
    122       {heap->new_space()->Available(), "new_space_available_bytes"},
    123       {heap->new_space()->CommittedMemory(), "new_space_commited_bytes"},
    124       {heap->old_space()->Size(), "old_space_live_bytes"},
    125       {heap->old_space()->Available(), "old_space_available_bytes"},
    126       {heap->old_space()->CommittedMemory(), "old_space_commited_bytes"},
    127       {heap->code_space()->Size(), "code_space_live_bytes"},
    128       {heap->code_space()->Available(), "code_space_available_bytes"},
    129       {heap->code_space()->CommittedMemory(), "code_space_commited_bytes"},
    130       {heap->lo_space()->Size(), "lo_space_live_bytes"},
    131       {heap->lo_space()->Available(), "lo_space_available_bytes"},
    132       {heap->lo_space()->CommittedMemory(), "lo_space_commited_bytes"},
    133   };
    134 
    135   for (size_t i = 0; i < arraysize(numbers); i++) {
    136     AddNumber(args.GetIsolate(), result, numbers[i].number, numbers[i].name);
    137   }
    138 
    139   AddNumber64(args.GetIsolate(), result, heap->external_memory(),
    140               "amount_of_external_allocated_memory");
    141   args.GetReturnValue().Set(result);
    142 
    143   HeapIterator iterator(reinterpret_cast<Isolate*>(args.GetIsolate())->heap());
    144   HeapObject* obj;
    145   int reloc_info_total = 0;
    146   int source_position_table_total = 0;
    147   while ((obj = iterator.next())) {
    148     if (obj->IsCode()) {
    149       Code* code = Code::cast(obj);
    150       reloc_info_total += code->relocation_info()->Size();
    151       ByteArray* source_position_table = code->source_position_table();
    152       if (source_position_table->length() > 0) {
    153         source_position_table_total += code->source_position_table()->Size();
    154       }
    155     } else if (obj->IsBytecodeArray()) {
    156       source_position_table_total +=
    157           BytecodeArray::cast(obj)->source_position_table()->Size();
    158     }
    159   }
    160 
    161   AddNumber(args.GetIsolate(), result, reloc_info_total,
    162             "reloc_info_total_size");
    163   AddNumber(args.GetIsolate(), result, source_position_table_total,
    164             "source_position_table_total_size");
    165 }
    166 
    167 }  // namespace internal
    168 }  // namespace v8
    169