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 
GetNativeFunctionTemplate(v8::Isolate * isolate,v8::Local<v8::String> str)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 
AddCounter(v8::Isolate * isolate,v8::Local<v8::Object> object,StatsCounter * counter,const char * name)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 
AddNumber(v8::Isolate * isolate,v8::Local<v8::Object> object,double value,const char * name)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 
AddNumber64(v8::Isolate * isolate,v8::Local<v8::Object> object,int64_t value,const char * name)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 
GetCounters(const v8::FunctionCallbackInfo<v8::Value> & args)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