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